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

Updating GST to accept parameterised gates #1534

Merged
merged 9 commits into from
Jan 17, 2025
3 changes: 2 additions & 1 deletion doc/source/code-examples/advancedexamples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2242,7 +2242,8 @@ Let's first define the set of gates we want to estimate:

from qibo import gates

gate_set = {gates.X, gates.H, gates.CZ}
target_gates = [gates.RX(0, np.pi/3), gates.Z(0), gates.PRX(0, np.pi/2, np.pi/3), gates.GPI(0, np.pi/7), gates.CNOT(0,1)]
BrunoLiegiBastonLiegi marked this conversation as resolved.
Show resolved Hide resolved
gate_set = [(g.__class__, [g.parameters[i] for i in range(len(g.parameters))]) if g.parameters else (g.__class__, []) for g in target_gates]
BrunoLiegiBastonLiegi marked this conversation as resolved.
Show resolved Hide resolved

For simulation purposes we can define a noise model. Naturally this is not needed when running on real quantum hardware, which is intrinsically noisy. For example, we can suppose that the three gates we want to estimate are going to be noisy:

Expand Down
32 changes: 27 additions & 5 deletions src/qibo/tomography/gate_set_tomography.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
from functools import cache
from inspect import signature
from itertools import product
from random import Random
BrunoLiegiBastonLiegi marked this conversation as resolved.
Show resolved Hide resolved
from typing import List, Union

import numpy as np
from sympy import S

from qibo import Circuit, gates, symbols
from qibo.backends import _check_backend, get_transpiler
from qibo.backends import _check_backend
from qibo.config import raise_error
from qibo.hamiltonians import SymbolicHamiltonian
from qibo.transpiler.optimizer import Preprocessing
Expand Down Expand Up @@ -227,7 +228,12 @@ def GST(
"""Runs Gate Set Tomography on the input ``gate_set``.
mho291 marked this conversation as resolved.
Show resolved Hide resolved

Args:
gate_set (tuple or set or list): set of :class:`qibo.gates.Gate` to run GST on.
gate_set (tuple or set or list): set of :class:`qibo.gates.Gate` and parameters to run
GST on.
E.g. target_gates = [gates.RX(0, np.pi/3), gates.Z(0), gates.PRX(0, np.pi/2, np.pi/3),
gates.GPI(0, np.pi/7), gates.CNOT(0,1)]
gate_set = [(g.__class__, [g.parameters[i] for i in range(len(g.parameters))])
if g.parameters else (g.__class__, []) for g in target_gates]
BrunoLiegiBastonLiegi marked this conversation as resolved.
Show resolved Hide resolved
nshots (int, optional): number of shots used in Gate Set Tomography per gate.
Defaults to :math:`10^{4}`.
noise_model (:class:`qibo.noise.NoiseModel`, optional): noise model applied to simulate
Expand Down Expand Up @@ -260,7 +266,15 @@ def GST(
backend = _check_backend(backend)

if backend.name == "qibolab" and transpiler is None: # pragma: no cover
transpiler = get_transpiler()
transpiler = Passes(
connectivity=backend.platform.topology,
passes=[
Preprocessing(backend.platform.topology),
Random(backend.platform.topology),
Sabre(backend.platform.topology),
Unroller(NativeGates.default()),
],
)

matrices = []
empty_matrices = []
Expand All @@ -278,7 +292,15 @@ def GST(

for gate in gate_set:
if gate is not None:
init_args = signature(gate).parameters
init_args = signature(gate[0]).parameters
params = gate[1]

angle_names = [name for name in init_args if name in {"theta", "phi"}]
MatteoRobbiati marked this conversation as resolved.
Show resolved Hide resolved

angle_values = {}
for name, value in zip(angle_names, params): # Zip ensures correct order
angle_values[name] = value
BrunoLiegiBastonLiegi marked this conversation as resolved.
Show resolved Hide resolved

if "q" in init_args:
nqubits = 1
elif "q0" in init_args and "q1" in init_args and "q2" not in init_args:
Expand All @@ -288,7 +310,7 @@ def GST(
RuntimeError,
f"Gate {gate} is not supported for `GST`, only 1- and 2-qubits gates are supported.",
mho291 marked this conversation as resolved.
Show resolved Hide resolved
)
gate = gate(*range(nqubits))
gate = gate[0](*range(nqubits), **angle_values)
BrunoLiegiBastonLiegi marked this conversation as resolved.
Show resolved Hide resolved

matrices.append(
_gate_tomography(
Expand Down
27 changes: 22 additions & 5 deletions tests/test_tomography_gate_set_tomography.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,10 @@ def test_gate_tomography_noise_model(backend):

@pytest.mark.parametrize(
"target_gates",
[[gates.SX(0), gates.Z(0), gates.CY(0, 1)], [gates.TOFFOLI(0, 1, 2)]],
[
[gates.SX(0), gates.Z(0), gates.PRX(0, np.pi, np.pi / 2), gates.CY(0, 1)],
[gates.TOFFOLI(0, 1, 2)],
],
)
@pytest.mark.parametrize("pauli_liouville", [False, True])
def test_GST(backend, target_gates, pauli_liouville):
Expand All @@ -215,9 +218,16 @@ def test_GST(backend, target_gates, pauli_liouville):
target_matrices = [
to_pauli_liouville(m, normalize=True, backend=backend) for m in target_matrices
]
gate_set = [g.__class__ for g in target_gates]
gate_set = [
(
(g.__class__, [g.parameters[i] for i in range(len(g.parameters))])
if g.parameters
else (g.__class__, [])
)
for g in target_gates
]
BrunoLiegiBastonLiegi marked this conversation as resolved.
Show resolved Hide resolved

if len(target_gates) == 3:
if len(target_gates) == 4:
empty_1q, empty_2q, *approx_gates = GST(
gate_set=gate_set,
nshots=int(1e4),
Expand All @@ -241,7 +251,7 @@ def test_GST(backend, target_gates, pauli_liouville):
else:
with pytest.raises(RuntimeError):
empty_1q, empty_2q, *approx_gates = GST(
gate_set=[g.__class__ for g in target_gates],
gate_set=gate_set,
nshots=int(1e4),
include_empty=True,
pauli_liouville=pauli_liouville,
Expand All @@ -265,7 +275,14 @@ def test_GST_with_transpiler(backend, star_connectivity):
import networkx as nx

target_gates = [gates.SX(0), gates.Z(0), gates.CNOT(0, 1)]
gate_set = [g.__class__ for g in target_gates]
gate_set = [
(
(g.__class__, [g.parameters[i] for i in range(len(g.parameters))])
if g.parameters
else (g.__class__, [])
)
for g in target_gates
]
BrunoLiegiBastonLiegi marked this conversation as resolved.
Show resolved Hide resolved
# standard not transpiled GST
empty_1q, empty_2q, *approx_gates = GST(
gate_set=gate_set,
Expand Down
Loading