qiskit 2.0.2__cp39-abi3-macosx_11_0_arm64.whl → 2.1.0rc1__cp39-abi3-macosx_11_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- qiskit/VERSION.txt +1 -1
- qiskit/__init__.py +19 -1
- qiskit/_accelerate.abi3.so +0 -0
- qiskit/circuit/__init__.py +13 -21
- qiskit/circuit/_add_control.py +57 -31
- qiskit/circuit/_classical_resource_map.py +4 -0
- qiskit/circuit/annotation.py +404 -0
- qiskit/circuit/classical/expr/__init__.py +1 -1
- qiskit/circuit/classical/expr/expr.py +104 -446
- qiskit/circuit/classical/expr/visitors.py +6 -0
- qiskit/circuit/classical/types/types.py +7 -130
- qiskit/circuit/controlflow/box.py +32 -7
- qiskit/circuit/delay.py +11 -9
- qiskit/circuit/library/arithmetic/adders/adder.py +5 -5
- qiskit/circuit/library/arithmetic/multipliers/multiplier.py +3 -3
- qiskit/circuit/library/arithmetic/piecewise_chebyshev.py +7 -3
- qiskit/circuit/library/arithmetic/piecewise_linear_pauli_rotations.py +23 -15
- qiskit/circuit/library/arithmetic/piecewise_polynomial_pauli_rotations.py +22 -14
- qiskit/circuit/library/arithmetic/quadratic_form.py +6 -0
- qiskit/circuit/library/arithmetic/weighted_adder.py +43 -24
- qiskit/circuit/library/basis_change/qft.py +2 -2
- qiskit/circuit/library/blueprintcircuit.py +6 -0
- qiskit/circuit/library/boolean_logic/inner_product.py +2 -2
- qiskit/circuit/library/boolean_logic/quantum_and.py +2 -2
- qiskit/circuit/library/boolean_logic/quantum_or.py +3 -3
- qiskit/circuit/library/boolean_logic/quantum_xor.py +2 -2
- qiskit/circuit/library/data_preparation/_z_feature_map.py +2 -2
- qiskit/circuit/library/data_preparation/_zz_feature_map.py +2 -2
- qiskit/circuit/library/data_preparation/pauli_feature_map.py +2 -2
- qiskit/circuit/library/fourier_checking.py +2 -2
- qiskit/circuit/library/generalized_gates/diagonal.py +5 -1
- qiskit/circuit/library/generalized_gates/gms.py +5 -1
- qiskit/circuit/library/generalized_gates/linear_function.py +2 -2
- qiskit/circuit/library/generalized_gates/permutation.py +5 -1
- qiskit/circuit/library/generalized_gates/uc.py +1 -1
- qiskit/circuit/library/generalized_gates/unitary.py +21 -2
- qiskit/circuit/library/graph_state.py +2 -2
- qiskit/circuit/library/grover_operator.py +2 -2
- qiskit/circuit/library/hidden_linear_function.py +2 -2
- qiskit/circuit/library/iqp.py +2 -2
- qiskit/circuit/library/n_local/efficient_su2.py +2 -2
- qiskit/circuit/library/n_local/evolved_operator_ansatz.py +1 -1
- qiskit/circuit/library/n_local/excitation_preserving.py +7 -9
- qiskit/circuit/library/n_local/n_local.py +4 -3
- qiskit/circuit/library/n_local/pauli_two_design.py +2 -2
- qiskit/circuit/library/n_local/real_amplitudes.py +2 -2
- qiskit/circuit/library/n_local/two_local.py +2 -2
- qiskit/circuit/library/overlap.py +2 -2
- qiskit/circuit/library/pauli_evolution.py +3 -2
- qiskit/circuit/library/phase_estimation.py +2 -2
- qiskit/circuit/library/standard_gates/dcx.py +11 -12
- qiskit/circuit/library/standard_gates/ecr.py +21 -24
- qiskit/circuit/library/standard_gates/equivalence_library.py +232 -96
- qiskit/circuit/library/standard_gates/global_phase.py +5 -6
- qiskit/circuit/library/standard_gates/h.py +22 -45
- qiskit/circuit/library/standard_gates/i.py +1 -1
- qiskit/circuit/library/standard_gates/iswap.py +13 -31
- qiskit/circuit/library/standard_gates/p.py +19 -26
- qiskit/circuit/library/standard_gates/r.py +11 -17
- qiskit/circuit/library/standard_gates/rx.py +21 -45
- qiskit/circuit/library/standard_gates/rxx.py +7 -22
- qiskit/circuit/library/standard_gates/ry.py +21 -39
- qiskit/circuit/library/standard_gates/ryy.py +13 -28
- qiskit/circuit/library/standard_gates/rz.py +18 -35
- qiskit/circuit/library/standard_gates/rzx.py +7 -22
- qiskit/circuit/library/standard_gates/rzz.py +7 -19
- qiskit/circuit/library/standard_gates/s.py +44 -39
- qiskit/circuit/library/standard_gates/swap.py +25 -38
- qiskit/circuit/library/standard_gates/sx.py +34 -41
- qiskit/circuit/library/standard_gates/t.py +18 -27
- qiskit/circuit/library/standard_gates/u.py +8 -24
- qiskit/circuit/library/standard_gates/u1.py +28 -52
- qiskit/circuit/library/standard_gates/u2.py +9 -9
- qiskit/circuit/library/standard_gates/u3.py +24 -40
- qiskit/circuit/library/standard_gates/x.py +190 -336
- qiskit/circuit/library/standard_gates/xx_minus_yy.py +12 -50
- qiskit/circuit/library/standard_gates/xx_plus_yy.py +13 -52
- qiskit/circuit/library/standard_gates/y.py +19 -23
- qiskit/circuit/library/standard_gates/z.py +31 -38
- qiskit/circuit/parameter.py +14 -5
- qiskit/circuit/parameterexpression.py +109 -75
- qiskit/circuit/quantumcircuit.py +168 -98
- qiskit/circuit/quantumcircuitdata.py +1 -0
- qiskit/circuit/random/__init__.py +37 -2
- qiskit/circuit/random/utils.py +445 -56
- qiskit/circuit/tools/pi_check.py +5 -13
- qiskit/compiler/transpiler.py +1 -1
- qiskit/converters/circuit_to_instruction.py +2 -2
- qiskit/dagcircuit/dagnode.py +8 -3
- qiskit/primitives/__init__.py +2 -2
- qiskit/primitives/base/base_estimator.py +2 -2
- qiskit/primitives/containers/data_bin.py +0 -3
- qiskit/primitives/containers/observables_array.py +192 -108
- qiskit/primitives/primitive_job.py +29 -10
- qiskit/providers/fake_provider/generic_backend_v2.py +2 -0
- qiskit/qasm3/__init__.py +106 -12
- qiskit/qasm3/ast.py +15 -1
- qiskit/qasm3/exporter.py +59 -36
- qiskit/qasm3/printer.py +12 -0
- qiskit/qpy/__init__.py +183 -7
- qiskit/qpy/binary_io/circuits.py +256 -24
- qiskit/qpy/binary_io/parse_sympy_repr.py +5 -0
- qiskit/qpy/binary_io/schedules.py +12 -32
- qiskit/qpy/binary_io/value.py +36 -18
- qiskit/qpy/common.py +11 -3
- qiskit/qpy/formats.py +17 -1
- qiskit/qpy/interface.py +52 -12
- qiskit/qpy/type_keys.py +7 -1
- qiskit/quantum_info/__init__.py +10 -0
- qiskit/quantum_info/operators/__init__.py +1 -0
- qiskit/quantum_info/operators/symplectic/__init__.py +1 -0
- qiskit/quantum_info/operators/symplectic/clifford_circuits.py +26 -0
- qiskit/quantum_info/operators/symplectic/pauli.py +2 -2
- qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +1 -1
- qiskit/result/sampled_expval.py +3 -1
- qiskit/synthesis/__init__.py +10 -0
- qiskit/synthesis/arithmetic/__init__.py +1 -1
- qiskit/synthesis/arithmetic/adders/__init__.py +1 -0
- qiskit/synthesis/arithmetic/adders/draper_qft_adder.py +6 -2
- qiskit/synthesis/arithmetic/adders/rv_ripple_carry_adder.py +156 -0
- qiskit/synthesis/discrete_basis/generate_basis_approximations.py +14 -126
- qiskit/synthesis/discrete_basis/solovay_kitaev.py +161 -121
- qiskit/synthesis/evolution/lie_trotter.py +10 -7
- qiskit/synthesis/evolution/product_formula.py +10 -7
- qiskit/synthesis/evolution/qdrift.py +10 -7
- qiskit/synthesis/evolution/suzuki_trotter.py +10 -7
- qiskit/synthesis/multi_controlled/__init__.py +4 -0
- qiskit/synthesis/multi_controlled/mcx_synthesis.py +402 -178
- qiskit/synthesis/multi_controlled/multi_control_rotation_gates.py +14 -15
- qiskit/synthesis/qft/qft_decompose_lnn.py +7 -25
- qiskit/synthesis/unitary/qsd.py +80 -9
- qiskit/transpiler/__init__.py +19 -8
- qiskit/transpiler/instruction_durations.py +2 -20
- qiskit/transpiler/passes/__init__.py +4 -2
- qiskit/transpiler/passes/layout/dense_layout.py +26 -6
- qiskit/transpiler/passes/layout/disjoint_utils.py +1 -166
- qiskit/transpiler/passes/layout/sabre_layout.py +22 -3
- qiskit/transpiler/passes/layout/sabre_pre_layout.py +1 -1
- qiskit/transpiler/passes/layout/vf2_layout.py +49 -13
- qiskit/transpiler/passes/layout/vf2_utils.py +13 -1
- qiskit/transpiler/passes/optimization/__init__.py +1 -1
- qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +2 -1
- qiskit/transpiler/passes/optimization/optimize_clifford_t.py +68 -0
- qiskit/transpiler/passes/optimization/template_matching/template_substitution.py +3 -9
- qiskit/transpiler/passes/routing/sabre_swap.py +12 -2
- qiskit/transpiler/passes/routing/star_prerouting.py +106 -81
- qiskit/transpiler/passes/scheduling/__init__.py +1 -1
- qiskit/transpiler/passes/scheduling/alignments/check_durations.py +1 -1
- qiskit/transpiler/passes/scheduling/padding/__init__.py +1 -0
- qiskit/transpiler/passes/scheduling/padding/context_aware_dynamical_decoupling.py +876 -0
- qiskit/transpiler/passes/synthesis/__init__.py +1 -0
- qiskit/transpiler/passes/synthesis/clifford_unitary_synth_plugin.py +123 -0
- qiskit/transpiler/passes/synthesis/hls_plugins.py +472 -92
- qiskit/transpiler/passes/synthesis/solovay_kitaev_synthesis.py +27 -22
- qiskit/transpiler/passmanager_config.py +3 -0
- qiskit/transpiler/preset_passmanagers/builtin_plugins.py +149 -28
- qiskit/transpiler/preset_passmanagers/common.py +101 -0
- qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +6 -0
- qiskit/transpiler/preset_passmanagers/level3.py +2 -2
- qiskit/utils/optionals.py +6 -5
- qiskit/visualization/circuit/_utils.py +5 -3
- qiskit/visualization/circuit/latex.py +9 -2
- qiskit/visualization/circuit/matplotlib.py +26 -4
- qiskit/visualization/circuit/qcstyle.py +9 -157
- qiskit/visualization/dag/__init__.py +13 -0
- qiskit/visualization/dag/dagstyle.py +103 -0
- qiskit/visualization/dag/styles/__init__.py +13 -0
- qiskit/visualization/dag/styles/color.json +10 -0
- qiskit/visualization/dag/styles/plain.json +5 -0
- qiskit/visualization/dag_visualization.py +169 -98
- qiskit/visualization/style.py +223 -0
- {qiskit-2.0.2.dist-info → qiskit-2.1.0rc1.dist-info}/METADATA +14 -13
- {qiskit-2.0.2.dist-info → qiskit-2.1.0rc1.dist-info}/RECORD +177 -168
- {qiskit-2.0.2.dist-info → qiskit-2.1.0rc1.dist-info}/entry_points.txt +6 -0
- qiskit/synthesis/discrete_basis/commutator_decompose.py +0 -265
- qiskit/synthesis/discrete_basis/gate_sequence.py +0 -421
- {qiskit-2.0.2.dist-info → qiskit-2.1.0rc1.dist-info}/WHEEL +0 -0
- {qiskit-2.0.2.dist-info → qiskit-2.1.0rc1.dist-info}/licenses/LICENSE.txt +0 -0
- {qiskit-2.0.2.dist-info → qiskit-2.1.0rc1.dist-info}/top_level.txt +0 -0
@@ -14,42 +14,99 @@
|
|
14
14
|
|
15
15
|
from __future__ import annotations
|
16
16
|
|
17
|
+
import typing
|
18
|
+
import warnings
|
17
19
|
import numpy as np
|
20
|
+
from qiskit.circuit.quantumcircuit import QuantumCircuit
|
21
|
+
from qiskit.circuit.gate import Gate
|
22
|
+
from qiskit.circuit.library import get_standard_gate_name_mapping, IGate
|
23
|
+
from qiskit.utils.deprecation import deprecate_func
|
24
|
+
from qiskit._accelerate.synthesis.discrete_basis import (
|
25
|
+
SolovayKitaevSynthesis as RustSolovayKitaevSynthesis,
|
26
|
+
GateSequence,
|
27
|
+
)
|
18
28
|
|
19
|
-
|
20
|
-
from .
|
21
|
-
from .generate_basis_approximations import generate_basic_approximations, _1q_gates, _1q_inverses
|
29
|
+
if typing.TYPE_CHECKING:
|
30
|
+
from qiskit.dagcircuit import DAGCircuit
|
22
31
|
|
23
32
|
|
24
33
|
class SolovayKitaevDecomposition:
|
25
34
|
"""The Solovay Kitaev discrete decomposition algorithm.
|
26
35
|
|
27
36
|
This class is called recursively by the transpiler pass, which is why it is separated.
|
28
|
-
See :class
|
37
|
+
See :class:`~qiskit.transpiler.passes.SolovayKitaev` for more information.
|
29
38
|
"""
|
30
39
|
|
31
40
|
def __init__(
|
32
|
-
self,
|
41
|
+
self,
|
42
|
+
basic_approximations: str | dict[str, np.ndarray] | list[GateSequence] | None = None,
|
43
|
+
*,
|
44
|
+
basis_gates: list[str | Gate] | None = None,
|
45
|
+
depth: int = 12,
|
46
|
+
check_input: bool = False,
|
33
47
|
) -> None:
|
34
48
|
"""
|
35
49
|
Args:
|
36
50
|
basic_approximations: A specification of the basic SO(3) approximations in terms
|
37
51
|
of discrete gates. At each iteration this algorithm, the remaining error is
|
38
52
|
approximated with the closest sequence of gates in this set.
|
39
|
-
If a ``str``, this specifies a
|
53
|
+
If a ``str``, this specifies a filename from which to load the
|
40
54
|
approximation. If a ``dict``, then this contains
|
41
55
|
``{gates: effective_SO3_matrix}`` pairs,
|
42
56
|
e.g. ``{"h t": np.array([[0, 0.7071, -0.7071], [0, -0.7071, -0.7071], [-1, 0, 0]]}``.
|
43
57
|
If a list, this contains the same information as the dict, but already converted to
|
44
58
|
:class:`.GateSequence` objects, which contain the SO(3) matrix and gates.
|
59
|
+
|
60
|
+
Either this parameter, or ``basis_gates`` and ``depth`` can be specified.
|
61
|
+
basis_gates: A list of discrete (i.e., non-parameterized) standard gates.
|
62
|
+
Defaults to ``["h", "t", "tdg"]``.
|
63
|
+
depth: The number of basis gate combinations to consider in the basis set. This
|
64
|
+
determines how fast (and if) the algorithm converges and should be chosen
|
65
|
+
sufficiently high.
|
66
|
+
check_input: If ``True``, perform intermediate steps checking whether the matrices
|
67
|
+
are of expected form.
|
45
68
|
"""
|
46
69
|
if basic_approximations is None:
|
47
|
-
|
48
|
-
|
49
|
-
|
70
|
+
if basis_gates is not None:
|
71
|
+
basis_gates = normalize_gates(basis_gates)
|
72
|
+
self._sk = RustSolovayKitaevSynthesis(basis_gates, depth, None, check_input)
|
73
|
+
|
74
|
+
elif basis_gates is not None:
|
75
|
+
raise ValueError(
|
76
|
+
"Either basic_approximations or basis_gates + depth can be specified, not both."
|
50
77
|
)
|
51
78
|
|
52
|
-
|
79
|
+
else:
|
80
|
+
# Fast Rust path to load the file
|
81
|
+
if isinstance(basic_approximations, str) and basic_approximations[~3:] != ".npy":
|
82
|
+
self._sk = RustSolovayKitaevSynthesis.from_basic_approximations(
|
83
|
+
basic_approximations, True
|
84
|
+
)
|
85
|
+
else:
|
86
|
+
sequences = self.load_basic_approximations(basic_approximations)
|
87
|
+
self._sk = RustSolovayKitaevSynthesis.from_sequences(sequences, True)
|
88
|
+
|
89
|
+
self._depth = depth
|
90
|
+
self._check_input = check_input
|
91
|
+
self._basis_gates = basis_gates
|
92
|
+
|
93
|
+
@property
|
94
|
+
def depth(self) -> int:
|
95
|
+
"""The maximum gate depth of the basic approximations."""
|
96
|
+
return self._depth
|
97
|
+
|
98
|
+
@property
|
99
|
+
def check_input(self) -> bool:
|
100
|
+
"""Whether to perform runtime checks on the internal data."""
|
101
|
+
return self._check_input
|
102
|
+
|
103
|
+
@property
|
104
|
+
def basis_gates(self) -> list[str] | None:
|
105
|
+
"""The basis gate set of the basic approximations.
|
106
|
+
|
107
|
+
If ``None``, defaults to ``["h", "t", "tdg"]``.
|
108
|
+
"""
|
109
|
+
return self._basis_gates
|
53
110
|
|
54
111
|
@staticmethod
|
55
112
|
def load_basic_approximations(data: list | str | dict) -> list[GateSequence]:
|
@@ -71,14 +128,28 @@ class SolovayKitaevDecomposition:
|
|
71
128
|
Raises:
|
72
129
|
ValueError: If the number of gate combinations and associated matrices does not match.
|
73
130
|
"""
|
131
|
+
# new data format stored by the Rust internal class
|
132
|
+
if isinstance(data, str) and data[-4:] != ".npy":
|
133
|
+
sk = SolovayKitaevDecomposition(data)
|
134
|
+
return sk._sk.get_gate_sequences()
|
135
|
+
|
136
|
+
warnings.warn(
|
137
|
+
"It is suggested to pass basic_approximations in the binary format produced "
|
138
|
+
"by SolovayKitaevDecomposition.save_basic_approximations, which is more "
|
139
|
+
"performant than other formats. Other formats are pending deprecation "
|
140
|
+
"and will be deprecated in a future release.",
|
141
|
+
category=PendingDeprecationWarning,
|
142
|
+
)
|
143
|
+
|
74
144
|
# is already a list of GateSequences
|
75
145
|
if isinstance(data, list):
|
76
146
|
return data
|
77
147
|
|
78
|
-
#
|
148
|
+
# file is ``.npy``, load the dictionary it contains
|
79
149
|
if isinstance(data, str):
|
80
150
|
data = np.load(data, allow_pickle=True).item()
|
81
151
|
|
152
|
+
# parse the dictionary
|
82
153
|
sequences = []
|
83
154
|
for gatestring, matrix_and_phase in data.items():
|
84
155
|
if isinstance(matrix_and_phase, tuple):
|
@@ -86,100 +157,100 @@ class SolovayKitaevDecomposition:
|
|
86
157
|
else:
|
87
158
|
matrix, global_phase = matrix_and_phase, 0
|
88
159
|
|
89
|
-
|
90
|
-
|
91
|
-
sequence
|
92
|
-
sequence.product = np.asarray(matrix)
|
93
|
-
sequence.global_phase = global_phase
|
160
|
+
# gates = [_1q_gates[element] for element in gatestring.split()]
|
161
|
+
gates = normalize_gates(gatestring.split())
|
162
|
+
sequence = GateSequence.from_gates_and_matrix(gates, matrix, global_phase)
|
94
163
|
sequences.append(sequence)
|
95
164
|
|
96
165
|
return sequences
|
97
166
|
|
167
|
+
def save_basic_approximations(self, filename: str):
|
168
|
+
"""Save the basic approximations into a file.
|
169
|
+
|
170
|
+
This can then be loaded again via the class initializer (preferred) or
|
171
|
+
via :meth:`load_basic_approximations`::
|
172
|
+
|
173
|
+
filename = "approximations.bin"
|
174
|
+
sk.save_basic_approximations(filename)
|
175
|
+
|
176
|
+
new_sk = SolovayKitaevDecomposition(filename)
|
177
|
+
|
178
|
+
Args:
|
179
|
+
filename: The filename to store the approximations in.
|
180
|
+
|
181
|
+
Raises:
|
182
|
+
ValueError: If the filename has a `.npy` extension. The format is not `.npy`,
|
183
|
+
and storing as such can cause errors when loading the file again.
|
184
|
+
"""
|
185
|
+
# Safety guard: previously, we serialized via npy, but this format is incompatible
|
186
|
+
# with the current serialization, using Rust's serde + bincode. While we can still load
|
187
|
+
# .npy files in legacy format, the new format should not be stored as .npy.
|
188
|
+
if filename[~3:] == ".npy":
|
189
|
+
raise ValueError(
|
190
|
+
"The basic approximations are not stored in npy format. "
|
191
|
+
"Choose a different file extension (e.g. .bin)."
|
192
|
+
)
|
193
|
+
self._sk.save_basic_approximations(filename)
|
194
|
+
|
98
195
|
def run(
|
99
196
|
self,
|
100
|
-
gate_matrix: np.ndarray,
|
197
|
+
gate_matrix: np.ndarray | Gate,
|
101
198
|
recursion_degree: int,
|
102
199
|
return_dag: bool = False,
|
103
200
|
check_input: bool = True,
|
104
|
-
) ->
|
201
|
+
) -> QuantumCircuit | DAGCircuit:
|
105
202
|
r"""Run the algorithm.
|
106
203
|
|
107
204
|
Args:
|
108
|
-
gate_matrix: The
|
109
|
-
|
205
|
+
gate_matrix: The single-qubit gate to approximate. Can either be a :class:`.Gate`, where
|
206
|
+
:meth:`.Gate.to_matrix` returns the matrix, or a :math:`2\times 2` unitary matrix
|
207
|
+
representing the gate.
|
110
208
|
recursion_degree: The recursion degree, called :math:`n` in the paper.
|
111
209
|
return_dag: If ``True`` return a :class:`.DAGCircuit`, else a :class:`.QuantumCircuit`.
|
112
210
|
check_input: If ``True`` check that the input matrix is valid for the decomposition.
|
211
|
+
Overrides the class attribute with the same name, but only for this function call.
|
113
212
|
|
114
213
|
Returns:
|
115
214
|
A one-qubit circuit approximating the ``gate_matrix`` in the specified discrete basis.
|
116
215
|
"""
|
117
|
-
#
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
gate_matrix_as_sequence = GateSequence.from_matrix(gate_matrix_su2)
|
122
|
-
global_phase = np.arctan2(np.imag(z), np.real(z))
|
216
|
+
# handle overriding the check_input setting
|
217
|
+
self_check_input = self.check_input
|
218
|
+
if check_input != self_check_input:
|
219
|
+
self._sk.do_checks = check_input
|
123
220
|
|
124
|
-
|
125
|
-
|
126
|
-
gate_matrix_as_sequence, recursion_degree, check_input=check_input
|
127
|
-
)
|
128
|
-
|
129
|
-
# simplify
|
130
|
-
_remove_identities(decomposition)
|
131
|
-
_remove_inverse_follows_gate(decomposition)
|
132
|
-
|
133
|
-
# adjust to the correct SU(2) phase
|
134
|
-
adjust_phase = (
|
135
|
-
np.pi if _should_adjust_phase(decomposition._to_u2(), gate_matrix_su2) else 0.0
|
136
|
-
)
|
137
|
-
|
138
|
-
# convert to a circuit and attach the right phases
|
139
|
-
if return_dag:
|
140
|
-
out = decomposition.to_dag()
|
221
|
+
if isinstance(gate_matrix, Gate):
|
222
|
+
data = self._sk.synthesize(gate_matrix, recursion_degree)
|
141
223
|
else:
|
142
|
-
|
143
|
-
|
144
|
-
out.global_phase += adjust_phase
|
145
|
-
out.global_phase -= global_phase
|
224
|
+
data = self._sk.synthesize_matrix(gate_matrix, recursion_degree)
|
146
225
|
|
147
|
-
|
226
|
+
if check_input != self_check_input:
|
227
|
+
self._sk.do_checks = self_check_input
|
148
228
|
|
149
|
-
|
150
|
-
"""Performs ``n`` iterations of the Solovay-Kitaev algorithm on ``sequence``.
|
229
|
+
circuit = QuantumCircuit._from_circuit_data(data, add_regs=True)
|
151
230
|
|
152
|
-
|
153
|
-
|
154
|
-
n: The number of iterations that the algorithm needs to run.
|
155
|
-
check_input: If ``True`` check that the input matrix represented by ``GateSequence``
|
156
|
-
is valid for the decomposition.
|
157
|
-
|
158
|
-
Returns:
|
159
|
-
GateSequence that approximates ``sequence``.
|
231
|
+
if return_dag:
|
232
|
+
from qiskit.converters import circuit_to_dag # pylint: disable=cyclic-import
|
160
233
|
|
161
|
-
|
162
|
-
ValueError: If the matrix in ``GateSequence`` does not represent an SO(3)-matrix.
|
163
|
-
"""
|
164
|
-
if sequence.product.shape != (3, 3):
|
165
|
-
raise ValueError("Shape of U must be (3, 3) but is", sequence.shape)
|
234
|
+
return circuit_to_dag(circuit)
|
166
235
|
|
167
|
-
|
168
|
-
res = self.find_basic_approximation(sequence)
|
236
|
+
return circuit
|
169
237
|
|
238
|
+
def query_basic_approximation(self, gate: np.ndarray | Gate) -> QuantumCircuit:
|
239
|
+
"""Query a basic approximation of a matrix."""
|
240
|
+
if isinstance(gate, Gate):
|
241
|
+
data = self._sk.query_basic_approximation(gate)
|
170
242
|
else:
|
171
|
-
|
243
|
+
data = self._sk.query_basic_approximation_matrix(gate)
|
172
244
|
|
173
|
-
|
174
|
-
|
175
|
-
)
|
176
|
-
|
177
|
-
v_n1 = self._recurse(v_n, n - 1, check_input=check_input)
|
178
|
-
w_n1 = self._recurse(w_n, n - 1, check_input=check_input)
|
179
|
-
res = v_n1.dot(w_n1).dot(v_n1.adjoint()).dot(w_n1.adjoint()).dot(u_n1)
|
180
|
-
|
181
|
-
return res
|
245
|
+
circuit = QuantumCircuit._from_circuit_data(data, add_regs=True)
|
246
|
+
return circuit
|
182
247
|
|
248
|
+
@deprecate_func(
|
249
|
+
since="2.1",
|
250
|
+
additional_msg="Use query_basic_approximation instead, which takes a Gate or matrix "
|
251
|
+
"as input and returns a QuantumCircuit object.",
|
252
|
+
pending=True,
|
253
|
+
)
|
183
254
|
def find_basic_approximation(self, sequence: GateSequence) -> GateSequence:
|
184
255
|
"""Find ``GateSequence`` in ``self._basic_approximations`` that approximates ``sequence``.
|
185
256
|
|
@@ -187,54 +258,23 @@ class SolovayKitaevDecomposition:
|
|
187
258
|
sequence: ``GateSequence`` to find the approximation to.
|
188
259
|
|
189
260
|
Returns:
|
190
|
-
``GateSequence`` in
|
261
|
+
``GateSequence`` in that approximates ``sequence``.
|
191
262
|
"""
|
192
|
-
|
193
|
-
|
194
|
-
def key(x):
|
195
|
-
return np.linalg.norm(np.subtract(x.product, sequence.product))
|
196
|
-
|
197
|
-
best = min(self.basic_approximations, key=key)
|
198
|
-
return best
|
199
|
-
|
200
|
-
|
201
|
-
def _remove_inverse_follows_gate(sequence):
|
202
|
-
index = 0
|
203
|
-
while index < len(sequence.gates) - 1:
|
204
|
-
curr_gate = sequence.gates[index]
|
205
|
-
next_gate = sequence.gates[index + 1]
|
206
|
-
if curr_gate.name in _1q_inverses:
|
207
|
-
remove = _1q_inverses[curr_gate.name] == next_gate.name
|
208
|
-
else:
|
209
|
-
remove = curr_gate.inverse() == next_gate
|
210
|
-
|
211
|
-
if remove:
|
212
|
-
# remove gates at index and index + 1
|
213
|
-
sequence.remove_cancelling_pair([index, index + 1])
|
214
|
-
# take a step back to see if we have uncovered a new pair, e.g.
|
215
|
-
# [h, s, sdg, h] at index = 1 removes s, sdg but if we continue at index 1
|
216
|
-
# we miss the uncovered [h, h] pair at indices 0 and 1
|
217
|
-
if index > 0:
|
218
|
-
index -= 1
|
219
|
-
else:
|
220
|
-
# next index
|
221
|
-
index += 1
|
263
|
+
return self._sk.find_basic_approximation(sequence)
|
222
264
|
|
223
265
|
|
224
|
-
def
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
index += 1
|
266
|
+
def normalize_gates(gates: list[Gate | str]) -> list[Gate]:
|
267
|
+
"""Normalize a list[Gate | str] into list[Gate]."""
|
268
|
+
name_to_gate = get_standard_gate_name_mapping()
|
269
|
+
# special case: we used to support "i" as IGate, but the official name is "id", so
|
270
|
+
# we add it manually here
|
271
|
+
name_to_gate["i"] = IGate()
|
231
272
|
|
273
|
+
def normalize(gate: Gate | str) -> Gate:
|
274
|
+
if isinstance(gate, Gate):
|
275
|
+
return gate
|
276
|
+
if gate in name_to_gate:
|
277
|
+
return name_to_gate[gate]
|
278
|
+
raise ValueError(f"Unsupported gate: {gate}")
|
232
279
|
|
233
|
-
|
234
|
-
"""
|
235
|
-
The implemented SolovayKitaevDecomposition has a global phase uncertainty of +-1,
|
236
|
-
due to approximating not the original SU(2) matrix but its projection onto SO(3).
|
237
|
-
This function returns ``True`` if the global phase of the computed approximation
|
238
|
-
should be adjusted (by adding pi) to better much the target.
|
239
|
-
"""
|
240
|
-
return np.linalg.norm(-computed - target) < np.linalg.norm(computed - target)
|
280
|
+
return list(map(normalize, gates))
|
@@ -17,7 +17,8 @@ from __future__ import annotations
|
|
17
17
|
from collections.abc import Callable
|
18
18
|
from typing import Any
|
19
19
|
from qiskit.circuit.quantumcircuit import QuantumCircuit
|
20
|
-
from qiskit.quantum_info.operators import SparsePauliOp
|
20
|
+
from qiskit.quantum_info.operators import SparsePauliOp
|
21
|
+
import qiskit.quantum_info
|
21
22
|
|
22
23
|
from .suzuki_trotter import SuzukiTrotter
|
23
24
|
|
@@ -55,7 +56,8 @@ class LieTrotter(SuzukiTrotter):
|
|
55
56
|
insert_barriers: bool = False,
|
56
57
|
cx_structure: str = "chain",
|
57
58
|
atomic_evolution: (
|
58
|
-
Callable[[QuantumCircuit, Pauli | SparsePauliOp, float], None]
|
59
|
+
Callable[[QuantumCircuit, qiskit.quantum_info.Pauli | SparsePauliOp, float], None]
|
60
|
+
| None
|
59
61
|
) = None,
|
60
62
|
wrap: bool = False,
|
61
63
|
preserve_order: bool = True,
|
@@ -70,11 +72,12 @@ class LieTrotter(SuzukiTrotter):
|
|
70
72
|
``"chain"``, where next neighbor connections are used, or ``"fountain"``,
|
71
73
|
where all qubits are connected to one. This only takes effect when
|
72
74
|
``atomic_evolution is None``.
|
73
|
-
atomic_evolution: A function to apply the evolution of a single
|
74
|
-
:class:`.SparsePauliOp` of only commuting terms,
|
75
|
-
three arguments: the circuit to append the
|
76
|
-
evolve, and the evolution time. By default, a
|
77
|
-
into a chain of ``CX`` gates and a single
|
75
|
+
atomic_evolution: A function to apply the evolution of a single
|
76
|
+
:class:`~.quantum_info.Pauli`, or :class:`.SparsePauliOp` of only commuting terms,
|
77
|
+
to a circuit. The function takes in three arguments: the circuit to append the
|
78
|
+
evolution to, the Pauli operator to evolve, and the evolution time. By default, a
|
79
|
+
single Pauli evolution is decomposed into a chain of ``CX`` gates and a single
|
80
|
+
``RZ`` gate.
|
78
81
|
wrap: Whether to wrap the atomic evolutions into custom gate objects. This only takes
|
79
82
|
effect when ``atomic_evolution is None``.
|
80
83
|
preserve_order: If ``False``, allows reordering the terms of the operator to
|
@@ -24,8 +24,9 @@ import numpy as np
|
|
24
24
|
import rustworkx as rx
|
25
25
|
from qiskit.circuit.parameterexpression import ParameterExpression
|
26
26
|
from qiskit.circuit.quantumcircuit import QuantumCircuit, ParameterValueType
|
27
|
-
from qiskit.quantum_info import SparsePauliOp,
|
27
|
+
from qiskit.quantum_info import SparsePauliOp, SparseObservable
|
28
28
|
from qiskit._accelerate.circuit_library import pauli_evolution
|
29
|
+
import qiskit.quantum_info
|
29
30
|
|
30
31
|
from .evolution_synthesis import EvolutionSynthesis
|
31
32
|
|
@@ -48,7 +49,8 @@ class ProductFormula(EvolutionSynthesis):
|
|
48
49
|
insert_barriers: bool = False,
|
49
50
|
cx_structure: str = "chain",
|
50
51
|
atomic_evolution: (
|
51
|
-
Callable[[QuantumCircuit, Pauli | SparsePauliOp, float], None]
|
52
|
+
Callable[[QuantumCircuit, qiskit.quantum_info.Pauli | SparsePauliOp, float], None]
|
53
|
+
| None
|
52
54
|
) = None,
|
53
55
|
wrap: bool = False,
|
54
56
|
preserve_order: bool = True,
|
@@ -64,11 +66,12 @@ class ProductFormula(EvolutionSynthesis):
|
|
64
66
|
``"chain"``, where next neighbor connections are used, or ``"fountain"``,
|
65
67
|
where all qubits are connected to one. This only takes effect when
|
66
68
|
``atomic_evolution is None``.
|
67
|
-
atomic_evolution: A function to apply the evolution of a single
|
68
|
-
:class:`.SparsePauliOp` of only commuting terms,
|
69
|
-
three arguments: the circuit to append the
|
70
|
-
evolve, and the evolution time. By default, a
|
71
|
-
into a chain of ``CX`` gates and a single
|
69
|
+
atomic_evolution: A function to apply the evolution of a single
|
70
|
+
:class:`~.quantum_info.Pauli`, or :class:`.SparsePauliOp` of only commuting terms,
|
71
|
+
to a circuit. The function takes in three arguments: the circuit to append the
|
72
|
+
evolution to, the Pauli operator to evolve, and the evolution time. By default, a
|
73
|
+
single Pauli evolution is decomposed into a chain of ``CX`` gates and a single
|
74
|
+
``RZ`` gate.
|
72
75
|
wrap: Whether to wrap the atomic evolutions into custom gate objects. Note that setting
|
73
76
|
this to ``True`` is slower than ``False``. This only takes effect when
|
74
77
|
``atomic_evolution is None``.
|
@@ -20,8 +20,9 @@ from itertools import chain
|
|
20
20
|
from collections.abc import Callable
|
21
21
|
import numpy as np
|
22
22
|
from qiskit.circuit.quantumcircuit import QuantumCircuit
|
23
|
-
from qiskit.quantum_info.operators import SparsePauliOp
|
23
|
+
from qiskit.quantum_info.operators import SparsePauliOp
|
24
24
|
from qiskit.exceptions import QiskitError
|
25
|
+
import qiskit.quantum_info
|
25
26
|
|
26
27
|
from .product_formula import ProductFormula, reorder_paulis
|
27
28
|
|
@@ -45,7 +46,8 @@ class QDrift(ProductFormula):
|
|
45
46
|
insert_barriers: bool = False,
|
46
47
|
cx_structure: str = "chain",
|
47
48
|
atomic_evolution: (
|
48
|
-
Callable[[QuantumCircuit, Pauli | SparsePauliOp, float], None]
|
49
|
+
Callable[[QuantumCircuit, qiskit.quantum_info.Pauli | SparsePauliOp, float], None]
|
50
|
+
| None
|
49
51
|
) = None,
|
50
52
|
seed: int | None = None,
|
51
53
|
wrap: bool = False,
|
@@ -61,11 +63,12 @@ class QDrift(ProductFormula):
|
|
61
63
|
``"chain"``, where next neighbor connections are used, or ``"fountain"``, where all
|
62
64
|
qubits are connected to one. This only takes effect when
|
63
65
|
``atomic_evolution is None``.
|
64
|
-
atomic_evolution: A function to apply the evolution of a single
|
65
|
-
:class:`.SparsePauliOp` of only commuting terms,
|
66
|
-
three arguments: the circuit to append the
|
67
|
-
evolve, and the evolution time. By default, a
|
68
|
-
into a chain of ``CX`` gates and a single
|
66
|
+
atomic_evolution: A function to apply the evolution of a single
|
67
|
+
:class:`~.quantum_info.Pauli`, or :class:`.SparsePauliOp` of only commuting terms,
|
68
|
+
to a circuit. The function takes in three arguments: the circuit to append the
|
69
|
+
evolution to, the Pauli operator to evolve, and the evolution time. By default, a
|
70
|
+
single Pauli evolution is decomposed into a chain of ``CX`` gates and a single
|
71
|
+
``RZ`` gate.
|
69
72
|
seed: An optional seed for reproducibility of the random sampling process.
|
70
73
|
wrap: Whether to wrap the atomic evolutions into custom gate objects. This only takes
|
71
74
|
effect when ``atomic_evolution is None``.
|
@@ -21,7 +21,8 @@ import numpy as np
|
|
21
21
|
|
22
22
|
from qiskit.circuit.parameterexpression import ParameterExpression
|
23
23
|
from qiskit.circuit.quantumcircuit import QuantumCircuit
|
24
|
-
from qiskit.quantum_info import SparsePauliOp
|
24
|
+
from qiskit.quantum_info import SparsePauliOp
|
25
|
+
import qiskit.quantum_info
|
25
26
|
|
26
27
|
from .product_formula import ProductFormula, reorder_paulis
|
27
28
|
|
@@ -65,7 +66,8 @@ class SuzukiTrotter(ProductFormula):
|
|
65
66
|
insert_barriers: bool = False,
|
66
67
|
cx_structure: str = "chain",
|
67
68
|
atomic_evolution: (
|
68
|
-
Callable[[QuantumCircuit, Pauli | SparsePauliOp, float], None]
|
69
|
+
Callable[[QuantumCircuit, qiskit.quantum_info.Pauli | SparsePauliOp, float], None]
|
70
|
+
| None
|
69
71
|
) = None,
|
70
72
|
wrap: bool = False,
|
71
73
|
preserve_order: bool = True,
|
@@ -80,11 +82,12 @@ class SuzukiTrotter(ProductFormula):
|
|
80
82
|
cx_structure: How to arrange the CX gates for the Pauli evolutions, can be ``"chain"``,
|
81
83
|
where next neighbor connections are used, or ``"fountain"``, where all qubits are
|
82
84
|
connected to one. This only takes effect when ``atomic_evolution is None``.
|
83
|
-
atomic_evolution: A function to apply the evolution of a single
|
84
|
-
:class:`.SparsePauliOp` of only commuting terms,
|
85
|
-
three arguments: the circuit to append the
|
86
|
-
evolve, and the evolution time. By default, a
|
87
|
-
into a chain of ``CX`` gates and a single
|
85
|
+
atomic_evolution: A function to apply the evolution of a single
|
86
|
+
:class:`~.quantum_info.Pauli`, or :class:`.SparsePauliOp` of only commuting terms,
|
87
|
+
to a circuit. The function takes in three arguments: the circuit to append the
|
88
|
+
evolution to, the Pauli operator to evolve, and the evolution time. By default, a
|
89
|
+
single Pauli evolution is decomposed into a chain of ``CX`` gates and a single
|
90
|
+
``RZ`` gate.
|
88
91
|
wrap: Whether to wrap the atomic evolutions into custom gate objects. This only takes
|
89
92
|
effect when ``atomic_evolution is None``.
|
90
93
|
preserve_order: If ``False``, allows reordering the terms of the operator to
|
@@ -14,6 +14,10 @@
|
|
14
14
|
|
15
15
|
from .mcmt_vchain import synth_mcmt_vchain
|
16
16
|
from .mcx_synthesis import (
|
17
|
+
synth_mcx_1_clean_kg24,
|
18
|
+
synth_mcx_1_dirty_kg24,
|
19
|
+
synth_mcx_2_clean_kg24,
|
20
|
+
synth_mcx_2_dirty_kg24,
|
17
21
|
synth_mcx_n_dirty_i15,
|
18
22
|
synth_mcx_n_clean_m15,
|
19
23
|
synth_mcx_1_clean_b95,
|