2 from basic
import Basic
, S
, C
3 from operations
import AssocOp
4 from cache
import cacheit
6 from symbol
import Symbol
, Wild
, Temporary
7 # from numbers import Number /cyclic/
8 # from mul import Mul /cyclic/
9 # from function import FunctionClass /cyclic/
18 def flatten(cls
, seq
):
20 Takes the sequence "seq" of nested Adds and returns a flatten list.
22 Returns: (commutative_part, noncommutative_part, order_symbols)
24 Applies associativity, all terms are commutable with respect to
27 terms
= {} # term -> coeff
28 # e.g. x**2 -> 5 for ... + 5*x**2 + ...
30 coeff
= S
.Zero
# standalone term
38 for o1
in order_factors
:
44 order_factors
= [o
]+[o1
for o1
in order_factors
if not o
.contains(o1
)]
54 # NB: here we assume Add is always commutative
55 seq
.extend(o
.args
) # TODO zerocopy?
67 s
= o
.as_two_terms()[1]
83 # s is an expression with number factor extracted
85 # let's collect terms with the same s, so e.g.
86 # 2*x**2 + 3*x**2 -> 5*x**2
93 # now let's construct new args:
94 # [2*x**2, x**3, 7*x**4, pi, ...]
96 noncommutative
= False
97 for s
,c
in terms
.items():
107 # Mul, already keeps it's arguments in perfect order.
108 # so we can simply put c in slot0 and go the fast way.
109 cs
= s
._new
_rawargs
(*((c
,) + s
.args
))
113 # alternatively we have to call all Mul's machinery (slow)
114 newseq
.append(Mul(c
,s
))
116 noncommutative
= noncommutative
or not s
.is_commutative
120 # we know for sure the result will be nan
121 return [S
.NaN
], [], None
124 elif (coeff
is S
.Infinity
) or (coeff
is S
.NegativeInfinity
):
125 newseq
= [f
for f
in newseq
if not f
.is_real
]
132 for o
in order_factors
:
137 # x + O(x**2) -> x + O(x**2)
140 newseq
= newseq2
+ order_factors
142 for o
in order_factors
:
143 if o
.contains(coeff
):
148 # order args canonically
149 # Currently we sort things using hashes, as it is quite fast. A better
150 # solution is not to sort things at all - but this needs some more
152 newseq
.sort(key
=hash)
154 # current code expects coeff to be always in slot-0
155 if coeff
is not S
.Zero
:
156 newseq
.insert(0, coeff
)
160 return [], newseq
, None
162 return newseq
, [], None
166 def as_coeff_factors(self
, x
=None):
175 return Add(*l1
), tuple(l2
)
178 return coeff
, self
.args
[1:]
179 return S
.Zero
, self
.args
181 def _eval_derivative(self
, s
):
182 return Add(*[f
.diff(s
) for f
in self
.args
])
184 def _eval_nseries(self
, x
, x0
, n
):
185 terms
= [t
.nseries(x
, x0
, n
) for t
in self
.args
]
188 def _matches_simple(pattern
, expr
, repl_dict
):
189 # handle (w+3).matches('x+5') -> {w: x+2}
190 coeff
, factors
= pattern
.as_coeff_factors()
192 return factors
[0].matches(expr
- coeff
, repl_dict
)
195 matches
= AssocOp
._matches
_commutative
198 def _combine_inverse(lhs
, rhs
):
202 def as_two_terms(self
):
203 if len(self
.args
) == 1:
205 return self
.args
[0], Add(*self
.args
[1:])
207 def as_numer_denom(self
):
208 numers
, denoms
= [],[]
209 for n
,d
in [f
.as_numer_denom() for f
in self
.args
]:
212 r
= xrange(len(numers
))
213 return Add(*[Mul(*(denoms
[:i
]+[numers
[i
]]+denoms
[i
+1:])) for i
in r
]),Mul(*denoms
)
215 def count_ops(self
, symbolic
=True):
217 return Add(*[t
.count_ops(symbolic
) for t
in self
[:]]) + Symbol('ADD') * (len(self
[:])-1)
218 return Add(*[t
.count_ops(symbolic
) for t
in self
.args
[:]]) + (len(self
.args
[:])-1)
220 def _eval_is_polynomial(self
, syms
):
221 for term
in self
.args
:
222 if not term
._eval
_is
_polynomial
(syms
):
227 _eval_is_real
= lambda self
: self
._eval
_template
_is
_attr
('is_real')
228 _eval_is_bounded
= lambda self
: self
._eval
_template
_is
_attr
('is_bounded')
229 _eval_is_commutative
= lambda self
: self
._eval
_template
_is
_attr
('is_commutative')
230 _eval_is_integer
= lambda self
: self
._eval
_template
_is
_attr
('is_integer')
231 _eval_is_comparable
= lambda self
: self
._eval
_template
_is
_attr
('is_comparable')
233 def _eval_is_odd(self
):
234 l
= [f
for f
in self
.args
if not (f
.is_even
==True)]
238 return Add(*l
[1:]).is_even
240 def _eval_is_irrational(self
):
247 def _eval_is_positive(self
):
249 r
= Add(*self
.args
[1:])
250 if c
.is_positive
and r
.is_positive
:
254 # either c or r is negative
260 if c
.is_nonnegative
and r
.is_positive
:
262 if r
.is_nonnegative
and c
.is_positive
:
264 if c
.is_nonpositive
and r
.is_nonpositive
:
267 def _eval_is_negative(self
):
269 r
= Add(*self
.args
[1:])
270 if c
.is_negative
and r
.is_negative
:
274 # either c or r is positive
280 if c
.is_nonpositive
and r
.is_negative
:
282 if r
.is_nonpositive
and c
.is_negative
:
284 if c
.is_nonnegative
and r
.is_nonnegative
:
287 def as_coeff_terms(self
, x
=None):
288 # -2 + 2 * a -> -1, 2-2*a
289 if self
.args
[0].is_Number
and self
.args
[0].is_negative
:
290 return -S
.One
,(-self
,)
293 def _eval_subs(self
, old
, new
):
294 if self
==old
: return new
295 if isinstance(old
, FunctionClass
):
296 return self
.__class
__(*[s
.subs(old
, new
) for s
in self
.args
])
297 coeff1
,factors1
= self
.as_coeff_factors()
298 coeff2
,factors2
= old
.as_coeff_factors()
299 if factors1
==factors2
: # (2+a).subs(3+a,y) -> 2-3+y
300 return new
+ coeff1
- coeff2
302 l1
,l2
= len(factors1
),len(factors2
)
303 if l2
<l1
: # (a+b+c+d).subs(b+c,x) -> a+x+d
304 for i
in xrange(l1
-l2
+1):
305 if factors2
==factors1
[i
:i
+l2
]:
306 factors1
= list(factors1
)
307 factors2
= list(factors2
)
308 return Add(*([coeff1
-coeff2
]+factors1
[:i
]+[new
]+factors1
[i
+l2
:]))
309 return self
.__class
__(*[s
.subs(old
, new
) for s
in self
.args
])
312 def extract_leading_order(self
, *symbols
):
314 Returns the leading term and it's order.
318 >>> (x+1+1/x**5).extract_leading_order(x)
319 ((1/x**5, O(1/x**5)),)
320 >>> (1+x).extract_leading_order(x)
322 >>> (x+x**2).extract_leading_order(x)
326 seq
= [(f
, C
.Order(f
, *symbols
)) for f
in self
.args
]
338 new_lst
.append((e
,o
))
342 def _eval_as_leading_term(self
, x
):
343 coeff
, factors
= self
.as_coeff_factors(x
)
344 has_unbounded
= bool([f
for f
in self
.args
if f
.is_unbounded
])
346 if isinstance(factors
, Basic
):
347 factors
= factors
.args
348 factors
= [f
for f
in factors
if not f
.is_bounded
]
349 if coeff
is not S
.Zero
:
352 o
= C
.Order(factors
[0]*x
,x
)
354 s
= self
.nseries(x
, 0, n
)
357 s
= self
.nseries(x
, 0, n
)
361 lst
= s
.extract_leading_order(x
)
362 return Add(*[e
for (e
,f
) in lst
])
363 return s
.as_leading_term(x
)
365 def _eval_conjugate(self
):
366 return Add(*[t
.conjugate() for t
in self
.args
])
369 return Add(*[-t
for t
in self
.args
])
391 import operations
as _