Skip to content

Commit

Permalink
[0.46] upgrade to symengine>=0.11 (#11340)
Browse files Browse the repository at this point in the history
* port #11315

* Update requirements.txt

Co-authored-by: Matthew Treinish <mtreinish@kortar.org>

* Update releasenotes/notes/symengine_1-c907ed541eeb9a02.yaml

---------

Co-authored-by: Matthew Treinish <mtreinish@kortar.org>
  • Loading branch information
1ucian0 and mtreinish committed Jan 30, 2024
1 parent 3e0d346 commit 155a790
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 29 deletions.
16 changes: 4 additions & 12 deletions qiskit/circuit/parameterexpression.py
Original file line number Diff line number Diff line change
Expand Up @@ -567,25 +567,17 @@ def __eq__(self, other):

def is_real(self):
"""Return whether the expression is real"""

# workaround for symengine behavior that const * (0 + 1 * I) is not real
# see https://github.com/symengine/symengine.py/issues/414
if _optionals.HAS_SYMENGINE and self._symbol_expr.is_real is None:
symbol_expr = self._symbol_expr.evalf()
else:
symbol_expr = self._symbol_expr

if not symbol_expr.is_real and symbol_expr.is_real is not None:
if not self._symbol_expr.is_real and self._symbol_expr.is_real is not None:
# Symengine returns false for is_real on the expression if
# there is a imaginary component (even if that component is 0),
# there is an imaginary component (even if that component is 0),
# but the parameter will evaluate as real. Check that if the
# expression's is_real attribute returns false that we have a
# non-zero imaginary
if _optionals.HAS_SYMENGINE:
if symbol_expr.imag == 0.0:
if self._symbol_expr.imag == 0.0:
return True
return False
return symbol_expr.is_real
return self._symbol_expr.is_real

def sympify(self):
"""Return symbolic expression as a raw Sympy or Symengine object.
Expand Down
6 changes: 6 additions & 0 deletions releasenotes/notes/symengine_1-c907ed541eeb9a02.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
upgrade:
- |
The minimum version required for symengine was bumped to >=0.11.
This enabled removing workarounds from :meth:`.ParameterExpression.is_real`
to handle a bug in earlier releases of symengine.
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ dill>=0.3
python-dateutil>=2.8.0
stevedore>=3.0.0
typing-extensions; python_version<'3.11'
symengine>=0.9,!=0.10.0; platform_machine == 'x86_64' or platform_machine == 'aarch64' or platform_machine == 'ppc64le' or platform_machine == 'amd64' or platform_machine == 'arm64'
symengine>=0.11; platform_machine == 'x86_64' or platform_machine == 'aarch64' or platform_machine == 'ppc64le' or platform_machine == 'amd64' or platform_machine == 'arm64'
30 changes: 14 additions & 16 deletions test/python/circuit/test_parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -1497,31 +1497,29 @@ def test_raise_if_subbing_in_parameter_name_conflict(self):
with self.assertRaisesRegex(CircuitError, "Name conflict"):
expr.subs({x: y_second})

def test_expressions_of_parameter_with_constant(self):
@data(2, 1.3, 0, -1, -1.0, numpy.pi, 1j)
def test_expressions_of_parameter_with_constant(self, const):
"""Verify operating on a Parameter with a constant."""

good_constants = [2, 1.3, 0, -1, -1.0, numpy.pi, 1j]

x = Parameter("x")

for op in self.supported_operations:
for const in good_constants:
expr = op(const, x)
bound_expr = expr.bind({x: 2.3})
expr = op(const, x)
bound_expr = expr.bind({x: 2.3})

self.assertEqual(complex(bound_expr), op(const, 2.3))
self.assertEqual(complex(bound_expr), op(const, 2.3))

# Division by zero will raise. Tested elsewhere.
if const == 0 and op == truediv:
continue
# Division by zero will raise. Tested elsewhere.
if const == 0 and op == truediv:
continue

# Repeat above, swapping position of Parameter and constant.
expr = op(x, const)
bound_expr = expr.bind({x: 2.3})
# Repeat above, swapping position of Parameter and constant.
expr = op(x, const)
bound_expr = expr.bind({x: 2.3})

res = complex(bound_expr)
expected = op(2.3, const)
self.assertTrue(cmath.isclose(res, expected), f"{res} != {expected}")
res = complex(bound_expr)
expected = op(2.3, const)
self.assertTrue(cmath.isclose(res, expected), f"{res} != {expected}")

def test_complex_parameter_bound_to_real(self):
"""Test a complex parameter expression can be real if bound correctly."""
Expand Down

0 comments on commit 155a790

Please sign in to comment.