2 from basic
import Basic
, S
, C
3 from sympify
import _sympify
4 from cache
import cacheit
6 # from add import Add /cyclic/
7 # from mul import Mul /cyclic/
8 # from function import Lambda, WildFunction /cyclic/
9 from symbol
import Symbol
, Wild
12 """ Associative operations, can separate noncommutative and
15 (a op b) op c == a op (b op c) == a op b op c.
17 Base class for Add and Mul.
20 # for performance reason, we don't let is_commutative go to assumptions,
21 # and keep it right here
22 __slots__
= ['is_commutative']
25 def __new__(cls
, *args
, **assumptions
):
26 if assumptions
.get('evaluate') is False:
27 return Basic
.__new
__(cls
, *map(_sympify
, args
), **assumptions
)
31 return _sympify(args
[0])
32 c_part
, nc_part
, order_symbols
= cls
.flatten(map(_sympify
, args
))
33 if len(c_part
) + len(nc_part
) <= 1:
34 if c_part
: obj
= c_part
[0]
35 elif nc_part
: obj
= nc_part
[0]
36 else: obj
= cls
.identity()
38 obj
= Basic
.__new
__(cls
, *(c_part
+ nc_part
), **assumptions
)
39 obj
.is_commutative
= not nc_part
41 if order_symbols
is not None:
42 obj
= C
.Order(obj
, *order_symbols
)
46 def _new_rawargs(self
, *args
):
47 """create new instance of own class with args exactly as provided by caller
49 This is handy when we want to optimize things, e.g.
51 >>> from sympy import Mul, symbols
52 >>> x,y = symbols('xy')
58 >>> e._new_rawargs(*e.args[1:]) # the same as above, but faster
62 obj
= Basic
.__new
__(type(self
), *args
) # NB no assumptions for Add/Mul
63 obj
.is_commutative
= self
.is_commutative
69 if cls
is Mul
: return S
.One
70 if cls
is Add
: return S
.Zero
71 if cls
is C
.Composition
:
72 s
= Symbol('x',dummy
=True)
74 raise NotImplementedError("identity not defined for class %r" % (cls
.__name
__))
77 def flatten(cls
, seq
):
78 # apply associativity, no commutativity property is used
82 if o
.__class
__ is cls
: # classes must match exactly
83 seq
= list(o
[:]) + seq
86 return [], new_seq
, None
88 _eval_subs
= Basic
._seq
_subs
90 def _matches_commutative(pattern
, expr
, repl_dict
={}, evaluate
=False):
91 # apply repl_dict to pattern to eliminate fixed wild parts
94 for old
,new
in repl_dict
.items():
95 pat
= pat
.subs(old
, new
)
97 return pat
.matches(expr
, repl_dict
)
99 # handle simple patterns
100 d
= pattern
._matches
_simple
(expr
, repl_dict
)
104 # eliminate exact part from pattern: (2+a+w1+w2).matches(expr) -> (w1+w2).matches(expr-a-2)
107 for p
in pattern
.args
:
108 if p
.atoms(Wild
, WildFunction
):
109 # not all Wild should stay Wilds, for example:
110 # (w2+w3).matches(w1) -> (w1+w3).matches(w1) -> w3.matches(0)
111 if (not p
in repl_dict
) and (not p
in expr
):
118 newpattern
= pattern
.__class
__(*wild_part
)
119 newexpr
= pattern
.__class
__._combine
_inverse
(expr
, pattern
.__class
__(*exact_part
))
120 return newpattern
.matches(newexpr
, repl_dict
)
122 # now to real work ;)
123 if isinstance(expr
, pattern
.__class
__):
124 expr_list
= list(expr
.args
)
129 last_op
= expr_list
.pop()
133 d1
= w
.matches(last_op
, repl_dict
)
135 d2
= pattern
.matches(expr
, d1
, evaluate
=True)
140 def _eval_template_is_attr(self
, is_attr
):
141 # return True if all elements have the property
144 a
= getattr(t
, is_attr
)
146 if r
and not a
: r
= False
149 _eval_evalf
= Basic
._seq
_eval
_evalf