2 __all__
= ['TERM_COEFF_DICT']
4 from .base
import heads
, heads_precedence
, ArithmeticHead
, Pair
6 from ..core
import init_module
, Expr
7 init_module
.import_heads()
8 init_module
.import_numbers()
9 init_module
.import_lowlevel_operations()
13 from ..arithmetic
.number_theory
import multinomial_coefficients
14 module
.multinomial_coefficients
= multinomial_coefficients
16 class TermCoeffDictHead(ArithmeticHead
):
18 def is_data_ok(self
, cls
, data
):
19 if type(data
) is dict:
22 # return 'data dictonary should have more than 1 item'
23 for item
in data
.iteritems():
24 msg
= TERM_COEFF
.is_data_ok(cls
, item
, allow_number_term
=True)
26 return 'TERM_COEFF data=%s: %s' % (item
, msg
) #pragma: no cover
28 return 'data must be dict instance but got %s' % (type(data
)) #pragma: no cover
31 def __repr__(self
): return 'TERM_COEFF_DICT'
33 def data_to_str_and_precedence(self
, cls
, term_coeff_dict
):
34 r
= [cls(TERM_COEFF
, tc
) for tc
in term_coeff_dict
.items()]
35 return ADD
.data_to_str_and_precedence(cls
, r
)
37 def new(self
, cls
, data
, evaluate
=True):
38 return term_coeff_dict_new(cls
, data
)
40 def reevaluate(self
, cls
, data
):
42 for term
, coeff
in data
.iteritems():
46 def to_ADD(self
, Algebra
, data
, expr
):
47 return add_new(Algebra
, [term_coeff_new(Algebra
, term_coeff
) for term_coeff
in data
.iteritems()])
49 def to_EXP_COEFF_DICT(self
, cls
, data
, expr
, variables
=None):
51 r
= cls(EXP_COEFF_DICT
, Pair((), {}))
53 r
= cls(EXP_COEFF_DICT
, Pair(variables
, {}))
54 for term
, coeff
in data
.iteritems():
58 def term_coeff(self
, cls
, expr
):
59 term_coeff_dict
= expr
.data
60 if len(term_coeff_dict
)==1:
61 return dict_get_item(term_coeff_dict
)
64 def inplace_add(self
, cls
, lhs
, rhs
):
68 data
= lhs
.data
.copy()
70 self
.add(cls
, data
, rhs
, inplace
=True)
72 return term_coeff_dict_new(cls
, data
)
74 def add(self
, cls
, lhs
, rhs
, inplace
=False):
78 data
= lhs
.data
.copy()
83 dict_add_item(cls
, data
, cls(NUMBER
, 1), d2
)
85 dict_add_item(cls
, data
, rhs
, 1)
86 elif h2
is TERM_COEFF
:
88 dict_add_item(cls
, data
, term
, coeff
)
89 elif h2
is TERM_COEFF_DICT
:
90 dict_add_dict(cls
, data
, d2
)
93 term
, coeff
= op
.term_coeff()
94 dict_add_item(cls
, data
, term
, coeff
)
95 elif h2
is SUB
or h2
is NEG
or h2
is POS
:
96 raise NotImplementedError(`self
, rhs
.pair`
)
97 elif h2
is BASE_EXP_DICT
:
98 c
= base_exp_dict_get_coefficient(cls
, d2
)
102 t
= BASE_EXP_DICT
.new(cls
, d
)
103 if t
.head
is BASE_EXP_DICT
:
104 dict_add_item(cls
, data
, t
, c
)
106 self
.add(cls
, data
, t
* c
, inplace
=True)
108 dict_add_item(cls
, data
, rhs
, 1)
110 dict_add_item(cls
, data
, rhs
, 1)
115 return term_coeff_dict_new(cls
, data
)
117 def add_number(self
, cls
, lhs
, rhs
):
120 data
= lhs
.data
.copy()
121 term_coeff_dict_add_item(cls
, data
, cls(NUMBER
, 1), rhs
)
122 return term_coeff_dict_new(cls
, data
)
124 def sub_number(self
, cls
, lhs
, rhs
):
127 data
= lhs
.data
.copy()
128 term_coeff_dict_add_item(cls
, data
, cls(NUMBER
, 1), -rhs
)
129 return term_coeff_dict_new(cls
, data
)
131 def sub(self
, cls
, lhs
, rhs
):
133 self
.add(cls
, d
, -rhs
, inplace
=True)
134 return term_coeff_dict_new(cls
, d
)
136 def commutative_mul(self
, cls
, lhs
, rhs
):
137 rhead
, rdata
= rhs
.pair
141 data
= lhs
.data
.copy()
142 dict_mul_value(cls
, data
, rdata
)
143 return term_coeff_dict_new(cls
, data
)
144 if rhead
is TERM_COEFF
:
146 return (lhs
* term
) * coeff
150 return POW
.new(cls
, (lhs
, exp
+ 1))
151 return cls(BASE_EXP_DICT
, {lhs
:1, base
:exp
})
152 if rhead
is SYMBOL
or rhead
is APPLY
:
153 return cls(BASE_EXP_DICT
, {lhs
:1, rhs
:1})
154 if rhead
is TERM_COEFF_DICT
:
156 return cls(POW
, (lhs
, 2))
157 return cls(BASE_EXP_DICT
, {lhs
:1, rhs
:1})
158 if rhead
is BASE_EXP_DICT
:
160 dict_add_item(cls
, data
, lhs
, 1)
161 return BASE_EXP_DICT
.new(cls
, data
)
163 return cls(BASE_EXP_DICT
, {lhs
:1, rhs
:1})
164 return ArithmeticHead
.commutative_mul(self
, cls
, lhs
, rhs
)
166 def commutative_mul_number(self
, cls
, lhs
, rhs
):
168 return cls(NUMBER
, 0)
169 data
= lhs
.data
.copy()
170 dict_mul_value(cls
, data
, rhs
)
171 return cls(self
, data
)
173 non_commutative_mul_number
= commutative_mul_number
175 def commutative_rdiv_number(self
, cls
, lhs
, rhs
):
176 return term_coeff_new(cls
, (cls(POW
, (lhs
, -1)), rhs
))
178 def commutative_div(self
, cls
, lhs
, rhs
):
179 rhead
, rdata
= rhs
.pair
181 return self
.commutative_div_number(cls
, lhs
, rdata
)
182 if rhead
is TERM_COEFF_DICT
:
183 if lhs
.data
== rdata
:
184 return cls(NUMBER
, 1)
185 return cls(BASE_EXP_DICT
, {lhs
:1, rhs
:-1})
186 if rhead
is SYMBOL
or rhead
is APPLY
:
187 return cls(BASE_EXP_DICT
, {lhs
:1, rhs
:-1})
188 if rhead
is TERM_COEFF
:
190 return number_div(cls
, 1, coeff
) * (lhs
/ term
)
194 return pow_new(cls
, (lhs
, 1-exp
))
195 return cls(BASE_EXP_DICT
, {lhs
:1, base
:-exp
})
196 if rhead
is BASE_EXP_DICT
:
198 for base
, exp
in rdata
.iteritems():
199 base_exp_dict_add_item(cls
, data
, base
, -exp
)
200 return base_exp_dict_new(cls
, data
)
201 return ArithmeticHead
.commutative_div(self
, cls
, lhs
, rhs
)
204 def pow(self
, cls
, base
, exp
):
205 if exp
==0: return cls(NUMBER
, 1)
206 if exp
==1: return base
209 t
,c
= dict_get_item(d
)
211 if t
==1: return cls(NUMBER
, c
)
213 return cls(TERM_COEFF
, (t
, c
))
214 return POW
.new(cls
, (base
, exp
))
218 def neg(self
, cls
, expr
):
222 return cls(TERM_COEFF_DICT
, d
)
224 def expand(self
, cls
, expr
):
226 for t
, c
in expr
.data
.items():
227 self
.add(cls
, d
, t
.expand() * c
, inplace
=True)
228 return term_coeff_dict_new(cls
, d
)
230 def expand_intpow(self
, cls
, expr
, intexp
):
232 return cls(POW
, (expr
, intexp
))
234 return cls(NUMBER
, 1)
237 term_coeff_list
= [(term
.base_exp(), coeff
) for term
, coeff
in expr
.data
.items()]
238 mdata
= multinomial_coefficients(len(term_coeff_list
), intexp
)
240 for e
,c
in mdata
.iteritems():
243 for e_i
, ((base
, exp
), coeff
) in zip(e
, term_coeff_list
):
246 base_exp_dict_add_item(cls
, df
, base
, exp
)
250 base_exp_dict_add_item(cls
, df
, base
, exp
*e_i
)
252 new_coeff
*= coeff
** e_i
253 new_term
= base_exp_dict_new(cls
, df
)
254 term_coeff_dict_add_item(cls
, d
, new_term
, new_coeff
)
255 return term_coeff_dict_new(cls
, d
)
257 def walk(self
, func
, cls
, data
, target
):
261 for t
, c
in data
.iteritems():
262 t1
= t
.head
.walk(func
, cls
, t
.data
, t
)
263 if isinstance(c
, Expr
):
264 c1
= c
.head
.walk(func
, cls
, c
.data
, c
)
266 c1
= NUMBER
.walk(func
, cls
, c
, c
)
267 if t1
is not t
or c1
is not c
:
269 add(cls
, d
, t1
* c1
, inplace
=True)
271 r
= term_coeff_dict_new(cls
, d
)
272 return func(cls
, r
.head
, r
.data
, r
)
273 return func(cls
, self
, data
, target
)
275 def scan(self
, proc
, cls
, data
, target
):
276 for t
, c
in data
.iteritems():
277 t
.head
.scan(proc
, cls
, t
.data
, target
)
278 if isinstance(c
, Expr
):
279 c
.head
.scan(proc
, cls
, c
.data
, target
)
281 NUMBER
.scan(proc
, cls
, c
, target
)
282 proc(cls
, self
, data
, target
)
284 def diff(self
, cls
, data
, expr
, symbol
, order
, cache
={}):
285 key
= (expr
, symbol
, order
)
286 result
= cache
.get(key
)
287 if result
is not None:
291 result
= cls(NUMBER
, 0)
292 for term
, coeff
in data
.iteritems():
293 result
+= term
.head
.diff(cls
, term
.data
, term
, symbol
, order
, cache
=cache
) * coeff
294 key1
= (expr
, symbol
, 1)
298 def apply(self
, cls
, data
, func
, args
):
299 result
= cls(NUMBER
, 0)
300 for term
, coeff
in data
.iteritems():
301 result
+= term
.head
.apply(cls
, term
.data
, term
, args
) * coeff
304 def integrate_indefinite(self
, cls
, data
, expr
, x
):
305 result
= cls(NUMBER
, 0)
306 for term
, coeff
in data
.iteritems():
307 result
+= term
.head
.integrate_indefinite(cls
, term
.data
, term
, x
) * coeff
310 def integrate_definite(self
, cls
, data
, expr
, x
, a
, b
):
311 result
= cls(NUMBER
, 0)
312 for term
, coeff
in data
.iteritems():
313 result
+= term
.head
.integrate_definite(cls
, term
.data
, term
, x
, a
, b
) * coeff
316 def algebra_pos(self
, Algebra
, expr
):
319 def algebra_neg(self
, Algebra
, expr
):
320 if Algebra
.algebra_options
.get('evaluate_addition'):
324 return Algebra(TERM_COEFF_DICT
, d
)
325 return Algebra(NEG
, expr
)
327 def algebra_add_number(self
, Algebra
, lhs
, rhs
, inplace
):
331 term_coeff_dict_add_item(Algebra
, lhs
.data
, Algebra(NUMBER
, 1), rhs
)
332 return term_coeff_dict(Algebra
, lhs
)
334 term_coeff_dict_add_item(Algebra
, d
, Algebra(NUMBER
, 1), rhs
)
335 return term_coeff_dict_new(Algebra
, d
)
337 def algebra_add(self
, Algebra
, lhs
, rhs
, inplace
):
338 rhead
, rdata
= rhs
.pair
339 if Algebra
.algebra_options
.get('evaluate_addition'):
341 if rhead
is ADD
or rhead
is EXP_COEFF_DICT
or rhead
is MUL
or rhead
is NEG
:
342 rhs
= rhead
.to_TERM_COEFF_DICT(Algebra
, rdata
, rhs
)
343 rhead
, rdata
= rhs
.pair
347 rterm
, rcoeff
= Algebra(NUMBER
, 1), rdata
348 elif rhead
is SYMBOL
:
349 rterm
, rcoeff
= rhs
, 1
350 elif rhead
is TERM_COEFF
:
351 rterm
, rcoeff
= rdata
352 elif rhead
is TERM_COEFF_DICT
:
354 term_coeff_dict_add_dict(Algebra
, ldata
, rdata
)
355 return term_coeff_dict(Algebra
, lhs
)
357 term_coeff_dict_add_dict(Algebra
, d
, rdata
)
358 return term_coeff_dict_new(Algebra
, d
)
360 return super(type(self
), self
).algebra_add(Algebra
, lhs
, rhs
, inplace
)
363 term_coeff_dict_add_item(Algebra
, ldata
, rterm
, rcoeff
)
364 return term_coeff_dict(Algebra
, lhs
)
366 term_coeff_dict_add_item(Algebra
, d
, rterm
, rcoeff
)
367 return term_coeff_dict_new(Algebra
, d
)
369 return TERM_COEFF_DICT
.to_ADD(Algebra
, lhs
.data
, lhs
) + rhs
370 return super(type(self
), self
).algebra_add(Algebra
, lhs
, rhs
, inplace
)
372 def algebra_mul_number(self
, Algebra
, lhs
, rhs
, inplace
):
373 if Algebra
.algebra_options
.get('evaluate_addition'):
375 return Algebra(NUMBER
, 0)
379 term_coeff_dict_mul_value(Algebra
, lhs
.data
, rhs
)
382 term_coeff_dict_mul_value(Algebra
, d
, rhs
)
383 return Algebra(TERM_COEFF_DICT
, d
)
384 return Algebra(MUL
, [lhs
, Algebra(NUMBER
, rhs
)])
386 def algebra_mul(self
, Algebra
, lhs
, rhs
, inplace
):
387 rhead
, rdata
= rhs
.pair
389 return self
.algebra_mul_number(Algebra
, lhs
, rdata
, inplace
)
390 return super(type(self
), self
).algebra_mul(Algebra
, lhs
, rhs
, inplace
)
392 def algebra_div_number(self
, Algebra
, lhs
, rhs
, inplace
):
393 if Algebra
.algebra_options
.get('evaluate_addition'):
396 d1
= gcd(*lhs
.data
.values())
401 for t
,c
in lhs
.data
.items():
407 s
= term_coeff_dict_new(Algebra
, d
)
409 assert rd
==0,`lsh
, rhs
, s
,rd`
411 return Algebra(DIV
, [s
, Algebra(NUMBER
, d3
)]) + rd
412 return Algebra(DIV
, [lhs
, Algebra(NUMBER
, rhs
)])
414 def algebra_div(self
, Algebra
, lhs
, rhs
, inplace
):
415 rhead
, rdata
= rhs
.pair
417 return self
.algebra_div_number(Algebra
, lhs
, rdata
, inplace
)
418 return super(type(self
), self
).algebra_div(Algebra
, lhs
, rhs
, inplace
)
420 TERM_COEFF_DICT
= TermCoeffDictHead()