Skip to content

Commit

Permalink
Improve performance
Browse files Browse the repository at this point in the history
  • Loading branch information
itoko committed Oct 19, 2023
1 parent 800075f commit cafe761
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,18 @@
from typing import Sequence

from qiskit.circuit import QuantumCircuit, Operation
from qiskit.compiler import transpile
from qiskit.circuit.equivalence_library import SessionEquivalenceLibrary as sel
from qiskit.exceptions import QiskitError
from qiskit.synthesis.clifford import synth_clifford_full
from qiskit.transpiler import PassManager, CouplingMap, Layout
from qiskit.transpiler.passes import SabreSwap, LayoutTransformation
from qiskit.transpiler.passes import (
SabreSwap,
LayoutTransformation,
BasisTranslator,
CheckGateDirection,
GateDirection,
Optimize1qGatesDecomposition,
)
from qiskit.transpiler.passes.synthesis.plugin import HighLevelSynthesisPlugin


Expand Down Expand Up @@ -48,25 +56,41 @@ def run(
Returns:
The quantum circuit representation of the Operation
when successful, and ``None`` otherwise.
Raises:
QiskitError: If basis_gates is not supplied.
"""
# synthesize cliffords
circ = synth_clifford_full(high_level_object)

# post processing to comply with basis gates and coupling map
if coupling_map is None: # Sabre does not work with coupling_map=None
return circ
# run Sabre routing and undo the layout change
# assuming Sabre routing does not change the initial layout

if basis_gates is None:
raise QiskitError("basis_gates are required to run this synthesis plugin")

basis_gates = list(basis_gates)

# Run Sabre routing and undo the layout change
# assuming Sabre routing does not change the initial layout.
# And then decompose swap gates, fix 2q-gate direction and optimize 1q gates
initial_layout = Layout.generate_trivial_layout(*circ.qubits)
undo_layout_change = LayoutTransformation(
coupling_map=coupling_map, from_layout="final_layout", to_layout=initial_layout
)
pm = PassManager([SabreSwap(coupling_map), undo_layout_change])
circ = pm.run(circ)
# for fixing 2q-gate direction and optimizing 1q gates
return transpile(
circ,
basis_gates=basis_gates,
coupling_map=coupling_map,
optimization_level=1,

def _direction_condition(property_set):
return not property_set["is_direction_mapped"]

pm = PassManager(
[
SabreSwap(coupling_map),
undo_layout_change,
BasisTranslator(sel, basis_gates),
CheckGateDirection(coupling_map),
]
)
pm.append([GateDirection(coupling_map)], condition=_direction_condition)
pm.append([Optimize1qGatesDecomposition(basis=basis_gates)])
return pm.run(circ)
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,44 @@ def _clifford_2q_int_to_instruction(
).to_instruction()


def _hash_cliff(cliff):
return cliff.tableau.tobytes(), cliff.tableau.shape


def _dehash_cliff(cliff_hash):
tableau = np.frombuffer(cliff_hash[0], dtype=bool).reshape(cliff_hash[1])
return Clifford(tableau)


def _clifford_to_instruction(
clifford: Clifford,
basis_gates: Optional[Tuple[str]],
coupling_tuple: Optional[Tuple[Tuple[int, int]]],
synthesis_method: str = DEFAULT_SYNTHESIS_METHOD,
) -> Instruction:
return _cached_clifford_to_instruction(
_hash_cliff(clifford),
basis_gates=basis_gates,
coupling_tuple=coupling_tuple,
synthesis_method=synthesis_method,
)


@lru_cache(maxsize=256)
def _cached_clifford_to_instruction(
cliff_hash: Tuple[str, Tuple[int, int]],
basis_gates: Optional[Tuple[str]],
coupling_tuple: Optional[Tuple[Tuple[int, int]]],
synthesis_method: str = DEFAULT_SYNTHESIS_METHOD,
) -> Instruction:
return _synthesize_clifford(
_dehash_cliff(cliff_hash),
basis_gates=basis_gates,
coupling_tuple=coupling_tuple,
synthesis_method=synthesis_method,
).to_instruction()


# The classes VGate and WGate are not actually used in the code - we leave them here to give
# a better understanding of the composition of the layers for 2-qubit Cliffords.
class VGate(Gate):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@
inverse_2q,
_clifford_1q_int_to_instruction,
_clifford_2q_int_to_instruction,
_clifford_to_instruction,
_transpile_clifford_circuit,
_synthesize_clifford,
)
from .rb_analysis import RBAnalysis

Expand Down Expand Up @@ -332,8 +332,7 @@ def _to_instruction(
if self.num_qubits == 2:
return _clifford_2q_int_to_instruction(elem, **synthesis_options)

cliff_circ = _synthesize_clifford(elem, **synthesis_options)
return cliff_circ.to_instruction()
return _clifford_to_instruction(elem, **synthesis_options)

def __identity_clifford(self) -> SequenceElementType:
if self.num_qubits <= 2:
Expand All @@ -347,11 +346,11 @@ def __compose_clifford_seq(
return functools.reduce(
compose_1q if self.num_qubits == 1 else compose_2q, elements, base_elem
)
# 3 or more qubits: compose Clifford from circuits for speed
circ = QuantumCircuit(self.num_qubits)
# 3 or more qubits
res = base_elem
for elem in elements:
circ.compose(elem, inplace=True)
return base_elem.compose(Clifford.from_circuit(circ))
res = res.compose(elem)
return res

def __adjoint_clifford(self, op: SequenceElementType) -> SequenceElementType:
if self.num_qubits == 1:
Expand Down

0 comments on commit cafe761

Please sign in to comment.