HPAC / matchpy

A library for pattern matching on symbolic expressions in Python.
MIT License
164 stars 25 forks source link

Error while replace in `ManyToOneReplacer` #24

Closed arihantparsoya closed 7 years ago

arihantparsoya commented 7 years ago

Pattern is matching but .replace in ManyToOneReplacer is showing error.

Code

import matchpy
Pattern, ReplacementRule, ManyToOneReplacer = matchpy.Pattern, matchpy.ReplacementRule, matchpy.ManyToOneReplacer

from matchpy import replace_all, is_match, Wildcard
from sympy.integrals import Integral
from sympy import Symbol, Pow, cacheit, Basic, S, Add, Mul, srepr, Or, And
from matchpy.expressions.functions import register_operation_iterator, register_operation_factory
from matchpy import Operation, CommutativeOperation, AssociativeOperation, OneIdentityOperation, match, CustomConstraint

class WC(Wildcard, Symbol):
    def __init__(self, min_length, fixed_size, variable_name=None, optional=None, **assumptions):
        Wildcard.__init__(self, min_length, fixed_size, variable_name, optional)

    def __new__(cls, min_length, fixed_size, variable_name=None, optional=None, **assumptions):
        cls._sanitize(assumptions, cls)
        return WC.__xnew__(cls, min_length, fixed_size, variable_name, optional, **assumptions)

    def __getnewargs__(self):
        return (self.min_length, self.fixed_size, self.variable_name, self.optional)

    @staticmethod
    def __xnew__(cls, min_length, fixed_size, variable_name=None, optional=None, **assumptions):
        obj = Symbol.__xnew__(cls, variable_name, **assumptions)
        return obj

    def _hashable_content(self):
        return super()._hashable_content() + (self.min_count, self.fixed_size, self.variable_name, self.optional)

Operation.register(Integral)
register_operation_iterator(Integral, lambda a: (a._args[0],) + a._args[1], lambda a: len((a._args[0],) + a._args[1]))

Operation.register(Pow)
OneIdentityOperation.register(Pow)
register_operation_iterator(Pow, lambda a: a._args, lambda a: len(a._args))

Operation.register(Add)
OneIdentityOperation.register(Add)
CommutativeOperation.register(Add)
AssociativeOperation.register(Add)
register_operation_iterator(Add, lambda a: a._args, lambda a: len(a._args))

Operation.register(Mul)
OneIdentityOperation.register(Mul)
CommutativeOperation.register(Mul)
AssociativeOperation.register(Mul)
register_operation_iterator(Mul, lambda a: a._args, lambda a: len(a._args))

def sympy_op_factory(old_operation, new_operands, variable_name):
     return type(old_operation)(*new_operands)

register_operation_factory(Basic, sympy_op_factory)

m_ = WC(1, True, 'm')
x_ = WC(1, True, 'x')
c_ = WC(1, True, 'c')
n_ = WC(1, True, 'n')
x = Symbol('x')
b = Symbol('b')
a = Symbol('a')
c = Symbol('c')
d = Symbol('d')
m = Symbol('m')
n = Symbol('n')

subject = Integral(x**(S(4)/3)/(a + b*x)**2, x)

rubi = ManyToOneReplacer()

pattern32 = Pattern(Integral(Mul(Pow(Add(WC(1, True, 'a', S('0')), Mul(WC(1, True, 'b', S('1')), x_)), m_), Pow(Add(WC(1, True, 'c', S('0')), Mul(WC(1, True, 'd', S('1')), x_)), n_)), x_))
rule32 = ReplacementRule(pattern32, lambda a, d, x, b, c, m, n : Add(Mul(Pow(Add(a, Mul(b, x)), Add(m, S('1'))), Mul(Pow(Add(c, Mul(d, x)), n), Pow(Mul(b, Add(m, S('1'))), S('-1')))), Mul(S('-1'), Mul(d, Mul(n, Pow(Mul(b, Add(m, S('1'))), S('-1'))), Integral(Mul(Pow(Add(a, Mul(b, x)), Add(m, S('1'))), Pow(Add(c, Mul(d, x)), Add(n, S('-1')))), x)))))
rubi.add(rule32)

print(is_match(subject, pattern32))
print(rubi.replace(subject))

Error:

Traceback (most recent call last):
  File "r1.py", line 74, in <module>
    print(rubi.replace(subject))
  File "/Users/parsoyaarihant/anaconda/lib/python3.6/site-packages/matchpy-0.5.dev56+g9b820f8-py3.6.egg/matchpy/matching/many_to_one.py", line 798, in replace
  File "/Users/parsoyaarihant/anaconda/lib/python3.6/site-packages/matchpy-0.5.dev56+g9b820f8-py3.6.egg/matchpy/functions.py", line 126, in replace
TypeError: object of type 'Add' has no len()
wheerd commented 7 years ago

Now the replacement will not stop because the pattern keeps matching the newly replaced term as well again.