Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New QEM benchmarking method: "rotated" RB circuits #2028

Merged
Show file tree
Hide file tree
Changes from 5 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
7 changes: 7 additions & 0 deletions docs/source/apidoc.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@
:members:
```

### Rotated Randomized Benchmarking Circuits

```{eval-rst}
.. automodule:: mitiq.benchmarks.rotated_randomized_benchmarking
:members:
```

### GHZ Circuits
```{eval-rst}
.. automodule:: mitiq.benchmarks.ghz_circuits
Expand Down
3 changes: 3 additions & 0 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@
r"https://dl.acm.org/doi/10.1145/3466752.3480059",
r"https://doi.org/10.1145/3466752.3480059",
r"https://doi.org/10.7566/jpsj.90.032001",
r"https://arxiv.org/abs/1612.02058",
r"https://arxiv.org/abs/1805.04492",
r"https://arxiv.org/abs/1807.05572",
]


Expand Down
3 changes: 3 additions & 0 deletions mitiq/benchmarks/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
# LICENSE file in the root directory of this source tree.

from mitiq.benchmarks.randomized_benchmarking import generate_rb_circuits
from mitiq.benchmarks.rotated_randomized_benchmarking import (
generate_rotated_rb_circuits,
)
from mitiq.benchmarks.mirror_circuits import generate_mirror_circuit
from mitiq.benchmarks.ghz_circuits import generate_ghz_circuit
from mitiq.benchmarks.quantum_volume_circuits import (
Expand Down
81 changes: 81 additions & 0 deletions mitiq/benchmarks/rotated_randomized_benchmarking.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Copyright (C) Unitary Fund
#
# This source code is licensed under the GPL license (v3) found in the
# LICENSE file in the root directory of this source tree.

"""Functions for generating rotated randomized benchmarking circuits."""
from typing import List, Optional

import cirq
import numpy as np

from mitiq import QPROGRAM
from mitiq.benchmarks import generate_rb_circuits
from mitiq.interface import convert_from_mitiq, convert_to_mitiq


def generate_rotated_rb_circuits(
n_qubits: int,
num_cliffords: int,
trials: int = 1,
return_type: Optional[str] = None,
seed: Optional[int] = None,
) -> List[QPROGRAM]:
r"""
Generates a list of "rotated" randomized benchmarking circuits.
This benchmarking method enables testing QEM techniques in more general
scenarios, closer to real-world applications in which expectation values
can take arbitrary values.

Rotated randomized bencmarking circuits are randomized benchmarking
circuits in which an $R_z(\theta)$ rotation is inserted in the middle, such
that:

$$ C(\theta) = G_n \dots G_{n/2 +1} R_z(\theta)G_{n/2} \dots G_2 G_1 $$

where $G_j$ are Clifford elements or Clifford gates.

The circuits generate expectation values which are sinusoidal functions of
$\theta$, which in the ideal (noiseless) case vary in a continuous interval
of $ E_{\rm ideal} \in [-1, 1] $.

Since (up to factors of 2) we have
$R_z(\theta) =cos(\theta) I + i \ sin(\theta) Z$, the rotated Clifford
circuit $C(\theta)$ can be written as a linear combination of just two
Clifford circuits and, therefore, it is still easy to classically simulate.

Args:
n_qubits: The number of qubits. Can be either 1 or 2.
num_cliffords: The number of Clifford group elements in the
random circuits. This is proportional to the depth per circuit.
trials: The number of random circuits at each num_cfd.
return_type: String which specifies the type of the
returned circuits. See the keys of
``mitiq.SUPPORTED_PROGRAM_TYPES`` for options. If ``None``, the
returned circuits have type ``cirq.Circuit``.
seed: An optional seed for reproducibility of $\theta$ in
$R_z(\theta)$.

Returns:
A list of rotated randomized benchmarking circuits.
"""

circuits = generate_rb_circuits(n_qubits, num_cliffords, 2 * trials)
rotated_circuits = []

rng = np.random.default_rng(seed=seed)

for circ in circuits:
rotated_circ, _ = convert_to_mitiq(circ)
Misty-W marked this conversation as resolved.
Show resolved Hide resolved
qubits = rotated_circ.all_qubits()
rads = rng.random() * np.pi
rotated_circ.insert(
len(circ) // 2, cirq.Rz(rads=rads).on_each(*qubits)
)
rotated_circuits.append(rotated_circ)

return_type = "cirq" if not return_type else return_type
return [
convert_from_mitiq(circuit, return_type)
for circuit in rotated_circuits
]
44 changes: 44 additions & 0 deletions mitiq/benchmarks/tests/test_rotated_randomized_benchmarking.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Copyright (C) Unitary Fund
#
# This source code is licensed under the GPL license (v3) found in the
# LICENSE file in the root directory of this source tree.

"""Tests for rotated randomized benchmarking circuits."""

import pytest

from mitiq import SUPPORTED_PROGRAM_TYPES
from mitiq.benchmarks.rotated_randomized_benchmarking import (
generate_rotated_rb_circuits,
)


@pytest.mark.parametrize("n_qubits", (1, 2))
def test_rotated_rb_circuits(n_qubits):
depth = 10
results = []
for trials in [5, 10]:
circuits = generate_rotated_rb_circuits(
n_qubits=n_qubits, num_cliffords=depth, trials=trials
)
for qc in circuits:
# we check the ground state population to ignore any global phase
wvf = qc.final_state_vector()
zero_prob = abs(wvf[0] ** 2)
assert -1.0001 <= zero_prob <= 1.0001
results.append(zero_prob)


@pytest.mark.parametrize("n_qubits", (1, 2))
@pytest.mark.parametrize("return_type", SUPPORTED_PROGRAM_TYPES.keys())
def test_rotated_rb_conversion(n_qubits, return_type):
depth = 10
for trials in [2, 3]:
circuits = generate_rotated_rb_circuits(
n_qubits=n_qubits,
num_cliffords=depth,
trials=trials,
return_type=return_type,
)
for qc in circuits:
assert return_type in qc.__module__