Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug in ManyToOneReplacer #26

Closed
arihantparsoya opened this issue Aug 29, 2017 · 4 comments
Closed

Bug in ManyToOneReplacer #26

arihantparsoya opened this issue Aug 29, 2017 · 4 comments

Comments

@arihantparsoya
Copy link

arihantparsoya commented Aug 29, 2017

Adding multiple rules is leading to mismatch of subject.

Code

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

from matchpy import replace_all, is_match, Wildcard, CustomConstraint
from sympy.integrals import Integral
from sympy import Symbol, Pow, cacheit, Basic, Add, Mul, S
from matchpy.expressions.functions import register_operation_iterator, register_operation_factory
from matchpy import Operation, CommutativeOperation, AssociativeOperation, OneIdentityOperation
from sympy.integrals.rubi.utility_function import *

class WC(Wildcard, Symbol):
    def __init__(self, min_length, fixed_size, variable_name=None, optional=None, **assumptions):
        Wildcard.__init__(self, min_length, fixed_size, str(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):
        if self.optional:
            return super()._hashable_content() + (self.min_count, self.fixed_size, self.variable_name, self.optional)
        else:
            return super()._hashable_content() + (self.min_count, self.fixed_size, self.variable_name)

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(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)

A_, B_, C_, F_, G_, H_, a_, b_, c_, d_, e_, f_, g_, h_, i_, j_, k_, l_, m_, n_, p_, q_, r_, t_, u_, v_, s_, w_, x_, y_, z_ = [WC(1, True, i) for i in 'ABCFGHabcdefghijklmnpqrtuvswxyz']
Pm_ = WC(1, True, 'Pm')

rubi = ManyToOneReplacer()

pattern7 = Pattern(Integral(Pm_**p_*WC(1, True,'u', S(1)), x_), CustomConstraint(lambda p, x: FreeQ(p, x)), CustomConstraint(lambda x, Pm: PolyQ(Pm, x)), CustomConstraint(lambda p: Not(RationalQ(p))), CustomConstraint(lambda p: RationalQ(p)))
rule7 = ReplacementRule(pattern7, lambda x, p, u, Pm : Int(Pm**p*u, x))
rubi.add(rule7)

pattern8 = Pattern(Integral(a_, x_), CustomConstraint(lambda a, x: FreeQ(a, x)))
rule8 = ReplacementRule(pattern8, lambda x, a : a*x)
rubi.add(rule8)

pattern30 = Pattern(Integral((x_**WC(1, True,'p', S(1))*WC(1, True,'a', S(1)) + x_**WC(1, True,'q', S(1))*WC(1, True,'b', S(1)) + x_**WC(1, True,'r', S(1))*WC(1, True,'c', S(1)))**WC(1, True,'m', S(1))*WC(1, True,'u', S(1)), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda p, x: FreeQ(p, x)), CustomConstraint(lambda q, x: FreeQ(q, x)), CustomConstraint(lambda r, x: FreeQ(r, x)), CustomConstraint(lambda m: IntegerQ(m)), CustomConstraint(lambda q, p: PosQ(-p + q)), CustomConstraint(lambda p, r: PosQ(-p + r)))
rule30 = ReplacementRule(pattern30, lambda x, p, m, c, u, q, b, a, r : Int(u*x**(m*p)*(a + b*x**(-p + q) + c*x**(-p + r))**m, x))
rubi.add(rule30)

from sympy.abc import a, x
subject = Integral(x + a, x)
print(rubi.replace(subject))

returns s*(x + a).

rule8 is being applied when all the patterns are added. When rule8 alone is added in ManyToOneReplacer, it does not match as expected.

@wheerd
Copy link
Collaborator

wheerd commented Aug 29, 2017

I will look into this later, I am currently traveling back home. rule8 does not match your example subject though, independently of the other rules.

EDIT: Sorry, I am tired and did not read your message properly. My apologies.

@arihantparsoya
Copy link
Author

I think that the matcher is matching Pattern wrong even-though Integral is not Commutative:

Pattern(Integral(a_, x_), CustomConstraint(lambda a, x: FreeQ(a, x)))

Integral(x + a, x) gets matched as {a ↦ x, x ↦ x + a} and hence the Constraint gets passed.

@wheerd
Copy link
Collaborator

wheerd commented Sep 3, 2017

Fixed it in the last commit.

@wheerd wheerd closed this as completed Sep 3, 2017
@arihantparsoya
Copy link
Author

Thanks !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants