PageRenderTime 45ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/sympycore/heads/term_coeff.py

https://github.com/escheffel/pymaclab
Python | 351 lines | 301 code | 46 blank | 4 comment | 102 complexity | d9cce7e3ec4099c0f4a80df8498c738e MD5 | raw file
  1. __all__ = ['TERM_COEFF']
  2. from .base import heads_precedence, ArithmeticHead, Expr
  3. from ..core import init_module
  4. init_module.import_heads()
  5. init_module.import_numbers()
  6. init_module.import_lowlevel_operations()
  7. class TermCoeff(ArithmeticHead):
  8. """ Expr(TERM_COEFF, (term, coeff)) represents term*coeff
  9. where term is symbolic expression and coeff is a number or
  10. symbolic expression.
  11. """
  12. def is_data_ok(self, cls, data, allow_number_term=True):
  13. if type(data) is tuple and len(data)==2:
  14. term, coeff = data
  15. if isinstance(term, cls):
  16. if isinstance(coeff, numbertypes) or type(coeff) is not cls:
  17. if term.head is self or (not allow_number_term and term.head is NUMBER):
  18. return 'data[0].head cannot be %s' %(term.head)
  19. return
  20. elif isinstance(coeff, cls):
  21. if coeff.head is NUMBER:
  22. if not isinstance(coeff.data, numbertypes): #pragma: no cover
  23. return 'data[1].data must be %s instance for NUMBER head but got %s instance' % (numbertypes, type(coeff.data)) #pragma: no cover
  24. else:
  25. return 'data[1] must be %s instance but got %s instance' % ((cls, numbertypes), type(coeff)) #pragma: no cover
  26. else:
  27. return 'data[0] must be %s instance but got %s instance' % (cls, type(term)) #pragma: no cover
  28. else:
  29. return 'data must be 2-tuple' #pragma: no cover
  30. return
  31. def __repr__(self): return 'TERM_COEFF'
  32. def new(self, cls, data):
  33. return term_coeff_new(cls, data)
  34. def reevaluate(self, cls, (term, coeff)):
  35. return term * coeff
  36. def to_EXP_COEFF_DICT(self, cls, (term, coeff), expr, variables=None):
  37. return term.head.to_EXP_COEFF_DICT(cls, term.data, term, variables) * coeff
  38. def to_MUL(self, Algebra, (term, coeff), expr):
  39. term = term.head.to_MUL(Algebra, term.data, term)
  40. if term.head is MUL:
  41. data = [Algebra(NUMBER, coeff)] + term.data
  42. else:
  43. data = [Algebra(NUMBER, coeff), term]
  44. return Algebra(MUL, data)
  45. def to_ADD(self, Algebra, (term, coeff), expr):
  46. return coeff * term.head.to_ADD(Algebra, term.data, term)
  47. def data_to_str_and_precedence(self, cls, (term, coeff)):
  48. neg_p = heads_precedence.NEG
  49. mul_p = heads_precedence.MUL
  50. if term==1:
  51. t, t_p = NUMBER.data_to_str_and_precedence(cls, coeff)
  52. elif coeff==1:
  53. t, t_p = term.head.data_to_str_and_precedence(cls, term.data)
  54. elif coeff==-1:
  55. t, t_p = term.head.data_to_str_and_precedence(cls, term.data)
  56. t, t_p = ('-('+t+')' if t_p < mul_p else '-' + t), neg_p
  57. elif coeff==0:
  58. t, t_p = '0', heads_precedence.NUMBER
  59. else:
  60. t, t_p = term.head.data_to_str_and_precedence(cls, term.data)
  61. c, c_p = NUMBER.data_to_str_and_precedence(cls, coeff)
  62. if t=='1':
  63. return c, c_p
  64. cs = '('+c+')' if c_p < mul_p else c
  65. ts = '('+t+')' if t_p < mul_p else t
  66. t = cs + (ts[1:] if ts.startswith('1/') else '*' + ts)
  67. t_p = mul_p
  68. return t, t_p
  69. def term_coeff(self, cls, expr):
  70. return expr.data
  71. def neg(self, cls, expr):
  72. term, coeff = expr.data
  73. return term_coeff_new(cls, (term, -coeff))
  74. def add(self, cls, lhs, rhs):
  75. term, coeff = lhs.data
  76. head, data = rhs.pair
  77. if head is ADD:
  78. return ADD.new(cls, [lhs] + data)
  79. if head is TERM_COEFF_DICT:
  80. data = data.copy()
  81. dict_add_item(cls, data, term, coeff)
  82. return term_coeff_dict_new(cls, data)
  83. if head is NUMBER:
  84. if data==0:
  85. return lhs
  86. return cls(TERM_COEFF_DICT,{term:coeff, cls(NUMBER,1):data})
  87. if head is SYMBOL:
  88. if term==rhs:
  89. return term_coeff_new(cls, (term, coeff + 1))
  90. return cls(TERM_COEFF_DICT,{term:coeff, rhs:1})
  91. if head is TERM_COEFF:
  92. rterm, rcoeff = data
  93. if rterm==term:
  94. return term_coeff_new(cls, (term, coeff + rcoeff))
  95. return cls(TERM_COEFF_DICT,{term:coeff, rterm:rcoeff})
  96. if head is BASE_EXP_DICT:
  97. rcoeff = base_exp_dict_get_coefficient(cls, data)
  98. if rcoeff is not None:
  99. d = data.copy()
  100. del d[rcoeff]
  101. rterm = base_exp_dict_new(cls, d)
  102. if rterm==term:
  103. return term_coeff_new(cls, (term, coeff + rcoeff))
  104. return cls(TERM_COEFF_DICT,{term:coeff, rterm:rcoeff})
  105. else:
  106. if term==rhs:
  107. return term_coeff_new(cls, (term, coeff + 1))
  108. return cls(TERM_COEFF_DICT,{term:coeff, rhs:1})
  109. if head is POW or head is APPLY or head is DIFF or head is FDIFF or head is SUBSCRIPT:
  110. if term==rhs:
  111. return term_coeff_new(cls, (term, coeff + 1))
  112. return cls(TERM_COEFF_DICT,{term:coeff, rhs:1})
  113. if head is MUL:
  114. return cls(ADD, [lhs, rhs])
  115. raise NotImplementedError(`self, rhs.head`)
  116. inplace_add = add
  117. def add_number(self, cls, lhs, rhs):
  118. if rhs==0:
  119. return lhs
  120. term, coeff = lhs.data
  121. return cls(TERM_COEFF_DICT, {term: coeff, cls(NUMBER, 1): rhs})
  122. def sub_number(self, cls, lhs, rhs):
  123. if rhs==0:
  124. return lhs
  125. term, coeff = lhs.data
  126. return cls(TERM_COEFF_DICT, {term: coeff, cls(NUMBER, 1): -rhs})
  127. def sub(self, cls, lhs, rhs):
  128. return lhs + (-rhs)
  129. def non_commutative_mul(self, cls, lhs, rhs):
  130. term, coeff = lhs.data
  131. head, data = rhs.pair
  132. if head is NUMBER:
  133. return term_coeff_new(cls, (term, coeff * data))
  134. return (term * rhs) * coeff
  135. commutative_mul = non_commutative_mul
  136. def commutative_mul_number(self, cls, lhs, rhs):
  137. if rhs==1:
  138. return lhs
  139. if rhs==0:
  140. return cls(NUMBER, 0)
  141. term, coeff = lhs.data
  142. new_coeff = coeff * rhs
  143. if new_coeff==1:
  144. return term
  145. return cls(TERM_COEFF, (term, new_coeff))
  146. non_commutative_mul_number = commutative_mul_number
  147. inplace_commutative_mul = commutative_mul
  148. def commutative_div_number(self, cls, lhs, rhs):
  149. term, coeff = lhs.data
  150. r = number_div(cls, coeff, rhs)
  151. if rhs==0:
  152. return r * term
  153. return term_coeff_new(cls, (term, r))
  154. def commutative_rdiv_number(self, cls, lhs, rhs):
  155. term, coeff = lhs.data
  156. r = number_div(cls, rhs, coeff)
  157. if rhs==0:
  158. return r * (1/term)
  159. return term_coeff_new(cls, (1/term, r))
  160. def commutative_div(self, cls, lhs, rhs):
  161. rhead, rdata = rhs.pair
  162. if rhead is NUMBER:
  163. return self.commutative_div_number(cls, lhs, rdata)
  164. term, coeff = lhs.data
  165. if rhead is TERM_COEFF:
  166. rterm, rcoeff = rdata
  167. if term==rterm:
  168. return cls(NUMBER, number_div(cls, coeff, rcoeff))
  169. return term.head.commutative_div(cls, term, rterm) * number_div(cls, coeff, rcoeff)
  170. if rhead is SYMBOL or rhead is APPLY:
  171. if term == rhs:
  172. return cls(NUMBER, coeff)
  173. b, e = term.base_exp()
  174. return cls(TERM_COEFF, (cls(BASE_EXP_DICT, {b:e, rhs:-1}), coeff))
  175. if rhead is TERM_COEFF_DICT:
  176. b, e = term.base_exp()
  177. return cls(TERM_COEFF, (cls(BASE_EXP_DICT, {b:e, rhs:-1}), coeff))
  178. if term==rhs:
  179. return cls(NUMBER, coeff)
  180. return (term / rhs) * coeff
  181. return term.head.commutative_div(cls, term, rhs) * coeff
  182. def pow(self, cls, base, exp):
  183. term, coeff = base.data
  184. if isinstance(exp, Expr):
  185. head, data = exp.pair
  186. if head is NUMBER:
  187. exp = data
  188. if isinstance(exp, inttypes):
  189. if exp<0:
  190. return term ** exp / coeff ** (-exp)
  191. return term ** exp * coeff ** exp
  192. return pow_new(cls, (base, exp))
  193. def pow_number(self, cls, base, exp):
  194. term, coeff = base.data
  195. if isinstance(exp, inttypes):
  196. if exp<0:
  197. return term ** exp / coeff ** (-exp)
  198. return term ** exp * coeff ** exp
  199. return cls(POW, (base, exp))
  200. def walk(self, func, cls, data, target):
  201. term, coeff = data
  202. h, d = term.pair
  203. term = h.walk(func, cls, d, term)
  204. if isinstance(coeff, Expr):
  205. h, d = coeff.pair
  206. coeff = h.walk(func, type(coeff), d, coeff)
  207. s = term * coeff
  208. h, d = s.pair
  209. return func(cls, h, d, s)
  210. def scan(self, proc, cls, data, target):
  211. term, coeff = data
  212. term.head.scan(proc, cls, term.data, target)
  213. if isinstance(coeff, Expr):
  214. coeff.head.scan(proc, type(coeff), coeff.data, target)
  215. proc(cls, self, data, target)
  216. def expand(self, cls, expr):
  217. term, coeff = expr.data
  218. return term.head.expand(cls, term) * coeff
  219. def diff(self, cls, data, expr, symbol, order, cache={}):
  220. term, coeff = data
  221. return term.head.diff(cls, term.data, term, symbol, order, cache=cache) * coeff
  222. def diff_apply(self, cls, data, diff, expr):
  223. term, coeff = data
  224. return term.head.diff_apply(cls, term.data, term, expr) * coeff
  225. def apply(self, cls, data, func, args):
  226. term, coeff = data
  227. return term.head.apply(cls, term.data, term, args) * coeff
  228. def integrate_indefinite(self, cls, data, expr, x):
  229. term, coeff = data
  230. return term.head.integrate_indefinite(cls, term.data, term, x) * coeff
  231. def integrate_definite(self, cls, data, expr, x, a, b):
  232. term, coeff = data
  233. return term.head.integrate_definite(cls, term.data, term, x, a, b) * coeff
  234. def to_TERM_COEFF_DICT(self, Algebra, data, expr):
  235. term, coeff = data
  236. return term.head.to_TERM_COEFF_DICT(Algebra, term.data, term) * coeff
  237. def algebra_pos(self, Algebra, expr):
  238. return expr
  239. def algebra_neg(self, Algebra, expr):
  240. if Algebra.algebra_options.get('evaluate_addition'):
  241. term, coeff = expr.data
  242. return term_coeff_new(Algebra, (term, -coeff))
  243. return Algebra(NEG, expr)
  244. def algebra_add_number(self, Algebra, lhs, rhs, inplace):
  245. return self.algebra_add(Algebra, lhs, Algebra(NUMBER, rhs), inplace)
  246. def algebra_add(self, Algebra, lhs, rhs, inplace):
  247. rhead, rdata = rhs.pair
  248. if Algebra.algebra_options.get('is_additive_group_commutative'):
  249. lterm, lcoeff = lhs.data
  250. if Algebra.algebra_options.get('evaluate_addition'):
  251. if rhead is ADD or rhead is MUL or rhead is NEG:
  252. rhs = rhead.to_TERM_COEFF_DICT(Algebra, rdata, rhs)
  253. rhead, rdata = rhs.pair
  254. if rhead is NUMBER:
  255. if rdata==0:
  256. return lhs
  257. return Algebra(TERM_COEFF_DICT, {lterm:lcoeff, Algebra(NUMBER, 1): rdata})
  258. if rhead is SYMBOL:
  259. if lterm==rhs:
  260. return term_coeff_new(Algebra, (lterm, lcoeff + 1))
  261. return Algebra(TERM_COEFF_DICT, {lterm:lcoeff, rhs: 1})
  262. if rhead is TERM_COEFF:
  263. rterm, rcoeff = rdata
  264. if lterm == rterm:
  265. return term_coeff_new(Algebra, (lterm, lcoeff+rcoeff))
  266. return Algebra(TERM_COEFF_DICT, {lterm:lcoeff, rterm:rcoeff})
  267. if rhead is TERM_COEFF_DICT:
  268. d = rdata.copy()
  269. term_coeff_dict_add_item(Algebra, d, lterm, lcoeff)
  270. return term_coeff_dict_new(Algebra, d)
  271. else:
  272. if rhead is TERM_COEFF_DICT or rhead is EXP_COEFF_DICT:
  273. rhead, rdata = rhs.to(ADD).pair
  274. if rhead is ADD:
  275. data = [lhs] + rdata
  276. else:
  277. data = [lhs, rhs]
  278. return add_new(Algebra, data)
  279. return super(type(self), self).algebra_add(Algebra, lhs, rhs, inplace)
  280. else:
  281. if rhead is TERM_COEFF_DICT or rhead is EXP_COEFF_DICT:
  282. rhead, rdata = rhs.to(ADD).pair
  283. if rhead is ADD:
  284. data = [lhs] + rdata
  285. else:
  286. data = [lhs, rhs]
  287. if Algebra.algebra_options.get('evaluate_addition'):
  288. ADD.combine_add_list(Algebra, data)
  289. return add_new(Algebra, data)
  290. def algebra_mul_number(self, Algebra, lhs, rhs, inplace):
  291. if Algebra.algebra_options.get('evaluate_addition'):
  292. if not rhs:
  293. return Algebra(NUMBER, 0)
  294. term, coeff = lhs.data
  295. return term_coeff_new(Algebra, (term, coeff * rhs))
  296. return mul_new(Algebra, [lhs, Algebra(NUMBER, rhs)])
  297. def algebra_mul(self, Algebra, lhs, rhs, inplace):
  298. if Algebra.algebra_options.get('evaluate_addition'):
  299. term, coeff = lhs.data
  300. rhead, rdata = rhs.pair
  301. if rhead is NUMBER:
  302. return term_coeff_new(Algebra, (term, coeff*rdata))
  303. return super(type(self), self).algebra_mul(Algebra, lhs, rhs, inplace)
  304. return mul_new(Algebra, [lhs, rhs])
  305. TERM_COEFF = TermCoeff()