Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,11 @@


@deprecate_func(
since="2.1",
since="2.3",
additional_msg=(
"Use the SolovayKitaevDecomposition class directly, to generate, store, and load the "
"basic approximations."
),
pending=True,
)
def generate_basic_approximations(
basis_gates: list[str | Gate], depth: int, filename: str | None = None
Expand Down
23 changes: 17 additions & 6 deletions qiskit/synthesis/discrete_basis/solovay_kitaev.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ def __init__(
check_input: bool = False,
) -> None:
"""

.. note::

If ``basic_approximations`` is passed as ``.npy`` file, pickle is used internally
to load the data. This is a potential security vulnerability and only trusted files
should be loaded.

Args:
basic_approximations: A specification of the basic SO(3) approximations in terms
of discrete gates. At each iteration this algorithm, the remaining error is
Expand Down Expand Up @@ -112,6 +119,12 @@ def basis_gates(self) -> list[str] | None:
def load_basic_approximations(data: list | str | dict) -> list[GateSequence]:
"""Load basic approximations.

.. note::

If ``data`` is given as string, this method internally relies on pickle to load
the file. This is a potential security vulnerability and only trusted files should be
loaded.

Args:
data: If a string, specifies the path to the file from where to load the data.
If a dictionary, directly specifies the decompositions as ``{gates: matrix}``
Expand All @@ -136,9 +149,9 @@ def load_basic_approximations(data: list | str | dict) -> list[GateSequence]:
warnings.warn(
"It is suggested to pass basic_approximations in the binary format produced "
"by SolovayKitaevDecomposition.save_basic_approximations, which is more "
"performant than other formats. Other formats are pending deprecation "
"and will be deprecated in a future release.",
category=PendingDeprecationWarning,
"performant than other formats. Passing a .npy format is deprecated since Qiskit 2.3 "
"and support will be removed no sooner than 3 months after the release date.",
category=DeprecationWarning,
)

# is already a list of GateSequences
Expand All @@ -157,7 +170,6 @@ def load_basic_approximations(data: list | str | dict) -> list[GateSequence]:
else:
matrix, global_phase = matrix_and_phase, 0

# gates = [_1q_gates[element] for element in gatestring.split()]
gates = normalize_gates(gatestring.split())
sequence = GateSequence.from_gates_and_matrix(gates, matrix, global_phase)
sequences.append(sequence)
Expand Down Expand Up @@ -246,10 +258,9 @@ def query_basic_approximation(self, gate: np.ndarray | Gate) -> QuantumCircuit:
return circuit

@deprecate_func(
since="2.1",
since="2.3",
additional_msg="Use query_basic_approximation instead, which takes a Gate or matrix "
"as input and returns a QuantumCircuit object.",
pending=True,
)
def find_basic_approximation(self, sequence: GateSequence) -> GateSequence:
"""Find ``GateSequence`` in ``self._basic_approximations`` that approximates ``sequence``.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
deprecations_transpiler:
- |
Deprecated the legacy serialization format used in :class:`.SolovayKitaevDecomposition`,
which was based on pickling the basic approximations in form of a Python dictionary.
This loading process is a potential vulnerability and should only be used with trusted files
and the new format does not have this problem.
The functions to generate the legacy format, :func:`.generate_basic_approximations`, and load it,
:meth:`.SolovayKitaevDecomposition.load_basic_approximations` and in the initializer
of :class:`.SolovayKitaevDecomposition`, have been deprecated.
Instead, use :meth:`.SolovayKitaevDecomposition.save_basic_approximations` to generate a format
that can safely be loaded in the class initializer.
67 changes: 55 additions & 12 deletions test/python/transpiler/test_solovay_kitaev.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,11 @@ class TestSolovayKitaev(QiskitTestCase):
def setUp(self):
super().setUp()

self.basic_approx = generate_basic_approximations([HGate(), TGate(), TdgGate()], 3)
with self.assertWarnsRegex(
DeprecationWarning,
r".* is deprecated as of Qiskit 2\.3\. .* Use the SolovayKitaevDecomposition class",
):
self.basic_approx = generate_basic_approximations([HGate(), TGate(), TdgGate()], 3)
self.default_sk = SolovayKitaev()

def test_unitary_synthesis(self):
Expand Down Expand Up @@ -153,8 +157,17 @@ def test_str_basis_gates(self):
circuit = QuantumCircuit(1)
circuit.rx(0.8, 0)

basic_approx = generate_basic_approximations(["h", "t", "s"], 3)
sk = SolovayKitaev(3, basic_approx)
with self.assertWarnsRegex(
DeprecationWarning,
r".* is deprecated as of Qiskit 2\.3\. .* Use the SolovayKitaevDecomposition class",
):
basic_approx = generate_basic_approximations(["h", "t", "s"], 3)

with self.assertWarnsRegex(
DeprecationWarning,
r"basic_approximations in the binary format produced by .* deprecated since Qiskit 2.3 ",
):
sk = SolovayKitaev(3, basic_approx)

dag = circuit_to_dag(circuit)
discretized = dag_to_circuit(sk.run(dag))
Expand Down Expand Up @@ -209,9 +222,19 @@ def test_u_gates_work(self):

depth = 4
basis_gates = ["h", "t", "tdg", "s", "sdg", "z"]
gate_approx_library = generate_basic_approximations(basis_gates=basis_gates, depth=depth)
with self.assertWarnsRegex(
DeprecationWarning,
r".* is deprecated as of Qiskit 2\.3\. .* Use the SolovayKitaevDecomposition class",
):
gate_approx_library = generate_basic_approximations(
basis_gates=basis_gates, depth=depth
)

skd = SolovayKitaev(recursion_degree=2, basic_approximations=gate_approx_library)
with self.assertWarnsRegex(
DeprecationWarning,
r"basic_approximations in the binary format produced by .* deprecated since Qiskit 2.3 ",
):
skd = SolovayKitaev(recursion_degree=2, basic_approximations=gate_approx_library)
discretized = skd(circuit)

included_gates = set(discretized.count_ops().keys())
Expand All @@ -228,16 +251,24 @@ def test_load_from_file(self):
fullpath = os.path.join(tmp_dir, filename)

# dump approximations to file
gate_approx_library = generate_basic_approximations(
basis_gates=["h", "s", "sdg"], depth=3, filename=fullpath
)
with self.assertWarnsRegex(
DeprecationWarning,
r".* is deprecated as of Qiskit 2\.3\. .* Use the SolovayKitaevDecomposition class",
):
gate_approx_library = generate_basic_approximations(
basis_gates=["h", "s", "sdg"], depth=3, filename=fullpath
)

# circuit to decompose and reference decomp
circuit = QuantumCircuit(1)
circuit.rx(0.8, 0)

# Run SK pass using gate_approx_library
reference = SolovayKitaev(basic_approximations=gate_approx_library)(circuit)
with self.assertWarnsRegex(
DeprecationWarning,
r"basic_approximations in the binary format produced by .* deprecated since Qiskit 2.3 ",
):
reference = SolovayKitaev(basic_approximations=gate_approx_library)(circuit)

# Run SK pass using stored basis_approximations
discretized = SolovayKitaev(basic_approximations=fullpath)(circuit)
Expand Down Expand Up @@ -276,10 +307,18 @@ def test_load_legacy_format(self):
circuit.rx(0.8, 0)

# Run SK pass using gate_approx_library
reference = SolovayKitaev(basic_approximations=approximations)(circuit)
with self.assertWarnsRegex(
DeprecationWarning,
r"basic_approximations in the binary format produced by .* deprecated since Qiskit 2.3 ",
):
reference = SolovayKitaev(basic_approximations=approximations)(circuit)

# Run SK pass using stored basis_approximations
discretized = SolovayKitaev(basic_approximations=fullpath)(circuit)
with self.assertWarnsRegex(
DeprecationWarning,
r"basic_approximations in the binary format produced by .* deprecated since Qiskit 2.3 ",
):
discretized = SolovayKitaev(basic_approximations=fullpath)(circuit)

# Check that both flows produce the same result
self.assertEqual(discretized, reference)
Expand Down Expand Up @@ -367,7 +406,11 @@ def test_generate_basis_approximation_gates(self):
Regression test of Qiskit/qiskit-terra#9585.
"""
basis = ["i", "x", "y", "z", "h", "t", "tdg", "s", "sdg", "sx", "sxdg"]
approx = generate_basic_approximations(basis, depth=2)
with self.assertWarnsRegex(
DeprecationWarning,
r".* is deprecated as of Qiskit 2\.3\. .* Use the SolovayKitaevDecomposition class",
):
approx = generate_basic_approximations(basis, depth=2)

# This mainly checks that there are no errors in the generation (like
# in computing the inverse as described in #9585), so a simple check is enough.
Expand Down