Skip to content
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

Fix qpy.dump()'s use_symengine when passed a truthy object (backport #11730) #11731

Merged
merged 1 commit into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion qiskit/qpy/type_keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ class SymExprEncoding(TypeKeyBase):

@classmethod
def assign(cls, obj):
if obj is True:
if obj:
return cls.SYMENGINE
else:
return cls.SYMPY
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
fixes:
- |
Fixed an issue with the :func:`.qpy.dump` function, when the
``use_symengine`` flag was set to a truthy object that evaluated to
``True`` but was not actually the boolean ``True`` the generated QPY
payload would be corrupt. For example, if you set ``use_symengine`` to
:obj:`.HAS_SYMENGINE` which evaluates to ``True`` when cast as a bool,
but isn't actually ``True``.
35 changes: 33 additions & 2 deletions test/python/qpy/test_circuit_load_from_qpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,21 @@
from qiskit.transpiler import PassManager, TranspileLayout
from qiskit.transpiler import passes
from qiskit.compiler import transpile
from qiskit.utils import optionals
from qiskit.qpy.formats import FILE_HEADER_V10_PACK, FILE_HEADER_V10, FILE_HEADER_V10_SIZE
from test import QiskitTestCase # pylint: disable=wrong-import-order


class QpyCircuitTestCase(QiskitTestCase):
"""QPY schedule testing platform."""

def assert_roundtrip_equal(self, circuit, version=None):
def assert_roundtrip_equal(self, circuit, version=None, use_symengine=None):
"""QPY roundtrip equal test."""
qpy_file = io.BytesIO()
dump(circuit, qpy_file, version=version)
if use_symengine is None:
dump(circuit, qpy_file, version=version)
else:
dump(circuit, qpy_file, version=version, use_symengine=use_symengine)
qpy_file.seek(0)
new_circuit = load(qpy_file)[0]

Expand Down Expand Up @@ -296,3 +301,29 @@ def test_compatibility_version_roundtrip(self):
qc.cx(0, 1)
qc.measure_all()
self.assert_roundtrip_equal(qc, version=QPY_COMPATIBILITY_VERSION)


class TestUseSymengineFlag(QpyCircuitTestCase):
"""Test that the symengine flag works correctly."""

def test_use_symengine_with_bool_like(self):
"""Test that the use_symengine flag is set correctly with a bool-like input."""
theta = Parameter("theta")
two_theta = 2 * theta
qc = QuantumCircuit(1)
qc.rx(two_theta, 0)
qc.measure_all()
# Assert Roundtrip works
self.assert_roundtrip_equal(qc, use_symengine=optionals.HAS_SYMENGINE, version=10)
# Also check the qpy symbolic expression encoding is correct in the
# payload
with io.BytesIO() as file_obj:
dump(qc, file_obj, use_symengine=optionals.HAS_SYMENGINE)
file_obj.seek(0)
header_data = FILE_HEADER_V10._make(
struct.unpack(
FILE_HEADER_V10_PACK,
file_obj.read(FILE_HEADER_V10_SIZE),
)
)
self.assertEqual(header_data.symbolic_encoding, b"e")
Loading