qiskit 1.0.2__cp38-abi3-win32.whl → 1.1.0__cp38-abi3-win32.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 +27 -16
- qiskit/_accelerate.pyd +0 -0
- qiskit/_numpy_compat.py +73 -0
- qiskit/assembler/__init__.py +5 -10
- qiskit/assembler/disassemble.py +5 -6
- qiskit/circuit/__init__.py +1061 -232
- qiskit/circuit/_classical_resource_map.py +10 -6
- qiskit/circuit/_utils.py +18 -8
- qiskit/circuit/annotated_operation.py +21 -0
- qiskit/circuit/barrier.py +10 -13
- qiskit/circuit/bit.py +0 -1
- qiskit/circuit/classical/__init__.py +2 -2
- qiskit/circuit/classical/expr/__init__.py +39 -5
- qiskit/circuit/classical/expr/constructors.py +84 -1
- qiskit/circuit/classical/expr/expr.py +83 -13
- qiskit/circuit/classical/expr/visitors.py +83 -0
- qiskit/circuit/classical/types/__init__.py +5 -4
- qiskit/circuit/classicalfunction/__init__.py +1 -0
- qiskit/circuit/commutation_checker.py +86 -51
- qiskit/circuit/controlflow/_builder_utils.py +9 -1
- qiskit/circuit/controlflow/break_loop.py +8 -22
- qiskit/circuit/controlflow/builder.py +116 -1
- qiskit/circuit/controlflow/continue_loop.py +8 -22
- qiskit/circuit/controlflow/control_flow.py +47 -8
- qiskit/circuit/controlflow/for_loop.py +8 -23
- qiskit/circuit/controlflow/if_else.py +13 -27
- qiskit/circuit/controlflow/switch_case.py +14 -21
- qiskit/circuit/controlflow/while_loop.py +9 -23
- qiskit/circuit/controlledgate.py +2 -2
- qiskit/circuit/delay.py +7 -5
- qiskit/circuit/gate.py +20 -7
- qiskit/circuit/instruction.py +31 -30
- qiskit/circuit/instructionset.py +9 -22
- qiskit/circuit/library/__init__.py +3 -13
- qiskit/circuit/library/arithmetic/integer_comparator.py +2 -2
- qiskit/circuit/library/arithmetic/quadratic_form.py +3 -2
- qiskit/circuit/library/blueprintcircuit.py +29 -7
- qiskit/circuit/library/data_preparation/state_preparation.py +6 -5
- qiskit/circuit/library/generalized_gates/diagonal.py +5 -4
- qiskit/circuit/library/generalized_gates/isometry.py +51 -254
- qiskit/circuit/library/generalized_gates/pauli.py +2 -2
- qiskit/circuit/library/generalized_gates/permutation.py +4 -1
- qiskit/circuit/library/generalized_gates/rv.py +15 -11
- qiskit/circuit/library/generalized_gates/uc.py +2 -98
- qiskit/circuit/library/generalized_gates/unitary.py +9 -4
- qiskit/circuit/library/hamiltonian_gate.py +11 -5
- qiskit/circuit/library/n_local/efficient_su2.py +5 -5
- qiskit/circuit/library/n_local/n_local.py +100 -49
- qiskit/circuit/library/n_local/two_local.py +3 -59
- qiskit/circuit/library/overlap.py +3 -3
- qiskit/circuit/library/phase_oracle.py +1 -1
- qiskit/circuit/library/quantum_volume.py +39 -38
- qiskit/circuit/library/standard_gates/equivalence_library.py +50 -0
- qiskit/circuit/library/standard_gates/global_phase.py +4 -2
- qiskit/circuit/library/standard_gates/i.py +1 -2
- qiskit/circuit/library/standard_gates/iswap.py +1 -2
- qiskit/circuit/library/standard_gates/multi_control_rotation_gates.py +11 -5
- qiskit/circuit/library/standard_gates/p.py +31 -15
- qiskit/circuit/library/standard_gates/r.py +4 -3
- qiskit/circuit/library/standard_gates/rx.py +7 -4
- qiskit/circuit/library/standard_gates/rxx.py +4 -3
- qiskit/circuit/library/standard_gates/ry.py +7 -4
- qiskit/circuit/library/standard_gates/ryy.py +4 -3
- qiskit/circuit/library/standard_gates/rz.py +7 -4
- qiskit/circuit/library/standard_gates/rzx.py +4 -3
- qiskit/circuit/library/standard_gates/rzz.py +4 -3
- qiskit/circuit/library/standard_gates/s.py +4 -8
- qiskit/circuit/library/standard_gates/t.py +2 -4
- qiskit/circuit/library/standard_gates/u.py +16 -11
- qiskit/circuit/library/standard_gates/u1.py +6 -2
- qiskit/circuit/library/standard_gates/u2.py +4 -2
- qiskit/circuit/library/standard_gates/u3.py +9 -5
- qiskit/circuit/library/standard_gates/x.py +22 -11
- qiskit/circuit/library/standard_gates/xx_minus_yy.py +4 -3
- qiskit/circuit/library/standard_gates/xx_plus_yy.py +7 -5
- qiskit/circuit/library/standard_gates/z.py +1 -2
- qiskit/circuit/measure.py +4 -1
- qiskit/circuit/operation.py +13 -8
- qiskit/circuit/parameter.py +11 -6
- qiskit/circuit/quantumcircuit.py +1910 -260
- qiskit/circuit/quantumcircuitdata.py +2 -2
- qiskit/circuit/reset.py +5 -2
- qiskit/circuit/store.py +95 -0
- qiskit/compiler/assembler.py +22 -22
- qiskit/compiler/transpiler.py +63 -112
- qiskit/converters/__init__.py +17 -2
- qiskit/converters/circuit_to_dag.py +7 -0
- qiskit/converters/circuit_to_dagdependency_v2.py +47 -0
- qiskit/converters/circuit_to_gate.py +2 -0
- qiskit/converters/circuit_to_instruction.py +22 -0
- qiskit/converters/dag_to_circuit.py +4 -0
- qiskit/converters/dag_to_dagdependency_v2.py +44 -0
- qiskit/dagcircuit/collect_blocks.py +15 -10
- qiskit/dagcircuit/dagcircuit.py +434 -124
- qiskit/dagcircuit/dagdependency.py +19 -12
- qiskit/dagcircuit/dagdependency_v2.py +641 -0
- qiskit/dagcircuit/dagdepnode.py +19 -16
- qiskit/dagcircuit/dagnode.py +14 -4
- qiskit/passmanager/passmanager.py +11 -11
- qiskit/primitives/__init__.py +22 -12
- qiskit/primitives/backend_estimator.py +3 -5
- qiskit/primitives/backend_estimator_v2.py +410 -0
- qiskit/primitives/backend_sampler_v2.py +287 -0
- qiskit/primitives/base/base_estimator.py +4 -9
- qiskit/primitives/base/base_sampler.py +2 -2
- qiskit/primitives/containers/__init__.py +6 -4
- qiskit/primitives/containers/bit_array.py +293 -2
- qiskit/primitives/containers/data_bin.py +123 -50
- qiskit/primitives/containers/estimator_pub.py +10 -3
- qiskit/primitives/containers/observables_array.py +2 -2
- qiskit/primitives/containers/pub_result.py +1 -1
- qiskit/primitives/containers/sampler_pub.py +19 -3
- qiskit/primitives/containers/sampler_pub_result.py +74 -0
- qiskit/primitives/containers/shape.py +4 -4
- qiskit/primitives/statevector_estimator.py +4 -4
- qiskit/primitives/statevector_sampler.py +7 -12
- qiskit/providers/__init__.py +65 -34
- qiskit/providers/backend.py +2 -2
- qiskit/providers/backend_compat.py +8 -10
- qiskit/providers/basic_provider/__init__.py +2 -23
- qiskit/providers/basic_provider/basic_provider_tools.py +67 -31
- qiskit/providers/basic_provider/basic_simulator.py +81 -21
- qiskit/providers/fake_provider/__init__.py +1 -1
- qiskit/providers/fake_provider/fake_1q.py +1 -1
- qiskit/providers/fake_provider/fake_backend.py +3 -408
- qiskit/providers/fake_provider/generic_backend_v2.py +26 -14
- qiskit/providers/models/__init__.py +2 -2
- qiskit/providers/provider.py +16 -0
- qiskit/pulse/builder.py +4 -1
- qiskit/pulse/parameter_manager.py +60 -4
- qiskit/pulse/schedule.py +29 -13
- qiskit/pulse/utils.py +61 -20
- qiskit/qasm2/__init__.py +1 -5
- qiskit/qasm2/parse.py +1 -4
- qiskit/qasm3/__init__.py +42 -5
- qiskit/qasm3/ast.py +19 -0
- qiskit/qasm3/exporter.py +178 -106
- qiskit/qasm3/printer.py +27 -5
- qiskit/qobj/converters/pulse_instruction.py +6 -6
- qiskit/qpy/__init__.py +299 -67
- qiskit/qpy/binary_io/circuits.py +216 -47
- qiskit/qpy/binary_io/schedules.py +42 -36
- qiskit/qpy/binary_io/value.py +201 -22
- qiskit/qpy/common.py +1 -1
- qiskit/qpy/exceptions.py +20 -0
- qiskit/qpy/formats.py +29 -0
- qiskit/qpy/type_keys.py +21 -0
- qiskit/quantum_info/analysis/distance.py +3 -3
- qiskit/quantum_info/analysis/make_observable.py +2 -1
- qiskit/quantum_info/analysis/z2_symmetries.py +2 -1
- qiskit/quantum_info/operators/channel/chi.py +9 -8
- qiskit/quantum_info/operators/channel/choi.py +10 -9
- qiskit/quantum_info/operators/channel/kraus.py +2 -1
- qiskit/quantum_info/operators/channel/ptm.py +10 -9
- qiskit/quantum_info/operators/channel/quantum_channel.py +2 -1
- qiskit/quantum_info/operators/channel/stinespring.py +2 -1
- qiskit/quantum_info/operators/channel/superop.py +12 -11
- qiskit/quantum_info/operators/channel/transformations.py +12 -11
- qiskit/quantum_info/operators/dihedral/dihedral.py +5 -4
- qiskit/quantum_info/operators/operator.py +43 -30
- qiskit/quantum_info/operators/scalar_op.py +10 -9
- qiskit/quantum_info/operators/symplectic/base_pauli.py +70 -59
- qiskit/quantum_info/operators/symplectic/clifford.py +36 -9
- qiskit/quantum_info/operators/symplectic/pauli.py +53 -6
- qiskit/quantum_info/operators/symplectic/pauli_list.py +36 -14
- qiskit/quantum_info/operators/symplectic/random.py +3 -2
- qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +61 -36
- qiskit/quantum_info/states/densitymatrix.py +13 -13
- qiskit/quantum_info/states/stabilizerstate.py +3 -3
- qiskit/quantum_info/states/statevector.py +14 -13
- qiskit/quantum_info/states/utils.py +5 -3
- qiskit/result/__init__.py +6 -0
- qiskit/result/mitigation/correlated_readout_mitigator.py +3 -2
- qiskit/result/mitigation/local_readout_mitigator.py +2 -1
- qiskit/result/mitigation/utils.py +3 -2
- qiskit/scheduler/__init__.py +10 -1
- qiskit/scheduler/methods/__init__.py +1 -8
- qiskit/synthesis/__init__.py +3 -6
- qiskit/synthesis/discrete_basis/commutator_decompose.py +2 -2
- qiskit/synthesis/evolution/lie_trotter.py +7 -14
- qiskit/synthesis/evolution/qdrift.py +3 -4
- qiskit/synthesis/linear/cnot_synth.py +1 -3
- qiskit/synthesis/linear/linear_circuits_utils.py +1 -1
- qiskit/synthesis/linear_phase/cz_depth_lnn.py +4 -18
- qiskit/synthesis/permutation/__init__.py +1 -0
- qiskit/synthesis/permutation/permutation_reverse_lnn.py +90 -0
- qiskit/synthesis/qft/qft_decompose_lnn.py +2 -6
- qiskit/synthesis/two_qubit/two_qubit_decompose.py +165 -954
- qiskit/synthesis/two_qubit/xx_decompose/circuits.py +13 -12
- qiskit/synthesis/two_qubit/xx_decompose/decomposer.py +7 -1
- qiskit/synthesis/unitary/aqc/__init__.py +1 -1
- qiskit/synthesis/unitary/aqc/cnot_structures.py +2 -1
- qiskit/synthesis/unitary/aqc/fast_gradient/fast_gradient.py +2 -1
- qiskit/synthesis/unitary/qsd.py +3 -2
- qiskit/transpiler/__init__.py +7 -3
- qiskit/transpiler/layout.py +140 -61
- qiskit/transpiler/passes/__init__.py +10 -2
- qiskit/transpiler/passes/basis/basis_translator.py +9 -4
- qiskit/transpiler/passes/basis/unroll_3q_or_more.py +1 -1
- qiskit/transpiler/passes/basis/unroll_custom_definitions.py +1 -1
- qiskit/transpiler/passes/calibration/rzx_builder.py +2 -1
- qiskit/transpiler/passes/layout/apply_layout.py +8 -3
- qiskit/transpiler/passes/layout/sabre_layout.py +15 -3
- qiskit/transpiler/passes/layout/set_layout.py +1 -1
- qiskit/transpiler/passes/optimization/__init__.py +2 -0
- qiskit/transpiler/passes/optimization/commutation_analysis.py +2 -2
- qiskit/transpiler/passes/optimization/commutative_cancellation.py +1 -1
- qiskit/transpiler/passes/optimization/consolidate_blocks.py +1 -1
- qiskit/transpiler/passes/optimization/cx_cancellation.py +10 -0
- qiskit/transpiler/passes/optimization/elide_permutations.py +114 -0
- qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +9 -3
- qiskit/transpiler/passes/optimization/optimize_annotated.py +248 -12
- qiskit/transpiler/passes/optimization/remove_final_reset.py +37 -0
- qiskit/transpiler/passes/optimization/template_matching/forward_match.py +1 -3
- qiskit/transpiler/passes/routing/__init__.py +1 -0
- qiskit/transpiler/passes/routing/basic_swap.py +13 -2
- qiskit/transpiler/passes/routing/commuting_2q_gate_routing/commuting_2q_gate_router.py +8 -1
- qiskit/transpiler/passes/routing/lookahead_swap.py +7 -1
- qiskit/transpiler/passes/routing/sabre_swap.py +10 -6
- qiskit/transpiler/passes/routing/star_prerouting.py +417 -0
- qiskit/transpiler/passes/routing/stochastic_swap.py +24 -8
- qiskit/transpiler/passes/scheduling/__init__.py +1 -1
- qiskit/transpiler/passes/scheduling/alap.py +1 -2
- qiskit/transpiler/passes/scheduling/alignments/align_measures.py +1 -2
- qiskit/transpiler/passes/scheduling/alignments/check_durations.py +9 -6
- qiskit/transpiler/passes/scheduling/alignments/pulse_gate_validation.py +8 -0
- qiskit/transpiler/passes/scheduling/alignments/reschedule.py +13 -4
- qiskit/transpiler/passes/scheduling/asap.py +1 -2
- qiskit/transpiler/passes/scheduling/base_scheduler.py +21 -2
- qiskit/transpiler/passes/scheduling/dynamical_decoupling.py +26 -4
- qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +24 -2
- qiskit/transpiler/passes/scheduling/time_unit_conversion.py +28 -4
- qiskit/transpiler/passes/synthesis/aqc_plugin.py +2 -2
- qiskit/transpiler/passes/synthesis/high_level_synthesis.py +120 -13
- qiskit/transpiler/passes/synthesis/unitary_synthesis.py +162 -55
- qiskit/transpiler/passes/utils/gates_basis.py +3 -3
- qiskit/transpiler/passmanager.py +44 -1
- qiskit/transpiler/preset_passmanagers/__init__.py +3 -3
- qiskit/transpiler/preset_passmanagers/builtin_plugins.py +34 -16
- qiskit/transpiler/preset_passmanagers/common.py +4 -6
- qiskit/transpiler/preset_passmanagers/plugin.py +9 -1
- qiskit/utils/__init__.py +3 -2
- qiskit/utils/optionals.py +6 -2
- qiskit/utils/parallel.py +24 -15
- qiskit/visualization/array.py +1 -1
- qiskit/visualization/bloch.py +2 -3
- qiskit/visualization/circuit/matplotlib.py +44 -14
- qiskit/visualization/circuit/text.py +38 -18
- qiskit/visualization/counts_visualization.py +3 -6
- qiskit/visualization/dag_visualization.py +6 -7
- qiskit/visualization/gate_map.py +9 -1
- qiskit/visualization/pulse_v2/interface.py +8 -3
- qiskit/visualization/state_visualization.py +3 -2
- qiskit/visualization/timeline/interface.py +18 -8
- {qiskit-1.0.2.dist-info → qiskit-1.1.0.dist-info}/METADATA +12 -8
- {qiskit-1.0.2.dist-info → qiskit-1.1.0.dist-info}/RECORD +261 -251
- {qiskit-1.0.2.dist-info → qiskit-1.1.0.dist-info}/WHEEL +1 -1
- qiskit/_qasm2.pyd +0 -0
- qiskit/_qasm3.pyd +0 -0
- {qiskit-1.0.2.dist-info → qiskit-1.1.0.dist-info}/LICENSE.txt +0 -0
- {qiskit-1.0.2.dist-info → qiskit-1.1.0.dist-info}/entry_points.txt +0 -0
- {qiskit-1.0.2.dist-info → qiskit-1.1.0.dist-info}/top_level.txt +0 -0
@@ -21,7 +21,6 @@
|
|
21
21
|
|
22
22
|
from __future__ import annotations
|
23
23
|
|
24
|
-
import cmath
|
25
24
|
import math
|
26
25
|
|
27
26
|
import numpy as np
|
@@ -33,14 +32,11 @@ from qiskit.circuit.quantumregister import QuantumRegister
|
|
33
32
|
from qiskit.circuit.quantumcircuit import QuantumCircuit
|
34
33
|
from qiskit.circuit.exceptions import CircuitError
|
35
34
|
from qiskit.exceptions import QiskitError
|
36
|
-
|
37
|
-
# pylint: disable=cyclic-import
|
38
|
-
from qiskit.synthesis.one_qubit.one_qubit_decompose import OneQubitEulerDecomposer
|
35
|
+
from qiskit._accelerate import uc_gate
|
39
36
|
|
40
37
|
from .diagonal import Diagonal
|
41
38
|
|
42
39
|
_EPS = 1e-10 # global variable used to chop very small numbers to zero
|
43
|
-
_DECOMPOSER1Q = OneQubitEulerDecomposer("U3")
|
44
40
|
|
45
41
|
|
46
42
|
class UCGate(Gate):
|
@@ -203,99 +199,7 @@ class UCGate(Gate):
|
|
203
199
|
https://arxiv.org/pdf/quant-ph/0410066.pdf.
|
204
200
|
"""
|
205
201
|
single_qubit_gates = [gate.astype(complex) for gate in self.params]
|
206
|
-
|
207
|
-
num_contr = self.num_qubits - 1
|
208
|
-
for dec_step in range(num_contr):
|
209
|
-
num_ucgs = 2**dec_step
|
210
|
-
# The decomposition works recursively and the following loop goes over the different
|
211
|
-
# UCGates that arise in the decomposition
|
212
|
-
for ucg_index in range(num_ucgs):
|
213
|
-
len_ucg = 2 ** (num_contr - dec_step)
|
214
|
-
for i in range(int(len_ucg / 2)):
|
215
|
-
shift = ucg_index * len_ucg
|
216
|
-
a = single_qubit_gates[shift + i]
|
217
|
-
b = single_qubit_gates[shift + len_ucg // 2 + i]
|
218
|
-
# Apply the decomposition for UCGates given in equation (3) in
|
219
|
-
# https://arxiv.org/pdf/quant-ph/0410066.pdf
|
220
|
-
# to demultiplex one control of all the num_ucgs uniformly-controlled gates
|
221
|
-
# with log2(len_ucg) uniform controls
|
222
|
-
v, u, r = self._demultiplex_single_uc(a, b)
|
223
|
-
# replace the single-qubit gates with v,u (the already existing ones
|
224
|
-
# are not needed any more)
|
225
|
-
single_qubit_gates[shift + i] = v
|
226
|
-
single_qubit_gates[shift + len_ucg // 2 + i] = u
|
227
|
-
# Now we decompose the gates D as described in Figure 4 in
|
228
|
-
# https://arxiv.org/pdf/quant-ph/0410066.pdf and merge some of the gates
|
229
|
-
# into the UCGates and the diagonal at the end of the circuit
|
230
|
-
|
231
|
-
# Remark: The Rz(pi/2) rotation acting on the target qubit and the Hadamard
|
232
|
-
# gates arising in the decomposition of D are ignored for the moment (they will
|
233
|
-
# be added together with the C-NOT gates at the end of the decomposition
|
234
|
-
# (in the method dec_ucg()))
|
235
|
-
if ucg_index < num_ucgs - 1:
|
236
|
-
# Absorb the Rz(pi/2) rotation on the control into the UC-Rz gate and
|
237
|
-
# merge the UC-Rz rotation with the following UCGate,
|
238
|
-
# which hasn't been decomposed yet.
|
239
|
-
k = shift + len_ucg + i
|
240
|
-
single_qubit_gates[k] = single_qubit_gates[k].dot(
|
241
|
-
UCGate._ct(r)
|
242
|
-
) * UCGate._rz(np.pi / 2).item((0, 0))
|
243
|
-
k = k + len_ucg // 2
|
244
|
-
single_qubit_gates[k] = single_qubit_gates[k].dot(r) * UCGate._rz(
|
245
|
-
np.pi / 2
|
246
|
-
).item((1, 1))
|
247
|
-
else:
|
248
|
-
# Absorb the Rz(pi/2) rotation on the control into the UC-Rz gate and merge
|
249
|
-
# the trailing UC-Rz rotation into a diagonal gate at the end of the circuit
|
250
|
-
for ucg_index_2 in range(num_ucgs):
|
251
|
-
shift_2 = ucg_index_2 * len_ucg
|
252
|
-
k = 2 * (i + shift_2)
|
253
|
-
diag[k] = (
|
254
|
-
diag[k]
|
255
|
-
* UCGate._ct(r).item((0, 0))
|
256
|
-
* UCGate._rz(np.pi / 2).item((0, 0))
|
257
|
-
)
|
258
|
-
diag[k + 1] = (
|
259
|
-
diag[k + 1]
|
260
|
-
* UCGate._ct(r).item((1, 1))
|
261
|
-
* UCGate._rz(np.pi / 2).item((0, 0))
|
262
|
-
)
|
263
|
-
k = len_ucg + k
|
264
|
-
diag[k] *= r.item((0, 0)) * UCGate._rz(np.pi / 2).item((1, 1))
|
265
|
-
diag[k + 1] *= r.item((1, 1)) * UCGate._rz(np.pi / 2).item((1, 1))
|
266
|
-
return single_qubit_gates, diag
|
267
|
-
|
268
|
-
def _demultiplex_single_uc(self, a, b):
|
269
|
-
"""
|
270
|
-
This method implements the decomposition given in equation (3) in
|
271
|
-
https://arxiv.org/pdf/quant-ph/0410066.pdf.
|
272
|
-
The decomposition is used recursively to decompose uniformly controlled gates.
|
273
|
-
a,b = single qubit unitaries
|
274
|
-
v,u,r = outcome of the decomposition given in the reference mentioned above
|
275
|
-
(see there for the details).
|
276
|
-
"""
|
277
|
-
# The notation is chosen as in https://arxiv.org/pdf/quant-ph/0410066.pdf.
|
278
|
-
x = a.dot(UCGate._ct(b))
|
279
|
-
det_x = np.linalg.det(x)
|
280
|
-
x11 = x.item((0, 0)) / cmath.sqrt(det_x)
|
281
|
-
phi = cmath.phase(det_x)
|
282
|
-
r1 = cmath.exp(1j / 2 * (np.pi / 2 - phi / 2 - cmath.phase(x11)))
|
283
|
-
r2 = cmath.exp(1j / 2 * (np.pi / 2 - phi / 2 + cmath.phase(x11) + np.pi))
|
284
|
-
r = np.array([[r1, 0], [0, r2]], dtype=complex)
|
285
|
-
d, u = np.linalg.eig(r.dot(x).dot(r))
|
286
|
-
# If d is not equal to diag(i,-i), then we put it into this "standard" form
|
287
|
-
# (see eq. (13) in https://arxiv.org/pdf/quant-ph/0410066.pdf) by interchanging
|
288
|
-
# the eigenvalues and eigenvectors.
|
289
|
-
if abs(d[0] + 1j) < _EPS:
|
290
|
-
d = np.flip(d, 0)
|
291
|
-
u = np.flip(u, 1)
|
292
|
-
d = np.diag(np.sqrt(d))
|
293
|
-
v = d.dot(UCGate._ct(u)).dot(UCGate._ct(r)).dot(b)
|
294
|
-
return v, u, r
|
295
|
-
|
296
|
-
@staticmethod
|
297
|
-
def _ct(m):
|
298
|
-
return np.transpose(np.conjugate(m))
|
202
|
+
return uc_gate.dec_ucg_help(single_qubit_gates, self.num_qubits)
|
299
203
|
|
300
204
|
@staticmethod
|
301
205
|
def _rz(alpha):
|
@@ -13,10 +13,12 @@
|
|
13
13
|
"""Arbitrary unitary circuit instruction."""
|
14
14
|
|
15
15
|
from __future__ import annotations
|
16
|
+
import math
|
16
17
|
|
17
18
|
import typing
|
18
19
|
import numpy
|
19
20
|
|
21
|
+
from qiskit import _numpy_compat
|
20
22
|
from qiskit.circuit.gate import Gate
|
21
23
|
from qiskit.circuit.controlledgate import ControlledGate
|
22
24
|
from qiskit.circuit.annotated_operation import AnnotatedOperation, ControlModifier
|
@@ -69,6 +71,8 @@ class UnitaryGate(Gate):
|
|
69
71
|
data: numpy.ndarray | Gate | BaseOperator,
|
70
72
|
label: str | None = None,
|
71
73
|
check_input: bool = True,
|
74
|
+
*,
|
75
|
+
num_qubits: int | None = None,
|
72
76
|
) -> None:
|
73
77
|
"""Create a gate from a numeric unitary matrix.
|
74
78
|
|
@@ -80,6 +84,7 @@ class UnitaryGate(Gate):
|
|
80
84
|
be skipped. This should only ever be used if you know the
|
81
85
|
input is unitary, setting this to ``False`` and passing in
|
82
86
|
a non-unitary matrix will result unexpected behavior and errors.
|
87
|
+
num_qubits: If given, the number of qubits in the matrix. If not given, it is inferred.
|
83
88
|
|
84
89
|
Raises:
|
85
90
|
ValueError: If input data is not an N-qubit unitary operator.
|
@@ -96,7 +101,7 @@ class UnitaryGate(Gate):
|
|
96
101
|
# Convert to numpy array in case not already an array
|
97
102
|
data = numpy.asarray(data, dtype=complex)
|
98
103
|
input_dim, output_dim = data.shape
|
99
|
-
num_qubits = int(
|
104
|
+
num_qubits = num_qubits if num_qubits is not None else int(math.log2(input_dim))
|
100
105
|
if check_input:
|
101
106
|
# Check input is unitary
|
102
107
|
if not is_unitary_matrix(data):
|
@@ -114,10 +119,10 @@ class UnitaryGate(Gate):
|
|
114
119
|
return False
|
115
120
|
return matrix_equal(self.params[0], other.params[0])
|
116
121
|
|
117
|
-
def __array__(self, dtype=None):
|
122
|
+
def __array__(self, dtype=None, copy=_numpy_compat.COPY_ONLY_IF_NEEDED):
|
118
123
|
"""Return matrix for the unitary."""
|
119
|
-
|
120
|
-
return self.params[0]
|
124
|
+
dtype = self.params[0].dtype if dtype is None else dtype
|
125
|
+
return numpy.array(self.params[0], dtype=dtype, copy=copy)
|
121
126
|
|
122
127
|
def inverse(self, annotated: bool = False):
|
123
128
|
"""Return the adjoint of the unitary."""
|
@@ -15,11 +15,13 @@ Gate described by the time evolution of a Hermitian Hamiltonian operator.
|
|
15
15
|
"""
|
16
16
|
|
17
17
|
from __future__ import annotations
|
18
|
+
import math
|
18
19
|
import typing
|
19
20
|
|
20
21
|
from numbers import Number
|
21
22
|
import numpy as np
|
22
23
|
|
24
|
+
from qiskit import _numpy_compat
|
23
25
|
from qiskit.circuit.gate import Gate
|
24
26
|
from qiskit.circuit.quantumcircuit import QuantumCircuit
|
25
27
|
from qiskit.circuit.quantumregister import QuantumRegister
|
@@ -67,7 +69,7 @@ class HamiltonianGate(Gate):
|
|
67
69
|
# numpy matrix from `Operator.data`.
|
68
70
|
data = data.to_operator().data
|
69
71
|
# Convert to np array in case not already an array
|
70
|
-
data = np.
|
72
|
+
data = np.asarray(data, dtype=complex)
|
71
73
|
# Check input is unitary
|
72
74
|
if not is_hermitian_matrix(data):
|
73
75
|
raise ValueError("Input matrix is not Hermitian.")
|
@@ -75,7 +77,7 @@ class HamiltonianGate(Gate):
|
|
75
77
|
raise ValueError("Evolution time is not real.")
|
76
78
|
# Check input is N-qubit matrix
|
77
79
|
input_dim, output_dim = data.shape
|
78
|
-
num_qubits = int(
|
80
|
+
num_qubits = int(math.log2(input_dim))
|
79
81
|
if input_dim != output_dim or 2**num_qubits != input_dim:
|
80
82
|
raise ValueError("Input matrix is not an N-qubit operator.")
|
81
83
|
|
@@ -91,18 +93,22 @@ class HamiltonianGate(Gate):
|
|
91
93
|
times_eq = self.params[1] == other.params[1]
|
92
94
|
return operators_eq and times_eq
|
93
95
|
|
94
|
-
def __array__(self, dtype=None):
|
96
|
+
def __array__(self, dtype=None, copy=None):
|
95
97
|
"""Return matrix for the unitary."""
|
96
|
-
# pylint: disable=unused-argument
|
97
98
|
import scipy.linalg
|
98
99
|
|
100
|
+
if copy is False:
|
101
|
+
raise ValueError("unable to avoid copy while creating an array as requested")
|
99
102
|
try:
|
100
|
-
|
103
|
+
time = float(self.params[1])
|
101
104
|
except TypeError as ex:
|
102
105
|
raise TypeError(
|
103
106
|
"Unable to generate Unitary matrix for "
|
104
107
|
"unbound t parameter {}".format(self.params[1])
|
105
108
|
) from ex
|
109
|
+
arr = scipy.linalg.expm(-1j * self.params[0] * time)
|
110
|
+
dtype = complex if dtype is None else dtype
|
111
|
+
return np.array(arr, dtype=dtype, copy=_numpy_compat.COPY_ONLY_IF_NEEDED)
|
106
112
|
|
107
113
|
def inverse(self, annotated: bool = False):
|
108
114
|
"""Return the adjoint of the unitary."""
|
@@ -110,11 +110,11 @@ class EfficientSU2(TwoLocal):
|
|
110
110
|
If only one gate is provided, the same gate is applied to each qubit.
|
111
111
|
If a list of gates is provided, all gates are applied to each qubit in the provided
|
112
112
|
order.
|
113
|
-
entanglement: Specifies the entanglement structure. Can be a string
|
114
|
-
, 'reverse_linear', 'circular' or 'sca'),
|
115
|
-
of qubits entangled with one another,
|
116
|
-
the index of the entanglement layer.
|
117
|
-
|
113
|
+
entanglement: Specifies the entanglement structure. Can be a string
|
114
|
+
('full', 'linear', 'reverse_linear', 'pairwise', 'circular', or 'sca'),
|
115
|
+
a list of integer-pairs specifying the indices of qubits entangled with one another,
|
116
|
+
or a callable returning such a list provided with the index of the entanglement layer.
|
117
|
+
Defaults to 'reverse_linear' entanglement.
|
118
118
|
Note that 'reverse_linear' entanglement provides the same unitary as 'full'
|
119
119
|
with fewer entangling gates.
|
120
120
|
See the Examples section of :class:`~qiskit.circuit.library.TwoLocal` for more
|
@@ -13,16 +13,24 @@
|
|
13
13
|
"""The n-local circuit class."""
|
14
14
|
|
15
15
|
from __future__ import annotations
|
16
|
+
|
17
|
+
import collections
|
18
|
+
import itertools
|
16
19
|
import typing
|
17
20
|
from collections.abc import Callable, Mapping, Sequence
|
18
21
|
|
19
|
-
from itertools import combinations
|
20
|
-
|
21
22
|
import numpy
|
22
23
|
from qiskit.circuit.quantumcircuit import QuantumCircuit
|
23
24
|
from qiskit.circuit.quantumregister import QuantumRegister
|
24
|
-
from qiskit.circuit import
|
25
|
+
from qiskit.circuit import (
|
26
|
+
Instruction,
|
27
|
+
Parameter,
|
28
|
+
ParameterVector,
|
29
|
+
ParameterExpression,
|
30
|
+
CircuitInstruction,
|
31
|
+
)
|
25
32
|
from qiskit.exceptions import QiskitError
|
33
|
+
from qiskit.circuit.library.standard_gates import get_standard_gate_name_mapping
|
26
34
|
|
27
35
|
from ..blueprintcircuit import BlueprintCircuit
|
28
36
|
|
@@ -154,6 +162,17 @@ class NLocal(BlueprintCircuit):
|
|
154
162
|
self._bounds: list[tuple[float | None, float | None]] | None = None
|
155
163
|
self._flatten = flatten
|
156
164
|
|
165
|
+
# During the build, if a subclass hasn't overridden our parametrisation methods, we can use
|
166
|
+
# a newer fast-path method to parametrise the rotation and entanglement blocks if internally
|
167
|
+
# those are just simple stdlib gates that have been promoted to circuits. We don't
|
168
|
+
# precalculate the fast-path layers themselves because there's far too much that can be
|
169
|
+
# overridden between object construction and build, and far too many subclasses of `NLocal`
|
170
|
+
# that override bits and bobs of the internal private methods, so it'd be too hard to keep
|
171
|
+
# everything in sync.
|
172
|
+
self._allow_fast_path_parametrization = (
|
173
|
+
getattr(self._parameter_generator, "__func__", None) is NLocal._parameter_generator
|
174
|
+
)
|
175
|
+
|
157
176
|
if int(reps) != reps:
|
158
177
|
raise TypeError("The value of reps should be int")
|
159
178
|
|
@@ -779,13 +798,10 @@ class NLocal(BlueprintCircuit):
|
|
779
798
|
else:
|
780
799
|
entangler_map = entanglement
|
781
800
|
|
782
|
-
layer = QuantumCircuit(self.num_qubits)
|
783
801
|
for i in entangler_map:
|
784
802
|
params = self.ordered_parameters[-len(get_parameters(block)) :]
|
785
803
|
parameterized_block = self._parameterize_block(block, params=params)
|
786
|
-
|
787
|
-
|
788
|
-
self.compose(layer, inplace=True)
|
804
|
+
self.compose(parameterized_block, i, inplace=True, copy=False)
|
789
805
|
else:
|
790
806
|
# cannot prepend a block currently, just rebuild
|
791
807
|
self._invalidate()
|
@@ -843,52 +859,65 @@ class NLocal(BlueprintCircuit):
|
|
843
859
|
"""Build a rotation layer."""
|
844
860
|
# if the unentangled qubits are skipped, compute the set of qubits that are not entangled
|
845
861
|
if self._skip_unentangled_qubits:
|
846
|
-
|
862
|
+
skipped_qubits = self.get_unentangled_qubits()
|
863
|
+
else:
|
864
|
+
skipped_qubits = set()
|
865
|
+
|
866
|
+
target_qubits = circuit.qubits
|
847
867
|
|
848
868
|
# iterate over all rotation blocks
|
849
869
|
for j, block in enumerate(self.rotation_blocks):
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
870
|
+
skipped_blocks = {qubit // block.num_qubits for qubit in skipped_qubits}
|
871
|
+
if (
|
872
|
+
self._allow_fast_path_parametrization
|
873
|
+
and (simple_block := _stdlib_gate_from_simple_block(block)) is not None
|
874
|
+
):
|
875
|
+
all_qubits = (
|
876
|
+
tuple(target_qubits[k * block.num_qubits : (k + 1) * block.num_qubits])
|
877
|
+
for k in range(self.num_qubits // block.num_qubits)
|
878
|
+
if k not in skipped_blocks
|
879
|
+
)
|
880
|
+
for qubits in all_qubits:
|
881
|
+
instr = CircuitInstruction(
|
882
|
+
simple_block.gate(*itertools.islice(param_iter, simple_block.num_params)),
|
883
|
+
qubits,
|
884
|
+
)
|
885
|
+
circuit._append(instr)
|
886
|
+
else:
|
863
887
|
block_indices = [
|
864
|
-
|
865
|
-
for
|
866
|
-
if
|
888
|
+
list(range(k * block.num_qubits, (k + 1) * block.num_qubits))
|
889
|
+
for k in range(self.num_qubits // block.num_qubits)
|
890
|
+
if k not in skipped_blocks
|
867
891
|
]
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
layer.compose(parameterized_block, indices, inplace=True)
|
873
|
-
|
874
|
-
# add the layer to the circuit
|
875
|
-
circuit.compose(layer, inplace=True)
|
892
|
+
# apply the operations in the layer
|
893
|
+
for indices in block_indices:
|
894
|
+
parameterized_block = self._parameterize_block(block, param_iter, i, j, indices)
|
895
|
+
circuit.compose(parameterized_block, indices, inplace=True, copy=False)
|
876
896
|
|
877
897
|
def _build_entanglement_layer(self, circuit, param_iter, i):
|
878
898
|
"""Build an entanglement layer."""
|
879
899
|
# iterate over all entanglement blocks
|
900
|
+
target_qubits = circuit.qubits
|
880
901
|
for j, block in enumerate(self.entanglement_blocks):
|
881
|
-
# create a new layer and get the entangler map for this block
|
882
|
-
layer = QuantumCircuit(*self.qregs)
|
883
902
|
entangler_map = self.get_entangler_map(i, j, block.num_qubits)
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
903
|
+
if (
|
904
|
+
self._allow_fast_path_parametrization
|
905
|
+
and (simple_block := _stdlib_gate_from_simple_block(block)) is not None
|
906
|
+
):
|
907
|
+
for indices in entangler_map:
|
908
|
+
# It's actually nontrivially faster to use a listcomp and pass that to `tuple`
|
909
|
+
# than to pass a generator expression directly.
|
910
|
+
# pylint: disable=consider-using-generator
|
911
|
+
instr = CircuitInstruction(
|
912
|
+
simple_block.gate(*itertools.islice(param_iter, simple_block.num_params)),
|
913
|
+
tuple([target_qubits[i] for i in indices]),
|
914
|
+
)
|
915
|
+
circuit._append(instr)
|
916
|
+
else:
|
917
|
+
# apply the operations in the layer
|
918
|
+
for indices in entangler_map:
|
919
|
+
parameterized_block = self._parameterize_block(block, param_iter, i, j, indices)
|
920
|
+
circuit.compose(parameterized_block, indices, inplace=True, copy=False)
|
892
921
|
|
893
922
|
def _build_additional_layers(self, circuit, which):
|
894
923
|
if which == "appended":
|
@@ -901,13 +930,10 @@ class NLocal(BlueprintCircuit):
|
|
901
930
|
raise ValueError("`which` must be either `appended` or `prepended`.")
|
902
931
|
|
903
932
|
for block, ent in zip(blocks, entanglements):
|
904
|
-
layer = QuantumCircuit(*self.qregs)
|
905
933
|
if isinstance(ent, str):
|
906
934
|
ent = get_entangler_map(block.num_qubits, self.num_qubits, ent)
|
907
935
|
for indices in ent:
|
908
|
-
|
909
|
-
|
910
|
-
circuit.compose(layer, inplace=True)
|
936
|
+
circuit.compose(block, indices, inplace=True, copy=False)
|
911
937
|
|
912
938
|
def _build(self) -> None:
|
913
939
|
"""If not already built, build the circuit."""
|
@@ -926,7 +952,7 @@ class NLocal(BlueprintCircuit):
|
|
926
952
|
|
927
953
|
# use the initial state as starting circuit, if it is set
|
928
954
|
if self.initial_state:
|
929
|
-
circuit.compose(self.initial_state.copy(), inplace=True)
|
955
|
+
circuit.compose(self.initial_state.copy(), inplace=True, copy=False)
|
930
956
|
|
931
957
|
param_iter = iter(self.ordered_parameters)
|
932
958
|
|
@@ -972,7 +998,7 @@ class NLocal(BlueprintCircuit):
|
|
972
998
|
except QiskitError:
|
973
999
|
block = circuit.to_instruction()
|
974
1000
|
|
975
|
-
self.append(block, self.qubits)
|
1001
|
+
self.append(block, self.qubits, copy=False)
|
976
1002
|
|
977
1003
|
# pylint: disable=unused-argument
|
978
1004
|
def _parameter_generator(self, rep: int, block: int, indices: list[int]) -> Parameter | None:
|
@@ -1023,7 +1049,7 @@ def get_entangler_map(
|
|
1023
1049
|
raise ValueError("Pairwise entanglement is not defined for blocks with more than 2 qubits.")
|
1024
1050
|
|
1025
1051
|
if entanglement == "full":
|
1026
|
-
return list(combinations(list(range(n)), m))
|
1052
|
+
return list(itertools.combinations(list(range(n)), m))
|
1027
1053
|
elif entanglement == "reverse_linear":
|
1028
1054
|
# reverse linear connectivity. In the case of m=2 and the entanglement_block='cx'
|
1029
1055
|
# then it's equivalent to 'full' entanglement
|
@@ -1057,3 +1083,28 @@ def get_entangler_map(
|
|
1057
1083
|
|
1058
1084
|
else:
|
1059
1085
|
raise ValueError(f"Unsupported entanglement type: {entanglement}")
|
1086
|
+
|
1087
|
+
|
1088
|
+
_StdlibGateResult = collections.namedtuple("_StdlibGateResult", ("gate", "num_params"))
|
1089
|
+
_STANDARD_GATE_MAPPING = get_standard_gate_name_mapping()
|
1090
|
+
|
1091
|
+
|
1092
|
+
def _stdlib_gate_from_simple_block(block: QuantumCircuit) -> _StdlibGateResult | None:
|
1093
|
+
if block.global_phase != 0.0 or len(block) != 1:
|
1094
|
+
return None
|
1095
|
+
instruction = block.data[0]
|
1096
|
+
# If the single instruction isn't a standard-library gate that spans the full width of the block
|
1097
|
+
# in the correct order, we're not simple. If the gate isn't fully parametrised with pure,
|
1098
|
+
# unique `Parameter` instances (expressions are too complex) that are in order, we're not
|
1099
|
+
# simple.
|
1100
|
+
if (
|
1101
|
+
instruction.clbits
|
1102
|
+
or tuple(instruction.qubits) != tuple(block.qubits)
|
1103
|
+
or (
|
1104
|
+
getattr(_STANDARD_GATE_MAPPING.get(instruction.operation.name), "base_class", None)
|
1105
|
+
is not instruction.operation.base_class
|
1106
|
+
)
|
1107
|
+
or tuple(instruction.operation.params) != tuple(block.parameters)
|
1108
|
+
):
|
1109
|
+
return None
|
1110
|
+
return _StdlibGateResult(instruction.operation.base_class, len(instruction.operation.params))
|
@@ -17,35 +17,10 @@ import typing
|
|
17
17
|
from collections.abc import Callable, Sequence
|
18
18
|
|
19
19
|
from qiskit.circuit.quantumcircuit import QuantumCircuit
|
20
|
-
from qiskit.circuit import Gate, Instruction
|
20
|
+
from qiskit.circuit import Gate, Instruction
|
21
21
|
|
22
22
|
from .n_local import NLocal
|
23
|
-
from ..standard_gates import
|
24
|
-
IGate,
|
25
|
-
XGate,
|
26
|
-
YGate,
|
27
|
-
ZGate,
|
28
|
-
RXGate,
|
29
|
-
RYGate,
|
30
|
-
RZGate,
|
31
|
-
HGate,
|
32
|
-
SGate,
|
33
|
-
SdgGate,
|
34
|
-
TGate,
|
35
|
-
TdgGate,
|
36
|
-
RXXGate,
|
37
|
-
RYYGate,
|
38
|
-
RZXGate,
|
39
|
-
RZZGate,
|
40
|
-
SwapGate,
|
41
|
-
CXGate,
|
42
|
-
CYGate,
|
43
|
-
CZGate,
|
44
|
-
CRXGate,
|
45
|
-
CRYGate,
|
46
|
-
CRZGate,
|
47
|
-
CHGate,
|
48
|
-
)
|
23
|
+
from ..standard_gates import get_standard_gate_name_mapping
|
49
24
|
|
50
25
|
if typing.TYPE_CHECKING:
|
51
26
|
import qiskit # pylint: disable=cyclic-import
|
@@ -269,38 +244,7 @@ class TwoLocal(NLocal):
|
|
269
244
|
if isinstance(layer, QuantumCircuit):
|
270
245
|
return layer
|
271
246
|
|
272
|
-
|
273
|
-
# this could be a lot easier if the standard layers would have ``name`` and ``num_params``
|
274
|
-
# as static types, which might be something they should have anyway
|
275
|
-
theta = Parameter("θ")
|
276
|
-
valid_layers = {
|
277
|
-
"ch": CHGate(),
|
278
|
-
"cx": CXGate(),
|
279
|
-
"cy": CYGate(),
|
280
|
-
"cz": CZGate(),
|
281
|
-
"crx": CRXGate(theta),
|
282
|
-
"cry": CRYGate(theta),
|
283
|
-
"crz": CRZGate(theta),
|
284
|
-
"h": HGate(),
|
285
|
-
"i": IGate(),
|
286
|
-
"id": IGate(),
|
287
|
-
"iden": IGate(),
|
288
|
-
"rx": RXGate(theta),
|
289
|
-
"rxx": RXXGate(theta),
|
290
|
-
"ry": RYGate(theta),
|
291
|
-
"ryy": RYYGate(theta),
|
292
|
-
"rz": RZGate(theta),
|
293
|
-
"rzx": RZXGate(theta),
|
294
|
-
"rzz": RZZGate(theta),
|
295
|
-
"s": SGate(),
|
296
|
-
"sdg": SdgGate(),
|
297
|
-
"swap": SwapGate(),
|
298
|
-
"x": XGate(),
|
299
|
-
"y": YGate(),
|
300
|
-
"z": ZGate(),
|
301
|
-
"t": TGate(),
|
302
|
-
"tdg": TdgGate(),
|
303
|
-
}
|
247
|
+
valid_layers = get_standard_gate_name_mapping()
|
304
248
|
|
305
249
|
# try to exchange `layer` from a string to a gate instance
|
306
250
|
if isinstance(layer, str):
|
@@ -26,11 +26,11 @@ class UnitaryOverlap(QuantumCircuit):
|
|
26
26
|
names `"p1"` (for circuit ``unitary1``) and `"p2"` (for circuit ``unitary_2``) in the output
|
27
27
|
circuit.
|
28
28
|
|
29
|
-
This circuit is usually employed in computing the fidelity
|
29
|
+
This circuit is usually employed in computing the fidelity:
|
30
30
|
|
31
|
-
|
31
|
+
.. math::
|
32
32
|
|
33
|
-
|
33
|
+
\left|\langle 0| U_2^{\dag} U_1|0\rangle\right|^{2}
|
34
34
|
|
35
35
|
by computing the probability of being in the all-zeros bit-string, or equivalently,
|
36
36
|
the expectation value of projector :math:`|0\rangle\langle 0|`.
|
@@ -87,7 +87,7 @@ class PhaseOracle(QuantumCircuit):
|
|
87
87
|
|
88
88
|
super().__init__(oracle.num_qubits, name="Phase Oracle")
|
89
89
|
|
90
|
-
self.compose(oracle, inplace=True)
|
90
|
+
self.compose(oracle, inplace=True, copy=False)
|
91
91
|
|
92
92
|
def evaluate_bitstring(self, bitstring: str) -> bool:
|
93
93
|
"""Evaluate the oracle on a bitstring.
|