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
@@ -95,8 +95,7 @@ class AlignMeasures(TransformationPass):
|
|
95
95
|
"Instead, use :class:`~.ConstrainedReschedule`, which performs the same function "
|
96
96
|
"but also supports aligning to additional timing constraints."
|
97
97
|
),
|
98
|
-
since="
|
99
|
-
pending=True,
|
98
|
+
since="1.1.0",
|
100
99
|
)
|
101
100
|
def __init__(self, alignment: int = 1):
|
102
101
|
"""Create new pass.
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# This code is part of Qiskit.
|
2
2
|
#
|
3
|
-
# (C) Copyright IBM 2021.
|
3
|
+
# (C) Copyright IBM 2021, 2024.
|
4
4
|
#
|
5
5
|
# This code is licensed under the Apache License, Version 2.0. You may
|
6
6
|
# obtain a copy of this license in the LICENSE.txt file in the root directory
|
@@ -14,6 +14,7 @@
|
|
14
14
|
from qiskit.circuit.delay import Delay
|
15
15
|
from qiskit.dagcircuit import DAGCircuit
|
16
16
|
from qiskit.transpiler.basepasses import AnalysisPass
|
17
|
+
from qiskit.transpiler import Target
|
17
18
|
|
18
19
|
|
19
20
|
class InstructionDurationCheck(AnalysisPass):
|
@@ -28,11 +29,7 @@ class InstructionDurationCheck(AnalysisPass):
|
|
28
29
|
of the hardware alignment constraints, which is true in general.
|
29
30
|
"""
|
30
31
|
|
31
|
-
def __init__(
|
32
|
-
self,
|
33
|
-
acquire_alignment: int = 1,
|
34
|
-
pulse_alignment: int = 1,
|
35
|
-
):
|
32
|
+
def __init__(self, acquire_alignment: int = 1, pulse_alignment: int = 1, target: Target = None):
|
36
33
|
"""Create new duration validation pass.
|
37
34
|
|
38
35
|
The alignment values depend on the control electronics of your quantum processor.
|
@@ -42,10 +39,16 @@ class InstructionDurationCheck(AnalysisPass):
|
|
42
39
|
trigger acquisition instruction in units of ``dt``.
|
43
40
|
pulse_alignment: Integer number representing the minimum time resolution to
|
44
41
|
trigger gate instruction in units of ``dt``.
|
42
|
+
target: The :class:`~.Target` representing the target backend, if
|
43
|
+
``target`` is specified then this argument will take
|
44
|
+
precedence and ``acquire_alignment`` and ``pulse_alignment`` will be ignored.
|
45
45
|
"""
|
46
46
|
super().__init__()
|
47
47
|
self.acquire_align = acquire_alignment
|
48
48
|
self.pulse_align = pulse_alignment
|
49
|
+
if target is not None:
|
50
|
+
self.acquire_align = target.acquire_alignment
|
51
|
+
self.pulse_align = target.pulse_alignment
|
49
52
|
|
50
53
|
def run(self, dag: DAGCircuit):
|
51
54
|
"""Run duration validation passes.
|
@@ -16,6 +16,7 @@ from qiskit.dagcircuit import DAGCircuit
|
|
16
16
|
from qiskit.pulse import Play
|
17
17
|
from qiskit.transpiler.basepasses import AnalysisPass
|
18
18
|
from qiskit.transpiler.exceptions import TranspilerError
|
19
|
+
from qiskit.transpiler import Target
|
19
20
|
|
20
21
|
|
21
22
|
class ValidatePulseGates(AnalysisPass):
|
@@ -43,6 +44,7 @@ class ValidatePulseGates(AnalysisPass):
|
|
43
44
|
self,
|
44
45
|
granularity: int = 1,
|
45
46
|
min_length: int = 1,
|
47
|
+
target: Target = None,
|
46
48
|
):
|
47
49
|
"""Create new pass.
|
48
50
|
|
@@ -53,10 +55,16 @@ class ValidatePulseGates(AnalysisPass):
|
|
53
55
|
min_length: Integer number representing the minimum data point length to
|
54
56
|
define the pulse gate in units of ``dt``. This value depends on
|
55
57
|
the control electronics of your quantum processor.
|
58
|
+
target: The :class:`~.Target` representing the target backend, if
|
59
|
+
``target`` is specified then this argument will take
|
60
|
+
precedence and ``granularity`` and ``min_length`` will be ignored.
|
56
61
|
"""
|
57
62
|
super().__init__()
|
58
63
|
self.granularity = granularity
|
59
64
|
self.min_length = min_length
|
65
|
+
if target is not None:
|
66
|
+
self.granularity = target.granularity
|
67
|
+
self.min_length = target.min_length
|
60
68
|
|
61
69
|
def run(self, dag: DAGCircuit):
|
62
70
|
"""Run the pulse gate validation attached to ``dag``.
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# This code is part of Qiskit.
|
2
2
|
#
|
3
|
-
# (C) Copyright IBM 2022.
|
3
|
+
# (C) Copyright IBM 2022, 2024.
|
4
4
|
#
|
5
5
|
# This code is licensed under the Apache License, Version 2.0. You may
|
6
6
|
# obtain a copy of this license in the LICENSE.txt file in the root directory
|
@@ -17,9 +17,11 @@ from collections.abc import Generator
|
|
17
17
|
from qiskit.circuit.gate import Gate
|
18
18
|
from qiskit.circuit.delay import Delay
|
19
19
|
from qiskit.circuit.measure import Measure
|
20
|
+
from qiskit.circuit.reset import Reset
|
20
21
|
from qiskit.dagcircuit import DAGCircuit, DAGOpNode, DAGOutNode
|
21
22
|
from qiskit.transpiler.basepasses import AnalysisPass
|
22
23
|
from qiskit.transpiler.exceptions import TranspilerError
|
24
|
+
from qiskit.transpiler import Target
|
23
25
|
|
24
26
|
|
25
27
|
class ConstrainedReschedule(AnalysisPass):
|
@@ -63,6 +65,7 @@ class ConstrainedReschedule(AnalysisPass):
|
|
63
65
|
self,
|
64
66
|
acquire_alignment: int = 1,
|
65
67
|
pulse_alignment: int = 1,
|
68
|
+
target: Target = None,
|
66
69
|
):
|
67
70
|
"""Create new rescheduler pass.
|
68
71
|
|
@@ -73,10 +76,16 @@ class ConstrainedReschedule(AnalysisPass):
|
|
73
76
|
trigger acquisition instruction in units of ``dt``.
|
74
77
|
pulse_alignment: Integer number representing the minimum time resolution to
|
75
78
|
trigger gate instruction in units of ``dt``.
|
79
|
+
target: The :class:`~.Target` representing the target backend, if
|
80
|
+
``target`` is specified then this argument will take
|
81
|
+
precedence and ``acquire_alignment`` and ``pulse_alignment`` will be ignored.
|
76
82
|
"""
|
77
83
|
super().__init__()
|
78
84
|
self.acquire_align = acquire_alignment
|
79
85
|
self.pulse_align = pulse_alignment
|
86
|
+
if target is not None:
|
87
|
+
self.acquire_align = target.acquire_alignment
|
88
|
+
self.pulse_align = target.pulse_alignment
|
80
89
|
|
81
90
|
@classmethod
|
82
91
|
def _get_next_gate(cls, dag: DAGCircuit, node: DAGOpNode) -> Generator[DAGOpNode, None, None]:
|
@@ -113,7 +122,7 @@ class ConstrainedReschedule(AnalysisPass):
|
|
113
122
|
|
114
123
|
if isinstance(node.op, Gate):
|
115
124
|
alignment = self.pulse_align
|
116
|
-
elif isinstance(node.op, Measure):
|
125
|
+
elif isinstance(node.op, (Measure, Reset)):
|
117
126
|
alignment = self.acquire_align
|
118
127
|
elif isinstance(node.op, Delay) or getattr(node.op, "_directive", False):
|
119
128
|
# Directive or delay. These can start at arbitrary time.
|
@@ -135,7 +144,7 @@ class ConstrainedReschedule(AnalysisPass):
|
|
135
144
|
# Compute shifted t1 of this node separately for qreg and creg
|
136
145
|
new_t1q = this_t0 + node.op.duration
|
137
146
|
this_qubits = set(node.qargs)
|
138
|
-
if isinstance(node.op, Measure):
|
147
|
+
if isinstance(node.op, (Measure, Reset)):
|
139
148
|
# creg access ends at the end of instruction
|
140
149
|
new_t1c = new_t1q
|
141
150
|
this_clbits = set(node.cargs)
|
@@ -153,7 +162,7 @@ class ConstrainedReschedule(AnalysisPass):
|
|
153
162
|
# Compute next node start time separately for qreg and creg
|
154
163
|
next_t0q = node_start_time[next_node]
|
155
164
|
next_qubits = set(next_node.qargs)
|
156
|
-
if isinstance(next_node.op, Measure):
|
165
|
+
if isinstance(next_node.op, (Measure, Reset)):
|
157
166
|
# creg access starts after write latency
|
158
167
|
next_t0c = next_t0q + clbit_write_latency
|
159
168
|
next_clbits = set(next_node.cargs)
|
@@ -38,8 +38,7 @@ class ASAPSchedule(BaseSchedulerTransform):
|
|
38
38
|
"Instead, use :class:`~.ASAPScheduleAnalysis`, which is an "
|
39
39
|
"analysis pass that requires a padding pass to later modify the circuit."
|
40
40
|
),
|
41
|
-
since="
|
42
|
-
pending=True,
|
41
|
+
since="1.1.0",
|
43
42
|
)
|
44
43
|
def __init__(self, *args, **kwargs):
|
45
44
|
super().__init__(*args, **kwargs)
|
@@ -11,11 +11,13 @@
|
|
11
11
|
# that they have been altered from the originals.
|
12
12
|
|
13
13
|
"""Base circuit scheduling pass."""
|
14
|
+
import warnings
|
15
|
+
|
14
16
|
from qiskit.transpiler import InstructionDurations
|
15
17
|
from qiskit.transpiler.basepasses import TransformationPass
|
16
18
|
from qiskit.transpiler.passes.scheduling.time_unit_conversion import TimeUnitConversion
|
17
|
-
from qiskit.dagcircuit import DAGOpNode, DAGCircuit
|
18
|
-
from qiskit.circuit import Delay, Gate
|
19
|
+
from qiskit.dagcircuit import DAGOpNode, DAGCircuit, DAGOutNode
|
20
|
+
from qiskit.circuit import Delay, Gate, Measure, Reset
|
19
21
|
from qiskit.circuit.parameterexpression import ParameterExpression
|
20
22
|
from qiskit.transpiler.exceptions import TranspilerError
|
21
23
|
from qiskit.transpiler.target import Target
|
@@ -269,6 +271,23 @@ class BaseSchedulerTransform(TransformationPass):
|
|
269
271
|
else:
|
270
272
|
duration = node.op.duration
|
271
273
|
|
274
|
+
if isinstance(node.op, Reset):
|
275
|
+
warnings.warn(
|
276
|
+
"Qiskit scheduler assumes Reset works similarly to Measure instruction. "
|
277
|
+
"Actual behavior depends on the control system of your quantum backend. "
|
278
|
+
"Your backend may provide a plugin scheduler pass."
|
279
|
+
)
|
280
|
+
elif isinstance(node.op, Measure):
|
281
|
+
is_mid_circuit = not any(
|
282
|
+
isinstance(x, DAGOutNode) for x in dag.quantum_successors(node)
|
283
|
+
)
|
284
|
+
if is_mid_circuit:
|
285
|
+
warnings.warn(
|
286
|
+
"Qiskit scheduler assumes mid-circuit measurement works as a standard instruction. "
|
287
|
+
"Actual backend may apply custom scheduling. "
|
288
|
+
"Your backend may provide a plugin scheduler pass."
|
289
|
+
)
|
290
|
+
|
272
291
|
if isinstance(duration, ParameterExpression):
|
273
292
|
raise TranspilerError(
|
274
293
|
f"Parameterized duration ({duration}) "
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# This code is part of Qiskit.
|
2
2
|
#
|
3
|
-
# (C) Copyright IBM 2021.
|
3
|
+
# (C) Copyright IBM 2021, 2024.
|
4
4
|
#
|
5
5
|
# This code is licensed under the Apache License, Version 2.0. You may
|
6
6
|
# obtain a copy of this license in the LICENSE.txt file in the root directory
|
@@ -20,6 +20,7 @@ from qiskit.circuit.library.standard_gates import IGate, UGate, U3Gate
|
|
20
20
|
from qiskit.dagcircuit import DAGOpNode, DAGInNode
|
21
21
|
from qiskit.quantum_info.operators.predicates import matrix_equal
|
22
22
|
from qiskit.synthesis.one_qubit import OneQubitEulerDecomposer
|
23
|
+
from qiskit.transpiler import InstructionDurations
|
23
24
|
from qiskit.transpiler.passes.optimization import Optimize1qGates
|
24
25
|
from qiskit.transpiler.basepasses import TransformationPass
|
25
26
|
from qiskit.transpiler.exceptions import TranspilerError
|
@@ -109,8 +110,7 @@ class DynamicalDecoupling(TransformationPass):
|
|
109
110
|
"Instead, use :class:`~.PadDynamicalDecoupling`, which performs the same "
|
110
111
|
"function but requires scheduling and alignment analysis passes to run prior to it."
|
111
112
|
),
|
112
|
-
since="
|
113
|
-
pending=True,
|
113
|
+
since="1.1.0",
|
114
114
|
)
|
115
115
|
def __init__(
|
116
116
|
self, durations, dd_sequence, qubits=None, spacing=None, skip_reset_qubits=True, target=None
|
@@ -169,6 +169,8 @@ class DynamicalDecoupling(TransformationPass):
|
|
169
169
|
if dag.duration is None:
|
170
170
|
raise TranspilerError("DD runs after circuit is scheduled.")
|
171
171
|
|
172
|
+
durations = self._update_inst_durations(dag)
|
173
|
+
|
172
174
|
num_pulses = len(self._dd_sequence)
|
173
175
|
sequence_gphase = 0
|
174
176
|
if num_pulses != 1:
|
@@ -209,7 +211,7 @@ class DynamicalDecoupling(TransformationPass):
|
|
209
211
|
for index, gate in enumerate(self._dd_sequence):
|
210
212
|
gate = gate.to_mutable()
|
211
213
|
self._dd_sequence[index] = gate
|
212
|
-
gate.duration =
|
214
|
+
gate.duration = durations.get(gate, physical_qubit)
|
213
215
|
|
214
216
|
dd_sequence_duration += gate.duration
|
215
217
|
index_sequence_duration_map[physical_qubit] = dd_sequence_duration
|
@@ -278,6 +280,26 @@ class DynamicalDecoupling(TransformationPass):
|
|
278
280
|
|
279
281
|
return new_dag
|
280
282
|
|
283
|
+
def _update_inst_durations(self, dag):
|
284
|
+
"""Update instruction durations with circuit information. If the dag contains gate
|
285
|
+
calibrations and no instruction durations were provided through the target or as a
|
286
|
+
standalone input, the circuit calibration durations will be used.
|
287
|
+
The priority order for instruction durations is: target > standalone > circuit.
|
288
|
+
"""
|
289
|
+
circ_durations = InstructionDurations()
|
290
|
+
|
291
|
+
if dag.calibrations:
|
292
|
+
cal_durations = []
|
293
|
+
for gate, gate_cals in dag.calibrations.items():
|
294
|
+
for (qubits, parameters), schedule in gate_cals.items():
|
295
|
+
cal_durations.append((gate, qubits, parameters, schedule.duration))
|
296
|
+
circ_durations.update(cal_durations, circ_durations.dt)
|
297
|
+
|
298
|
+
if self._durations is not None:
|
299
|
+
circ_durations.update(self._durations, getattr(self._durations, "dt", None))
|
300
|
+
|
301
|
+
return circ_durations
|
302
|
+
|
281
303
|
def __gate_supported(self, gate: Gate, qarg: int) -> bool:
|
282
304
|
"""A gate is supported on the qubit (qarg) or not."""
|
283
305
|
if self._target is None or self._target.instruction_supported(gate.name, qargs=(qarg,)):
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# This code is part of Qiskit.
|
2
2
|
#
|
3
|
-
# (C) Copyright IBM 2021.
|
3
|
+
# (C) Copyright IBM 2021, 2024.
|
4
4
|
#
|
5
5
|
# This code is licensed under the Apache License, Version 2.0. You may
|
6
6
|
# obtain a copy of this license in the LICENSE.txt file in the root directory
|
@@ -179,9 +179,31 @@ class PadDynamicalDecoupling(BasePadding):
|
|
179
179
|
f"{gate.name} in dd_sequence is not supported in the target"
|
180
180
|
)
|
181
181
|
|
182
|
+
def _update_inst_durations(self, dag):
|
183
|
+
"""Update instruction durations with circuit information. If the dag contains gate
|
184
|
+
calibrations and no instruction durations were provided through the target or as a
|
185
|
+
standalone input, the circuit calibration durations will be used.
|
186
|
+
The priority order for instruction durations is: target > standalone > circuit.
|
187
|
+
"""
|
188
|
+
circ_durations = InstructionDurations()
|
189
|
+
|
190
|
+
if dag.calibrations:
|
191
|
+
cal_durations = []
|
192
|
+
for gate, gate_cals in dag.calibrations.items():
|
193
|
+
for (qubits, parameters), schedule in gate_cals.items():
|
194
|
+
cal_durations.append((gate, qubits, parameters, schedule.duration))
|
195
|
+
circ_durations.update(cal_durations, circ_durations.dt)
|
196
|
+
|
197
|
+
if self._durations is not None:
|
198
|
+
circ_durations.update(self._durations, getattr(self._durations, "dt", None))
|
199
|
+
|
200
|
+
return circ_durations
|
201
|
+
|
182
202
|
def _pre_runhook(self, dag: DAGCircuit):
|
183
203
|
super()._pre_runhook(dag)
|
184
204
|
|
205
|
+
durations = self._update_inst_durations(dag)
|
206
|
+
|
185
207
|
num_pulses = len(self._dd_sequence)
|
186
208
|
|
187
209
|
# Check if physical circuit is given
|
@@ -245,7 +267,7 @@ class PadDynamicalDecoupling(BasePadding):
|
|
245
267
|
f"is not acceptable in {self.__class__.__name__} pass."
|
246
268
|
)
|
247
269
|
except KeyError:
|
248
|
-
gate_length =
|
270
|
+
gate_length = durations.get(gate, physical_index)
|
249
271
|
sequence_lengths.append(gate_length)
|
250
272
|
# Update gate duration. This is necessary for current timeline drawer, i.e. scheduled.
|
251
273
|
gate = gate.to_mutable()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# This code is part of Qiskit.
|
2
2
|
#
|
3
|
-
# (C) Copyright IBM 2021.
|
3
|
+
# (C) Copyright IBM 2021, 2024.
|
4
4
|
#
|
5
5
|
# This code is licensed under the Apache License, Version 2.0. You may
|
6
6
|
# obtain a copy of this license in the LICENSE.txt file in the root directory
|
@@ -51,6 +51,7 @@ class TimeUnitConversion(TransformationPass):
|
|
51
51
|
self.inst_durations = inst_durations or InstructionDurations()
|
52
52
|
if target is not None:
|
53
53
|
self.inst_durations = target.durations()
|
54
|
+
self._durations_provided = inst_durations is not None or target is not None
|
54
55
|
|
55
56
|
def run(self, dag: DAGCircuit):
|
56
57
|
"""Run the TimeUnitAnalysis pass on `dag`.
|
@@ -64,8 +65,11 @@ class TimeUnitConversion(TransformationPass):
|
|
64
65
|
Raises:
|
65
66
|
TranspilerError: if the units are not unifiable
|
66
67
|
"""
|
68
|
+
|
69
|
+
inst_durations = self._update_inst_durations(dag)
|
70
|
+
|
67
71
|
# Choose unit
|
68
|
-
if
|
72
|
+
if inst_durations.dt is not None:
|
69
73
|
time_unit = "dt"
|
70
74
|
else:
|
71
75
|
# Check what units are used in delays and other instructions: dt or SI or mixed
|
@@ -75,7 +79,7 @@ class TimeUnitConversion(TransformationPass):
|
|
75
79
|
"Fail to unify time units in delays. SI units "
|
76
80
|
"and dt unit must not be mixed when dt is not supplied."
|
77
81
|
)
|
78
|
-
units_other =
|
82
|
+
units_other = inst_durations.units_used()
|
79
83
|
if self._unified(units_other) == "mixed":
|
80
84
|
raise TranspilerError(
|
81
85
|
"Fail to unify time units in instruction_durations. SI units "
|
@@ -96,7 +100,7 @@ class TimeUnitConversion(TransformationPass):
|
|
96
100
|
# Make units consistent
|
97
101
|
for node in dag.op_nodes():
|
98
102
|
try:
|
99
|
-
duration =
|
103
|
+
duration = inst_durations.get(
|
100
104
|
node.op, [dag.find_bit(qarg).index for qarg in node.qargs], unit=time_unit
|
101
105
|
)
|
102
106
|
except TranspilerError:
|
@@ -108,6 +112,26 @@ class TimeUnitConversion(TransformationPass):
|
|
108
112
|
self.property_set["time_unit"] = time_unit
|
109
113
|
return dag
|
110
114
|
|
115
|
+
def _update_inst_durations(self, dag):
|
116
|
+
"""Update instruction durations with circuit information. If the dag contains gate
|
117
|
+
calibrations and no instruction durations were provided through the target or as a
|
118
|
+
standalone input, the circuit calibration durations will be used.
|
119
|
+
The priority order for instruction durations is: target > standalone > circuit.
|
120
|
+
"""
|
121
|
+
circ_durations = InstructionDurations()
|
122
|
+
|
123
|
+
if dag.calibrations:
|
124
|
+
cal_durations = []
|
125
|
+
for gate, gate_cals in dag.calibrations.items():
|
126
|
+
for (qubits, parameters), schedule in gate_cals.items():
|
127
|
+
cal_durations.append((gate, qubits, parameters, schedule.duration))
|
128
|
+
circ_durations.update(cal_durations, circ_durations.dt)
|
129
|
+
|
130
|
+
if self._durations_provided:
|
131
|
+
circ_durations.update(self.inst_durations, getattr(self.inst_durations, "dt", None))
|
132
|
+
|
133
|
+
return circ_durations
|
134
|
+
|
111
135
|
@staticmethod
|
112
136
|
def _units_used_in_delays(dag: DAGCircuit) -> Set[str]:
|
113
137
|
units_used = set()
|
@@ -20,7 +20,7 @@ AQC Synthesis Plugin (in :mod:`qiskit.transpiler.passes.synthesis.aqc_plugin`)
|
|
20
20
|
AQCSynthesisPlugin
|
21
21
|
"""
|
22
22
|
from functools import partial
|
23
|
-
import
|
23
|
+
import math
|
24
24
|
|
25
25
|
from qiskit.converters import circuit_to_dag
|
26
26
|
from qiskit.transpiler.passes.synthesis.plugin import UnitarySynthesisPlugin
|
@@ -118,7 +118,7 @@ class AQCSynthesisPlugin(UnitarySynthesisPlugin):
|
|
118
118
|
from qiskit.synthesis.unitary.aqc.cnot_unit_circuit import CNOTUnitCircuit
|
119
119
|
from qiskit.synthesis.unitary.aqc.fast_gradient.fast_gradient import FastCNOTUnitObjective
|
120
120
|
|
121
|
-
num_qubits =
|
121
|
+
num_qubits = round(math.log2(unitary.shape[0]))
|
122
122
|
|
123
123
|
config = options.get("config") or {}
|
124
124
|
|
@@ -133,8 +133,9 @@ Permutation Synthesis
|
|
133
133
|
TokenSwapperSynthesisPermutation
|
134
134
|
"""
|
135
135
|
|
136
|
-
from typing import Optional, Union, List, Tuple
|
136
|
+
from typing import Optional, Union, List, Tuple, Callable
|
137
137
|
|
138
|
+
import numpy as np
|
138
139
|
import rustworkx as rx
|
139
140
|
|
140
141
|
from qiskit.circuit.operation import Operation
|
@@ -142,6 +143,7 @@ from qiskit.converters import circuit_to_dag, dag_to_circuit
|
|
142
143
|
from qiskit.transpiler.basepasses import TransformationPass
|
143
144
|
from qiskit.circuit.quantumcircuit import QuantumCircuit
|
144
145
|
from qiskit.circuit import ControlFlowOp, ControlledGate, EquivalenceLibrary
|
146
|
+
from qiskit.circuit.library import LinearFunction
|
145
147
|
from qiskit.transpiler.passes.utils import control_flow
|
146
148
|
from qiskit.transpiler.target import Target
|
147
149
|
from qiskit.transpiler.coupling import CouplingMap
|
@@ -163,7 +165,12 @@ from qiskit.synthesis.clifford import (
|
|
163
165
|
synth_clifford_ag,
|
164
166
|
synth_clifford_bm,
|
165
167
|
)
|
166
|
-
from qiskit.synthesis.linear import
|
168
|
+
from qiskit.synthesis.linear import (
|
169
|
+
synth_cnot_count_full_pmh,
|
170
|
+
synth_cnot_depth_line_kms,
|
171
|
+
calc_inverse_matrix,
|
172
|
+
)
|
173
|
+
from qiskit.synthesis.linear.linear_circuits_utils import transpose_cx_circ
|
167
174
|
from qiskit.synthesis.permutation import (
|
168
175
|
synth_permutation_basic,
|
169
176
|
synth_permutation_acg,
|
@@ -220,16 +227,34 @@ class HLSConfig:
|
|
220
227
|
:ref:`using-high-level-synthesis-plugins`.
|
221
228
|
"""
|
222
229
|
|
223
|
-
def __init__(
|
230
|
+
def __init__(
|
231
|
+
self,
|
232
|
+
use_default_on_unspecified: bool = True,
|
233
|
+
plugin_selection: str = "sequential",
|
234
|
+
plugin_evaluation_fn: Optional[Callable[[QuantumCircuit], int]] = None,
|
235
|
+
**kwargs,
|
236
|
+
):
|
224
237
|
"""Creates a high-level-synthesis config.
|
225
238
|
|
226
239
|
Args:
|
227
|
-
use_default_on_unspecified
|
240
|
+
use_default_on_unspecified: if True, every higher-level-object without an
|
228
241
|
explicitly specified list of methods will be synthesized using the "default"
|
229
242
|
algorithm if it exists.
|
243
|
+
plugin_selection: if set to ``"sequential"`` (default), for every higher-level-object
|
244
|
+
the synthesis pass will consider the specified methods sequentially, stopping
|
245
|
+
at the first method that is able to synthesize the object. If set to ``"all"``,
|
246
|
+
all the specified methods will be considered, and the best synthesized circuit,
|
247
|
+
according to ``plugin_evaluation_fn`` will be chosen.
|
248
|
+
plugin_evaluation_fn: a callable that evaluates the quality of the synthesized
|
249
|
+
quantum circuit; a smaller value means a better circuit. If ``None``, the
|
250
|
+
quality of the circuit its size (i.e. the number of gates that it contains).
|
230
251
|
kwargs: a dictionary mapping higher-level-objects to lists of synthesis methods.
|
231
252
|
"""
|
232
253
|
self.use_default_on_unspecified = use_default_on_unspecified
|
254
|
+
self.plugin_selection = plugin_selection
|
255
|
+
self.plugin_evaluation_fn = (
|
256
|
+
plugin_evaluation_fn if plugin_evaluation_fn is not None else lambda qc: qc.size()
|
257
|
+
)
|
233
258
|
self.methods = {}
|
234
259
|
|
235
260
|
for key, value in kwargs.items():
|
@@ -241,9 +266,6 @@ class HLSConfig:
|
|
241
266
|
self.methods[hls_name] = hls_methods
|
242
267
|
|
243
268
|
|
244
|
-
# ToDo: Do we have a way to specify optimization criteria (e.g., 2q gate count vs. depth)?
|
245
|
-
|
246
|
-
|
247
269
|
class HighLevelSynthesis(TransformationPass):
|
248
270
|
"""Synthesize higher-level objects and unroll custom definitions.
|
249
271
|
|
@@ -341,7 +363,7 @@ class HighLevelSynthesis(TransformationPass):
|
|
341
363
|
|
342
364
|
# include path for when target exists but target.num_qubits is None (BasicSimulator)
|
343
365
|
if not self._top_level_only and (self._target is None or self._target.num_qubits is None):
|
344
|
-
basic_insts = {"measure", "reset", "barrier", "snapshot", "delay"}
|
366
|
+
basic_insts = {"measure", "reset", "barrier", "snapshot", "delay", "store"}
|
345
367
|
self._device_insts = basic_insts | set(self._basis_gates)
|
346
368
|
|
347
369
|
def run(self, dag: DAGCircuit) -> DAGCircuit:
|
@@ -493,6 +515,9 @@ class HighLevelSynthesis(TransformationPass):
|
|
493
515
|
else:
|
494
516
|
methods = []
|
495
517
|
|
518
|
+
best_decomposition = None
|
519
|
+
best_score = np.inf
|
520
|
+
|
496
521
|
for method in methods:
|
497
522
|
# There are two ways to specify a synthesis method. The more explicit
|
498
523
|
# way is to specify it as a tuple consisting of a synthesis algorithm and a
|
@@ -531,11 +556,22 @@ class HighLevelSynthesis(TransformationPass):
|
|
531
556
|
)
|
532
557
|
|
533
558
|
# The synthesis methods that are not suited for the given higher-level-object
|
534
|
-
# will return None
|
559
|
+
# will return None.
|
535
560
|
if decomposition is not None:
|
536
|
-
|
561
|
+
if self.hls_config.plugin_selection == "sequential":
|
562
|
+
# In the "sequential" mode the first successful decomposition is
|
563
|
+
# returned.
|
564
|
+
best_decomposition = decomposition
|
565
|
+
break
|
537
566
|
|
538
|
-
|
567
|
+
# In the "run everything" mode we update the best decomposition
|
568
|
+
# discovered
|
569
|
+
current_score = self.hls_config.plugin_evaluation_fn(decomposition)
|
570
|
+
if current_score < best_score:
|
571
|
+
best_decomposition = decomposition
|
572
|
+
best_score = current_score
|
573
|
+
|
574
|
+
return best_decomposition
|
539
575
|
|
540
576
|
def _synthesize_annotated_op(self, op: Operation) -> Union[Operation, None]:
|
541
577
|
"""
|
@@ -720,11 +756,43 @@ class KMSSynthesisLinearFunction(HighLevelSynthesisPlugin):
|
|
720
756
|
|
721
757
|
This plugin name is :``linear_function.kms`` which can be used as the key on
|
722
758
|
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
759
|
+
|
760
|
+
The plugin supports the following plugin-specific options:
|
761
|
+
|
762
|
+
* use_inverted: Indicates whether to run the algorithm on the inverse matrix
|
763
|
+
and to invert the synthesized circuit.
|
764
|
+
In certain cases this provides a better decomposition than the direct approach.
|
765
|
+
* use_transposed: Indicates whether to run the algorithm on the transposed matrix
|
766
|
+
and to invert the order of CX gates in the synthesized circuit.
|
767
|
+
In certain cases this provides a better decomposition than the direct approach.
|
768
|
+
|
723
769
|
"""
|
724
770
|
|
725
771
|
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
726
772
|
"""Run synthesis for the given LinearFunction."""
|
727
|
-
|
773
|
+
|
774
|
+
if not isinstance(high_level_object, LinearFunction):
|
775
|
+
raise TranspilerError(
|
776
|
+
"PMHSynthesisLinearFunction only accepts objects of type LinearFunction"
|
777
|
+
)
|
778
|
+
|
779
|
+
use_inverted = options.get("use_inverted", False)
|
780
|
+
use_transposed = options.get("use_transposed", False)
|
781
|
+
|
782
|
+
mat = high_level_object.linear.astype(int)
|
783
|
+
|
784
|
+
if use_transposed:
|
785
|
+
mat = np.transpose(mat)
|
786
|
+
if use_inverted:
|
787
|
+
mat = calc_inverse_matrix(mat)
|
788
|
+
|
789
|
+
decomposition = synth_cnot_depth_line_kms(mat)
|
790
|
+
|
791
|
+
if use_transposed:
|
792
|
+
decomposition = transpose_cx_circ(decomposition)
|
793
|
+
if use_inverted:
|
794
|
+
decomposition = decomposition.inverse()
|
795
|
+
|
728
796
|
return decomposition
|
729
797
|
|
730
798
|
|
@@ -733,11 +801,50 @@ class PMHSynthesisLinearFunction(HighLevelSynthesisPlugin):
|
|
733
801
|
|
734
802
|
This plugin name is :``linear_function.pmh`` which can be used as the key on
|
735
803
|
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
804
|
+
|
805
|
+
The plugin supports the following plugin-specific options:
|
806
|
+
|
807
|
+
* section size: The size of each section used in the Patel–Markov–Hayes algorithm [1].
|
808
|
+
* use_inverted: Indicates whether to run the algorithm on the inverse matrix
|
809
|
+
and to invert the synthesized circuit.
|
810
|
+
In certain cases this provides a better decomposition than the direct approach.
|
811
|
+
* use_transposed: Indicates whether to run the algorithm on the transposed matrix
|
812
|
+
and to invert the order of CX gates in the synthesized circuit.
|
813
|
+
In certain cases this provides a better decomposition than the direct approach.
|
814
|
+
|
815
|
+
References:
|
816
|
+
1. Patel, Ketan N., Igor L. Markov, and John P. Hayes,
|
817
|
+
*Optimal synthesis of linear reversible circuits*,
|
818
|
+
Quantum Information & Computation 8.3 (2008): 282-294.
|
819
|
+
`arXiv:quant-ph/0302002 [quant-ph] <https://arxiv.org/abs/quant-ph/0302002>`_
|
736
820
|
"""
|
737
821
|
|
738
822
|
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
739
823
|
"""Run synthesis for the given LinearFunction."""
|
740
|
-
|
824
|
+
|
825
|
+
if not isinstance(high_level_object, LinearFunction):
|
826
|
+
raise TranspilerError(
|
827
|
+
"PMHSynthesisLinearFunction only accepts objects of type LinearFunction"
|
828
|
+
)
|
829
|
+
|
830
|
+
section_size = options.get("section_size", 2)
|
831
|
+
use_inverted = options.get("use_inverted", False)
|
832
|
+
use_transposed = options.get("use_transposed", False)
|
833
|
+
|
834
|
+
mat = high_level_object.linear.astype(int)
|
835
|
+
|
836
|
+
if use_transposed:
|
837
|
+
mat = np.transpose(mat)
|
838
|
+
if use_inverted:
|
839
|
+
mat = calc_inverse_matrix(mat)
|
840
|
+
|
841
|
+
decomposition = synth_cnot_count_full_pmh(mat, section_size=section_size)
|
842
|
+
|
843
|
+
if use_transposed:
|
844
|
+
decomposition = transpose_cx_circ(decomposition)
|
845
|
+
if use_inverted:
|
846
|
+
decomposition = decomposition.inverse()
|
847
|
+
|
741
848
|
return decomposition
|
742
849
|
|
743
850
|
|