-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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 ParameterExpression.numeric
to cast to number
#11109
Conversation
One or more of the the following people are requested to review this:
|
This is largely a wrap-up of the `if ParameterExpression.is_real(): ...` logic present in a few places across the library, but a bit more efficient for Symengine because it can re-use cases where it needed to force an evaluation to produce accurate results. Mostly, though, it simplifies a few call sites.
b3b0a4d
to
1c023bd
Compare
Pull Request Test Coverage Report for Build 7259881506Warning: This coverage report may be inaccurate.We've detected an issue with your CI configuration that might affect the accuracy of this pull request's coverage report.
💛 - Coveralls |
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.
Looks good to me! Just some comments here and there.
self.assertIsInstance(one_imaginary.numeric(), complex) | ||
self.assertEqual(one_imaginary.numeric(), 1j) | ||
|
||
# This is one particular case where symengine 0.9.2 (and probably others) struggles when |
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 corner case can be removed with #11315 ?
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'd leave it in regardless - it still works as a regression test for us.
# Symengine returns `complex` if any imaginary floating-point enters at all, even if | ||
# the result is zero. The best we can do is detect that and decay to a float. | ||
out = complex(self._symbol_expr) | ||
return out.real if out.imag == 0.0 else out |
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.
should this be a math.isclose? Zero-checking floats is always hard to me...
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.
Personally I'd say no - the only times we've seen uses where bad imaginary components enter is from bugs within Symengine itself (which this function works around), where the coefficient scales with the operation being done, so could be arbitrarily large. Auto clipping to zero also makes it tricky for people who were expecting to deal with very small numbers (which floating point is good at).
As an interface thing, a user can always clip the output themselves if needed, so I think not clipping is the safer choice.
Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> Co-authored-by: Luciano Bello <bel@zurich.ibm.com>
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.
LGTM (I'll add it to the queue in the interest of unblocking #11428)
Summary
This is largely a wrap-up of the
if ParameterExpression.is_real(): ...
logic present in a few places across the library, but a bit more efficient for Symengine because it can re-use cases where it needed to force an evaluation to produce accurate results. Mostly, though, it simplifies a few call sites.Details and comments
Depends on #11107, because
.evalf(real=True)
is a symengine-specific extension, and whenTemplateOptimization
produces mismatchedParameterExpression
s it breaks this handling.The additional handling in
numeric
to reduce the impact of the spurious imaginary components makes this generally more reliable. I came across problems with global phases during binding in a PR built on top of this - at the moment, the type of theglobal_phase
inQuantumCircuit.assign_parameters
isn't validated in the same way, but in a unification PR I had it was, and some deeply nested (but completely valid) assignments were failing.