2 from basic
import Basic
, S
, C
, sympify
3 from operations
import AssocOp
4 from cache
import cacheit
6 from logic
import fuzzy_not
8 from symbol
import Symbol
, Wild
9 # from function import FunctionClass, WildFunction /cyclic/
10 # from numbers import Number, Integer, Real /cyclic/
11 # from add import Add /cyclic/
12 # from power import Pow /cyclic/
14 import sympy
.mpmath
as mpmath
23 def flatten(cls
, seq
):
24 # apply associativity, separate commutative part of seq
31 coeff
= S
.One
# standalone term
34 c_powers
= {} # base -> exp z
35 # e.g. (x+y) -> z for ... * (x+y) * ...
37 exp_dict
= {} # num-base -> exp y
38 # e.g. 3 -> y for ... * 3 * ...
40 inv_exp_dict
= {} # exp -> Mul(num-bases) x x
41 # e.g. x -> 6 for ... * 2 * 3 * ...
46 while c_seq
or nc_seq
:
50 # first process commutative objects
55 o
, order_symbols
= o
.as_expr_symbols(order_symbols
)
60 c_seq
= list(o
.args
[:]) + c_seq
71 base
, exponent
= o
.as_base_exp()
77 # let's collect factors with numeric base
79 exp_dict
[base
] += exponent
81 exp_dict
[base
] = exponent
86 # exp(x) / exp(y) -> exp(x-y)
92 b
, e
= o
.as_base_exp()
98 # (-3 + y) -> (-1) * (3 - y)
99 if b
.is_Add
and e
.is_Number
:
100 #found factor (x+y)**number; split off initial coefficient
101 c
, t
= b
.as_coeff_terms()
102 #last time I checked, Add.as_coeff_terms returns One or NegativeOne
103 #but this might change
104 if c
.is_negative
and not e
.is_integer
:
105 # extracting root from negative number: ignore sign
106 if c
is not S
.NegativeOne
:
107 # make c positive (probably never occurs)
111 #else: ignoring sign from NegativeOne: nothing to do!
116 #else: c is One, so pass
118 # let's collect factors with the same base, so e.g.
130 if isinstance(o
, WildFunction
):
133 o
, order_symbols
= o
.as_expr_symbols(order_symbols
)
137 # separate commutative symbols
142 if o
.__class
__ is cls
:
144 nc_seq
= list(o
.args
) + nc_seq
151 # try to combine last terms: a * a -> a
153 b1
,e1
= o1
.as_base_exp()
154 b2
,e2
= o
.as_base_exp()
156 nc_seq
.insert(0, b1
** (e1
+ e2
))
162 # ................................
169 for b
, e
in c_powers
.items():
178 elif e
.is_Integer
and b
.is_Number
:
181 c_part
.append(Pow(b
, e
))
185 for b
,e
in exp_dict
.items():
186 if e
in inv_exp_dict
:
191 for e
,b
in inv_exp_dict
.items():
200 elif e
.is_Integer
and b
.is_Number
:
211 # (oo|nan|zero) * ...
212 if (coeff
is S
.Infinity
) or (coeff
is S
.NegativeInfinity
):
229 new_nc_part
.append(t
)
230 nc_part
= new_nc_part
231 c_part
.insert(0, coeff
)
232 elif (coeff
is S
.Zero
) or (coeff
is S
.NaN
):
233 c_part
, nc_part
= [coeff
], []
236 c_part
, nc_part
= [coeff
], []
237 elif coeff
!= Real(1):
238 c_part
.insert(0, coeff
)
239 elif coeff
is not S
.One
:
240 c_part
.insert(0, coeff
)
242 # order commutative part canonically
243 c_part
.sort(Basic
.compare
)
246 if len(c_part
)==2 and c_part
[0].is_Number
and c_part
[1].is_Add
:
247 # 2*(1+a) -> 2 + 2 * a
249 c_part
= [Add(*[coeff
*f
for f
in c_part
[1].args
])]
251 return c_part
, nc_part
, order_symbols
254 def _eval_power(b
, e
):
258 # (a*b)**2 -> a**2 * b**2
259 return Mul(*[s
**e
for s
in b
.args
])
262 coeff
, rest
= b
.as_coeff_terms()
266 return (-coeff
)**e
* Mul(*((S
.NegativeOne
,) +rest
))**e
268 return coeff
**e
* Mul(*[s
**e
for s
in rest
])
271 coeff
, rest
= b
.as_coeff_terms()
272 if coeff
is not S
.One
:
273 # (2*a)**3 -> 2**3 * a**3
274 return coeff
**e
* Mul(*[s
**e
for s
in rest
])
276 coeff
, rest
= b
.as_coeff_terms()
277 l
= [s
**e
for s
in rest
]
280 return coeff
**e
* Mul(*l
)
282 c
,t
= b
.as_coeff_terms()
283 if e
.is_even
and c
.is_Number
and c
< 0:
284 return (-c
* Mul(*t
)) ** e
287 # return Mul(*[t**e for t in b])
289 def _eval_evalf(self
, prec
):
290 return AssocOp
._eval
_evalf
(self
, prec
).expand()
293 def as_two_terms(self
):
294 if len(self
.args
) == 1:
296 return self
.args
[0], Mul(*self
.args
[1:])
299 def as_coeff_terms(self
, x
=None):
308 return Mul(*l1
), tuple(l2
)
311 return coeff
, self
.args
[1:]
312 return S
.One
, self
.args
315 def _expandsums(sums
):
320 left
= Mul
._expandsums
(sums
[:L
//2])
321 right
= Mul
._expandsums
(sums
[L
//2:])
322 if isinstance(right
, Basic
):
324 if isinstance(left
, Basic
):
327 if len(left
) == 1 and len(right
) == 1:
328 # no expansion needed, bail out now to avoid infinite recursion
329 return [Mul(left
[0], right
[0])]
334 terms
.append(Mul(a
,b
).expand())
337 terms
= list(added
.args
)
342 def _eval_expand_basic(self
):
343 plain
, sums
, rewrite
= [], [], False
345 for factor
in self
.args
:
346 terms
= factor
._eval
_expand
_basic
()
348 if terms
is not None:
355 if factor
.is_commutative
:
358 sums
.append([factor
])
360 if terms
is not None:
367 terms
= Mul
._expandsums
(sums
)
369 if isinstance(terms
, Basic
):
374 return Add(*(Mul(plain
, term
) for term
in terms
), **self
.assumptions0
)
376 return Mul(*plain
, **self
.assumptions0
)
378 def _eval_derivative(self
, s
):
379 terms
= list(self
.args
)
381 for i
in xrange(len(terms
)):
385 factors
.append(Mul(*(terms
[:i
]+[t
]+terms
[i
+1:])))
388 def _matches_simple(pattern
, expr
, repl_dict
):
389 # handle (w*3).matches('x*5') -> {w: x*5/3}
390 coeff
, terms
= pattern
.as_coeff_terms()
392 return terms
[0].matches(expr
/ coeff
, repl_dict
)
395 def matches(pattern
, expr
, repl_dict
={}, evaluate
=False):
397 if pattern
.is_commutative
and expr
.is_commutative
:
398 return AssocOp
._matches
_commutative
(pattern
, expr
, repl_dict
, evaluate
)
399 # todo for commutative parts, until then use the default matches method for non-commutative products
400 return Basic
.matches(pattern
, expr
, repl_dict
, evaluate
)
403 def _combine_inverse(lhs
, rhs
):
408 def as_powers_dict(self
):
409 return dict([ term
.as_base_exp() for term
in self
])
411 def as_numer_denom(self
):
412 numers
, denoms
= [],[]
414 n
,d
= t
.as_numer_denom()
417 return Mul(*numers
), Mul(*denoms
)
420 def count_ops(self
, symbolic
=True):
422 return Add(*[t
.count_ops(symbolic
) for t
in self
[:]]) + Symbol('MUL') * (len(self
[:])-1)
423 return Add(*[t
.count_ops(symbolic
) for t
in self
.args
[:]]) + (len(self
.args
)-1)
425 def _eval_is_polynomial(self
, syms
):
426 for term
in self
.args
:
427 if not term
._eval
_is
_polynomial
(syms
):
431 _eval_is_bounded
= lambda self
: self
._eval
_template
_is
_attr
('is_bounded')
432 _eval_is_commutative
= lambda self
: self
._eval
_template
_is
_attr
('is_commutative')
433 _eval_is_integer
= lambda self
: self
._eval
_template
_is
_attr
('is_integer')
434 _eval_is_comparable
= lambda self
: self
._eval
_template
_is
_attr
('is_comparable')
437 # I*I -> R, I*I*I -> -I
439 def _eval_is_real(self
):
452 elif fuzzy_not(t_real
):
461 return (im_count
% 2 == 0)
464 def _eval_is_imaginary(self
):
478 return (im_count
% 2 == 1)
482 def _eval_is_irrational(self
):
489 def _eval_is_positive(self
):
490 terms
= [t
for t
in self
.args
if not t
.is_positive
]
499 if c
.is_negative
and r
.is_negative
:
501 if r
.is_negative
and c
.is_negative
:
503 # check for nonpositivity, <=0
504 if c
.is_negative
and r
.is_nonnegative
:
506 if r
.is_negative
and c
.is_nonnegative
:
508 if c
.is_nonnegative
and r
.is_nonpositive
:
510 if r
.is_nonnegative
and c
.is_nonpositive
:
514 def _eval_is_negative(self
):
515 terms
= [t
for t
in self
.args
if not t
.is_positive
]
517 # all terms are either positive -- 2*Symbol('n', positive=T)
518 # or unknown -- 2*Symbol('x')
527 # check for nonnegativity, >=0
528 if c
.is_negative
and r
.is_nonpositive
:
530 if r
.is_negative
and c
.is_nonpositive
:
532 if c
.is_nonpositive
and r
.is_nonpositive
:
534 if c
.is_nonnegative
and r
.is_nonnegative
:
537 def _eval_is_odd(self
):
538 is_integer
= self
.is_integer
550 elif is_integer
== False:
554 def _eval_is_even(self
):
555 is_integer
= self
.is_integer
558 return fuzzy_not(self
._eval
_is
_odd
())
560 elif is_integer
== False:
563 def _eval_subs(self
, old
, new
):
566 if isinstance(old
, FunctionClass
):
567 return self
.__class
__(*[s
.subs(old
, new
) for s
in self
.args
])
568 coeff1
,terms1
= self
.as_coeff_terms()
569 coeff2
,terms2
= old
.as_coeff_terms()
570 if terms1
==terms2
: # (2*a).subs(3*a,y) -> 2/3*y
571 return new
* coeff1
/coeff2
572 l1
,l2
= len(terms1
),len(terms2
)
574 # if old is just a number, go through the self.args one by one
575 return Mul(*[x
.subs(old
, new
) for x
in self
.args
])
577 # old is some something more complex, like:
578 # (a*b*c*d).subs(b*c,x) -> a*x*d
579 # then we need to search where in self.args the "old" is, and then
580 # correctly substitute both terms and coefficients.
581 for i
in xrange(l1
-l2
+1):
582 if terms2
==terms1
[i
:i
+l2
]:
583 m1
= Mul(*terms1
[:i
]).subs(old
,new
)
584 m2
= Mul(*terms1
[i
+l2
:]).subs(old
,new
)
585 return Mul(*([coeff1
/coeff2
,m1
,new
,m2
]))
586 return self
.__class
__(*[s
.subs(old
, new
) for s
in self
.args
])
588 def _eval_oseries(self
, order
):
593 #separate terms containing "x" (r) and the rest (l)
599 #if r is empty or just one term, it's easy:
601 if order
.contains(1,x
): return S
.Zero
604 return Mul(*(l
+ [r
[0].oseries(order
)]))
605 #otherwise, we need to calculate how many orders we need to calculate
606 #in each term. Currently this is done using as_leading_term, but this
607 #is fragile and slow, because this involves limits. Let's find some
608 #more clever approach.
609 lt
= [t
.as_leading_term(x
) for t
in r
]
610 for i
in xrange(len(r
)):
611 m
= Mul(*(lt
[:i
]+lt
[i
+1:]))
612 #calculate how many orders we want
614 #expand each term and multiply things together
615 l
.append(r
[i
].oseries(o
))
616 #shouldn't we rather expand everything? This seems to me to leave
617 #things as (x+x**2+...)*(x-x**2+...) etc.:
620 def nseries(self
, x
, x0
, n
):
621 terms
= [t
.nseries(x
, x0
, n
) for t
in self
.args
]
622 return Mul(*terms
).expand()
625 def _eval_as_leading_term(self
, x
):
626 return Mul(*[t
.as_leading_term(x
) for t
in self
.args
])
628 def _eval_conjugate(self
):
629 return Mul(*[t
.conjugate() for t
in self
.args
])
655 import operations
as _