1
2
3
4 """ Provides elementary calculus functions sqrt, exp, log, sin, etc and constants pi, E.
5 """
6
7 __all__ = ['sqrt', 'exp', 'log', 'sin', 'cos', 'tan', 'cot', 'sign', 'E', 'pi', 'gamma']
8 __docformat__ = "restructuredtext"
9
10 from ..algebra import Calculus, I, NUMBER, TERMS, FACTORS, SYMBOL, TERMS
11 from ..infinity import oo, undefined, CalculusInfinity
12 from ..constants import const_pi, const_E, const_gamma
13 from ..function import Function
14 from ...arithmetic.evalf import evalf
15 from ...arithmetic.numbers import complextypes, realtypes, inttypes
16 from ...arithmetic.number_theory import factorial
17 from ...arithmetic import infinity
18
19 import math
20
21 zero = Calculus.zero
22 one = Calculus.one
23 half = one/2
24 sqrt2 = Calculus.convert('2**(1/2)')
25 sqrt3 = Calculus.convert('3**(1/2)')
26
27
28
29
30
31 pi = const_pi.as_algebra(Calculus)
32 E = const_E.as_algebra(Calculus)
33 gamma = const_gamma.as_algebra(Calculus)
34
35 Ipi = I*pi
36 Ipi2 = Ipi/2
37
38 -class sign(Function):
43
44 -class sqrt(Function):
47
55
56 log_number_table = {
57 zero.data : -oo,
58 one.data : zero,
59 I.data : Ipi2,
60 (-I).data : -Ipi2
61 }
62
65 if type(arg) is not Calculus:
66 if isinstance(arg, CalculusInfinity):
67 if arg == oo:
68 return oo
69 if arg == undefined:
70 return undefined
71 return Calculus(cls, arg)
72 else:
73 arg = Calculus.convert(arg)
74 if base != E:
75 base = Calculus.convert(base)
76 bd = base.data
77 ad = arg.data
78 if base.head is NUMBER and isinstance(bd, inttypes) and \
79 arg.head is NUMBER and isinstance(ad, inttypes) and \
80 ad > 0 and bd > 1:
81 l = int(math.log(ad, bd) + 0.5)
82 if bd**l == ad:
83 return Calculus.convert(l)
84 return cls(arg) / cls(base)
85 head = arg.head
86 data = arg.data
87 if head is NUMBER:
88 v = log_number_table.get(data)
89 if v is not None:
90 return v
91 if isinstance(data, realtypes) and data < 0:
92 return Ipi + log(-arg)
93 if isinstance(data, complextypes) and data.real == 0:
94 im = data.imag
95 if im > 0: return Calculus(cls, Calculus(NUMBER, im)) + Ipi2
96 if im < 0: return Calculus(cls, Calculus(NUMBER, -im)) - Ipi2
97 return Calculus(cls, arg)
98 if arg == E:
99 return one
100 from ..relational import is_positive
101 if head is FACTORS and len(data) == 1:
102 base, expt = data.items()[0]
103 if is_positive(base) and isinstance(expt, realtypes):
104 return Calculus(cls, base) * expt
105 if head is TERMS and len(data) == 1:
106 term, coeff = data.items()[0]
107 if (isinstance(coeff, realtypes) and coeff < 0) and is_positive(base):
108 return Ipi + log(-arg)
109 return Calculus(cls, arg)
110
111 @classmethod
114
115 @classmethod
118
119
120
121
122
123
124 C0 = (sqrt3-1)/(2*sqrt2)
125 C1 = one/2
126 C2 = sqrt2/2
127 C3 = sqrt3/2
128 C4 = (sqrt3+1)/(2*sqrt2)
129
130
131 sine_table = [ \
132 Calculus.zero, C0, C1, C2, C3, C4, Calculus.one, C4, C3, C2, C1,C0,
133 Calculus.zero,-C0,-C1,-C2,-C3,-C4,-Calculus.one,-C4,-C3,-C2,-C1,-C0]
134
136 """Parse as x, n where arg = x + n*pi/N"""
137 if arg.head is TERMS:
138
139 if len(arg.data) == 1:
140 e, c = arg.data.items()[0]
141 if e == pi:
142 c *= N
143 if isinstance(c, (int, long)):
144 return zero, c
145 c = arg.data.get(pi)
146 if c is not None:
147 c *= N
148 if isinstance(c, (int, long)):
149 d = arg.data.copy()
150 d.pop(pi)
151 return Calculus.Terms(*d.items()), c
152 return arg, 0
153 if arg == pi:
154 return zero, N
155 return arg, 0
156
158 """Detect symmetry cases for odd/even functions."""
159 if arg.head is NUMBER:
160 if arg < 0:
161 return True
162 if arg.head is TERMS and len(arg.data) == 1:
163 e, c = arg.data.items()[0]
164 if c < 0:
165 return True
166 return None
167
209
210 -class sin(TrigonometricFunction):
211 parity = 'odd'
212 period = 2
213 @classmethod
216
217 @classmethod
221
222 @classmethod
225
226 -class cos(TrigonometricFunction):
227 parity = 'even'
228 period = 2
229
230 @classmethod
233
234 @classmethod
237
238 @classmethod
241
242 -class tan(TrigonometricFunction):
243 parity = 'odd'
244 period = 1
245
246 @classmethod
248 a = sine_table[m % 24]
249 b = sine_table[(m+6) % 24]
250 if a == None or b == None:
251 return
252 return a / b
253
254 @classmethod
257
258 -class cot(TrigonometricFunction):
259 parity = 'odd'
260 period = 1
261
262 @classmethod
264 a = sine_table[m % 24]
265 b = sine_table[(m+6) % 24]
266 if a == None or b == None:
267 return
268 return b / a
269
270 @classmethod
273
274
275 conjugates = {
276 sin : cos,
277 cos : sin,
278 tan : cot,
279 cot : tan
280 }
281