Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions qiskit_device_benchmarking/bench_code/mrb/mirror_rb_experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,13 @@
from qiskit_experiments.library.randomized_benchmarking.clifford_utils import (
inverse_1q,
_clifford_1q_int_to_instruction,
_clifford_2q_int_to_instruction,

Check failure on line 55 in qiskit_device_benchmarking/bench_code/mrb/mirror_rb_experiment.py

View workflow job for this annotation

GitHub Actions / build

Ruff (F401)

qiskit_device_benchmarking/bench_code/mrb/mirror_rb_experiment.py:55:5: F401 `qiskit_experiments.library.randomized_benchmarking.clifford_utils._clifford_2q_int_to_instruction` imported but unused
)
from .mirror_rb_analysis import MirrorRBAnalysis
from qiskit_device_benchmarking.utilities.clifford_utils import compute_target_bitstring
from qiskit_device_benchmarking.utilities.sampling_utils import (
EdgeGrabSampler,
MatchingSampler,
SingleQubitSampler,
GateInstruction,
GateDistribution,
Expand Down Expand Up @@ -106,7 +107,7 @@

"""

sampler_map = {"edge_grab": EdgeGrabSampler, "single_qubit": SingleQubitSampler}
sampler_map = {"edge_grab": EdgeGrabSampler, "matching": MatchingSampler, "single_qubit": SingleQubitSampler}

# pylint: disable=dangerous-default-value
def __init__(
Expand Down Expand Up @@ -243,10 +244,9 @@
based on experiment options. This method is currently implemented
for the default "edge_grab" sampler."""

if self.experiment_options.sampling_algorithm != "edge_grab":
if self.experiment_options.sampling_algorithm not in ["edge_grab", "matching"]:
raise QiskitError(
"Unsupported sampling algorithm provided. You must implement"
"a custom `_set_distribution_options` method."
"Unsupported sampling algorithm provided."
)

self._distribution.seed = self.experiment_options.seed
Expand All @@ -268,7 +268,8 @@
adjusted_2q_density = self.experiment_options.two_qubit_gate_density

if adjusted_2q_density > 1:
warnings.warn("Two-qubit gate density is too high, capping at 1.")
if self.experiment_options.two_qubit_gate_density > 1:
warnings.warn("Two-qubit gate density is too high, capping at 1.")
adjusted_2q_density = 1

self._distribution.gate_distribution = [
Expand Down Expand Up @@ -435,7 +436,7 @@
circ = QuantumCircuit(self.num_qubits)
# Hack to get target bitstrings until qiskit-terra#9475 is resolved
circ_target = QuantumCircuit(self.num_qubits)
for l, layer in enumerate(seq):

Check failure on line 439 in qiskit_device_benchmarking/bench_code/mrb/mirror_rb_experiment.py

View workflow job for this annotation

GitHub Actions / build

Ruff (E741)

qiskit_device_benchmarking/bench_code/mrb/mirror_rb_experiment.py:439:17: E741 Ambiguous variable name: `l`
for elem in layer:
instr = self._to_instruction(elem.op)
qargs = elem.qargs
Expand Down Expand Up @@ -499,7 +500,8 @@
self, layer: List[Tuple[GateInstruction, ...]]
) -> List[Tuple[GateInstruction, ...]]:
"""Generates the inverse layer of a Clifford mirror RB layer by inverting the
single-qubit Cliffords and keeping the two-qubit gate identical. See
single-qubit Cliffords and keeping the two-qubit gate identical. If the layer
contains both, it is assumed that two-qubit gates come first. See
:class:`.BaseSampler` for the format of the layer.

Args:
Expand All @@ -512,12 +514,13 @@
QiskitError: If the layer has invalid format.
"""
inverse_layer = []
for elem in layer:
for elem in layer: # first single qubit
if len(elem.qargs) == 1 and np.issubdtype(type(elem.op), int):
inverse_layer.append(GateInstruction(elem.qargs, inverse_1q(elem.op)))
elif len(elem.qargs) == 2 and elem.op in _self_adjoint_gates:
for elem in layer: # then two qubit qubit
if len(elem.qargs) == 2 and elem.op in _self_adjoint_gates:
inverse_layer.append(elem)
else:
elif not (len(elem.qargs) == 1 and np.issubdtype(type(elem.op), int)):
try:
inverse_layer.append(GateInstruction(elem.qargs, elem.op.inverse()))
except TypeError as exc:
Expand Down
48 changes: 38 additions & 10 deletions qiskit_device_benchmarking/utilities/sampling_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,13 +272,6 @@ class EdgeGrabSampler(BaseSampler):
2. Select edges from :math:`E` with the probability :math:`w\xi/2|E|`. These
edges will have two-qubit gates in the output layer.

If `matching=True`, step 1 above is replaced with

1. Perform a maximum weight matching :math:`E` of the graph defined by the
coupling map, using randomly chosen edges to acheive a random result.

|

This produces a layer with an expected two-qubit gate density :math:`\xi`. In the
default mirror RB configuration where these layers are dressed with single-qubit
Pauli layers, this means the overall expected two-qubit gate density will be
Expand Down Expand Up @@ -452,9 +445,10 @@ def __call__(
),
),
)
# remove these qubits from put_1q_gates
put_1q_gates.remove(edge[0])
put_1q_gates.remove(edge[1])
if not self._matching:
# remove these qubits from put_1q_gates
put_1q_gates.remove(edge[0])
put_1q_gates.remove(edge[1])
for q in put_1q_gates:
if sum(gateset[1][1]) > 0:
layer.append(
Expand All @@ -476,3 +470,37 @@ def __call__(
),
)
yield tuple(layer)

class MatchingSampler(EdgeGrabSampler):
r"""A sampler that uses maximum weight matching for sampling gate layers.

Given a list of :math:`w` qubits, their connectivity graph, and the desired
two-qubit gate density :math:`\xi_s`, this algorithm outputs a layer as follows:

1. Perform a maximum weight matching :math:`E` of the graph defined by the
coupling map, using randomly chosen edges to acheive a random result.

2. Select edges from :math:`E` with the probability :math:`w\xi/2|E|`. These
edges will have two-qubit gates in the output layer.

3. Random single qubit gates are then assigned to all qubits.

This produces a layer with an expected two-qubit gate density :math:`\xi`. In the
default mirror RB configuration where these layers are dressed with single-qubit
Pauli layers, this means the overall expected two-qubit gate density will be
:math:`\xi_s/2=\xi`. The actual density will converge to :math:`\xi_s` as the
circuit size increases.

"""
def __init__(
self,
gate_distribution=None,
coupling_map=None,
seed=None,
):
super().__init__(
gate_distribution=gate_distribution,
coupling_map=coupling_map,
seed=seed,
matching=True
)
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ numpy>=1.17
scipy>=1.4
qiskit>=2.0
qiskit-aer
qiskit-experiments>=0.10.0
qiskit-ibm-runtime>=0.28
qiskit-experiments>=0.10.0
matplotlib>=3.4
rustworkx
networkx
Expand Down
Loading