Skip to content

Commit

Permalink
Fixes for backends with ECRGate employing #1288
Browse files Browse the repository at this point in the history
  • Loading branch information
itoko committed Nov 30, 2023
1 parent ef8a05d commit 2846b0f
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,11 @@ def inverse_1q(num: Integral) -> Integral:


def num_from_1q_circuit(qc: QuantumCircuit) -> Integral:
"""Convert a given 1-qubit Clifford circuit to the corresponding integer."""
"""Convert a given 1-qubit Clifford circuit to the corresponding integer.
Note: The circuit must consist of gates in :const:`_CLIFF_SINGLE_GATE_MAP_1Q`,
RZGate, Delay and Barrier.
"""
num = 0
for inst in qc:
rhs = _num_from_1q_gate(op=inst.operation)
Expand All @@ -376,7 +380,7 @@ def num_from_1q_circuit(qc: QuantumCircuit) -> Integral:
def _num_from_1q_gate(op: Instruction) -> int:
"""
Convert a given 1-qubit clifford operation to the corresponding integer.
Note that supported operations are limited to ones in :const:`CLIFF_SINGLE_GATE_MAP_1Q` or Rz gate.
Note that supported operations are limited to ones in :const:`_CLIFF_SINGLE_GATE_MAP_1Q` or Rz gate.
Args:
op: operation to be converted.
Expand Down Expand Up @@ -435,7 +439,11 @@ def inverse_2q(num: Integral) -> Integral:


def num_from_2q_circuit(qc: QuantumCircuit) -> Integral:
"""Convert a given 2-qubit Clifford circuit to the corresponding integer."""
"""Convert a given 2-qubit Clifford circuit to the corresponding integer.
Note: The circuit must consist of gates in :const:`_CLIFF_SINGLE_GATE_MAP_2Q`,
RZGate, Delay and Barrier.
"""
lhs = 0
for rhs in _clifford_2q_nums_from_2q_circuit(qc):
lhs = _CLIFFORD_COMPOSE_2Q_DENSE[lhs, _clifford_num_to_dense_index[rhs]]
Expand All @@ -447,7 +455,7 @@ def _num_from_2q_gate(
) -> int:
"""
Convert a given 1-qubit clifford operation to the corresponding integer.
Note that supported operations are limited to ones in `CLIFF_SINGLE_GATE_MAP_2Q` or Rz gate.
Note that supported operations are limited to ones in `_CLIFF_SINGLE_GATE_MAP_2Q` or Rz gate.
Args:
op: operation of instruction to be converted.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"""
Layer Fidelity RB Experiment class.
"""
import functools
import logging
from collections import defaultdict
from typing import Union, Iterable, Optional, List, Sequence, Tuple
Expand All @@ -25,19 +26,21 @@
from qiskit.exceptions import QiskitError
from qiskit.providers import BackendV2Converter
from qiskit.providers.backend import Backend, BackendV1, BackendV2
from qiskit.quantum_info import Clifford
from qiskit.pulse.instruction_schedule_map import CalibrationPublisher

from qiskit_experiments.framework import BaseExperiment, Options
from qiskit_experiments.framework.restless_mixin import RestlessMixin

from .clifford_utils import (
CliffordUtils,
DEFAULT_SYNTHESIS_METHOD,
compose_1q,
compose_2q,
inverse_1q,
inverse_2q,
num_from_2q_circuit,
_product_1q_nums,
_num_from_2q_gate,
_clifford_1q_int_to_instruction,
_clifford_2q_int_to_instruction,
_decompose_clifford_ops,
Expand Down Expand Up @@ -150,6 +153,8 @@ def _default_experiment_options(cls) -> Options:
:meth:`circuits` is called.
two_qubit_gate (str): Two-qubit gate name (e.g. "cx", "cz", "ecr") of which the two qubit layers consist.
one_qubit_basis_gates (Tuple[str]): One-qubit gates to use for implementing 1q Clifford operations.
clifford_synthesis_method (str): The name of the Clifford synthesis plugin to use
for building circuits of RB sequences.
"""
options = super()._default_experiment_options()
options.update_options(
Expand All @@ -158,7 +163,8 @@ def _default_experiment_options(cls) -> Options:
seed=None,
two_qubit_layers=None,
two_qubit_gate=None,
one_qubit_basis_gates=tuple(),
one_qubit_basis_gates=(),
clifford_synthesis_method=DEFAULT_SYNTHESIS_METHOD,
)
return options

Expand Down Expand Up @@ -215,10 +221,20 @@ def circuits(self) -> List[QuantumCircuit]:
"""
opts = self.experiment_options
rng = default_rng(seed=opts.seed)
basis_gates = (opts.two_qubit_gate,) + opts.one_qubit_basis_gates
GATE2Q = GATE_NAME_MAP[opts.two_qubit_gate]
GATE2Q_CLIFF = _num_from_2q_gate(GATE2Q)
GATE2Q_CLIFF = num_from_2q_circuit(Clifford(GATE2Q).to_circuit())
residal_qubits_by_layer = [self.__residual_qubits(layer) for layer in opts.two_qubit_layers]
_to_gate_1q = functools.partial(
_clifford_1q_int_to_instruction,
basis_gates=opts.one_qubit_basis_gates,
synthesis_method=opts.clifford_synthesis_method,
)
_to_gate_2q = functools.partial(
_clifford_2q_int_to_instruction,
basis_gates=(opts.two_qubit_gate,) + opts.one_qubit_basis_gates,
coupling_tuple=((0, 1),),
synthesis_method=opts.clifford_synthesis_method,
)
# Circuit generation
circuits = []
num_qubits = max(self.physical_qubits) + 1
Expand All @@ -245,25 +261,15 @@ def circuits(self) -> List[QuantumCircuit]:
samples = rng.integers(NUM_1Q_CLIFFORD, size=2)
cliffs_2q[j] = compose_2q(cliffs_2q[j], _product_1q_nums(*samples))
for sample, q in zip(samples, qpair):
circ._append(
_clifford_1q_int_to_instruction(
sample, opts.one_qubit_basis_gates
),
(circ.qubits[q],),
tuple(),
)
circ._append(_to_gate_1q(sample), (circ.qubits[q],), ())
for k, q in enumerate(one_qubits):
sample = rng.integers(NUM_1Q_CLIFFORD)
cliffs_1q[k] = compose_1q(cliffs_1q[k], sample)
circ._append(
_clifford_1q_int_to_instruction(sample, opts.one_qubit_basis_gates),
(circ.qubits[q],),
tuple(),
)
circ._append(_to_gate_1q(sample), (circ.qubits[q],), ())
circ.barrier(self.physical_qubits)
# add two qubit gates
for j, qpair in enumerate(two_qubit_layer):
circ._append(GATE2Q, tuple(circ.qubits[q] for q in qpair), tuple())
circ._append(GATE2Q, tuple(circ.qubits[q] for q in qpair), ())
cliffs_2q[j] = compose_2q(cliffs_2q[j], GATE2Q_CLIFF)
# TODO: add dd if necessary
for k, q in enumerate(one_qubits):
Expand All @@ -273,18 +279,10 @@ def circuits(self) -> List[QuantumCircuit]:
# add the last inverse
for j, qpair in enumerate(two_qubit_layer):
inv = inverse_2q(cliffs_2q[j])
circ._append(
_clifford_2q_int_to_instruction(inv, basis_gates),
tuple(circ.qubits[q] for q in qpair),
tuple(),
)
circ._append(_to_gate_2q(inv), tuple(circ.qubits[q] for q in qpair), ())
for k, q in enumerate(one_qubits):
inv = inverse_1q(cliffs_1q[k])
circ._append(
_clifford_1q_int_to_instruction(inv, opts.one_qubit_basis_gates),
(circ.qubits[q],),
tuple(),
)
circ._append(_to_gate_1q(inv), (circ.qubits[q],), ())
# add the measurements
circ.barrier(self.physical_qubits)
for qubits, clbits in zip(composite_qubits, composite_clbits):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,15 +232,15 @@ def _run_analysis(
quality=quality_lf,
extra={},
)
eplg = 1 - (lf ** (1/self.num_2q_gates))
eplg = 1 - (lf ** (1 / self.num_2q_gates))
eplg_result = AnalysisResultData(
name="EPLG",
value=eplg,
chisq=None,
quality=quality_lf,
extra={},
)

# Return combined results
analysis_results = [lf_result, eplg_result] + analysis_results
return analysis_results, figures
6 changes: 2 additions & 4 deletions test/library/randomized_benchmarking/test_layer_fidelity.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,15 @@ def test_invalid_two_qubit_layers(self):
# not disjoit
with self.assertRaises(QiskitError):
LayerFidelity(
physical_qubits=(0, 1, 2, 3),
two_qubit_layers=[[(0, 1), (1, 2)]],
**valid_kwargs
physical_qubits=(0, 1, 2, 3), two_qubit_layers=[[(0, 1), (1, 2)]], **valid_kwargs
)
# no 2q-gate on the qubits (FakeManilaV2 has no cx gate on (0, 3))
with self.assertRaises(QiskitError):
LayerFidelity(
physical_qubits=(0, 1, 2, 3),
two_qubit_layers=[[(0, 3)]],
backend=FakeManilaV2(),
**valid_kwargs
**valid_kwargs,
)

def test_roundtrip_serializable(self):
Expand Down

0 comments on commit 2846b0f

Please sign in to comment.