removing .args all overy sympy
[sympy.git] / sympy / functions / elementary / exponential.py
blob7d59ea2b2087c19463e4be4f650526ae49a2bccf
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):
7 nofargs = 1
9 def fdiff(self, argindex=1):
10 if argindex == 1:
11 return self
12 else:
13 raise ArgumentIndexError(self, argindex)
15 def inverse(self, argindex=1):
16 return S.Log
18 def _eval_apply(self, arg):
19 arg = Basic.sympify(arg)
21 if isinstance(arg, Basic.Number):
22 if isinstance(arg, Basic.NaN):
23 return S.NaN
24 elif isinstance(arg, Basic.Zero):
25 return S.One
26 elif isinstance(arg, Basic.One):
27 return S.Exp1
28 elif isinstance(arg, Basic.Infinity):
29 return S.Infinity
30 elif isinstance(arg, Basic.NegativeInfinity):
31 return S.Zero
32 elif isinstance(arg, Basic.ApplyLog):
33 return arg[0]
34 elif isinstance(arg, Basic.Mul):
35 coeff = arg.as_coefficient(S.Pi*S.ImaginaryUnit)
37 if coeff is not None:
38 if isinstance(2*coeff, Basic.Integer):
39 cst_table = {
40 0 : S.One,
41 1 : S.ImaginaryUnit,
42 2 : S.NegativeOne,
43 3 : -S.ImaginaryUnit,
46 return cst_table[int(2*coeff) % 4]
48 if isinstance(arg, Basic.Add):
49 args = arg[:]
50 else:
51 args = [arg]
53 included, excluded = [], []
55 for arg in args:
56 coeff, terms = arg.as_coeff_terms()
58 if isinstance(coeff, Basic.Infinity):
59 excluded.append(coeff**Basic.Mul(*terms))
60 else:
61 coeffs, log_term = [coeff], None
63 for term in terms:
64 if isinstance(term, Basic.ApplyLog):
65 if log_term is None:
66 log_term = term[0]
67 else:
68 log_term = None
69 break
70 elif term.is_comparable:
71 coeffs.append(term)
72 else:
73 break
75 if log_term is not None:
76 excluded.append(log_term**Basic.Mul(*coeffs))
77 else:
78 included.append(arg)
80 if excluded:
81 return Basic.Mul(*(excluded+[self(Basic.Add(*included))]))
83 def _eval_apply_evalf(self, arg):
84 arg = arg.evalf()
86 if isinstance(arg, Basic.Number):
87 return arg.exp()
89 @cache_it_immutable
90 def taylor_term(self, n, x, *previous_terms):
91 if n<0: return S.Zero
92 if n==0: return S.One
93 x = Basic.sympify(x)
94 if previous_terms:
95 p = previous_terms[-1]
96 if p is not None:
97 return p * x / n
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):
115 arg = self[0]
116 if x is not 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]
121 return S.One,[self]
123 def _eval_subs(self, old, new):
124 if self==old: return new
125 arg = self[0]
126 o = old
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()
132 if b==bo:
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))
136 oarg = old[0]
137 new_l = []
138 old_al = []
139 coeff2,terms2 = oarg.as_coeff_terms()
140 for a in arg:
141 a = a.subs(old, new)
142 coeff1,terms1 = a.as_coeff_terms()
143 if terms1==terms2:
144 new_l.append(new**(coeff1/coeff2))
145 else:
146 old_al.append(a.subs(old, new))
147 if new_l:
148 new_l.append(self.func(Basic.Add(*old_al)))
149 r = Basic.Mul(*new_l)
150 return r
151 old = o
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):
157 if self[0].is_real:
158 return True
159 def _eval_is_bounded(self):
160 arg = self[0]
161 if arg.is_unbounded:
162 if arg.is_negative: return True
163 if arg.is_positive: return False
164 if arg.is_bounded:
165 return True
166 if arg.is_real:
167 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):
175 arg = self[0]
176 x = order.symbols[0]
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):
181 return S.Exp(arg)
182 else:
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):
188 arg = self[0]
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):
193 return S.One
194 return S.Exp(arg)
196 def _eval_expand_basic(self, *args):
197 arg = self[0].expand()
198 if isinstance(arg, Basic.Add):
199 expr = 1
200 for x in arg:
201 expr *= self.func(x).expand()
202 return expr
203 return self.func(arg)
205 class Log(DefinedFunction):
207 nofargs = (1,2)
208 is_comparable = True
210 def fdiff(self, argindex=1):
211 if argindex == 1:
212 s = Basic.Symbol('x', dummy=True)
213 return Lambda(s**(-1), s)
214 else:
215 raise ArgumentIndexError(self, argindex)
217 def inverse(self, argindex=1):
218 return S.Exp
220 def _eval_apply(self, arg, base=None):
221 if base is not 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):
233 return S.Zero
234 elif isinstance(arg, Basic.Infinity):
235 return S.Infinity
236 elif isinstance(arg, Basic.NegativeInfinity):
237 return S.Infinity
238 elif isinstance(arg, Basic.NaN):
239 return S.NaN
240 elif arg.is_negative:
241 return S.Pi * S.ImaginaryUnit + self(-arg)
242 elif isinstance(arg, Basic.Exp1):
243 return S.One
244 elif isinstance(arg, ApplyExp) and arg[0].is_real:
245 return arg[0]
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):
257 return S.Infinity
258 elif isinstance(coeff, Basic.NegativeInfinity):
259 return S.Infinity
260 elif isinstance(coeff, Basic.Rational):
261 if coeff.is_nonnegative:
262 return S.Pi * S.ImaginaryUnit * S.Half + self(coeff)
263 else:
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):
270 arg = arg.evalf()
272 if isinstance(arg, Basic.Number):
273 return arg.log()
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
281 @cache_it_immutable
282 def taylor_term(self, n, x, *previous_terms): # of log(1+x)
283 if n<0: return S.Zero
284 x = Basic.sympify(x)
285 if n==0: return x
286 if previous_terms:
287 p = previous_terms[-1]
288 if p is not None:
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):
303 arg = self[0]
304 if arg.is_infinitesimal:
305 return False
306 return arg.is_bounded
308 def _eval_is_positive(self):
309 arg = self[0]
310 if arg.is_positive:
311 if arg.is_unbounded: return True
312 if arg.is_infinitesimal: return False
313 if isinstance(arg, Basic.Number):
314 return arg>1
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):
330 arg = self[0]
331 x = order.symbols[0]
332 ln = S.Log
333 use_lt = not Basic.Order(1,x).contains(arg)
334 if not use_lt:
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))
343 z = (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):
353 arg = self[0]
354 if isinstance(arg, Basic.Mul) and arg.is_real:
355 expr = 0
356 for x in arg:
357 expr += self.func(x).expand()
358 return expr
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()
363 return self
365 # MrvLog is used by limit.py
366 class MrvLog(Log):
367 pass
369 class ApplyMrvLog(ApplyLog):
371 def subs(self, old, new):
372 old = Basic.sympify(old)
373 if old==self.func:
374 arg = self[0]
375 new = Basic.sympify(new)
376 return new(arg.subs(old, new))
377 return self
380 Basic.singleton['exp'] = Exp
381 Basic.singleton['log'] = Log
382 Basic.singleton['ln'] = Log