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
:
138 newseq
= newseq2
+ order_factors
140 # order args canonically
141 # Currently we sort things using hashes, as it is quite fast. A better
142 # solution is not to sort things at all - but this needs some more
144 newseq
.sort(key
=hash)
146 # current code expects coeff to be always in slot-0
147 if coeff
is not S
.Zero
:
148 newseq
.insert(0, coeff
)
152 return [], newseq
, None
154 return newseq
, [], None
158 def as_coeff_factors(self
, x
=None):
167 return Add(*l1
), tuple(l2
)
170 return coeff
, self
.args
[1:]
171 return S
.Zero
, self
.args
173 def _eval_derivative(self
, s
):
174 return Add(*[f
.diff(s
) for f
in self
.args
])
176 def nseries(self
, x
, x0
, n
):
177 terms
= [t
.nseries(x
, x0
, n
) for t
in self
.args
]
180 def _matches_simple(pattern
, expr
, repl_dict
):
181 # handle (w+3).matches('x+5') -> {w: x+2}
182 coeff
, factors
= pattern
.as_coeff_factors()
184 return factors
[0].matches(expr
- coeff
, repl_dict
)
187 matches
= AssocOp
._matches
_commutative
190 def _combine_inverse(lhs
, rhs
):
194 def as_two_terms(self
):
195 if len(self
.args
) == 1:
197 return self
.args
[0], Add(*self
.args
[1:])
199 def as_numer_denom(self
):
200 numers
, denoms
= [],[]
201 for n
,d
in [f
.as_numer_denom() for f
in self
.args
]:
204 r
= xrange(len(numers
))
205 return Add(*[Mul(*(denoms
[:i
]+[numers
[i
]]+denoms
[i
+1:])) for i
in r
]),Mul(*denoms
)
207 def count_ops(self
, symbolic
=True):
209 return Add(*[t
.count_ops(symbolic
) for t
in self
[:]]) + Symbol('ADD') * (len(self
[:])-1)
210 return Add(*[t
.count_ops(symbolic
) for t
in self
.args
[:]]) + (len(self
.args
[:])-1)
212 def _eval_is_polynomial(self
, syms
):
213 for term
in self
.args
:
214 if not term
._eval
_is
_polynomial
(syms
):
219 _eval_is_real
= lambda self
: self
._eval
_template
_is
_attr
('is_real')
220 _eval_is_bounded
= lambda self
: self
._eval
_template
_is
_attr
('is_bounded')
221 _eval_is_commutative
= lambda self
: self
._eval
_template
_is
_attr
('is_commutative')
222 _eval_is_integer
= lambda self
: self
._eval
_template
_is
_attr
('is_integer')
223 _eval_is_comparable
= lambda self
: self
._eval
_template
_is
_attr
('is_comparable')
225 def _eval_is_odd(self
):
226 l
= [f
for f
in self
.args
if not (f
.is_even
==True)]
230 return Add(*l
[1:]).is_even
232 def _eval_is_irrational(self
):
239 def _eval_is_positive(self
):
241 r
= Add(*self
.args
[1:])
242 if c
.is_positive
and r
.is_positive
:
246 # either c or r is negative
252 if c
.is_nonnegative
and r
.is_positive
:
254 if r
.is_nonnegative
and c
.is_positive
:
256 if c
.is_nonpositive
and r
.is_nonpositive
:
259 def _eval_is_negative(self
):
261 r
= Add(*self
.args
[1:])
262 if c
.is_negative
and r
.is_negative
:
266 # either c or r is positive
272 if c
.is_nonpositive
and r
.is_negative
:
274 if r
.is_nonpositive
and c
.is_negative
:
276 if c
.is_nonnegative
and r
.is_nonnegative
:
279 def as_coeff_terms(self
, x
=None):
280 # -2 + 2 * a -> -1, 2-2*a
281 if self
.args
[0].is_Number
and self
.args
[0].is_negative
:
282 return -S
.One
,(-self
,)
285 def _eval_subs(self
, old
, new
):
286 if self
==old
: return new
287 if isinstance(old
, FunctionClass
):
288 return self
.__class
__(*[s
.subs(old
, new
) for s
in self
.args
])
289 coeff1
,factors1
= self
.as_coeff_factors()
290 coeff2
,factors2
= old
.as_coeff_factors()
291 if factors1
==factors2
: # (2+a).subs(3+a,y) -> 2-3+y
292 return new
+ coeff1
- coeff2
294 l1
,l2
= len(factors1
),len(factors2
)
295 if l2
<l1
: # (a+b+c+d).subs(b+c,x) -> a+x+d
296 for i
in xrange(l1
-l2
+1):
297 if factors2
==factors1
[i
:i
+l2
]:
298 factors1
= list(factors1
)
299 factors2
= list(factors2
)
300 return Add(*([coeff1
-coeff2
]+factors1
[:i
]+[new
]+factors1
[i
+l2
:]))
301 return self
.__class
__(*[s
.subs(old
, new
) for s
in self
.args
])
303 def _eval_oseries(self
, order
):
304 return Add(*[f
.oseries(order
) for f
in self
.args
])
307 def extract_leading_order(self
, *symbols
):
309 seq
= [(f
, C
.Order(f
, *symbols
)) for f
in self
.args
]
321 new_lst
.append((e
,o
))
325 def _eval_as_leading_term(self
, x
):
326 coeff
, factors
= self
.as_coeff_factors(x
)
327 has_unbounded
= bool([f
for f
in self
.args
if f
.is_unbounded
])
329 if isinstance(factors
, Basic
):
330 factors
= factors
.args
331 factors
= [f
for f
in factors
if not f
.is_bounded
]
332 if coeff
is not S
.Zero
:
335 o
= C
.Order(factors
[0]*x
,x
)
341 lst
= s
.extract_leading_order(x
)
342 return Add(*[e
for (e
,f
) in lst
])
343 return s
.as_leading_term(x
)
345 def _eval_conjugate(self
):
346 return Add(*[t
.conjugate() for t
in self
.args
])
349 return Add(*[-t
for t
in self
.args
])
371 import operations
as _