| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394 |
- from itertools import combinations
- from ..node import Scope, OP_ADD
- from ..possibilities import Possibility as P, MESSAGES
- from .numerics import add_numerics
- def match_combine_polynomes(node, verbose=False):
- """
- n + exp + m -> exp + (n + m)
- k0 * v ^ n + exp + k1 * v ^ n -> exp + (k0 + k1) * v ^ n
- """
- assert node.is_op(OP_ADD)
- p = []
- # Collect all nodes that can be combined:
- # a ^ e = 1 * a ^ e
- # c * a = c * a ^ 1
- # c * a ^ e
- # a = 1 * a ^ 1
- #
- # Identifier nodes of all polynomes, tuple format is:
- # (root, exponent, coefficient, literal_coefficient)
- polys = []
- if verbose: # pragma: nocover
- print 'match combine factors:', node
- scope = Scope(node)
- for n in scope:
- polynome = n.extract_polynome_properties()
- if verbose: # pragma: nocover
- print 'n:', n, 'polynome:', polynome
- if polynome:
- polys.append((n, polynome))
- # Each combination of powers of the same value and polynome can be added
- if len(polys) >= 2:
- for left, right in combinations(polys, 2):
- n0, p0 = left
- n1, p1 = right
- c0, r0, e0 = p0
- c1, r1, e1 = p1
- # Both numeric root and same exponent -> combine coefficients and
- # roots, or: same root and exponent -> combine coefficients.
- # TODO: Addition with zero, e.g. a + 0 -> a
- #if c0 == 1 and c1 == 1 and e0 == 1 and e1 == 1 \
- # and all(map(lambda n: n.is_numeric(), [r0, r1])):
- # # 2 + 3 -> 5
- # # 2 + -3 -> -1
- # # -2 + 3 -> 1
- # # -2 + -3 -> -5
- # p.append(P(node, add_numerics, (scope, n0, n1, r0, r1)))
- #el
- if c0.is_numeric() and c1.is_numeric() and r0 == r1 and e0 == e1:
- # 2a + 2a -> 4a
- # a + 2a -> 3a
- # 2a + a -> 3a
- # a + a -> 2a
- p.append(P(node, combine_polynomes, (scope, n0, n1,
- c0, c1, r0, e0)))
- return p
- def combine_polynomes(root, args):
- """
- Combine two multiplications of any polynome in an n-ary plus.
- Synopsis:
- c0 * a ^ b + c1 * a ^ b -> (c0 + c1) * a ^ b
- """
- scope, n0, n1, c0, c1, r, e = args
- # a ^ 1 -> a
- if e == 1:
- power = r
- else:
- power = r ** e
- # Replace the left node with the new expression:
- # (c0 + c1) * a ^ b
- # a, b and c are from 'left', d is from 'right'.
- scope.replace(n0, (c0 + c1) * power)
- # Remove the right node
- scope.remove(n1)
- return scope.as_nary_node()
|