poly.py 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. from itertools import combinations
  2. from ..node import Scope, OP_ADD
  3. from ..possibilities import Possibility as P, MESSAGES
  4. from .numerics import add_numerics
  5. def match_combine_polynomes(node, verbose=False):
  6. """
  7. n + exp + m -> exp + (n + m)
  8. k0 * v ^ n + exp + k1 * v ^ n -> exp + (k0 + k1) * v ^ n
  9. """
  10. assert node.is_op(OP_ADD)
  11. p = []
  12. # Collect all nodes that can be combined:
  13. # a ^ e = 1 * a ^ e
  14. # c * a = c * a ^ 1
  15. # c * a ^ e
  16. # a = 1 * a ^ 1
  17. #
  18. # Identifier nodes of all polynomes, tuple format is:
  19. # (root, exponent, coefficient, literal_coefficient)
  20. polys = []
  21. if verbose: # pragma: nocover
  22. print 'match combine factors:', node
  23. scope = Scope(node)
  24. for n in scope:
  25. polynome = n.extract_polynome_properties()
  26. if verbose: # pragma: nocover
  27. print 'n:', n, 'polynome:', polynome
  28. if polynome:
  29. polys.append((n, polynome))
  30. # Each combination of powers of the same value and polynome can be added
  31. if len(polys) >= 2:
  32. for left, right in combinations(polys, 2):
  33. n0, p0 = left
  34. n1, p1 = right
  35. c0, r0, e0 = p0
  36. c1, r1, e1 = p1
  37. # Both numeric root and same exponent -> combine coefficients and
  38. # roots, or: same root and exponent -> combine coefficients.
  39. # TODO: Addition with zero, e.g. a + 0 -> a
  40. #if c0 == 1 and c1 == 1 and e0 == 1 and e1 == 1 \
  41. # and all(map(lambda n: n.is_numeric(), [r0, r1])):
  42. # # 2 + 3 -> 5
  43. # # 2 + -3 -> -1
  44. # # -2 + 3 -> 1
  45. # # -2 + -3 -> -5
  46. # p.append(P(node, add_numerics, (scope, n0, n1, r0, r1)))
  47. #el
  48. if c0.is_numeric() and c1.is_numeric() and r0 == r1 and e0 == e1:
  49. # 2a + 2a -> 4a
  50. # a + 2a -> 3a
  51. # 2a + a -> 3a
  52. # a + a -> 2a
  53. p.append(P(node, combine_polynomes, (scope, n0, n1,
  54. c0, c1, r0, e0)))
  55. return p
  56. def combine_polynomes(root, args):
  57. """
  58. Combine two multiplications of any polynome in an n-ary plus.
  59. Synopsis:
  60. c0 * a ^ b + c1 * a ^ b -> (c0 + c1) * a ^ b
  61. """
  62. scope, n0, n1, c0, c1, r, e = args
  63. # a ^ 1 -> a
  64. if e == 1:
  65. power = r
  66. else:
  67. power = r ** e
  68. # Replace the left node with the new expression:
  69. # (c0 + c1) * a ^ b
  70. # a, b and c are from 'left', d is from 'right'.
  71. scope.replace(n0, (c0 + c1) * power)
  72. # Remove the right node
  73. scope.remove(n1)
  74. return scope.as_nary_node()