-
Notifications
You must be signed in to change notification settings - Fork 25
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
substitute not working with SymPy #65
Comments
As a convention, operands in commutative functions are sorted in MatchPy. If I'm not mistaken, in that line we know that the operands come from a commutative functions because they are stored in a multiset. As a result, it's necessary to sort operands there. |
In order to reproduce this bug, using the branch in sympy/sympy#20612 I have the following: In [1]: from sympy.utilities.matchpy_connector import WildDot, WildPlus, WildStar
In [2]: from matchpy import substitute
In [3]: from sympy import *
In [4]: x, y, z = symbols("x y z")
In [5]: w = WildPlus("w")
In [6]: from matchpy import ManyToOneMatcher
In [7]: matcher = ManyToOneMatcher()
In [8]: from matchpy import Pattern
In [9]: matcher.add(Pattern(x + w))
In [10]: result = matcher.match(x + y + z)
In [11]: result
Out[11]: <matchpy.matching.many_to_one._MatchIter at 0x7f3022a3da10>
In [12]: result = next(iter(result))
In [13]: result
Out[13]: (Pattern(x + w), {'w': Multiset({y: 1, z: 1})})
In [14]: substitute(result[0], result[1])
---------------------------------------------------------------------------
TypeError: cannot determine truth value of Relational
Now, if I redefine the MatchPy from matchpy import *
from matchpy.functions import *
from typing import *
from multiset import *
from sympy.core.compatibility import default_sort_key
def substitute(expression: Union[Expression, Pattern], substitution: Substitution) -> Replacement:
if isinstance(expression, Pattern):
expression = expression.expression
return _substitute(expression, substitution)[0]
def _substitute(expression: Expression, substitution: Substitution) -> Tuple[Replacement, bool]:
if getattr(expression, 'variable_name', False) and expression.variable_name in substitution:
return substitution[expression.variable_name], True
elif isinstance(expression, Operation):
any_replaced = False
new_operands = []
for operand in op_iter(expression):
result, replaced = _substitute(operand, substitution)
if replaced:
any_replaced = True
if isinstance(result, (list, tuple)):
new_operands.extend(result)
elif isinstance(result, Multiset):
new_operands.extend(sorted(result, key=default_sort_key))
else:
new_operands.append(result)
if any_replaced:
return create_operation_expression(expression, new_operands), True
return expression, False The code now works correctly: In [24]: substitute(result[0], result[1])
Out[24]: x + y + z So it looks like the usage of @hbarthels is |
Ah, now it makes a lot more sense that all the other stuff works. 😄
To be honest, I don't know the code well enough to know for sure if it is necessary there. I guess it's not necessary if the expression that is returned by
I have the following idea to solve this problem: You add a function to MatchPy that allows to pass a custom sort key, which is stored in some global variable. Then, you implement something like a By the way, is it possible that in the code you posted, you accidentally used to original version of |
Here it is: #66
Removing
Is it possible to add a unit test to MatchPy with a few checks for SymPy's compatibility? It would be great to keep SymPy and MatchPy compatible with each other in the future (there's been a lot of effort to make them compatible, so why not enforcing a check to make sure it won't break in the future?).
I copy-pasted the wrong code. Now it's fixed. |
You could change |
I don't think that removing or changing
Sure, that makes sense. |
The other utilities of MatchPy appear to work well with SymPy... |
I searched the code for calls to sorting functions. The call that makes sure that operands are sorted is part of the matchpy/matchpy/matching/many_to_one.py Line 881 in d542872
However, I can't tell if the comparison depends on comparing expressions just by looking at it. So maybe changing substitute( ) is indeed sufficient, but I wouldn't rely on it without a lot of testing.
Does SymPy automatically sort operands in commutative functions? |
|
Is it important to you that we create a new release of MatchPy as soon as possible? If not, I would prefer to wait a bit in case more problems show up. I guess it would also make sense to add tests for the SymPy compatibility before the next release. Are you working on those tests? |
We have these tests in SymPy. I have merged some extensions to |
Calling
sorted( )
inmatchpy/matchpy/functions.py
Line 87 in 5cae3f2
fails with SymPy, as SymPy objects are not comparable with operators (
<
,<=
,>
,>=
). Operators are overloaded in SymPy to create instances of inequality objects.SymPy has a function called
default_sort_key
meant to deal with this problem:The question is, is it possible to modify MatchPy to specify a custom sorting key so that SymPy can specify the way its objects should be sorted?
Or is it an issue with
Multiset
?The text was updated successfully, but these errors were encountered: