2 from sympy
.core
.basic
import Basic
, S
, cache_it
, cache_it_immutable
3 from sympy
.core
.function
import Lambda
, SingleValuedFunction
, Function
5 class exp(SingleValuedFunction
):
9 def fdiff(self
, argindex
=1):
13 raise ArgumentIndexError(self
, argindex
)
15 def inverse(self
, argindex
=1):
19 def _eval_apply_subs(self
, *args
):
22 #XXX: investigate why we need the **optionsXXX and remove it
24 def canonize(cls
, arg
, **optionsXXX
):
25 arg
= Basic
.sympify(arg
)
27 if isinstance(arg
, Basic
.Number
):
28 if isinstance(arg
, Basic
.NaN
):
30 elif isinstance(arg
, Basic
.Zero
):
32 elif isinstance(arg
, Basic
.One
):
34 elif isinstance(arg
, Basic
.Infinity
):
36 elif isinstance(arg
, Basic
.NegativeInfinity
):
38 elif isinstance(arg
, log
):
40 elif isinstance(arg
, Basic
.Mul
):
41 coeff
= arg
.as_coefficient(S
.Pi
*S
.ImaginaryUnit
)
44 if isinstance(2*coeff
, Basic
.Integer
):
52 return cst_table
[int(2*coeff
) % 4]
54 if isinstance(arg
, Basic
.Add
):
59 included
, excluded
= [], []
62 coeff
, terms
= arg
.as_coeff_terms()
64 if isinstance(coeff
, Basic
.Infinity
):
65 excluded
.append(coeff
**Basic
.Mul(*terms
))
67 coeffs
, log_term
= [coeff
], None
70 if isinstance(term
, log
):
76 elif term
.is_comparable
:
81 if log_term
is not None:
82 excluded
.append(log_term
**Basic
.Mul(*coeffs
))
87 return Basic
.Mul(*(excluded
+[cls(Basic
.Add(*included
))]))
91 def taylor_term(self
, n
, x
, *previous_terms
):
96 p
= previous_terms
[-1]
99 return x
**n
/Basic
.Factorial()(n
)
101 def _eval_expand_complex(self
, *args
):
102 re
, im
= self
[0].as_real_imag()
103 cos
, sin
= Basic
.cos(im
), Basic
.sin(im
)
104 return exp(re
) * cos
+ S
.ImaginaryUnit
* exp(re
) * sin
106 def _eval_conjugate(self
):
107 return self
.func(self
[0].conjugate())
109 def as_base_exp(self
):
110 coeff
, terms
= self
[0].as_coeff_terms()
111 return self
.func(Basic
.Mul(*terms
)), coeff
113 def as_coeff_terms(self
, x
=None):
116 c
,f
= arg
.as_coeff_factors(x
)
117 return self
.func(c
), [self
.func(a
) for a
in f
]
118 if isinstance(arg
, Basic
.Add
):
119 return S
.One
, [self
.func(a
) for a
in arg
]
122 def _eval_subs(self
, old
, new
):
123 if self
==old
: return new
126 if isinstance(old
, Basic
.Pow
): # handle (exp(3*log(x))).subs(x**2, z) -> z**(3/2)
127 old
= exp(old
.exp
* S
.Log(old
.base
))
128 if isinstance(old
, exp
):
129 b
,e
= self
.as_base_exp()
130 bo
,eo
= old
.as_base_exp()
132 return new
** (e
/eo
) # exp(2/3*x*3).subs(exp(3*x),y) -> y**(2/3)
133 if isinstance(arg
, Basic
.Add
): # exp(2*x+a).subs(exp(3*x),y) -> y**(2/3) * exp(a)
134 # exp(exp(x) + exp(x**2)).subs(exp(exp(x)), w) -> w * exp(exp(x**2))
138 coeff2
,terms2
= oarg
.as_coeff_terms()
141 coeff1
,terms1
= a
.as_coeff_terms()
143 new_l
.append(new
**(coeff1
/coeff2
))
145 old_al
.append(a
.subs(old
, new
))
147 new_l
.append(self
.func(Basic
.Add(*old_al
)))
148 r
= Basic
.Mul(*new_l
)
151 return Function
._eval
_subs
(self
, old
, new
)
153 def _eval_is_real(self
):
154 return self
[0].is_real
155 def _eval_is_positive(self
):
158 def _eval_is_bounded(self
):
161 if arg
.is_negative
: return True
162 if arg
.is_positive
: return False
167 def _eval_is_zero(self
):
168 return isinstance(self
[0], Basic
.NegativeInfinity
)
170 def _eval_power(b
, e
):
171 """exp(b[0])**e -> exp(b[0]*e)"""
174 def _eval_oseries(self
, order
):
175 #XXX quick hack, to pass the tests:
176 #print "XX", self, order
177 #w = Basic.Symbol("w")
178 #if self[0] == (1 + w)*(-log(w) + log(Basic.sin(2*w))):
179 # if order == Basic.Order(w**3,w):
183 #if self[0] == w*log(2*Basic.cos(w)*Basic.sin(w)) - w*log(w):
184 # if order == Basic.Order(w**3,w):
185 # return 1 + w*log(2) + w**2*log(2)**2/2
188 #if self[0] == (1 + w)*log(1/w*Basic.sin(2*w)):
189 # return exp((1 + w)*(-log(w) + log(Basic.sin(2*w))))
192 # self = exp(log(1 + x)/x)
199 if not Basic
.Order(1,x
).contains(arg
): # singularity
200 arg0
= arg
.as_leading_term(x
)
201 d
= (arg
-arg0
).limit(x
, S
.Zero
)
202 if not isinstance(d
, Basic
.Zero
):
205 # arg = log(1+x)/x ~ O(1)
206 arg0
= arg
.limit(x
, S
.Zero
)
208 o
= order
* exp(-arg0
)
209 # o = O(x**2) * exp(-1)
210 return self
._compute
_oseries
(arg
-arg0
, o
, exp
.taylor_term
, exp
) * exp(arg0
)
212 def _eval_as_leading_term(self
, x
):
214 if isinstance(arg
, Basic
.Add
):
215 return Basic
.Mul(*[exp(f
).as_leading_term(x
) for f
in arg
])
216 arg
= self
[0].as_leading_term(x
)
217 if Basic
.Order(1,x
).contains(arg
):
221 def _eval_expand_basic(self
, *args
):
222 arg
= self
[0].expand()
223 if isinstance(arg
, Basic
.Add
):
226 expr
*= self
.func(x
).expand()
228 return self
.func(arg
)
231 import sage
.all
as sage
232 return sage
.exp(self
[0]._sage
_())
234 class log(SingleValuedFunction
):
239 def fdiff(self
, argindex
=1):
242 s
= Basic
.Symbol('x', dummy
=True)
243 return Lambda(s
**(-1), s
)
245 raise ArgumentIndexError(self
, argindex
)
247 def inverse(self
, argindex
=1):
251 def _eval_apply_subs(self
, *args
):
254 #XXX: why is the fixme parameter needed here?
256 def canonize(cls
, arg
, base
=None, **fixme
):
258 base
= Basic
.sympify(base
)
260 if not isinstance(base
, Basic
.Exp1
):
261 return cls(arg
)/cls(base
)
263 arg
= Basic
.sympify(arg
)
265 if isinstance(arg
, Basic
.Number
):
266 if isinstance(arg
, Basic
.Zero
):
267 return S
.NegativeInfinity
268 elif isinstance(arg
, Basic
.One
):
270 elif isinstance(arg
, Basic
.Infinity
):
272 elif isinstance(arg
, Basic
.NegativeInfinity
):
274 elif isinstance(arg
, Basic
.NaN
):
276 elif arg
.is_negative
:
277 return S
.Pi
* S
.ImaginaryUnit
+ cls(-arg
)
278 elif isinstance(arg
, Basic
.Exp1
):
280 #this doesn't work due to caching: :(
281 #elif isinstance(arg, exp) and arg[0].is_real:
282 #using this one instead:
283 elif isinstance(arg
, exp
):
285 #this shouldn't happen automatically (see the issue 252):
286 #elif isinstance(arg, Basic.Pow):
287 # if isinstance(arg.exp, Basic.Number) or \
288 # isinstance(arg.exp, Basic.NumberSymbol) or arg.exp.is_number:
289 # return arg.exp * self(arg.base)
290 #elif isinstance(arg, Basic.Mul) and arg.is_real:
291 # return Basic.Add(*[self(a) for a in arg])
292 elif not isinstance(arg
, Basic
.Add
):
293 coeff
= arg
.as_coefficient(S
.ImaginaryUnit
)
295 if coeff
is not None:
296 if isinstance(coeff
, Basic
.Infinity
):
298 elif isinstance(coeff
, Basic
.NegativeInfinity
):
300 elif isinstance(coeff
, Basic
.Rational
):
301 if coeff
.is_nonnegative
:
302 return S
.Pi
* S
.ImaginaryUnit
* S
.Half
+ cls(coeff
)
304 return -S
.Pi
* S
.ImaginaryUnit
* S
.Half
+ cls(-coeff
)
306 def as_base_exp(self
):
309 return exp
, S
.NegativeOne
311 def _calc_apply_positive(self
, x
):
312 if x
.is_positive
and x
.is_unbounded
: return True
314 def _calc_apply_unbounded(self
, x
):
315 return x
.is_unbounded
319 def taylor_term(self
, n
, x
, *previous_terms
): # of log(1+x)
320 if n
<0: return S
.Zero
324 p
= previous_terms
[-1]
326 return (-n
) * p
* x
/ (n
+1)
327 return (1-2*(n
%2)) * x
**(n
+1)/(n
+1)
329 def _eval_expand_complex(self
, *args
):
330 re
, im
= self
[0].as_real_imag()
331 return S
.Log(S
.Sqrt(re
) + S
.Sqrt(im
)) + \
332 S
.ImaginaryUnit
* S
.Arg(self
[0])
334 def _eval_is_real(self
):
335 return self
[0].is_positive
337 def _eval_is_bounded(self
):
339 if arg
.is_infinitesimal
:
341 return arg
.is_bounded
343 def _eval_is_positive(self
):
346 if arg
.is_unbounded
: return True
347 if arg
.is_infinitesimal
: return False
348 if isinstance(arg
, Basic
.Number
):
351 def _eval_is_zero(self
):
352 # XXX This is not quite useless. Try evaluating log(0.5).is_negative
353 # without it. There's probably a nicer way though.
354 return isinstance(self
[0], Basic
.One
)
356 def as_numer_denom(self
):
357 n
, d
= self
[0].as_numer_denom()
358 if isinstance(d
, Basic
.One
):
359 return self
.func(n
), d
360 return (self
.func(n
) - self
.func(d
)).as_numer_denom()
362 # similar code must be added to other functions with have singularites
363 # in their domains eg. cot(), tan() ...
364 # the trick is to factor out the singularity and leave it as is, and expand
365 # the rest, that can be expanded.
366 def _eval_oseries(self
, order
):
370 use_lt
= not Basic
.Order(1,x
).contains(arg
)
372 arg0
= arg
.limit(x
, 0)
373 use_lt
= isinstance(arg0
, Basic
.Zero
)
374 if use_lt
: # singularity, #example: self = log(sin(x))
375 # arg = (arg / lt) * lt
376 lt
= arg
.as_leading_term(x
) # arg = sin(x); lt = x
377 a
= (arg
/lt
).expand() # a = sin(x)/x
378 #the idea is to recursively call ln(a).series(), but the problem
379 #is, that ln(sin(x)/x) gets "simplified" to -log(x)+ln(sin(x)) and
380 #an infinite recursion occurs, see also the issue 252.
381 return ln(lt
) + ln(a
).oseries(order
)
382 # arg -> arg0 + (arg - arg0) -> arg0 * (1 + (arg/arg0 - 1))
384 return self
._compute
_oseries
(z
, order
, ln
.taylor_term
, lambda z
: ln(1+z
)) + ln(arg0
)
386 def _eval_as_leading_term(self
, x
):
387 arg
= self
[0].as_leading_term(x
)
388 if isinstance(arg
, Basic
.One
):
389 return (self
[0] - 1).as_leading_term(x
)
390 return self
.func(arg
)
392 def _eval_expand_basic(self
, *args
):
394 if isinstance(arg
, Basic
.Mul
) and arg
.is_real
:
397 expr
+= self
.func(x
).expand()
399 elif isinstance(arg
, Basic
.Pow
):
400 if isinstance(arg
.exp
, Basic
.Number
) or \
401 isinstance(arg
.exp
, Basic
.NumberSymbol
):
402 return arg
.exp
* self
.func(arg
.base
).expand()
405 #this is a lot faster:
407 def _eval_apply_evalf(cls
, arg
):
411 from sympy
import Real
412 return Real(math
.log(arg
))
415 import sage
.all
as sage
416 return sage
.log(self
[0]._sage
_())
418 # MrvLog is used by limit.py
421 def subs(self
, old
, new
):
422 old
= Basic
.sympify(old
)
425 new
= Basic
.sympify(new
)
426 return new(arg
.subs(old
, new
))