HPAC / matchpy

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

Using `int` objects in ReplacementRule #1

Closed arihantparsoya closed 7 years ago

arihantparsoya commented 7 years ago

I am unable to use int objects in ReplacementRule:

>>> from matchpy import *
>>> a, b = map(Symbol, 'ab')
>>> Plus = Operation.new('+', Arity.variadic, 'Plus', associative=True, one_identity=True, infix=True)
>>> e = Plus(a,b)
>>> a_ = Wildcard.dot('a')
>>> b_ = Wildcard.dot('b')
>>> p = Pattern(Plus(a_,b_))
>>> rule = ReplacementRule(p, lambda a, b: Plus(a, 1)) # Ubable to apply rule due to the presence of `1`
>>> replace_all(e, [rule])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/parsoyaarihant/anaconda/lib/python3.6/site-packages/matchpy-0.2-py3.6.egg/matchpy/functions.py", line 251, in replace_all
  File "/Users/parsoyaarihant/anaconda/lib/python3.6/site-packages/matchpy-0.2-py3.6.egg/matchpy/matching/one_to_one.py", line 36, in match
  File "/Users/parsoyaarihant/anaconda/lib/python3.6/site-packages/matchpy-0.2-py3.6.egg/matchpy/utils.py", line 584, in __get__
  File "/Users/parsoyaarihant/anaconda/lib/python3.6/site-packages/matchpy-0.2-py3.6.egg/matchpy/expressions/expressions.py", line 131, in is_constant
  File "/Users/parsoyaarihant/anaconda/lib/python3.6/site-packages/matchpy-0.2-py3.6.egg/matchpy/expressions/expressions.py", line 507, in _is_constant
  File "/Users/parsoyaarihant/anaconda/lib/python3.6/site-packages/matchpy-0.2-py3.6.egg/matchpy/expressions/expressions.py", line 507, in <genexpr>
AttributeError: 'int' object has no attribute 'is_constant'

Is there any alternative way to use int or float in expressions?

wheerd commented 7 years ago

Unfortunately, currently all subexpressions must be subclasses of Expression as well. As a workaround, you could use a custom Symbol subclass for constants:

class ConstantSymbol(Symbol):
    def __init__(self. value):
        super().__init__(str(value))
        self.value = value

I am planing on making the expressions more flexible, so that the matching works with any types and not just Expression subclasses.

arihantparsoya commented 7 years ago

Thanks @wheerd .

New release of matchpy does not resolve this issue:

>>> from matchpy import *
>>> Plus = Operation.new('+', Arity.variadic, 'Plus', associative=True, one_identity=True, infix=True)
>>> Plus(1, -1).symbols
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/parsoyaarihant/anaconda/lib/python3.6/site-packages/matchpy-0.3-py3.6.egg/matchpy/utils.py", line 587, in __get__
  File "/Users/parsoyaarihant/anaconda/lib/python3.6/site-packages/matchpy-0.3-py3.6.egg/matchpy/expressions/expressions.py", line 113, in symbols
  File "/Users/parsoyaarihant/anaconda/lib/python3.6/site-packages/matchpy-0.3-py3.6.egg/matchpy/expressions/expressions.py", line 568, in collect_symbols
AttributeError: 'int' object has no attribute 'collect_symbols'
wheerd commented 7 years ago

Oh, all the properties of expressions do not work when mixing Expression-subclasses and other types. This is because something like int does not implement the needed methods. However, there is a workaround that would solve that problem. For example, you can use the following code to find out if an expression contains a 1:

from matchpy.expressions.functions import preorder_iter
if any(subexpr == 1 for subexpr in preorder_iter(expr)):
    print('Contains 1')

I need to release a new version so that the __contains__ method works with mixed types, too.

wheerd commented 7 years ago

The __contains__ method is fixed in version 0.3.1. I will look into the remaining attributes/methods of Expressions as well, but you should probably just use the functions in matchpy.expressions.functions if you are using mixed types. x.symbols will still fail if x happens to be matched with an int instead of an Expression.