2 from sympy
.core
.basic
import Basic
, S
, cache_it
, cache_it_immutable
3 from sympy
.core
.function
import DefinedFunction
, Apply
, Lambda
5 class Exp(DefinedFunction
):
9 def fdiff(self
, argindex
=1):
13 raise ArgumentIndexError(self
, argindex
)
15 def inverse(self
, argindex
=1):
18 def _eval_apply(self
, arg
):
19 arg
= Basic
.sympify(arg
)
21 if isinstance(arg
, Basic
.Number
):
22 if isinstance(arg
, Basic
.NaN
):
24 elif isinstance(arg
, Basic
.Zero
):
26 elif isinstance(arg
, Basic
.One
):
28 elif isinstance(arg
, Basic
.Infinity
):
30 elif isinstance(arg
, Basic
.NegativeInfinity
):
32 elif isinstance(arg
, Basic
.ApplyLog
):
34 elif isinstance(arg
, Basic
.Mul
):
35 coeff
= arg
.as_coefficient(S
.Pi
*S
.ImaginaryUnit
)
38 if isinstance(2*coeff
, Basic
.Integer
):
46 return cst_table
[int(2*coeff
) % 4]
48 if isinstance(arg
, Basic
.Add
):
53 included
, excluded
= [], []
56 coeff
, terms
= arg
.as_coeff_terms()
58 if isinstance(coeff
, Basic
.Infinity
):
59 excluded
.append(coeff
**Basic
.Mul(*terms
))
61 coeffs
, log_term
= [coeff
], None
64 if isinstance(term
, Basic
.ApplyLog
):
70 elif term
.is_comparable
:
75 if log_term
is not None:
76 excluded
.append(log_term
**Basic
.Mul(*coeffs
))
81 return Basic
.Mul(*(excluded
+[self(Basic
.Add(*included
))]))
83 def _eval_apply_evalf(self
, arg
):
86 if isinstance(arg
, Basic
.Number
):
90 def taylor_term(self
, n
, x
, *previous_terms
):
95 p
= previous_terms
[-1]
98 return x
**n
/Basic
.Factorial()(n
)
100 class ApplyExp(Apply
):
102 def _eval_expand_complex(self
, *args
):
103 re
, im
= self
[0].as_real_imag()
104 exp
, cos
, sin
= S
.Exp(re
), S
.Cos(im
), S
.Sin(im
)
105 return exp
* cos
+ S
.ImaginaryUnit
* exp
* sin
107 def _eval_conjugate(self
):
108 return self
.func(self
[0].conjugate())
110 def as_base_exp(self
):
111 coeff
, terms
= self
[0].as_coeff_terms()
112 return self
.func(Basic
.Mul(*terms
)), coeff
114 def as_coeff_terms(self
, x
=None):
117 c
,f
= arg
.as_coeff_factors(x
)
118 return self
.func(c
), [self
.func(a
) for a
in f
]
119 if isinstance(arg
, Basic
.Add
):
120 return S
.One
, [self
.func(a
) for a
in arg
]
123 def _eval_subs(self
, old
, new
):
124 if self
==old
: return new
127 if isinstance(old
, Basic
.Pow
): # handle (exp(3*log(x))).subs(x**2, z) -> z**(3/2)
128 old
= S
.Exp(old
.exp
* S
.Log(old
.base
))
129 if isinstance(old
, ApplyExp
):
130 b
,e
= self
.as_base_exp()
131 bo
,eo
= old
.as_base_exp()
133 return new
** (e
/eo
) # exp(2/3*x*3).subs(exp(3*x),y) -> y**(2/3)
134 if isinstance(arg
, Basic
.Add
): # exp(2*x+a).subs(exp(3*x),y) -> y**(2/3) * exp(a)
135 # exp(exp(x) + exp(x**2)).subs(exp(exp(x)), w) -> w * exp(exp(x**2))
139 coeff2
,terms2
= oarg
.as_coeff_terms()
142 coeff1
,terms1
= a
.as_coeff_terms()
144 new_l
.append(new
**(coeff1
/coeff2
))
146 old_al
.append(a
.subs(old
, new
))
148 new_l
.append(self
.func(Basic
.Add(*old_al
)))
149 r
= Basic
.Mul(*new_l
)
152 return Apply
._eval
_subs
(self
, old
, new
)
154 def _eval_is_real(self
):
155 return self
[0].is_real
156 def _eval_is_positive(self
):
159 def _eval_is_bounded(self
):
162 if arg
.is_negative
: return True
163 if arg
.is_positive
: return False
168 def _eval_is_zero(self
):
169 return isinstance(self
[0], Basic
.NegativeInfinity
)
171 def _eval_power(b
, e
):
172 return b
.func(b
[0] * e
)
174 def _eval_oseries(self
, order
):
177 if not Basic
.Order(1,x
).contains(arg
): # singularity
178 arg0
= arg
.as_leading_term(x
)
179 d
= (arg
-arg0
).limit(x
, S
.Zero
)
180 if not isinstance(d
, Basic
.Zero
):
183 arg0
= arg
.limit(x
, S
.Zero
)
184 o
= order
* S
.Exp(-arg0
)
185 return self
._compute
_oseries
(arg
-arg0
, o
, S
.Exp
.taylor_term
, S
.Exp
) * S
.Exp(arg0
)
187 def _eval_as_leading_term(self
, x
):
189 if isinstance(arg
, Basic
.Add
):
190 return Basic
.Mul(*[S
.Exp(f
).as_leading_term(x
) for f
in arg
])
191 arg
= self
[0].as_leading_term(x
)
192 if Basic
.Order(1,x
).contains(arg
):
196 def _eval_expand_basic(self
, *args
):
197 arg
= self
[0].expand()
198 if isinstance(arg
, Basic
.Add
):
201 expr
*= self
.func(x
).expand()
203 return self
.func(arg
)
205 class Log(DefinedFunction
):
210 def fdiff(self
, argindex
=1):
212 s
= Basic
.Symbol('x', dummy
=True)
213 return Lambda(s
**(-1), s
)
215 raise ArgumentIndexError(self
, argindex
)
217 def inverse(self
, argindex
=1):
220 def _eval_apply(self
, arg
, base
=None):
222 base
= Basic
.sympify(base
)
224 if not isinstance(base
, Basic
.Exp1
):
225 return self(arg
)/self(base
)
227 arg
= Basic
.sympify(arg
)
229 if isinstance(arg
, Basic
.Number
):
230 if isinstance(arg
, Basic
.Zero
):
231 return S
.NegativeInfinity
232 elif isinstance(arg
, Basic
.One
):
234 elif isinstance(arg
, Basic
.Infinity
):
236 elif isinstance(arg
, Basic
.NegativeInfinity
):
238 elif isinstance(arg
, Basic
.NaN
):
240 elif arg
.is_negative
:
241 return S
.Pi
* S
.ImaginaryUnit
+ self(-arg
)
242 elif isinstance(arg
, Basic
.Exp1
):
244 elif isinstance(arg
, ApplyExp
) and arg
[0].is_real
:
246 elif isinstance(arg
, Basic
.Pow
):
247 if isinstance(arg
.exp
, Basic
.Number
) or \
248 isinstance(arg
.exp
, Basic
.NumberSymbol
):
249 return arg
.exp
* self(arg
.base
)
250 elif isinstance(arg
, Basic
.Mul
) and arg
.is_real
:
251 return Basic
.Add(*[self(a
) for a
in arg
])
252 elif not isinstance(arg
, Basic
.Add
):
253 coeff
= arg
.as_coefficient(S
.ImaginaryUnit
)
255 if coeff
is not None:
256 if isinstance(coeff
, Basic
.Infinity
):
258 elif isinstance(coeff
, Basic
.NegativeInfinity
):
260 elif isinstance(coeff
, Basic
.Rational
):
261 if coeff
.is_nonnegative
:
262 return S
.Pi
* S
.ImaginaryUnit
* S
.Half
+ self(coeff
)
264 return -S
.Pi
* S
.ImaginaryUnit
* S
.Half
+ self(-coeff
)
266 def as_base_exp(self
):
267 return S
.Exp
, S
.NegativeOne
269 def _eval_apply_evalf(self
, arg
):
272 if isinstance(arg
, Basic
.Number
):
275 def _calc_apply_positive(self
, x
):
276 if x
.is_positive
and x
.is_unbounded
: return True
278 def _calc_apply_unbounded(self
, x
):
279 return x
.is_unbounded
282 def taylor_term(self
, n
, x
, *previous_terms
): # of log(1+x)
283 if n
<0: return S
.Zero
287 p
= previous_terms
[-1]
289 return (-n
) * p
* x
/ (n
+1)
290 return (1-2*(n
%2)) * x
**(n
+1)/(n
+1)
292 class ApplyLog(Apply
):
294 def _eval_expand_complex(self
, *args
):
295 re
, im
= self
[0].as_real_imag()
296 return S
.Log(S
.Sqrt(re
) + S
.Sqrt(im
)) + \
297 S
.ImaginaryUnit
* S
.Arg(self
[0])
299 def _eval_is_real(self
):
300 return self
[0].is_positive
302 def _eval_is_bounded(self
):
304 if arg
.is_infinitesimal
:
306 return arg
.is_bounded
308 def _eval_is_positive(self
):
311 if arg
.is_unbounded
: return True
312 if arg
.is_infinitesimal
: return False
313 if isinstance(arg
, Basic
.Number
):
316 def _eval_is_zero(self
):
317 # XXX This is not quite useless. Try evaluating log(0.5).is_negative
318 # without it. There's probably a nicer way though.
319 return isinstance(self
[0], Basic
.One
)
321 def as_numer_denom(self
):
322 n
, d
= self
[0].as_numer_denom()
323 if isinstance(d
, Basic
.One
):
324 return self
.func(n
), d
325 return (self
.func(n
) - self
.func(d
)).as_numer_denom()
327 # similar code must be added to other functions with have singularites
328 # in their domains eg. cot(), tan() ...
329 def _eval_oseries(self
, order
):
333 use_lt
= not Basic
.Order(1,x
).contains(arg
)
335 arg0
= arg
.limit(x
, 0)
336 use_lt
= isinstance(arg0
, Basic
.Zero
)
337 if use_lt
: # singularity
338 # arg = (arg / lt) * lt
339 lt
= arg
.as_leading_term(x
)
340 a
= (arg
/lt
).expand()
341 return ln(lt
) + ln(a
).oseries(order
)
342 # arg -> arg0 + (arg - arg0) -> arg0 * (1 + (arg/arg0 - 1))
344 return self
._compute
_oseries
(z
, order
, ln
.taylor_term
, lambda z
: ln(1+z
)) + ln(arg0
)
346 def _eval_as_leading_term(self
, x
):
347 arg
= self
[0].as_leading_term(x
)
348 if isinstance(arg
, Basic
.One
):
349 return (self
[0] - 1).as_leading_term(x
)
350 return self
.func(arg
)
352 def _eval_expand_basic(self
, *args
):
354 if isinstance(arg
, Basic
.Mul
) and arg
.is_real
:
357 expr
+= self
.func(x
).expand()
359 elif isinstance(arg
, Basic
.Pow
):
360 if isinstance(arg
.exp
, Basic
.Number
) or \
361 isinstance(arg
.exp
, Basic
.NumberSymbol
):
362 return arg
.exp
* self
.func(arg
.base
).expand()
365 # MrvLog is used by limit.py
369 class ApplyMrvLog(ApplyLog
):
371 def subs(self
, old
, new
):
372 old
= Basic
.sympify(old
)
375 new
= Basic
.sympify(new
)
376 return new(arg
.subs(old
, new
))
380 Basic
.singleton
['exp'] = Exp
381 Basic
.singleton
['log'] = Log
382 Basic
.singleton
['ln'] = Log