import json
from typing import Dict, List, Union, Optional, Literal
from deprecated.sphinx import deprecated
from rpcq.messages import TargetDevice as TargetQuantumProcessor
from dataclasses import dataclass, field
JsonValue = Union[type(None), bool, int, float, str, List["JsonValue"], Dict[str, "JsonValue"]]
[docs]@dataclass
class Operator:
operator: Optional[str] = None
duration: Optional[float] = None
fidelity: Optional[float] = None
def __post_init__(self):
self.duration = float(self.duration) if self.duration is not None else None
self.fidelity = float(self.fidelity) if self.fidelity is not None else None
def _dict(self) -> Dict[str, JsonValue]:
if type(self) is Operator:
raise ValueError("Should be a subclass")
return dict(
operator=self.operator,
duration=self.duration,
fidelity=self.fidelity,
)
[docs] @deprecated(
version="4.6.2",
reason="No longer requires serialization of RPCQ objects and is dropping Pydantic as a dependency.", # noqa: E501
)
def dict(self):
return self._dict()
@classmethod
def _parse_obj(cls, dictionary: Dict):
return Operator(**dictionary)
[docs] @classmethod
@deprecated(
version="4.6.2",
reason="No longer requires serialization of RPCQ objects and is dropping Pydantic as a dependency.", # noqa: E501
)
def parse_obj(cls, dictionary: Dict):
return cls._parse_obj(dictionary)
[docs]@dataclass
class MeasureInfo(Operator):
qubit: Optional[Union[int, str]] = None
target: Optional[Union[int, str]] = None
operator_type: Literal["measure"] = "measure"
def __post_init__(self):
self.qubit = str(self.qubit)
def _dict(self) -> Dict[str, JsonValue]:
return dict(
operator_type=self.operator_type,
operator=self.operator,
duration=self.duration,
fidelity=self.fidelity,
qubit=self.qubit,
target=self.target,
)
[docs] @deprecated(
version="4.7",
reason="No longer requires serialization of RPCQ objects and is dropping Pydantic as a dependency.", # noqa: E501
)
def dict(self):
return self._dict()
@classmethod
def _parse_obj(cls, dictionary: Dict) -> "MeasureInfo":
return MeasureInfo(
operator=dictionary.get("operator"),
duration=dictionary.get("duration"),
fidelity=dictionary.get("fidelity"),
qubit=dictionary.get("qubit"),
target=dictionary.get("target"),
)
[docs] @classmethod
@deprecated(
version="4.6.2",
reason="No longer requires serialization of RPCQ objects and is dropping Pydantic as a dependency.", # noqa: E501
)
def parse_obj(cls, dictionary: Dict):
return cls._parse_obj(dictionary)
[docs]@dataclass
class GateInfo(Operator):
parameters: List[Union[float, str]] = field(default_factory=list)
arguments: List[Union[int, str]] = field(default_factory=list)
operator_type: Literal["gate"] = "gate"
def _dict(self) -> Dict[str, JsonValue]:
return dict(
operator_type=self.operator_type,
operator=self.operator,
duration=self.duration,
fidelity=self.fidelity,
parameters=self.parameters,
arguments=self.arguments,
)
[docs] @deprecated(
version="4.6.2",
reason="No longer requires serialization of RPCQ objects and is dropping Pydantic as a dependency.", # noqa: E501
)
def dict(self):
return self._dict()
@classmethod
def _parse_obj(cls, dictionary: dict) -> "GateInfo":
return GateInfo(
operator=dictionary.get("operator"),
duration=dictionary.get("duration"),
fidelity=dictionary.get("fidelity"),
parameters=dictionary["parameters"],
arguments=dictionary["arguments"],
)
[docs] @classmethod
@deprecated(
version="4.6.2",
reason="No longer requires serialization of RPCQ objects and is dropping Pydantic as a dependency.", # noqa: E501
)
def parse_obj(cls, dictionary: Dict):
return cls._parse_obj(dictionary)
def _parse_operator(dictionary: dict) -> Union[GateInfo, MeasureInfo]:
operator_type = dictionary["operator_type"]
if operator_type == "measure":
return MeasureInfo._parse_obj(dictionary)
if operator_type == "gate":
return GateInfo._parse_obj(dictionary)
raise ValueError("Should be a subclass of Operator")
[docs]@dataclass
class Qubit:
id: int
dead: Optional[bool] = False
gates: List[Union[GateInfo, MeasureInfo]] = field(default_factory=list)
def _dict(self) -> Dict[str, JsonValue]:
encoding = dict(id=self.id, gates=[g._dict() for g in self.gates])
if self.dead:
encoding["dead"] = self.dead
return encoding
[docs] @deprecated(
version="4.6.2",
reason="No longer requires serialization of RPCQ objects and is dropping Pydantic as a dependency.", # noqa: E501
)
def dict(self):
return self._dict()
@classmethod
def _parse_obj(cls, dictionary: Dict) -> "Qubit":
return Qubit(
id=dictionary["id"],
dead=bool(dictionary.get("dead")),
gates=[_parse_operator(v) for v in dictionary.get("gates", [])],
)
[docs] @classmethod
@deprecated(
version="4.6.2",
reason="No longer requires serialization of RPCQ objects and is dropping Pydantic as a dependency.", # noqa: E501
)
def parse_obj(cls, dictionary: Dict):
return cls._parse_obj(dictionary)
[docs]@dataclass
class Edge:
ids: List[int]
dead: Optional[bool] = False
gates: List[GateInfo] = field(default_factory=list)
def _dict(self) -> Dict[str, JsonValue]:
encoding = dict(ids=self.ids, gates=[g._dict() for g in self.gates])
if self.dead:
encoding["dead"] = self.dead
return encoding
[docs] @deprecated(
version="4.6.2",
reason="No longer requires serialization of RPCQ objects and is dropping Pydantic as a dependency.", # noqa: E501
)
def dict(self):
return self._dict()
@classmethod
def _parse_obj(cls, dictionary: dict) -> "Edge":
return Edge(
ids=dictionary["ids"],
dead=bool(dictionary.get("dead")),
gates=[GateInfo._parse_obj(g) for g in dictionary.get("gates", [])],
)
[docs] @classmethod
@deprecated(
version="4.6.2",
reason="No longer requires serialization of RPCQ objects and is dropping Pydantic as a dependency.", # noqa: E501
)
def parse_obj(cls, dictionary: Dict):
return cls._parse_obj(dictionary)
[docs]@dataclass
class CompilerISA:
qubits: Dict[str, Qubit] = field(default_factory=dict)
edges: Dict[str, Edge] = field(default_factory=dict)
def _dict(self, by_alias=False) -> Dict[str, JsonValue]:
return {
"1Q" if by_alias else "qubits": {k: q._dict() for k, q in self.qubits.items()},
"2Q" if by_alias else "edges": {k: e._dict() for k, e in self.edges.items()},
}
[docs] @deprecated(
version="4.6.2",
reason="No longer requires serialization of RPCQ objects and is dropping Pydantic as a dependency.", # noqa: E501
)
def dict(self, by_alias=False):
return self._dict(by_alias=by_alias)
@classmethod
def _parse_obj(cls, dictionary: Dict):
qubit_dict = dictionary.get("1Q", {})
edge_dict = dictionary.get("2Q", {})
return CompilerISA(
qubits={k: Qubit._parse_obj(v) for k, v in qubit_dict.items()},
edges={k: Edge._parse_obj(v) for k, v in edge_dict.items()},
)
[docs] @classmethod
@deprecated(
version="4.6.2",
reason="No longer requires serialization of RPCQ objects and is dropping Pydantic as a dependency.", # noqa: E501
)
def parse_obj(cls, dictionary: Dict):
return cls._parse_obj(dictionary)
[docs] @classmethod
@deprecated(
version="4.6.2",
reason="No longer requires serialization of RPCQ objects and is dropping Pydantic as a dependency.", # noqa: E501
)
def parse_file(cls, filename: str):
with open(filename, "r") as file:
json_dict = json.load(file)
return cls._parse_obj(json_dict)
[docs]def add_qubit(quantum_processor: CompilerISA, node_id: int) -> Qubit:
if node_id not in quantum_processor.qubits:
quantum_processor.qubits[str(node_id)] = Qubit(id=node_id)
return quantum_processor.qubits[str(node_id)]
[docs]def get_qubit(quantum_processor: CompilerISA, node_id: int) -> Optional[Qubit]:
return quantum_processor.qubits.get(str(node_id))
[docs]def make_edge_id(qubit1: int, qubit2: int) -> str:
return "-".join([str(qubit) for qubit in sorted([qubit1, qubit2])])
[docs]def add_edge(quantum_processor: CompilerISA, qubit1: int, qubit2: int) -> Edge:
edge_id = make_edge_id(qubit1, qubit2)
if edge_id not in quantum_processor.edges:
quantum_processor.edges[edge_id] = Edge(ids=sorted([qubit1, qubit2]))
return quantum_processor.edges[edge_id]
[docs]def get_edge(quantum_processor: CompilerISA, qubit1: int, qubit2: int) -> Optional[Edge]:
edge_id = make_edge_id(qubit1, qubit2)
return quantum_processor.edges.get(edge_id)
[docs]def compiler_isa_to_target_quantum_processor(compiler_isa: CompilerISA) -> TargetQuantumProcessor:
return TargetQuantumProcessor(isa=compiler_isa.dict(by_alias=True), specs={})
[docs]class Supported1QGate:
I = "I"
RX = "RX"
RZ = "RZ"
MEASURE = "MEASURE"
WILDCARD = "WILDCARD"
[docs]class Supported2QGate:
WILDCARD = "WILDCARD"
CZ = "CZ"
ISWAP = "ISWAP"
CPHASE = "CPHASE"
XY = "XY"