PageRenderTime 57ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/sympycore/heads/term_coeff_dict.py

https://github.com/escheffel/pymaclab
Python | 420 lines | 368 code | 50 blank | 2 comment | 118 complexity | 74a6188ecdc269019f75ae3d5a885062 MD5 | raw file
  1. __all__ = ['TERM_COEFF_DICT']
  2. from .base import heads, heads_precedence, ArithmeticHead, Pair
  3. from ..core import init_module, Expr
  4. init_module.import_heads()
  5. init_module.import_numbers()
  6. init_module.import_lowlevel_operations()
  7. @init_module
  8. def _init(module):
  9. from ..arithmetic.number_theory import multinomial_coefficients
  10. module.multinomial_coefficients = multinomial_coefficients
  11. class TermCoeffDictHead(ArithmeticHead):
  12. def is_data_ok(self, cls, data):
  13. if type(data) is dict:
  14. n = len(data)
  15. #if n<=1:
  16. # return 'data dictonary should have more than 1 item'
  17. for item in data.iteritems():
  18. msg = TERM_COEFF.is_data_ok(cls, item, allow_number_term=True)
  19. if msg:
  20. return 'TERM_COEFF data=%s: %s' % (item, msg) #pragma: no cover
  21. else:
  22. return 'data must be dict instance but got %s' % (type(data)) #pragma: no cover
  23. return
  24. def __repr__(self): return 'TERM_COEFF_DICT'
  25. def data_to_str_and_precedence(self, cls, term_coeff_dict):
  26. r = [cls(TERM_COEFF, tc) for tc in term_coeff_dict.items()]
  27. return ADD.data_to_str_and_precedence(cls, r)
  28. def new(self, cls, data, evaluate=True):
  29. return term_coeff_dict_new(cls, data)
  30. def reevaluate(self, cls, data):
  31. r = cls(NUMBER, 0)
  32. for term, coeff in data.iteritems():
  33. r += term * coeff
  34. return r
  35. def to_ADD(self, Algebra, data, expr):
  36. return add_new(Algebra, [term_coeff_new(Algebra, term_coeff) for term_coeff in data.iteritems()])
  37. def to_EXP_COEFF_DICT(self, cls, data, expr, variables=None):
  38. if variables is None:
  39. r = cls(EXP_COEFF_DICT, Pair((), {}))
  40. else:
  41. r = cls(EXP_COEFF_DICT, Pair(variables, {}))
  42. for term, coeff in data.iteritems():
  43. r += term * coeff
  44. return r
  45. def term_coeff(self, cls, expr):
  46. term_coeff_dict = expr.data
  47. if len(term_coeff_dict)==1:
  48. return dict_get_item(term_coeff_dict)
  49. return expr, 1
  50. def inplace_add(self, cls, lhs, rhs):
  51. if lhs.is_writable:
  52. data = lhs.data
  53. else:
  54. data = lhs.data.copy()
  55. self.add(cls, data, rhs, inplace=True)
  56. return term_coeff_dict_new(cls, data)
  57. def add(self, cls, lhs, rhs, inplace=False):
  58. if inplace:
  59. data = lhs
  60. else:
  61. data = lhs.data.copy()
  62. h2, d2 = rhs.pair
  63. if h2 is NUMBER:
  64. if d2 != 0:
  65. dict_add_item(cls, data, cls(NUMBER, 1), d2)
  66. elif h2 is SYMBOL:
  67. dict_add_item(cls, data, rhs, 1)
  68. elif h2 is TERM_COEFF:
  69. term, coeff = d2
  70. dict_add_item(cls, data, term, coeff)
  71. elif h2 is TERM_COEFF_DICT:
  72. dict_add_dict(cls, data, d2)
  73. elif h2 is ADD:
  74. for op in d2:
  75. term, coeff = op.term_coeff()
  76. dict_add_item(cls, data, term, coeff)
  77. elif h2 is SUB or h2 is NEG or h2 is POS:
  78. raise NotImplementedError(`self, rhs.pair`)
  79. elif h2 is BASE_EXP_DICT:
  80. c = base_exp_dict_get_coefficient(cls, d2)
  81. if c is not None:
  82. d = d2.copy()
  83. del d[c]
  84. t = BASE_EXP_DICT.new(cls, d)
  85. if t.head is BASE_EXP_DICT:
  86. dict_add_item(cls, data, t, c)
  87. else:
  88. self.add(cls, data, t * c, inplace=True)
  89. else:
  90. dict_add_item(cls, data, rhs, 1)
  91. else:
  92. dict_add_item(cls, data, rhs, 1)
  93. if inplace:
  94. return lhs
  95. return term_coeff_dict_new(cls, data)
  96. def add_number(self, cls, lhs, rhs):
  97. if rhs==0:
  98. return lhs
  99. data = lhs.data.copy()
  100. term_coeff_dict_add_item(cls, data, cls(NUMBER, 1), rhs)
  101. return term_coeff_dict_new(cls, data)
  102. def sub_number(self, cls, lhs, rhs):
  103. if rhs==0:
  104. return lhs
  105. data = lhs.data.copy()
  106. term_coeff_dict_add_item(cls, data, cls(NUMBER, 1), -rhs)
  107. return term_coeff_dict_new(cls, data)
  108. def sub(self, cls, lhs, rhs):
  109. d = lhs.data.copy()
  110. self.add(cls, d, -rhs, inplace=True)
  111. return term_coeff_dict_new(cls, d)
  112. def commutative_mul(self, cls, lhs, rhs):
  113. rhead, rdata = rhs.pair
  114. if rhead is NUMBER:
  115. if rdata==0:
  116. return rhs
  117. data = lhs.data.copy()
  118. dict_mul_value(cls, data, rdata)
  119. return term_coeff_dict_new(cls, data)
  120. if rhead is TERM_COEFF:
  121. term, coeff = rdata
  122. return (lhs * term) * coeff
  123. if rhead is POW:
  124. base, exp = rdata
  125. if lhs==base:
  126. return POW.new(cls, (lhs, exp + 1))
  127. return cls(BASE_EXP_DICT, {lhs:1, base:exp})
  128. if rhead is SYMBOL or rhead is APPLY:
  129. return cls(BASE_EXP_DICT, {lhs:1, rhs:1})
  130. if rhead is TERM_COEFF_DICT:
  131. if rdata==lhs.data:
  132. return cls(POW, (lhs, 2))
  133. return cls(BASE_EXP_DICT, {lhs:1, rhs:1})
  134. if rhead is BASE_EXP_DICT:
  135. data = rdata.copy()
  136. dict_add_item(cls, data, lhs, 1)
  137. return BASE_EXP_DICT.new(cls, data)
  138. if rhead is ADD:
  139. return cls(BASE_EXP_DICT, {lhs:1, rhs:1})
  140. return ArithmeticHead.commutative_mul(self, cls, lhs, rhs)
  141. def commutative_mul_number(self, cls, lhs, rhs):
  142. if rhs==0:
  143. return cls(NUMBER, 0)
  144. data = lhs.data.copy()
  145. dict_mul_value(cls, data, rhs)
  146. return cls(self, data)
  147. non_commutative_mul_number = commutative_mul_number
  148. def commutative_rdiv_number(self, cls, lhs, rhs):
  149. return term_coeff_new(cls, (cls(POW, (lhs, -1)), rhs))
  150. def commutative_div(self, cls, lhs, rhs):
  151. rhead, rdata = rhs.pair
  152. if rhead is NUMBER:
  153. return self.commutative_div_number(cls, lhs, rdata)
  154. if rhead is TERM_COEFF_DICT:
  155. if lhs.data == rdata:
  156. return cls(NUMBER, 1)
  157. return cls(BASE_EXP_DICT, {lhs:1, rhs:-1})
  158. if rhead is SYMBOL or rhead is APPLY:
  159. return cls(BASE_EXP_DICT, {lhs:1, rhs:-1})
  160. if rhead is TERM_COEFF:
  161. term, coeff = rdata
  162. return number_div(cls, 1, coeff) * (lhs / term)
  163. if rhead is POW:
  164. base, exp = rdata
  165. if lhs==base:
  166. return pow_new(cls, (lhs, 1-exp))
  167. return cls(BASE_EXP_DICT, {lhs:1, base:-exp})
  168. if rhead is BASE_EXP_DICT:
  169. data = {lhs:1}
  170. for base, exp in rdata.iteritems():
  171. base_exp_dict_add_item(cls, data, base, -exp)
  172. return base_exp_dict_new(cls, data)
  173. return ArithmeticHead.commutative_div(self, cls, lhs, rhs)
  174. def pow(self, cls, base, exp):
  175. if exp==0: return cls(NUMBER, 1)
  176. if exp==1: return base
  177. d = base.data
  178. if len(d)==1:
  179. t,c = dict_get_item(d)
  180. t,c = t**exp, c**exp
  181. if t==1: return cls(NUMBER, c)
  182. if c==1: return t
  183. return cls(TERM_COEFF, (t, c))
  184. return POW.new(cls, (base, exp))
  185. pow_number = pow
  186. def neg(self, cls, expr):
  187. d = expr.data.copy()
  188. for key in d:
  189. d[key] = -d[key]
  190. return cls(TERM_COEFF_DICT, d)
  191. def expand(self, cls, expr):
  192. d = {}
  193. for t, c in expr.data.items():
  194. self.add(cls, d, t.expand() * c, inplace=True)
  195. return term_coeff_dict_new(cls, d)
  196. def expand_intpow(self, cls, expr, intexp):
  197. if intexp<0:
  198. return cls(POW, (expr, intexp))
  199. if intexp==0:
  200. return cls(NUMBER, 1)
  201. if intexp==1:
  202. return expr
  203. term_coeff_list = [(term.base_exp(), coeff) for term, coeff in expr.data.items()]
  204. mdata = multinomial_coefficients(len(term_coeff_list), intexp)
  205. d = {}
  206. for e,c in mdata.iteritems():
  207. new_coeff = c
  208. df = {}
  209. for e_i, ((base, exp), coeff) in zip(e, term_coeff_list):
  210. if e_i:
  211. if e_i==1:
  212. base_exp_dict_add_item(cls, df, base, exp)
  213. if coeff is not 1:
  214. new_coeff *= coeff
  215. else:
  216. base_exp_dict_add_item(cls, df, base, exp*e_i)
  217. if coeff is not 1:
  218. new_coeff *= coeff ** e_i
  219. new_term = base_exp_dict_new(cls, df)
  220. term_coeff_dict_add_item(cls, d, new_term, new_coeff)
  221. return term_coeff_dict_new(cls, d)
  222. def walk(self, func, cls, data, target):
  223. d = {}
  224. flag = False
  225. add = self.add
  226. for t, c in data.iteritems():
  227. t1 = t.head.walk(func, cls, t.data, t)
  228. if isinstance(c, Expr):
  229. c1 = c.head.walk(func, cls, c.data, c)
  230. else:
  231. c1 = NUMBER.walk(func, cls, c, c)
  232. if t1 is not t or c1 is not c:
  233. flag = True
  234. add(cls, d, t1 * c1, inplace=True)
  235. if flag:
  236. r = term_coeff_dict_new(cls, d)
  237. return func(cls, r.head, r.data, r)
  238. return func(cls, self, data, target)
  239. def scan(self, proc, cls, data, target):
  240. for t, c in data.iteritems():
  241. t.head.scan(proc, cls, t.data, target)
  242. if isinstance(c, Expr):
  243. c.head.scan(proc, cls, c.data, target)
  244. else:
  245. NUMBER.scan(proc, cls, c, target)
  246. proc(cls, self, data, target)
  247. def diff(self, cls, data, expr, symbol, order, cache={}):
  248. key = (expr, symbol, order)
  249. result = cache.get(key)
  250. if result is not None:
  251. return result
  252. if result is None:
  253. d = {}
  254. result = cls(NUMBER, 0)
  255. for term, coeff in data.iteritems():
  256. result += term.head.diff(cls, term.data, term, symbol, order, cache=cache) * coeff
  257. key1 = (expr, symbol, 1)
  258. cache[key] = result
  259. return result
  260. def apply(self, cls, data, func, args):
  261. result = cls(NUMBER, 0)
  262. for term, coeff in data.iteritems():
  263. result += term.head.apply(cls, term.data, term, args) * coeff
  264. return result
  265. def integrate_indefinite(self, cls, data, expr, x):
  266. result = cls(NUMBER, 0)
  267. for term, coeff in data.iteritems():
  268. result += term.head.integrate_indefinite(cls, term.data, term, x) * coeff
  269. return result
  270. def integrate_definite(self, cls, data, expr, x, a, b):
  271. result = cls(NUMBER, 0)
  272. for term, coeff in data.iteritems():
  273. result += term.head.integrate_definite(cls, term.data, term, x, a, b) * coeff
  274. return result
  275. def algebra_pos(self, Algebra, expr):
  276. return expr
  277. def algebra_neg(self, Algebra, expr):
  278. if Algebra.algebra_options.get('evaluate_addition'):
  279. d = expr.data.copy()
  280. for key in d:
  281. d[key] = -d[key]
  282. return Algebra(TERM_COEFF_DICT, d)
  283. return Algebra(NEG, expr)
  284. def algebra_add_number(self, Algebra, lhs, rhs, inplace):
  285. if not rhs:
  286. return lhs
  287. if inplace:
  288. term_coeff_dict_add_item(Algebra, lhs.data, Algebra(NUMBER, 1), rhs)
  289. return term_coeff_dict(Algebra, lhs)
  290. d = lhs.data.copy()
  291. term_coeff_dict_add_item(Algebra, d, Algebra(NUMBER, 1), rhs)
  292. return term_coeff_dict_new(Algebra, d)
  293. def algebra_add(self, Algebra, lhs, rhs, inplace):
  294. rhead, rdata = rhs.pair
  295. if Algebra.algebra_options.get('evaluate_addition'):
  296. ldata = lhs.data
  297. if rhead is ADD or rhead is EXP_COEFF_DICT or rhead is MUL or rhead is NEG:
  298. rhs = rhead.to_TERM_COEFF_DICT(Algebra, rdata, rhs)
  299. rhead, rdata = rhs.pair
  300. if rhead is NUMBER:
  301. if not rdata:
  302. return lhs
  303. rterm, rcoeff = Algebra(NUMBER, 1), rdata
  304. elif rhead is SYMBOL:
  305. rterm, rcoeff = rhs, 1
  306. elif rhead is TERM_COEFF:
  307. rterm, rcoeff = rdata
  308. elif rhead is TERM_COEFF_DICT:
  309. if inplace:
  310. term_coeff_dict_add_dict(Algebra, ldata, rdata)
  311. return term_coeff_dict(Algebra, lhs)
  312. d = ldata.copy()
  313. term_coeff_dict_add_dict(Algebra, d, rdata)
  314. return term_coeff_dict_new(Algebra, d)
  315. else:
  316. return super(type(self), self).algebra_add(Algebra, lhs, rhs, inplace)
  317. if inplace:
  318. term_coeff_dict_add_item(Algebra, ldata, rterm, rcoeff)
  319. return term_coeff_dict(Algebra, lhs)
  320. d = ldata.copy()
  321. term_coeff_dict_add_item(Algebra, d, rterm, rcoeff)
  322. return term_coeff_dict_new(Algebra, d)
  323. else:
  324. return TERM_COEFF_DICT.to_ADD(Algebra, lhs.data, lhs) + rhs
  325. return super(type(self), self).algebra_add(Algebra, lhs, rhs, inplace)
  326. def algebra_mul_number(self, Algebra, lhs, rhs, inplace):
  327. if Algebra.algebra_options.get('evaluate_addition'):
  328. if not rhs:
  329. return Algebra(NUMBER, 0)
  330. if rhs==1:
  331. return lhs
  332. if inplace:
  333. term_coeff_dict_mul_value(Algebra, lhs.data, rhs)
  334. return lhs
  335. d = lhs.data.copy()
  336. term_coeff_dict_mul_value(Algebra, d, rhs)
  337. return Algebra(TERM_COEFF_DICT, d)
  338. return Algebra(MUL, [lhs, Algebra(NUMBER, rhs)])
  339. def algebra_mul(self, Algebra, lhs, rhs, inplace):
  340. rhead, rdata = rhs.pair
  341. if rhead is NUMBER:
  342. return self.algebra_mul_number(Algebra, lhs, rdata, inplace)
  343. return super(type(self), self).algebra_mul(Algebra, lhs, rhs, inplace)
  344. def algebra_div_number(self, Algebra, lhs, rhs, inplace):
  345. if Algebra.algebra_options.get('evaluate_addition'):
  346. if rhs==1:
  347. return lhs
  348. d1 = gcd(*lhs.data.values())
  349. d2 = gcd(d1, rhs)
  350. d3 = rhs / d2
  351. d = {}
  352. rd = 0
  353. for t,c in lhs.data.items():
  354. c /= d2
  355. q, c = divmod(c, d3)
  356. if c:
  357. d[t] = c
  358. rd += q
  359. s = term_coeff_dict_new(Algebra, d)
  360. if rhs==d2:
  361. assert rd==0,`lsh, rhs, s,rd`
  362. return s
  363. return Algebra(DIV, [s, Algebra(NUMBER, d3)]) + rd
  364. return Algebra(DIV, [lhs, Algebra(NUMBER, rhs)])
  365. def algebra_div(self, Algebra, lhs, rhs, inplace):
  366. rhead, rdata = rhs.pair
  367. if rhead is NUMBER:
  368. return self.algebra_div_number(Algebra, lhs, rdata, inplace)
  369. return super(type(self), self).algebra_div(Algebra, lhs, rhs, inplace)
  370. TERM_COEFF_DICT = TermCoeffDictHead()