-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
add abs function to parameterexpression #7497
Conversation
Pull Request Test Coverage Report for Build 1722151454
💛 - Coveralls |
else: | ||
return self._symbol_expr.__lt__(other._symbol_expr) | ||
elif isinstance(other, numbers.Number): | ||
return len(self.parameters) == 0 and float(self._symbol_expr) < other |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If len(self.parameters) !=0
this returns False
, but it should raise an exception.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the __eq__
method should also have this behaviour. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for looking at this! The addition of abs
looks fine to me, though it needs a release note to go with it.
I'm not sure it's a good idea to add the comparison operators, though. The class is called ParameterExpression
, but in general between two instances of it, the comparison is unknowable. Storing the result of <
or so turns it into a "relation" not an "expression". For example, see one of the comments below about how sympy
doesn't usually return Booleans in comparisons. At the very least, I think adding the comparison operators should be a separate PR, but honestly, I think it would be better to leave them undefined; I don't see any use-cases for them working only very occasionally.
if len(self.parameters) == 0: | ||
return float(self._symbol_expr) < other | ||
else: | ||
raise TypeError( | ||
"'<' not supported between instances of {type(self)} " | ||
"with unbound parameters {self.parameters} and {type(other)}." | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like there will be situations where an expression might not have a single numerical value, but can be bound for certain comparisons. For example, abs(x) >= 0
is knowable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved the implementation to #7539, please have a look there.
def test_raise_if_compare_not_supported(self): | ||
"""Verify raises if compare to object.""" | ||
x = Parameter("x") | ||
y = object |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You probably meant to instantiate an object
here (y = object()
), rather than use the type object
. It'll work the same, but the way it's written is slightly confusing.
with self.assertRaisesRegex(TypeError, "not supported"): | ||
x.__lt__(y) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'd be clearer to write x < y
if that's what you mean; it's good to test the exact paths you expect to be used.
self.assertTrue(bound_expr < 3.0) | ||
self.assertTrue(bound_expr > 1.0) | ||
self.assertEqual(abs(bound_expr), 2.3) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we keep the comparison operators __le__
and __ge__
, we'd need to those here too.
return sympify(self._symbol_expr).__lt__(sympify(other._symbol_expr)) | ||
else: | ||
return self._symbol_expr.__lt__(other._symbol_expr) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These don't do what you think they do; they don't always return Boolean values. Also, in general it's better to use the Python operations, and let Python handle the numerics; this way can fail if the left-hand side doesn't evaluate __lt__
, but the right hand does evaluate __gt__
, whereas if you'd used <
in that situation, Python would evaluate it correctly.
For not returning a Boolean, see:
In [1]: import sympy
...: x = sympy.Symbol("x")
...: x + 1 > x
Out[1]: x + 1 > x
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is better as the simpler PR - it will be safe to add this functionality without issue. Please could you add some more rigorous tests, and also add a release note (see the contributing guide).
self.assertEqual(bound_expr, 2.3) | ||
self.assertEqual(abs(bound_expr), 2.3) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be best to separate out the tests of abs
into their own function; they're not really related to this.
Also, I think we could do with more stringent tests of it; at the moment, if abs
is implemented incorrectly this test can still fail. We need to actually test the mathematical properties of abs
, for example that it makes negative numbers positive, and complex numbers positive-real. We should also test that it works for symbolic expressions, such as abs(< -x >)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As suggested, I added more tests to the implementation. What do you mean by testing symbolic expressions, such as abs(< -x >)
?
Dear @czachow , |
Dear @king-p3nguin, thanks for working on this old PR that would have been forgotten otherwise. In my memory most of the implementation is done. You only need to add more tests like @jakelishman suggested. Feel free to do so! |
Thank you very much! |
Closing this as duplicate of #9309. |
Summary
Details and comments