From 206fbee391a0b394052716ffd890e94dbfc686c4 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Fri, 5 Aug 2022 11:41:49 +0000 Subject: [PATCH] Fix ``ParameterExpression.is_real`` if ``symengine`` is installed (#8456) (#8462) * Fix is_real on ParameterExpression * typo in reno Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> (cherry picked from commit 2bab09c1aae84e5bf38ba52fa3a272667c1887cc) Co-authored-by: Julien Gacon --- qiskit/circuit/parameterexpression.py | 11 +++++++++-- .../fix-paramexpr-isreal-8d20348b4ce6cbe7.yaml | 14 ++++++++++++++ test/python/circuit/test_parameters.py | 8 ++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 releasenotes/notes/fix-paramexpr-isreal-8d20348b4ce6cbe7.yaml diff --git a/qiskit/circuit/parameterexpression.py b/qiskit/circuit/parameterexpression.py index 641a7404c553..30bc46922197 100644 --- a/qiskit/circuit/parameterexpression.py +++ b/qiskit/circuit/parameterexpression.py @@ -508,14 +508,21 @@ def __eq__(self, other): def is_real(self): """Return whether the expression is real""" - if not self._symbol_expr.is_real and self._symbol_expr.is_real is not None: + # 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: # Symengine returns false for is_real on the expression if # there is a 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 self._symbol_expr.imag != 0.0: + if symbol_expr.imag != 0.0: return False else: return False diff --git a/releasenotes/notes/fix-paramexpr-isreal-8d20348b4ce6cbe7.yaml b/releasenotes/notes/fix-paramexpr-isreal-8d20348b4ce6cbe7.yaml new file mode 100644 index 000000000000..f9219b813169 --- /dev/null +++ b/releasenotes/notes/fix-paramexpr-isreal-8d20348b4ce6cbe7.yaml @@ -0,0 +1,14 @@ +--- +fixes: + - | + Fix a bug where a bound :class:`.ParameterExpression` was not identified as real + if ``symengine`` was installed and the bound expression was not a plain ``1j``. + For example:: + + from qiskit.circuit import Parameter + + x = Parameter("x") + expr = 1j * x + bound = expr.bind({x: 2}) + print(bound.is_real()) # used to be True, but is now False + diff --git a/test/python/circuit/test_parameters.py b/test/python/circuit/test_parameters.py index ed25350bf227..3a96963b7f86 100644 --- a/test/python/circuit/test_parameters.py +++ b/test/python/circuit/test_parameters.py @@ -1718,6 +1718,14 @@ def test_parameter_expression_grad(self): self.assertEqual(expr.gradient(x), 2 * x) self.assertEqual(expr.gradient(x).gradient(x), 2) + def test_bound_expression_is_real(self): + """Test is_real on bound parameters.""" + x = Parameter("x") + expr = 1j * x + bound = expr.bind({x: 2}) + + self.assertFalse(bound.is_real()) + class TestParameterEquality(QiskitTestCase): """Test equality of Parameters and ParameterExpressions."""