##############################################################################
# Copyright 2016-2019 Rigetti Computing
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
##############################################################################
import sys
import warnings
from typing import Any, Dict, Optional, Sequence, Tuple
import networkx as nx
if sys.version_info < (3, 7):
from pyquil.external.dataclasses import dataclass
else:
from dataclasses import dataclass
@dataclass
class QubitSpecs:
id: int
fRO: Optional[float]
f1QRB: Optional[float]
f1QRB_std_err: Optional[float]
f1Q_simultaneous_RB: Optional[float]
f1Q_simultaneous_RB_std_err: Optional[float]
T1: Optional[float]
T2: Optional[float]
fActiveReset: Optional[float]
@dataclass
class EdgeSpecs:
targets: Tuple[int, ...]
fBellState: Optional[float]
fCZ: Optional[float]
fCZ_std_err: Optional[float]
fCPHASE: Optional[float]
fCPHASE_std_err: Optional[float]
fXY: Optional[float]
fXY_std_err: Optional[float]
fISWAP: Optional[float]
fISWAP_std_err: Optional[float]
[docs]@dataclass
class Specs:
"""
Basic specifications for the device, such as gate fidelities and coherence times.
:ivar qubits_specs: The specs associated with individual qubits.
:ivar edges_specs: The specs associated with edges, or qubit-qubit pairs.
"""
qubits_specs: Sequence[QubitSpecs]
edges_specs: Sequence[EdgeSpecs]
def f1QRBs(self) -> Dict[int, Optional[float]]:
"""
Get a dictionary of single-qubit randomized benchmarking fidelities (for individual gate
operation, normalized to unity) from the specs, keyed by qubit index.
:return: A dictionary of 1Q RB fidelities, normalized to unity.
"""
return {qs.id: qs.f1QRB for qs in self.qubits_specs}
def f1QRB_std_errs(self) -> Dict[int, Optional[float]]:
"""
Get a dictionary of the standard errors of single-qubit randomized
benchmarking fidelities (for individual gate operation, normalized to unity)
from the specs, keyed by qubit index.
:return: A dictionary of 1Q RB fidelity standard errors, normalized to unity.
"""
return {qs.id: qs.f1QRB_std_err for qs in self.qubits_specs}
def f1Q_simultaneous_RBs(self) -> Dict[int, Optional[float]]:
"""
Get a dictionary of single-qubit randomized benchmarking fidelities (for simultaneous gate
operation across the chip, normalized to unity) from the specs, keyed by qubit index.
:return: A dictionary of simultaneous 1Q RB fidelities, normalized to unity.
"""
return {qs.id: qs.f1Q_simultaneous_RB for qs in self.qubits_specs}
def f1Q_simultaneous_RB_std_errs(self) -> Dict[int, Optional[float]]:
"""
Get a dictionary of the standard errors of single-qubit randomized
benchmarking fidelities (for simultaneous gate operation across the chip, normalized to
unity) from the specs, keyed by qubit index.
:return: A dictionary of simultaneous 1Q RB fidelity standard errors, normalized to unity.
"""
return {qs.id: qs.f1Q_simultaneous_RB_std_err for qs in self.qubits_specs}
def fROs(self) -> Dict[int, Optional[float]]:
"""
Get a dictionary of single-qubit readout fidelities (normalized to unity)
from the specs, keyed by qubit index.
:return: A dictionary of RO fidelities, normalized to unity.
"""
return {qs.id: qs.fRO for qs in self.qubits_specs}
def fActiveResets(self) -> Dict[int, Optional[float]]:
"""
Get a dictionary of single-qubit active reset fidelities (normalized to unity) from the
specs, keyed by qubit index.
:return: A dictionary of reset fidelities, normalized to unity.
"""
return {qs.id: qs.fActiveReset for qs in self.qubits_specs}
def T1s(self) -> Dict[int, Optional[float]]:
"""
Get a dictionary of T1s (in seconds) from the specs, keyed by qubit index.
:return: A dictionary of T1s, in seconds.
"""
return {qs.id: qs.T1 for qs in self.qubits_specs}
def T2s(self) -> Dict[int, Optional[float]]:
"""
Get a dictionary of T2s (in seconds) from the specs, keyed by qubit index.
:return: A dictionary of T2s, in seconds.
"""
return {qs.id: qs.T2 for qs in self.qubits_specs}
def fBellStates(self) -> Dict[Tuple[int, ...], Optional[float]]:
"""
Get a dictionary of two-qubit Bell state fidelities (normalized to unity)
from the specs, keyed by targets (qubit-qubit pairs).
:return: A dictionary of Bell state fidelities, normalized to unity.
"""
warnings.warn(
DeprecationWarning(
"fBellState device specs have been deprecated, and will "
"be removed in release v2.13 (targeted for October 2019)"
)
)
return {tuple(es.targets): es.fBellState for es in self.edges_specs}
def fCZs(self) -> Dict[Tuple[int, ...], Optional[float]]:
"""
Get a dictionary of CZ fidelities (normalized to unity) from the specs,
keyed by targets (qubit-qubit pairs).
:return: A dictionary of CZ fidelities, normalized to unity.
"""
return {tuple(es.targets): es.fCZ for es in self.edges_specs}
def fISWAPs(self) -> Dict[Tuple[int, ...], Optional[float]]:
"""
Get a dictionary of ISWAP fidelities (normalized to unity) from the specs,
keyed by targets (qubit-qubit pairs).
:return: A dictionary of ISWAP fidelities, normalized to unity.
"""
return {tuple(es.targets): es.fISWAP for es in self.edges_specs}
def fISWAP_std_errs(self) -> Dict[Tuple[int, ...], Optional[float]]:
"""
Get a dictionary of the standard errors of the ISWAP fidelities from the specs,
keyed by targets (qubit-qubit pairs).
:return: A dictionary of ISWAP fidelities, normalized to unity.
"""
return {tuple(es.targets): es.fISWAP_std_err for es in self.edges_specs}
def fXYs(self) -> Dict[Tuple[int, ...], Optional[float]]:
"""
Get a dictionary of XY(pi) fidelities (normalized to unity) from the specs,
keyed by targets (qubit-qubit pairs).
:return: A dictionary of XY/2 fidelities, normalized to unity.
"""
return {tuple(es.targets): es.fXY for es in self.edges_specs}
def fXY_std_errs(self) -> Dict[Tuple[int, ...], Optional[float]]:
"""
Get a dictionary of the standard errors of the XY fidelities from the specs,
keyed by targets (qubit-qubit pairs).
:return: A dictionary of XY fidelities, normalized to unity.
"""
return {tuple(es.targets): es.fXY_std_err for es in self.edges_specs}
def fCZ_std_errs(self) -> Dict[Tuple[int, ...], Optional[float]]:
"""
Get a dictionary of the standard errors of the CZ fidelities from the specs,
keyed by targets (qubit-qubit pairs).
:return: A dictionary of CZ fidelities, normalized to unity.
"""
return {tuple(es.targets): es.fCZ_std_err for es in self.edges_specs}
def fCPHASEs(self) -> Dict[Tuple[int, ...], Optional[float]]:
"""
Get a dictionary of CPHASE fidelities (normalized to unity) from the specs,
keyed by targets (qubit-qubit pairs).
:return: A dictionary of CPHASE fidelities, normalized to unity.
"""
warnings.warn(
DeprecationWarning(
"fCPHASE device specs have been deprecated, and will "
"be removed in release v2.13 (targeted for October 2019)"
)
)
return {tuple(es.targets): es.fCPHASE for es in self.edges_specs}
def to_dict(self) -> Dict[str, Any]:
"""
Create a JSON-serializable representation of the device Specs.
The dictionary representation is of the form::
{
'1Q': {
"0": {
"f1QRB": 0.99,
"f1QRB_std_err": 0.02,
"T1": 20e-6,
...
},
"1": {
"f1QRB": 0.989,
"f1QRB_std_err": 0.015,
"T1": 19e-6,
...
},
...
},
'2Q': {
"1-4": {
"fBellState": 0.93,
"fCZ": 0.92,
"fCZ_std_err": 0.03,
"fCPHASE": 0.91
},
"1-5": {
"fBellState": 0.9,
"fCZ": 0.89,
"fCZ_std_err": 0.05,
"fCPHASE": 0.88
},
...
},
...
}
:return: A dctionary representation of self.
"""
return {
"1Q": {
"{}".format(qs.id): {
"f1QRB": qs.f1QRB,
"f1QRB_std_err": qs.f1QRB_std_err,
"f1Q_simultaneous_RB": qs.f1Q_simultaneous_RB,
"f1Q_simultaneous_RB_std_err": qs.f1Q_simultaneous_RB_std_err,
"fRO": qs.fRO,
"T1": qs.T1,
"T2": qs.T2,
"fActiveReset": qs.fActiveReset,
}
for qs in self.qubits_specs
},
"2Q": {
"{}-{}".format(*es.targets): {
"fBellState": es.fBellState,
"fCZ": es.fCZ,
"fCZ_std_err": es.fCZ_std_err,
"fCPHASE": es.fCPHASE,
"fCPHASE_std_err": es.fCPHASE_std_err,
"fXY": es.fXY,
"fXY_std_err": es.fXY_std_err,
"fISWAP": es.fISWAP,
"fISWAP_std_err": es.fISWAP_std_err,
}
for es in self.edges_specs
},
}
@staticmethod
def from_dict(d: Dict[str, Any]) -> "Specs":
"""
Re-create the Specs from a dictionary representation.
:param d: The dictionary representation.
:return: The restored Specs.
"""
return Specs(
qubits_specs=sorted(
[
QubitSpecs(
id=int(q),
fRO=qspecs.get("fRO"),
f1QRB=qspecs.get("f1QRB"),
f1QRB_std_err=qspecs.get("f1QRB_std_err"),
f1Q_simultaneous_RB=qspecs.get("f1Q_simultaneous_RB"),
f1Q_simultaneous_RB_std_err=qspecs.get("f1Q_simultaneous_RB_std_err"),
T1=qspecs.get("T1"),
T2=qspecs.get("T2"),
fActiveReset=qspecs.get("fActiveReset"),
)
for q, qspecs in d["1Q"].items()
],
key=lambda qubit_specs: qubit_specs.id,
),
edges_specs=sorted(
[
EdgeSpecs(
targets=tuple(int(q) for q in e.split("-")),
fBellState=especs.get("fBellState"),
fCZ=especs.get("fCZ"),
fCZ_std_err=especs.get("fCZ_std_err"),
fCPHASE=especs.get("fCPHASE"),
fCPHASE_std_err=especs.get("fCPHASE_std_err"),
fXY=especs.get("fXY"),
fXY_std_err=especs.get("fXY_std_err"),
fISWAP=especs.get("fISWAP"),
fISWAP_std_err=especs.get("fISWAP_std_err"),
)
for e, especs in d["2Q"].items()
],
key=lambda edge_specs: edge_specs.targets,
),
)
[docs]def specs_from_graph(graph: nx.Graph) -> Specs:
"""
Generate a Specs object from a NetworkX graph with placeholder values for the actual specs.
:param graph: The graph
"""
qspecs = [
QubitSpecs(
id=q,
fRO=0.90,
f1QRB=0.99,
f1QRB_std_err=0.01,
f1Q_simultaneous_RB=0.99,
f1Q_simultaneous_RB_std_err=0.02,
T1=30e-6,
T2=30e-6,
fActiveReset=0.99,
)
for q in graph.nodes
]
especs = [
EdgeSpecs(
targets=(q1, q2),
fBellState=0.90,
fCZ=0.90,
fCZ_std_err=0.05,
fCPHASE=0.80,
fCPHASE_std_err=0.05,
fXY=0.86,
fXY_std_err=0.05,
fISWAP=0.90,
fISWAP_std_err=0.05,
)
for q1, q2 in graph.edges
]
return Specs(qspecs, especs)