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
@@ -15,7 +15,7 @@ ScalarOp class
|
|
15
15
|
"""
|
16
16
|
|
17
17
|
from __future__ import annotations
|
18
|
-
import copy
|
18
|
+
import copy as _copy
|
19
19
|
from numbers import Number
|
20
20
|
import numpy as np
|
21
21
|
|
@@ -52,10 +52,11 @@ class ScalarOp(LinearOp):
|
|
52
52
|
self._coeff = coeff
|
53
53
|
super().__init__(input_dims=dims, output_dims=dims)
|
54
54
|
|
55
|
-
def __array__(self, dtype=None):
|
56
|
-
if
|
57
|
-
|
58
|
-
|
55
|
+
def __array__(self, dtype=None, copy=None):
|
56
|
+
if copy is False:
|
57
|
+
raise ValueError("could not produce matrix without calculation")
|
58
|
+
arr = self.to_matrix()
|
59
|
+
return arr if dtype is None else arr.astype(dtype, copy=False)
|
59
60
|
|
60
61
|
def __repr__(self):
|
61
62
|
return f"ScalarOp({self.input_dims()}, coeff={self.coeff})"
|
@@ -104,7 +105,7 @@ class ScalarOp(LinearOp):
|
|
104
105
|
# If other is also an ScalarOp we only need to
|
105
106
|
# update the coefficient and dimensions
|
106
107
|
if isinstance(other, ScalarOp):
|
107
|
-
ret =
|
108
|
+
ret = _copy.copy(self)
|
108
109
|
ret._coeff = self.coeff * other.coeff
|
109
110
|
ret._op_shape = new_shape
|
110
111
|
return ret
|
@@ -112,7 +113,7 @@ class ScalarOp(LinearOp):
|
|
112
113
|
# If we are composing on the full system we return the
|
113
114
|
# other operator with reshaped dimensions
|
114
115
|
if qargs is None:
|
115
|
-
ret =
|
116
|
+
ret = _copy.copy(other)
|
116
117
|
ret._op_shape = new_shape
|
117
118
|
# Other operator might not support scalar multiplication
|
118
119
|
# so we treat the identity as a special case to avoid a
|
@@ -148,7 +149,7 @@ class ScalarOp(LinearOp):
|
|
148
149
|
other = Operator(other)
|
149
150
|
|
150
151
|
if isinstance(other, ScalarOp):
|
151
|
-
ret =
|
152
|
+
ret = _copy.copy(self)
|
152
153
|
ret._coeff = self.coeff * other.coeff
|
153
154
|
ret._op_shape = self._op_shape.tensor(other._op_shape)
|
154
155
|
return ret
|
@@ -160,7 +161,7 @@ class ScalarOp(LinearOp):
|
|
160
161
|
other = Operator(other)
|
161
162
|
|
162
163
|
if isinstance(other, ScalarOp):
|
163
|
-
ret =
|
164
|
+
ret = _copy.copy(self)
|
164
165
|
ret._coeff = self.coeff * other.coeff
|
165
166
|
ret._op_shape = self._op_shape.expand(other._op_shape)
|
166
167
|
return ret
|
@@ -541,75 +541,50 @@ class BasePauli(BaseOperator, AdjointMixin, MultiplyMixin):
|
|
541
541
|
if qargs is None:
|
542
542
|
qargs = list(range(self.num_qubits))
|
543
543
|
|
544
|
-
if isinstance(circuit, QuantumCircuit):
|
545
|
-
gate = circuit.to_instruction()
|
546
|
-
else:
|
544
|
+
if not isinstance(circuit, QuantumCircuit):
|
547
545
|
gate = circuit
|
548
546
|
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
if name in basis_1q:
|
580
|
-
if len(qargs) != 1:
|
581
|
-
raise QiskitError("Invalid qubits for 1-qubit gate.")
|
582
|
-
return basis_1q[name](self, qargs[0])
|
583
|
-
if name in basis_2q:
|
584
|
-
if len(qargs) != 2:
|
585
|
-
raise QiskitError("Invalid qubits for 2-qubit gate.")
|
586
|
-
return basis_2q[name](self, qargs[0], qargs[1])
|
587
|
-
|
588
|
-
# If not a Clifford basis gate we try to unroll the gate and
|
589
|
-
# raise an exception if unrolling reaches a non-Clifford gate.
|
590
|
-
if gate.definition is None:
|
591
|
-
raise QiskitError(f"Cannot apply Instruction: {gate.name}")
|
592
|
-
if not isinstance(gate.definition, QuantumCircuit):
|
593
|
-
raise QiskitError(
|
594
|
-
"{} instruction definition is {}; expected QuantumCircuit".format(
|
595
|
-
gate.name, type(gate.definition)
|
547
|
+
if isinstance(gate, str):
|
548
|
+
# Check if gate is a valid Clifford basis gate string
|
549
|
+
if gate not in _basis_1q and gate not in _basis_2q:
|
550
|
+
raise QiskitError(f"Invalid Clifford gate name string {gate}")
|
551
|
+
name = gate
|
552
|
+
else:
|
553
|
+
# Assume gate is an Instruction
|
554
|
+
name = gate.name
|
555
|
+
|
556
|
+
# Apply gate if it is a Clifford basis gate
|
557
|
+
if name in _non_clifford:
|
558
|
+
raise QiskitError(f"Cannot update Pauli with non-Clifford gate {name}")
|
559
|
+
if name in _basis_1q:
|
560
|
+
if len(qargs) != 1:
|
561
|
+
raise QiskitError("Invalid qubits for 1-qubit gate.")
|
562
|
+
return _basis_1q[name](self, qargs[0])
|
563
|
+
if name in _basis_2q:
|
564
|
+
if len(qargs) != 2:
|
565
|
+
raise QiskitError("Invalid qubits for 2-qubit gate.")
|
566
|
+
return _basis_2q[name](self, qargs[0], qargs[1])
|
567
|
+
|
568
|
+
# If not a Clifford basis gate we try to unroll the gate and
|
569
|
+
# raise an exception if unrolling reaches a non-Clifford gate.
|
570
|
+
if gate.definition is None:
|
571
|
+
raise QiskitError(f"Cannot apply Instruction: {gate.name}")
|
572
|
+
if not isinstance(gate.definition, QuantumCircuit):
|
573
|
+
raise QiskitError(
|
574
|
+
"{} instruction definition is {}; expected QuantumCircuit".format(
|
575
|
+
gate.name, type(gate.definition)
|
576
|
+
)
|
596
577
|
)
|
597
|
-
)
|
598
578
|
|
599
|
-
|
600
|
-
bit_indices = {
|
601
|
-
bit: index
|
602
|
-
for bits in [flat_instr.qubits, flat_instr.clbits]
|
603
|
-
for index, bit in enumerate(bits)
|
604
|
-
}
|
579
|
+
circuit = gate.definition
|
605
580
|
|
606
|
-
for instruction in
|
581
|
+
for instruction in circuit:
|
607
582
|
if instruction.clbits:
|
608
583
|
raise QiskitError(
|
609
584
|
f"Cannot apply Instruction with classical bits: {instruction.operation.name}"
|
610
585
|
)
|
611
586
|
# Get the integer position of the flat register
|
612
|
-
new_qubits = [qargs[
|
587
|
+
new_qubits = [qargs[circuit.find_bit(qb)[0]] for qb in instruction.qubits]
|
613
588
|
self._append_circuit(instruction.operation, new_qubits)
|
614
589
|
|
615
590
|
# Since the individual gate evolution functions don't take mod
|
@@ -715,6 +690,42 @@ def _evolve_swap(base_pauli, q1, q2):
|
|
715
690
|
return base_pauli
|
716
691
|
|
717
692
|
|
693
|
+
def _evolve_ecr(base_pauli, q1, q2):
|
694
|
+
"""Update P -> ECR.P.ECR"""
|
695
|
+
base_pauli = _evolve_s(base_pauli, q1)
|
696
|
+
base_pauli = _evolve_h(base_pauli, q2)
|
697
|
+
base_pauli = _evolve_s(base_pauli, q2)
|
698
|
+
base_pauli = _evolve_h(base_pauli, q2)
|
699
|
+
base_pauli = _evolve_cx(base_pauli, q1, q2)
|
700
|
+
base_pauli = _evolve_x(base_pauli, q1)
|
701
|
+
return base_pauli
|
702
|
+
|
703
|
+
|
718
704
|
def _count_y(x, z, dtype=None):
|
719
705
|
"""Count the number of I Paulis"""
|
720
706
|
return (x & z).sum(axis=1, dtype=dtype)
|
707
|
+
|
708
|
+
|
709
|
+
# Basis Clifford Gates
|
710
|
+
_basis_1q = {
|
711
|
+
"i": _evolve_i,
|
712
|
+
"id": _evolve_i,
|
713
|
+
"iden": _evolve_i,
|
714
|
+
"x": _evolve_x,
|
715
|
+
"y": _evolve_y,
|
716
|
+
"z": _evolve_z,
|
717
|
+
"h": _evolve_h,
|
718
|
+
"s": _evolve_s,
|
719
|
+
"sdg": _evolve_sdg,
|
720
|
+
"sinv": _evolve_sdg,
|
721
|
+
}
|
722
|
+
_basis_2q = {
|
723
|
+
"cx": _evolve_cx,
|
724
|
+
"cz": _evolve_cz,
|
725
|
+
"cy": _evolve_cy,
|
726
|
+
"swap": _evolve_swap,
|
727
|
+
"ecr": _evolve_ecr,
|
728
|
+
}
|
729
|
+
|
730
|
+
# Non-Clifford gates
|
731
|
+
_non_clifford = ["t", "tdg", "ccx", "ccz"]
|
@@ -16,6 +16,7 @@ from __future__ import annotations
|
|
16
16
|
|
17
17
|
import functools
|
18
18
|
import itertools
|
19
|
+
import math
|
19
20
|
import re
|
20
21
|
from typing import Literal
|
21
22
|
|
@@ -36,7 +37,23 @@ from .clifford_circuits import _append_circuit, _append_operation
|
|
36
37
|
|
37
38
|
|
38
39
|
class Clifford(BaseOperator, AdjointMixin, Operation):
|
39
|
-
"""
|
40
|
+
r"""
|
41
|
+
An N-qubit unitary operator from the Clifford group.
|
42
|
+
|
43
|
+
An N-qubit Clifford operator takes Paulis to Paulis via conjugation
|
44
|
+
(up to a global phase). More precisely, the Clifford group :math:`\mathcal{C}_N`
|
45
|
+
is defined as
|
46
|
+
|
47
|
+
.. math::
|
48
|
+
|
49
|
+
\mathcal{C}_N = \{ U \in U(2^N) | U \mathcal{P}_N U^{\dagger} = \mathcal{P}_N \} / U(1)
|
50
|
+
|
51
|
+
where :math:`\mathcal{P}_N` is the Pauli group on :math:`N` qubits
|
52
|
+
that is generated by single-qubit Pauli operators,
|
53
|
+
and :math:`U` is a unitary operator in the unitary group
|
54
|
+
:math:`U(2^N)` representing operations on :math:`N` qubits.
|
55
|
+
:math:`\mathcal{C}_N` is the quotient group by the subgroup of
|
56
|
+
scalar unitary matrices :math:`U(1)`.
|
40
57
|
|
41
58
|
**Representation**
|
42
59
|
|
@@ -90,7 +107,7 @@ class Clifford(BaseOperator, AdjointMixin, Operation):
|
|
90
107
|
:class:`~qiskit.circuit.library.SGate`, :class:`~qiskit.circuit.library.SdgGate`,
|
91
108
|
:class:`~qiskit.circuit.library.SXGate`, :class:`~qiskit.circuit.library.SXdgGate`,
|
92
109
|
:class:`~qiskit.circuit.library.CXGate`, :class:`~qiskit.circuit.library.CZGate`,
|
93
|
-
:class:`~qiskit.circuit.library.CYGate`, :class:`~qiskit.circuit.library.
|
110
|
+
:class:`~qiskit.circuit.library.CYGate`, :class:`~qiskit.circuit.library.DCXGate`,
|
94
111
|
:class:`~qiskit.circuit.library.SwapGate`, :class:`~qiskit.circuit.library.iSwapGate`,
|
95
112
|
:class:`~qiskit.circuit.library.ECRGate`, :class:`~qiskit.circuit.library.LinearFunction`,
|
96
113
|
:class:`~qiskit.circuit.library.PermutationGate`.
|
@@ -121,10 +138,11 @@ class Clifford(BaseOperator, AdjointMixin, Operation):
|
|
121
138
|
_COMPOSE_PHASE_LOOKUP = None
|
122
139
|
_COMPOSE_1Q_LOOKUP = None
|
123
140
|
|
124
|
-
def __array__(self, dtype=None):
|
125
|
-
if
|
126
|
-
|
127
|
-
|
141
|
+
def __array__(self, dtype=None, copy=None):
|
142
|
+
if copy is False:
|
143
|
+
raise ValueError("unable to avoid copy while creating an array as requested")
|
144
|
+
arr = self.to_matrix()
|
145
|
+
return arr if dtype is None else arr.astype(dtype, copy=False)
|
128
146
|
|
129
147
|
def __init__(self, data, validate=True, copy=True):
|
130
148
|
"""Initialize an operator object."""
|
@@ -163,8 +181,17 @@ class Clifford(BaseOperator, AdjointMixin, Operation):
|
|
163
181
|
|
164
182
|
# Initialize StabilizerTable directly from the data
|
165
183
|
else:
|
166
|
-
if
|
167
|
-
|
184
|
+
if (
|
185
|
+
isinstance(data, (list, np.ndarray))
|
186
|
+
and (data_asarray := np.asarray(data, dtype=bool)).ndim == 2
|
187
|
+
):
|
188
|
+
# This little dance is to avoid Numpy 1/2 incompatiblities between the availability
|
189
|
+
# and meaning of the 'copy' argument in 'array' and 'asarray', when the input needs
|
190
|
+
# its dtype converting. 'asarray' prefers to return 'self' if possible in both.
|
191
|
+
if copy and np.may_share_memory(data, data_asarray):
|
192
|
+
data = data_asarray.copy()
|
193
|
+
else:
|
194
|
+
data = data_asarray
|
168
195
|
if data.shape[0] == data.shape[1]:
|
169
196
|
self.tableau = self._stack_table_phase(
|
170
197
|
data, np.zeros(data.shape[0], dtype=bool)
|
@@ -973,7 +1000,7 @@ class Clifford(BaseOperator, AdjointMixin, Operation):
|
|
973
1000
|
@staticmethod
|
974
1001
|
def _unitary_matrix_to_tableau(matrix):
|
975
1002
|
# pylint: disable=invalid-name
|
976
|
-
num_qubits = int(
|
1003
|
+
num_qubits = int(math.log2(len(matrix)))
|
977
1004
|
|
978
1005
|
stab = np.empty((num_qubits, 2 * num_qubits + 1), dtype=bool)
|
979
1006
|
for i in range(num_qubits):
|
@@ -33,6 +33,7 @@ from qiskit.quantum_info.operators.symplectic.base_pauli import BasePauli, _coun
|
|
33
33
|
if TYPE_CHECKING:
|
34
34
|
from qiskit.quantum_info.operators.symplectic.clifford import Clifford
|
35
35
|
from qiskit.quantum_info.operators.symplectic.pauli_list import PauliList
|
36
|
+
from qiskit.transpiler.layout import TranspileLayout
|
36
37
|
|
37
38
|
|
38
39
|
class Pauli(BasePauli):
|
@@ -143,13 +144,13 @@ class Pauli(BasePauli):
|
|
143
144
|
|
144
145
|
.. code-block:: python
|
145
146
|
|
146
|
-
|
147
|
+
P = Pauli('-iXYZ')
|
147
148
|
|
148
149
|
print('P[0] =', repr(P[0]))
|
149
150
|
print('P[1] =', repr(P[1]))
|
150
151
|
print('P[2] =', repr(P[2]))
|
151
152
|
print('P[:] =', repr(P[:]))
|
152
|
-
print('P[::-1]
|
153
|
+
print('P[::-1] =', repr(P[::-1]))
|
153
154
|
"""
|
154
155
|
|
155
156
|
# Set the max Pauli string size before truncation
|
@@ -221,10 +222,11 @@ class Pauli(BasePauli):
|
|
221
222
|
return front + "..."
|
222
223
|
return self.to_label()
|
223
224
|
|
224
|
-
def __array__(self, dtype=None):
|
225
|
-
if
|
226
|
-
|
227
|
-
|
225
|
+
def __array__(self, dtype=None, copy=None):
|
226
|
+
if copy is False:
|
227
|
+
raise ValueError("unable to avoid copy while creating an array as requested")
|
228
|
+
arr = self.to_matrix()
|
229
|
+
return arr if dtype is None else arr.astype(dtype, copy=False)
|
228
230
|
|
229
231
|
@classmethod
|
230
232
|
def set_truncation(cls, val: int):
|
@@ -697,6 +699,51 @@ class Pauli(BasePauli):
|
|
697
699
|
ret = ret.compose(next_instr, qargs=qargs)
|
698
700
|
return ret._z, ret._x, ret._phase
|
699
701
|
|
702
|
+
def apply_layout(
|
703
|
+
self, layout: TranspileLayout | list[int] | None, num_qubits: int | None = None
|
704
|
+
) -> Pauli:
|
705
|
+
"""Apply a transpiler layout to this :class:`~.Pauli`
|
706
|
+
|
707
|
+
Args:
|
708
|
+
layout: Either a :class:`~.TranspileLayout`, a list of integers or None.
|
709
|
+
If both layout and num_qubits are none, a copy of the operator is
|
710
|
+
returned.
|
711
|
+
num_qubits: The number of qubits to expand the operator to. If not
|
712
|
+
provided then if ``layout`` is a :class:`~.TranspileLayout` the
|
713
|
+
number of the transpiler output circuit qubits will be used by
|
714
|
+
default. If ``layout`` is a list of integers the permutation
|
715
|
+
specified will be applied without any expansion. If layout is
|
716
|
+
None, the operator will be expanded to the given number of qubits.
|
717
|
+
|
718
|
+
Returns:
|
719
|
+
A new :class:`.Pauli` with the provided layout applied
|
720
|
+
"""
|
721
|
+
from qiskit.transpiler.layout import TranspileLayout
|
722
|
+
|
723
|
+
if layout is None and num_qubits is None:
|
724
|
+
return self.copy()
|
725
|
+
|
726
|
+
n_qubits = self.num_qubits
|
727
|
+
if isinstance(layout, TranspileLayout):
|
728
|
+
n_qubits = len(layout._output_qubit_list)
|
729
|
+
layout = layout.final_index_layout()
|
730
|
+
if num_qubits is not None:
|
731
|
+
if num_qubits < n_qubits:
|
732
|
+
raise QiskitError(
|
733
|
+
f"The input num_qubits is too small, a {num_qubits} qubit layout cannot be "
|
734
|
+
f"applied to a {n_qubits} qubit operator"
|
735
|
+
)
|
736
|
+
n_qubits = num_qubits
|
737
|
+
if layout is None:
|
738
|
+
layout = list(range(self.num_qubits))
|
739
|
+
else:
|
740
|
+
if any(x < 0 or x >= n_qubits for x in layout):
|
741
|
+
raise QiskitError("Provided layout contains indices outside the number of qubits.")
|
742
|
+
if len(set(layout)) != len(layout):
|
743
|
+
raise QiskitError("Provided layout contains duplicate indices.")
|
744
|
+
new_op = type(self)("I" * n_qubits)
|
745
|
+
return new_op.compose(self, qargs=layout)
|
746
|
+
|
700
747
|
|
701
748
|
# Update docstrings for API docs
|
702
749
|
generate_apidocs(Pauli)
|
@@ -148,14 +148,15 @@ class PauliList(BasePauli, LinearMixin, GroupMixin):
|
|
148
148
|
"""Return settings."""
|
149
149
|
return {"data": self.to_labels()}
|
150
150
|
|
151
|
-
def __array__(self, dtype=None):
|
151
|
+
def __array__(self, dtype=None, copy=None):
|
152
152
|
"""Convert to numpy array"""
|
153
|
-
|
153
|
+
if copy is False:
|
154
|
+
raise ValueError("cannot provide a matrix without calculation")
|
154
155
|
shape = (len(self),) + 2 * (2**self.num_qubits,)
|
155
156
|
ret = np.zeros(shape, dtype=complex)
|
156
157
|
for i, mat in enumerate(self.matrix_iter()):
|
157
158
|
ret[i] = mat
|
158
|
-
return ret
|
159
|
+
return ret if dtype is None else ret.astype(dtype, copy=False)
|
159
160
|
|
160
161
|
@staticmethod
|
161
162
|
def _from_paulis(data):
|
@@ -1155,23 +1156,50 @@ class PauliList(BasePauli, LinearMixin, GroupMixin):
|
|
1155
1156
|
# results from one triangle to avoid symmetric duplications.
|
1156
1157
|
return list(zip(*np.where(np.triu(adjacency_mat, k=1))))
|
1157
1158
|
|
1158
|
-
def
|
1159
|
-
"""
|
1159
|
+
def noncommutation_graph(self, qubit_wise: bool) -> rx.PyGraph:
|
1160
|
+
"""Create the non-commutation graph of this PauliList.
|
1161
|
+
|
1162
|
+
This transforms the measurement operator grouping problem into graph coloring problem. The
|
1163
|
+
constructed graph contains one node for each Pauli. The nodes will be connecting for any two
|
1164
|
+
Pauli terms that do _not_ commute.
|
1160
1165
|
|
1161
1166
|
Args:
|
1162
1167
|
qubit_wise (bool): whether the commutation rule is applied to the whole operator,
|
1163
1168
|
or on a per-qubit basis.
|
1164
1169
|
|
1165
1170
|
Returns:
|
1166
|
-
rustworkx.PyGraph:
|
1171
|
+
rustworkx.PyGraph: the non-commutation graph with nodes for each Pauli and edges
|
1172
|
+
indicating a non-commutation relation. Each node will hold the index of the Pauli
|
1173
|
+
term it corresponds to in its data. The edges of the graph hold no data.
|
1167
1174
|
"""
|
1168
|
-
|
1169
1175
|
edges = self._noncommutation_graph(qubit_wise)
|
1170
1176
|
graph = rx.PyGraph()
|
1171
1177
|
graph.add_nodes_from(range(self.size))
|
1172
1178
|
graph.add_edges_from_no_data(edges)
|
1173
1179
|
return graph
|
1174
1180
|
|
1181
|
+
def _commuting_groups(self, qubit_wise: bool) -> dict[int, list[int]]:
|
1182
|
+
"""Partition a PauliList into sets of commuting Pauli strings.
|
1183
|
+
|
1184
|
+
This is the internal logic of the public ``PauliList.group_commuting`` method which returns
|
1185
|
+
a mapping of colors to Pauli indices. The same logic is re-used by
|
1186
|
+
``SparsePauliOp.group_commuting``.
|
1187
|
+
|
1188
|
+
Args:
|
1189
|
+
qubit_wise (bool): whether the commutation rule is applied to the whole operator,
|
1190
|
+
or on a per-qubit basis.
|
1191
|
+
|
1192
|
+
Returns:
|
1193
|
+
dict[int, list[int]]: Dictionary of color indices mapping to a list of Pauli indices.
|
1194
|
+
"""
|
1195
|
+
graph = self.noncommutation_graph(qubit_wise)
|
1196
|
+
# Keys in coloring_dict are nodes, values are colors
|
1197
|
+
coloring_dict = rx.graph_greedy_color(graph)
|
1198
|
+
groups = defaultdict(list)
|
1199
|
+
for idx, color in coloring_dict.items():
|
1200
|
+
groups[color].append(idx)
|
1201
|
+
return groups
|
1202
|
+
|
1175
1203
|
def group_qubit_wise_commuting(self) -> list[PauliList]:
|
1176
1204
|
"""Partition a PauliList into sets of mutually qubit-wise commuting Pauli strings.
|
1177
1205
|
|
@@ -1199,11 +1227,5 @@ class PauliList(BasePauli, LinearMixin, GroupMixin):
|
|
1199
1227
|
Returns:
|
1200
1228
|
list[PauliList]: List of PauliLists where each PauliList contains commuting Pauli operators.
|
1201
1229
|
"""
|
1202
|
-
|
1203
|
-
graph = self._create_graph(qubit_wise)
|
1204
|
-
# Keys in coloring_dict are nodes, values are colors
|
1205
|
-
coloring_dict = rx.graph_greedy_color(graph)
|
1206
|
-
groups = defaultdict(list)
|
1207
|
-
for idx, color in coloring_dict.items():
|
1208
|
-
groups[color].append(idx)
|
1230
|
+
groups = self._commuting_groups(qubit_wise)
|
1209
1231
|
return [self[group] for group in groups.values()]
|
@@ -14,6 +14,7 @@ Random symplectic operator functions
|
|
14
14
|
"""
|
15
15
|
|
16
16
|
from __future__ import annotations
|
17
|
+
import math
|
17
18
|
|
18
19
|
import numpy as np
|
19
20
|
from numpy.random import default_rng
|
@@ -80,7 +81,7 @@ def random_pauli_list(
|
|
80
81
|
z = rng.integers(2, size=(size, num_qubits)).astype(bool)
|
81
82
|
x = rng.integers(2, size=(size, num_qubits)).astype(bool)
|
82
83
|
if phase:
|
83
|
-
_phase = rng.integers(4, size=
|
84
|
+
_phase = rng.integers(4, size=size)
|
84
85
|
return PauliList.from_symplectic(z, x, _phase)
|
85
86
|
return PauliList.from_symplectic(z, x)
|
86
87
|
|
@@ -173,7 +174,7 @@ def _sample_qmallows(n, rng=None):
|
|
173
174
|
m = n - i
|
174
175
|
eps = 4 ** (-m)
|
175
176
|
r = rng.uniform(0, 1)
|
176
|
-
index = -
|
177
|
+
index = -math.ceil(math.log2(r + (1 - r) * eps))
|
177
178
|
had[i] = index < m
|
178
179
|
if index < m:
|
179
180
|
k = index
|