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(0), gates.H(0), gates.CZ(0, 1)}
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]

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
25 changes: 22 additions & 3 deletions src/qibo/tomography/gate_set_tomography.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from functools import cache
from inspect import signature
from itertools import product
from random import Random
from typing import List, Union
Expand Down Expand Up @@ -227,7 +228,12 @@ def GST(
"""Runs Gate Set Tomography on the input ``gate_set``.

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]
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 @@ -286,12 +292,25 @@ def GST(

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

angle_names = [name for name in init_args if name in {"theta", "phi"}]

angle_values = {}
for name, value in zip(angle_names, params): # Zip ensures correct order
angle_values[name] = value

if "q" in init_args:
nqubits = 1
elif "q0" in init_args and "q1" in init_args and "q2" not in init_args:
nqubits = 2
else:
raise_error(
RuntimeError,
f"Gate {gate} is not supported for `GST`, only 1- and 2-qubits gates are supported.",
)
gate = gate[0](*range(nqubits), **angle_values)

matrices.append(
_gate_tomography(
Expand Down
26 changes: 20 additions & 6 deletions tests/test_tomography_gate_set_tomography.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,11 +218,18 @@ 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
]

if len(target_gates) == 4:
empty_1q, empty_2q, *approx_gates = GST(
gate_set=target_gates,
gate_set=gate_set,
nshots=int(1e4),
include_empty=True,
pauli_liouville=pauli_liouville,
Expand All @@ -244,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=target_gates, # [g.__class__ for g in target_gates],
gate_set=gate_set,
nshots=int(1e4),
include_empty=True,
pauli_liouville=pauli_liouville,
Expand All @@ -268,10 +275,17 @@ 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
]
# standard not transpiled GST
empty_1q, empty_2q, *approx_gates = GST(
gate_set=target_gates,
gate_set=gate_set,
nshots=int(1e4),
include_empty=True,
pauli_liouville=False,
Expand All @@ -291,7 +305,7 @@ def test_GST_with_transpiler(backend, star_connectivity):
)
# transpiled GST
T_empty_1q, T_empty_2q, *T_approx_gates = GST(
gate_set=target_gates,
gate_set=gate_set,
nshots=int(1e4),
include_empty=True,
pauli_liouville=False,
Expand Down
Loading