qiskit 2.0.3__cp39-abi3-macosx_11_0_arm64.whl → 2.1.0__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 +104 -20
- qiskit/circuit/_add_control.py +57 -31
- qiskit/circuit/_classical_resource_map.py +4 -0
- qiskit/circuit/annotation.py +504 -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 +4 -4
- qiskit/circuit/library/arithmetic/multipliers/multiplier.py +2 -2
- qiskit/circuit/library/arithmetic/piecewise_chebyshev.py +8 -4
- 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 +172 -99
- 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 +182 -6
- 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/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 +10 -3
- qiskit/transpiler/instruction_durations.py +2 -20
- qiskit/transpiler/passes/__init__.py +5 -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 +10 -0
- 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 +4 -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 +494 -93
- qiskit/transpiler/passes/synthesis/plugin.py +4 -0
- 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/transpiler/target.py +15 -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.3.dist-info → qiskit-2.1.0.dist-info}/METADATA +7 -6
- {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/RECORD +178 -169
- {qiskit-2.0.3.dist-info → qiskit-2.1.0.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.3.dist-info → qiskit-2.1.0.dist-info}/WHEEL +0 -0
- {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/licenses/LICENSE.txt +0 -0
- {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,156 @@
|
|
1
|
+
# This code is part of Qiskit.
|
2
|
+
#
|
3
|
+
# (C) Copyright IBM 2025.
|
4
|
+
#
|
5
|
+
# This code is licensed under the Apache License, Version 2.0. You may
|
6
|
+
# obtain a copy of this license in the LICENSE.txt file in the root directory
|
7
|
+
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
|
8
|
+
#
|
9
|
+
# Any modifications or derivative works of this code must retain this
|
10
|
+
# copyright notice, and modified files need to carry a notice indicating
|
11
|
+
# that they have been altered from the originals.
|
12
|
+
|
13
|
+
"""Compute the sum of two qubit registers without any ancillary qubits."""
|
14
|
+
|
15
|
+
from __future__ import annotations
|
16
|
+
from math import ceil
|
17
|
+
from qiskit.circuit.quantumcircuit import QuantumCircuit
|
18
|
+
from qiskit.circuit import QuantumRegister
|
19
|
+
|
20
|
+
|
21
|
+
def _mcx_ladder(n_mcx: int, alpha: int):
|
22
|
+
r"""Implements a log-depth MCX ladder circuit as outlined in Algorithm 2 of [1]. The circuit
|
23
|
+
relies on log-depth decomposition of MCX gate that uses conditionally clean ancillae of [2].
|
24
|
+
Selecting :math:`\alpha=1` creates a CX ladder as shown in Fig. 2 of [1] and selecting
|
25
|
+
:math:`\alpha=2` creates a Toffoli ladder as shown in Fig. 3 of [1].
|
26
|
+
|
27
|
+
Args:
|
28
|
+
n_mcx: Number of MCX gates in the ladder.
|
29
|
+
alpha: Number of controls per MCX gate.
|
30
|
+
|
31
|
+
Returns:
|
32
|
+
QuantumCircuit: The MCX ladder circuit.
|
33
|
+
|
34
|
+
References:
|
35
|
+
1. Remaud and Vandaele, Ancilla-free Quantum Adder with Sublinear Depth, 2025.
|
36
|
+
`arXiv:2501.16802 <https://arxiv.org/abs/2501.16802>`__
|
37
|
+
|
38
|
+
2. Khattar and Gidney, Rise of conditionally clean ancillae for optimizing quantum circuits
|
39
|
+
`arXiv:2407.17966 <https://arxiv.org/abs/2407.17966>`__
|
40
|
+
"""
|
41
|
+
|
42
|
+
def helper(qubit_indices, alphas) -> list[list[int]]:
|
43
|
+
k = len(alphas) + 1
|
44
|
+
if k == 1:
|
45
|
+
return []
|
46
|
+
if k == 2:
|
47
|
+
return [qubit_indices[: alphas[0] + 1]]
|
48
|
+
|
49
|
+
x_bar = [qubit_indices[alphas[0]]]
|
50
|
+
alpha_bar = []
|
51
|
+
right_pairs = [qubit_indices[0 : alphas[0] + 1]]
|
52
|
+
left_pairs = [qubit_indices[alphas[k - 3] : alphas[-1] + 1]]
|
53
|
+
|
54
|
+
for i in range(1, ceil(k / 2) - 1):
|
55
|
+
left_pairs += [qubit_indices[alphas[2 * i - 2] : alphas[2 * i - 1] + 1]]
|
56
|
+
right_pairs += [qubit_indices[alphas[2 * i - 1] : alphas[2 * i] + 1]]
|
57
|
+
x_bar += (
|
58
|
+
qubit_indices[alphas[2 * i - 2] + 1 : alphas[2 * i - 1]]
|
59
|
+
+ qubit_indices[alphas[2 * i - 1] + 1 : alphas[2 * i] + 1]
|
60
|
+
)
|
61
|
+
alpha_bar.append(alphas[2 * i] - alphas[0] - i)
|
62
|
+
|
63
|
+
if k % 2 == 0:
|
64
|
+
x_bar += qubit_indices[alphas[k - 4] + 1 : alphas[k - 3] + 1]
|
65
|
+
alpha_bar.append(alphas[k - 3] - alphas[0] - int(k / 2) + 2)
|
66
|
+
|
67
|
+
return left_pairs + helper(x_bar, alpha_bar) + right_pairs
|
68
|
+
|
69
|
+
n = n_mcx * alpha + 1
|
70
|
+
qc = QuantumCircuit(n)
|
71
|
+
qubit_indices, alphas = list(range(n)), list(range(alpha, n, alpha))
|
72
|
+
mcxs = helper(qubit_indices, alphas)
|
73
|
+
for mcx in mcxs:
|
74
|
+
qc.mcx(mcx[:-1], mcx[-1])
|
75
|
+
|
76
|
+
return qc
|
77
|
+
|
78
|
+
|
79
|
+
def adder_ripple_r25(num_qubits: int) -> QuantumCircuit:
|
80
|
+
# pylint: disable=line-too-long
|
81
|
+
r"""The RV ripple carry adder [1].
|
82
|
+
Construct an ancilla-free quantum adder circuit with sublinear depth based on the RV ripple-carry
|
83
|
+
adder shown in [1]. The implementation has a depth of :math:`O(\log^2 n)` and uses
|
84
|
+
math:`O(n \log n)` gates.
|
85
|
+
|
86
|
+
As an example, a ripple-carry adder circuit that performs addition on two 4-qubit sized
|
87
|
+
registers is as follows:
|
88
|
+
|
89
|
+
.. parsed-literal::
|
90
|
+
|
91
|
+
┌───────────┐ ┌────────┐
|
92
|
+
a_0: ─────────────────────────┤0 ├────────────────────┤0 ├───────────────■─────────────────
|
93
|
+
┌────────┐│ │ │ │┌───────────┐ │
|
94
|
+
a_1: ──■────────────┤0 ├┤2 ├──■─────────────────┤2 ├┤0 ├──┼────■────────────
|
95
|
+
│ │ ││ │ │ │ ││ │ │ │
|
96
|
+
a_2: ──┼────■───────┤1 ├┤4 ├──┼────■────────────┤4 ├┤1 LAD_1_dg ├──┼────┼────■───────
|
97
|
+
│ │ │ ││ │ │ │ │ ││ │ │ │ │
|
98
|
+
a_3: ──┼────┼────■──┤2 ├┤6 ├──┼────┼────■───────┤6 LAD_2 ├┤2 ├──┼────┼────┼────■──
|
99
|
+
│ │ │ │ ││ │ │ │ │ │ │└───────────┘┌─┴─┐ │ │ │
|
100
|
+
b_0: ──┼────┼────┼──┤ ├┤1 LAD_2_dg ├──┼────┼────┼───────┤1 ├─────────────┤ X ├──┼────┼────┼──
|
101
|
+
┌─┴─┐ │ │ │ LAD_1 ││ │┌─┴─┐ │ │ ┌───┐│ │ ┌───┐ └───┘┌─┴─┐ │ │
|
102
|
+
b_1: ┤ X ├──┼────┼──┤ ├┤3 ├┤ X ├──┼────┼──┤ X ├┤3 ├────┤ X ├─────────┤ X ├──┼────┼──
|
103
|
+
└───┘┌─┴─┐ │ │ ││ │└───┘┌─┴─┐ │ ├───┤│ │ ├───┤ └───┘┌─┴─┐ │
|
104
|
+
b_2: ─────┤ X ├──┼──┤ ├┤5 ├─────┤ X ├──┼──┤ X ├┤5 ├────┤ X ├──────────────┤ X ├──┼──
|
105
|
+
└───┘┌─┴─┐│ ││ │ └───┘┌─┴─┐└───┘└────────┘ └───┘ └───┘┌─┴─┐
|
106
|
+
b_3: ──────────┤ X ├┤ ├┤7 ├──────────┤ X ├───────────────────────────────────────────┤ X ├
|
107
|
+
└───┘│ ││ │ └───┘ └───┘
|
108
|
+
cout: ───────────────┤3 ├┤8 ├───────────────────────────────────────────────────────────────
|
109
|
+
└────────┘└───────────┘
|
110
|
+
|
111
|
+
Here *LAD_1* and *LAD_2* are the CX and CCX ladders respectively introduced in [1]. Note that
|
112
|
+
in this implementation the input register qubits are ordered as all qubits from
|
113
|
+
the first input register, followed by all qubits from the second input register.
|
114
|
+
|
115
|
+
Args:
|
116
|
+
num_qubits: The size of the register.
|
117
|
+
|
118
|
+
Returns:
|
119
|
+
The quantum circuit implementing the RV ripple carry adder.
|
120
|
+
|
121
|
+
Raises:
|
122
|
+
ValueError: If ``num_state_qubits`` is lower than 1.
|
123
|
+
|
124
|
+
**References:**
|
125
|
+
|
126
|
+
1. Remaud and Vandaele, Ancilla-free Quantum Adder with Sublinear Depth, 2025.
|
127
|
+
`arXiv:2501.16802 <https://arxiv.org/abs/2501.16802>`__
|
128
|
+
|
129
|
+
"""
|
130
|
+
|
131
|
+
if num_qubits < 1:
|
132
|
+
raise ValueError("The number of qubits must be at least 1.")
|
133
|
+
|
134
|
+
qr_a = QuantumRegister(num_qubits, "a")
|
135
|
+
qr_b = QuantumRegister(num_qubits, "b")
|
136
|
+
qr_z = QuantumRegister(1, "cout")
|
137
|
+
qc = QuantumCircuit(qr_a, qr_b, qr_z)
|
138
|
+
|
139
|
+
if num_qubits == 1:
|
140
|
+
qc.ccx(qr_a[0], qr_b[0], qr_z[0])
|
141
|
+
qc.cx(qr_a[0], qr_b[0])
|
142
|
+
return qc
|
143
|
+
|
144
|
+
ab_interleaved = [q for pair in zip(qr_a, qr_b) for q in pair]
|
145
|
+
|
146
|
+
qc.cx(qr_a[1:], qr_b[1:])
|
147
|
+
qc.compose(_mcx_ladder(num_qubits - 1, 1), qr_a[1:] + qr_z[:], inplace=True)
|
148
|
+
qc.compose(_mcx_ladder(num_qubits, 2).inverse(), ab_interleaved + qr_z[:], inplace=True)
|
149
|
+
qc.cx(qr_a[1:], qr_b[1:])
|
150
|
+
qc.x(qr_b[1 : max(2, num_qubits - 1)])
|
151
|
+
qc.compose(_mcx_ladder(num_qubits - 1, 2), ab_interleaved[:-1], inplace=True)
|
152
|
+
qc.x(qr_b[1 : max(2, num_qubits - 1)])
|
153
|
+
qc.compose(_mcx_ladder(num_qubits - 2, 1).inverse(), qr_a[1:], inplace=True)
|
154
|
+
qc.cx(qr_a, qr_b)
|
155
|
+
|
156
|
+
return qc
|
@@ -14,112 +14,21 @@
|
|
14
14
|
|
15
15
|
from __future__ import annotations
|
16
16
|
|
17
|
-
import warnings
|
18
|
-
import collections
|
19
|
-
import numpy as np
|
20
|
-
|
21
|
-
import qiskit.circuit.library.standard_gates as gates
|
22
17
|
from qiskit.circuit import Gate
|
23
|
-
from qiskit.
|
24
|
-
from qiskit.
|
25
|
-
|
26
|
-
from .gate_sequence import GateSequence
|
27
|
-
|
28
|
-
Node = collections.namedtuple("Node", ("labels", "sequence", "children"))
|
29
|
-
|
30
|
-
_1q_inverses = {
|
31
|
-
"i": "i",
|
32
|
-
"x": "x",
|
33
|
-
"y": "y",
|
34
|
-
"z": "z",
|
35
|
-
"h": "h",
|
36
|
-
"t": "tdg",
|
37
|
-
"tdg": "t",
|
38
|
-
"s": "sdg",
|
39
|
-
"sdg": "s",
|
40
|
-
"sx": "sxdg",
|
41
|
-
"sxdg": "sx",
|
42
|
-
}
|
43
|
-
|
44
|
-
_1q_gates = {
|
45
|
-
"i": gates.IGate(),
|
46
|
-
"x": gates.XGate(),
|
47
|
-
"y": gates.YGate(),
|
48
|
-
"z": gates.ZGate(),
|
49
|
-
"h": gates.HGate(),
|
50
|
-
"t": gates.TGate(),
|
51
|
-
"tdg": gates.TdgGate(),
|
52
|
-
"s": gates.SGate(),
|
53
|
-
"sdg": gates.SdgGate(),
|
54
|
-
"sx": gates.SXGate(),
|
55
|
-
"sxdg": gates.SXdgGate(),
|
56
|
-
}
|
57
|
-
|
58
|
-
|
59
|
-
def _check_candidate(candidate, existing_sequences, tol=1e-10):
|
60
|
-
if optionals.HAS_SKLEARN:
|
61
|
-
return _check_candidate_kdtree(candidate, existing_sequences, tol)
|
62
|
-
|
63
|
-
warnings.warn(
|
64
|
-
"The SolovayKitaev algorithm relies on scikit-learn's KDTree for a "
|
65
|
-
"fast search over the basis approximations. Without this, we fallback onto a "
|
66
|
-
"greedy search with is significantly slower. We highly suggest to install "
|
67
|
-
"scikit-learn to use this feature.",
|
68
|
-
category=RuntimeWarning,
|
69
|
-
)
|
70
|
-
return _check_candidate_greedy(candidate, existing_sequences, tol)
|
71
|
-
|
72
|
-
|
73
|
-
def _check_candidate_greedy(candidate, existing_sequences, tol=1e-10):
|
74
|
-
# do a quick, string-based check if the same sequence already exists
|
75
|
-
if any(candidate.name == existing.name for existing in existing_sequences):
|
76
|
-
return False
|
77
|
-
|
78
|
-
for existing in existing_sequences:
|
79
|
-
if matrix_equal(existing.product, candidate.product, ignore_phase=True, atol=tol):
|
80
|
-
# is the new sequence less or more efficient?
|
81
|
-
return len(candidate.gates) < len(existing.gates)
|
82
|
-
return True
|
83
|
-
|
84
|
-
|
85
|
-
@optionals.HAS_SKLEARN.require_in_call
|
86
|
-
def _check_candidate_kdtree(candidate, existing_sequences, tol=1e-10):
|
87
|
-
"""Check if there's a candidate implementing the same matrix up to ``tol``.
|
18
|
+
from qiskit.utils.deprecation import deprecate_func
|
19
|
+
from qiskit._accelerate.synthesis.discrete_basis import GateSequence
|
88
20
|
|
89
|
-
|
90
|
-
"""
|
91
|
-
from sklearn.neighbors import KDTree
|
92
|
-
|
93
|
-
# do a quick, string-based check if the same sequence already exists
|
94
|
-
if any(candidate.name == existing.name for existing in existing_sequences):
|
95
|
-
return False
|
96
|
-
|
97
|
-
points = np.array([sequence.product.flatten() for sequence in existing_sequences])
|
98
|
-
candidate = np.array([candidate.product.flatten()])
|
99
|
-
|
100
|
-
kdtree = KDTree(points)
|
101
|
-
dist, _ = kdtree.query(candidate)
|
102
|
-
|
103
|
-
return dist[0][0] > tol
|
104
|
-
|
105
|
-
|
106
|
-
def _process_node(node: Node, basis: list[str], sequences: list[GateSequence]):
|
107
|
-
inverse_last = _1q_inverses[node.labels[-1]] if node.labels else None
|
108
|
-
|
109
|
-
for label in basis:
|
110
|
-
if label == inverse_last:
|
111
|
-
continue
|
112
|
-
|
113
|
-
sequence = node.sequence.copy()
|
114
|
-
sequence.append(_1q_gates[label])
|
115
|
-
|
116
|
-
if _check_candidate(sequence, sequences):
|
117
|
-
sequences.append(sequence)
|
118
|
-
node.children.append(Node(node.labels + (label,), sequence, []))
|
119
|
-
|
120
|
-
return node.children
|
21
|
+
from .solovay_kitaev import SolovayKitaevDecomposition
|
121
22
|
|
122
23
|
|
24
|
+
@deprecate_func(
|
25
|
+
since="2.1",
|
26
|
+
additional_msg=(
|
27
|
+
"Use the SolovayKitaevDecomposition class directly, to generate, store, and load the "
|
28
|
+
"basic approximations."
|
29
|
+
),
|
30
|
+
pending=True,
|
31
|
+
)
|
123
32
|
def generate_basic_approximations(
|
124
33
|
basis_gates: list[str | Gate], depth: int, filename: str | None = None
|
125
34
|
) -> list[GateSequence]:
|
@@ -136,30 +45,9 @@ def generate_basic_approximations(
|
|
136
45
|
Raises:
|
137
46
|
ValueError: If ``basis_gates`` contains an invalid gate identifier.
|
138
47
|
"""
|
139
|
-
|
140
|
-
for gate in basis_gates:
|
141
|
-
if isinstance(gate, str):
|
142
|
-
if gate not in _1q_gates:
|
143
|
-
raise ValueError(f"Invalid gate identifier: {gate}")
|
144
|
-
basis.append(gate)
|
145
|
-
else: # gate is a qiskit.circuit.Gate
|
146
|
-
basis.append(gate.name)
|
147
|
-
|
148
|
-
tree = Node((), GateSequence(), [])
|
149
|
-
cur_level = [tree]
|
150
|
-
sequences = [tree.sequence]
|
151
|
-
for _ in [None] * depth:
|
152
|
-
next_level = []
|
153
|
-
for node in cur_level:
|
154
|
-
next_level.extend(_process_node(node, basis, sequences))
|
155
|
-
cur_level = next_level
|
48
|
+
sk = SolovayKitaevDecomposition(basis_gates=basis_gates, depth=depth)
|
156
49
|
|
157
50
|
if filename is not None:
|
158
|
-
|
159
|
-
for sequence in sequences:
|
160
|
-
gatestring = sequence.name
|
161
|
-
data[gatestring] = (sequence.product, sequence.global_phase)
|
162
|
-
|
163
|
-
np.save(filename, data)
|
51
|
+
sk.save_basic_approximations(filename)
|
164
52
|
|
165
|
-
return
|
53
|
+
return sk._sk.get_gate_sequences()
|