From 1a7be34ab79a9eafb1a02e432ca729b35764a220 Mon Sep 17 00:00:00 2001 From: Spencer Churchill <25377399+splch@users.noreply.github.com> Date: Fri, 1 May 2026 18:25:57 -0700 Subject: [PATCH] Restructure Gate_QisGate as discriminated union and add pauliexp Replace the flat-bag Gate_QisGate with a oneOf + discriminator(propertyName: gate) tagged union, one variant per gate. The old shape declared {gate, target, targets, control, controls, rotation} with additionalProperties: false, which made every pauliexp payload (terms/coefficients/time) violate the schema and let nonsensical combinations validate. Adds 20 per-gate variant schemas including Gate_Pauliexp(targets, terms, coefficients, time). Qubit indices are typed integer/int32/minimum: 0 instead of number/double. Each variant pins gate to a single-value enum so the generated client gets Literal["x"] typing. Test fixtures using singular target/control are updated to the canonical list form (targets: [t], controls: [c]). --- ionq_core/models/__init__.py | 82 ++++- ionq_core/models/gate_cnot.py | 91 ++++++ ionq_core/models/gate_cnot_gate.py | 14 + ionq_core/models/gate_h.py | 94 ++++++ ionq_core/models/gate_h_gate.py | 14 + ionq_core/models/gate_not.py | 93 ++++++ ionq_core/models/gate_not_gate.py | 14 + ionq_core/models/gate_pauliexp.py | 131 ++++++++ ionq_core/models/gate_pauliexp_gate.py | 14 + ionq_core/models/gate_qis_gate.py | 124 -------- ionq_core/models/gate_rx.py | 102 ++++++ ionq_core/models/gate_rx_gate.py | 14 + ionq_core/models/gate_ry.py | 102 ++++++ ionq_core/models/gate_ry_gate.py | 14 + ionq_core/models/gate_rz.py | 102 ++++++ ionq_core/models/gate_rz_gate.py | 14 + ionq_core/models/gate_s.py | 94 ++++++ ionq_core/models/gate_s_gate.py | 14 + ionq_core/models/gate_si.py | 95 ++++++ ionq_core/models/gate_si_gate.py | 14 + ionq_core/models/gate_swap.py | 80 +++++ ionq_core/models/gate_swap_gate.py | 14 + ionq_core/models/gate_t.py | 94 ++++++ ionq_core/models/gate_t_gate.py | 14 + ionq_core/models/gate_ti.py | 95 ++++++ ionq_core/models/gate_ti_gate.py | 14 + ionq_core/models/gate_v.py | 95 ++++++ ionq_core/models/gate_v_gate.py | 14 + ionq_core/models/gate_vi.py | 95 ++++++ ionq_core/models/gate_vi_gate.py | 14 + ionq_core/models/gate_x.py | 97 ++++++ ionq_core/models/gate_x_gate.py | 14 + ionq_core/models/gate_xx.py | 88 ++++++ ionq_core/models/gate_xx_gate.py | 14 + ionq_core/models/gate_y.py | 94 ++++++ ionq_core/models/gate_y_gate.py | 14 + ionq_core/models/gate_yy.py | 88 ++++++ ionq_core/models/gate_yy_gate.py | 14 + ionq_core/models/gate_z.py | 94 ++++++ ionq_core/models/gate_z_gate.py | 14 + ionq_core/models/gate_zz.py | 90 ++++++ ionq_core/models/gate_zz_gate.py | 14 + ionq_core/models/qis_circuit.py | 312 ++++++++++++++++++- ionq_core/models/qis_circuit_input.py | 310 +++++++++++++++++- openapi-overlay.yaml | 397 +++++++++++++++++++++++- tests/integration/test_simulator_job.py | 4 +- tests/test_api.py | 2 +- 47 files changed, 3276 insertions(+), 149 deletions(-) create mode 100644 ionq_core/models/gate_cnot.py create mode 100644 ionq_core/models/gate_cnot_gate.py create mode 100644 ionq_core/models/gate_h.py create mode 100644 ionq_core/models/gate_h_gate.py create mode 100644 ionq_core/models/gate_not.py create mode 100644 ionq_core/models/gate_not_gate.py create mode 100644 ionq_core/models/gate_pauliexp.py create mode 100644 ionq_core/models/gate_pauliexp_gate.py delete mode 100644 ionq_core/models/gate_qis_gate.py create mode 100644 ionq_core/models/gate_rx.py create mode 100644 ionq_core/models/gate_rx_gate.py create mode 100644 ionq_core/models/gate_ry.py create mode 100644 ionq_core/models/gate_ry_gate.py create mode 100644 ionq_core/models/gate_rz.py create mode 100644 ionq_core/models/gate_rz_gate.py create mode 100644 ionq_core/models/gate_s.py create mode 100644 ionq_core/models/gate_s_gate.py create mode 100644 ionq_core/models/gate_si.py create mode 100644 ionq_core/models/gate_si_gate.py create mode 100644 ionq_core/models/gate_swap.py create mode 100644 ionq_core/models/gate_swap_gate.py create mode 100644 ionq_core/models/gate_t.py create mode 100644 ionq_core/models/gate_t_gate.py create mode 100644 ionq_core/models/gate_ti.py create mode 100644 ionq_core/models/gate_ti_gate.py create mode 100644 ionq_core/models/gate_v.py create mode 100644 ionq_core/models/gate_v_gate.py create mode 100644 ionq_core/models/gate_vi.py create mode 100644 ionq_core/models/gate_vi_gate.py create mode 100644 ionq_core/models/gate_x.py create mode 100644 ionq_core/models/gate_x_gate.py create mode 100644 ionq_core/models/gate_xx.py create mode 100644 ionq_core/models/gate_xx_gate.py create mode 100644 ionq_core/models/gate_y.py create mode 100644 ionq_core/models/gate_y_gate.py create mode 100644 ionq_core/models/gate_yy.py create mode 100644 ionq_core/models/gate_yy_gate.py create mode 100644 ionq_core/models/gate_z.py create mode 100644 ionq_core/models/gate_z_gate.py create mode 100644 ionq_core/models/gate_zz.py create mode 100644 ionq_core/models/gate_zz_gate.py diff --git a/ionq_core/models/__init__.py b/ionq_core/models/__init__.py index 3c7d117..51c1145 100644 --- a/ionq_core/models/__init__.py +++ b/ionq_core/models/__init__.py @@ -33,8 +33,47 @@ from .error import Error from .failure import Failure from .failure_code import FailureCode +from .gate_cnot import GateCnot +from .gate_cnot_gate import GateCnotGate +from .gate_h import GateH +from .gate_h_gate import GateHGate from .gate_native_gate import GateNativeGate -from .gate_qis_gate import GateQisGate +from .gate_not import GateNot +from .gate_not_gate import GateNotGate +from .gate_pauliexp import GatePauliexp +from .gate_pauliexp_gate import GatePauliexpGate +from .gate_rx import GateRx +from .gate_rx_gate import GateRxGate +from .gate_ry import GateRy +from .gate_ry_gate import GateRyGate +from .gate_rz import GateRz +from .gate_rz_gate import GateRzGate +from .gate_s import GateS +from .gate_s_gate import GateSGate +from .gate_si import GateSi +from .gate_si_gate import GateSiGate +from .gate_swap import GateSwap +from .gate_swap_gate import GateSwapGate +from .gate_t import GateT +from .gate_t_gate import GateTGate +from .gate_ti import GateTi +from .gate_ti_gate import GateTiGate +from .gate_v import GateV +from .gate_v_gate import GateVGate +from .gate_vi import GateVi +from .gate_vi_gate import GateViGate +from .gate_x import GateX +from .gate_x_gate import GateXGate +from .gate_xx import GateXX +from .gate_xx_gate import GateXXGate +from .gate_y import GateY +from .gate_y_gate import GateYGate +from .gate_yy import GateYY +from .gate_yy_gate import GateYYGate +from .gate_z import GateZ +from .gate_z_gate import GateZGate +from .gate_zz import GateZZ +from .gate_zz_gate import GateZZGate from .generic_quantum_function_input import GenericQuantumFunctionInput from .generic_quantum_function_input_data import GenericQuantumFunctionInputData from .get_backend_backend import GetBackendBackend @@ -145,8 +184,47 @@ "Error", "Failure", "FailureCode", + "GateCnot", + "GateCnotGate", + "GateH", + "GateHGate", "GateNativeGate", - "GateQisGate", + "GateNot", + "GateNotGate", + "GatePauliexp", + "GatePauliexpGate", + "GateRx", + "GateRxGate", + "GateRy", + "GateRyGate", + "GateRz", + "GateRzGate", + "GateS", + "GateSGate", + "GateSi", + "GateSiGate", + "GateSwap", + "GateSwapGate", + "GateT", + "GateTGate", + "GateTi", + "GateTiGate", + "GateV", + "GateVGate", + "GateVi", + "GateViGate", + "GateX", + "GateXGate", + "GateXX", + "GateXXGate", + "GateY", + "GateYGate", + "GateYY", + "GateYYGate", + "GateZ", + "GateZGate", + "GateZZ", + "GateZZGate", "GenericQuantumFunctionInput", "GenericQuantumFunctionInputData", "GetBackendBackend", diff --git a/ionq_core/models/gate_cnot.py b/ionq_core/models/gate_cnot.py new file mode 100644 index 0000000..91aa4cc --- /dev/null +++ b/ionq_core/models/gate_cnot.py @@ -0,0 +1,91 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +from ..models.gate_cnot_gate import check_gate_cnot_gate +from ..models.gate_cnot_gate import GateCnotGate +from typing import cast + + + + + + +T = TypeVar("T", bound="GateCnot") + + + +@_attrs_define +class GateCnot: + """ Controlled-NOT with one control and one target. + + Attributes: + gate (GateCnotGate): + targets (list[int]): The single qubit the gate acts on. + controls (list[int]): The single control qubit. + """ + + gate: GateCnotGate + targets: list[int] + controls: list[int] + + + + + + def to_dict(self) -> dict[str, Any]: + gate: str = self.gate + + targets = self.targets + + + + controls = self.controls + + + + + field_dict: dict[str, Any] = {} + + field_dict.update({ + "gate": gate, + "targets": targets, + "controls": controls, + }) + + return field_dict + + + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + gate = check_gate_cnot_gate(d.pop("gate")) + + + + + targets = cast(list[int], d.pop("targets")) + + + controls = cast(list[int], d.pop("controls")) + + + gate_cnot = cls( + gate=gate, + targets=targets, + controls=controls, + ) + + return gate_cnot + diff --git a/ionq_core/models/gate_cnot_gate.py b/ionq_core/models/gate_cnot_gate.py new file mode 100644 index 0000000..3c01fbb --- /dev/null +++ b/ionq_core/models/gate_cnot_gate.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from typing import Literal, cast + +GateCnotGate = Literal['cnot'] + +GATE_CNOT_GATE_VALUES: set[GateCnotGate] = { 'cnot', } + +def check_gate_cnot_gate(value: str) -> GateCnotGate: + if value in GATE_CNOT_GATE_VALUES: + return cast(GateCnotGate, value) + raise TypeError(f"Unexpected value {value!r}. Expected one of {GATE_CNOT_GATE_VALUES!r}") diff --git a/ionq_core/models/gate_h.py b/ionq_core/models/gate_h.py new file mode 100644 index 0000000..9d3ea8f --- /dev/null +++ b/ionq_core/models/gate_h.py @@ -0,0 +1,94 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +from ..models.gate_h_gate import check_gate_h_gate +from ..models.gate_h_gate import GateHGate +from ..types import UNSET, Unset +from typing import cast + + + + + + +T = TypeVar("T", bound="GateH") + + + +@_attrs_define +class GateH: + """ + Attributes: + gate (GateHGate): + targets (list[int]): The single qubit the gate acts on. + controls (list[int] | Unset): Optional control qubits. + """ + + gate: GateHGate + targets: list[int] + controls: list[int] | Unset = UNSET + + + + + + def to_dict(self) -> dict[str, Any]: + gate: str = self.gate + + targets = self.targets + + + + controls: list[int] | Unset = UNSET + if not isinstance(self.controls, Unset): + controls = self.controls + + + + + field_dict: dict[str, Any] = {} + + field_dict.update({ + "gate": gate, + "targets": targets, + }) + if controls is not UNSET: + field_dict["controls"] = controls + + return field_dict + + + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + gate = check_gate_h_gate(d.pop("gate")) + + + + + targets = cast(list[int], d.pop("targets")) + + + controls = cast(list[int], d.pop("controls", UNSET)) + + + gate_h = cls( + gate=gate, + targets=targets, + controls=controls, + ) + + return gate_h + diff --git a/ionq_core/models/gate_h_gate.py b/ionq_core/models/gate_h_gate.py new file mode 100644 index 0000000..a9d4e88 --- /dev/null +++ b/ionq_core/models/gate_h_gate.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from typing import Literal, cast + +GateHGate = Literal['h'] + +GATE_H_GATE_VALUES: set[GateHGate] = { 'h', } + +def check_gate_h_gate(value: str) -> GateHGate: + if value in GATE_H_GATE_VALUES: + return cast(GateHGate, value) + raise TypeError(f"Unexpected value {value!r}. Expected one of {GATE_H_GATE_VALUES!r}") diff --git a/ionq_core/models/gate_not.py b/ionq_core/models/gate_not.py new file mode 100644 index 0000000..00692cc --- /dev/null +++ b/ionq_core/models/gate_not.py @@ -0,0 +1,93 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +from ..models.gate_not_gate import check_gate_not_gate +from ..models.gate_not_gate import GateNotGate +from typing import cast + + + + + + +T = TypeVar("T", bound="GateNot") + + + +@_attrs_define +class GateNot: + """ Multi-controlled NOT with one or more controls. Functionally + equivalent to Gate_X with `controls`; kept as an explicit + alternative. + + Attributes: + gate (GateNotGate): + targets (list[int]): The single qubit the gate acts on. + controls (list[int]): One or more control qubits. + """ + + gate: GateNotGate + targets: list[int] + controls: list[int] + + + + + + def to_dict(self) -> dict[str, Any]: + gate: str = self.gate + + targets = self.targets + + + + controls = self.controls + + + + + field_dict: dict[str, Any] = {} + + field_dict.update({ + "gate": gate, + "targets": targets, + "controls": controls, + }) + + return field_dict + + + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + gate = check_gate_not_gate(d.pop("gate")) + + + + + targets = cast(list[int], d.pop("targets")) + + + controls = cast(list[int], d.pop("controls")) + + + gate_not = cls( + gate=gate, + targets=targets, + controls=controls, + ) + + return gate_not + diff --git a/ionq_core/models/gate_not_gate.py b/ionq_core/models/gate_not_gate.py new file mode 100644 index 0000000..ae42231 --- /dev/null +++ b/ionq_core/models/gate_not_gate.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from typing import Literal, cast + +GateNotGate = Literal['not'] + +GATE_NOT_GATE_VALUES: set[GateNotGate] = { 'not', } + +def check_gate_not_gate(value: str) -> GateNotGate: + if value in GATE_NOT_GATE_VALUES: + return cast(GateNotGate, value) + raise TypeError(f"Unexpected value {value!r}. Expected one of {GATE_NOT_GATE_VALUES!r}") diff --git a/ionq_core/models/gate_pauliexp.py b/ionq_core/models/gate_pauliexp.py new file mode 100644 index 0000000..07cf972 --- /dev/null +++ b/ionq_core/models/gate_pauliexp.py @@ -0,0 +1,131 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +from ..models.gate_pauliexp_gate import check_gate_pauliexp_gate +from ..models.gate_pauliexp_gate import GatePauliexpGate +from typing import cast + + + + + + +T = TypeVar("T", bound="GatePauliexp") + + + +@_attrs_define +class GatePauliexp: + """ Sparse Pauli exponential gate. Trotter-decomposed per term: + + U = prod_k exp(-i * coefficients[k] * time * P_k) + + where P_k is the tensor product of single-qubit Paulis encoded + as `terms[k]`, and `terms[k][i]` (a character in {I,X,Y,Z}) acts + on the qubit at `targets[i]`. + + `time` is a global multiplier on every coefficient. + + Constraints: + * `terms[k]` has length equal to `len(targets)` for every k. + * `coefficients` has the same length as `terms`. + * `coefficients` are real numbers. + * `time` is strictly positive. + * Endianness: `terms[k][0]` acts on `targets[0]` (big-endian + by position). + + Because the formula is a Trotter decomposition, non-commuting + terms yield an approximation rather than the exact exp(-i t H). + + Attributes: + gate (GatePauliexpGate): + targets (list[int]): Qubits the Pauli operators act on, in order. + terms (list[str]): Pauli words in {I, X, Y, Z}. `terms[k][i]` acts on + `targets[i]`. Every term has length equal to `len(targets)`. + coefficients (list[float]): Real coefficient for each Pauli term, parallel to `terms`. + time (float): Strictly-positive global multiplier. The kth term's + effective rotation is `coefficients[k] * time`. + """ + + gate: GatePauliexpGate + targets: list[int] + terms: list[str] + coefficients: list[float] + time: float + + + + + + def to_dict(self) -> dict[str, Any]: + gate: str = self.gate + + targets = self.targets + + + + terms = self.terms + + + + coefficients = self.coefficients + + + + time = self.time + + + field_dict: dict[str, Any] = {} + + field_dict.update({ + "gate": gate, + "targets": targets, + "terms": terms, + "coefficients": coefficients, + "time": time, + }) + + return field_dict + + + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + gate = check_gate_pauliexp_gate(d.pop("gate")) + + + + + targets = cast(list[int], d.pop("targets")) + + + terms = cast(list[str], d.pop("terms")) + + + coefficients = cast(list[float], d.pop("coefficients")) + + + time = d.pop("time") + + gate_pauliexp = cls( + gate=gate, + targets=targets, + terms=terms, + coefficients=coefficients, + time=time, + ) + + return gate_pauliexp + diff --git a/ionq_core/models/gate_pauliexp_gate.py b/ionq_core/models/gate_pauliexp_gate.py new file mode 100644 index 0000000..fd4be4a --- /dev/null +++ b/ionq_core/models/gate_pauliexp_gate.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from typing import Literal, cast + +GatePauliexpGate = Literal['pauliexp'] + +GATE_PAULIEXP_GATE_VALUES: set[GatePauliexpGate] = { 'pauliexp', } + +def check_gate_pauliexp_gate(value: str) -> GatePauliexpGate: + if value in GATE_PAULIEXP_GATE_VALUES: + return cast(GatePauliexpGate, value) + raise TypeError(f"Unexpected value {value!r}. Expected one of {GATE_PAULIEXP_GATE_VALUES!r}") diff --git a/ionq_core/models/gate_qis_gate.py b/ionq_core/models/gate_qis_gate.py deleted file mode 100644 index 2cb1dd1..0000000 --- a/ionq_core/models/gate_qis_gate.py +++ /dev/null @@ -1,124 +0,0 @@ -# SPDX-FileCopyrightText: 2026 IonQ, Inc. -# SPDX-License-Identifier: Apache-2.0 -# @generated - -from __future__ import annotations - -from collections.abc import Mapping -from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -from ..models.qis_gate import check_qis_gate -from ..models.qis_gate import QisGate -from ..types import UNSET, Unset -from typing import cast - - - - - - -T = TypeVar("T", bound="GateQisGate") - - - -@_attrs_define -class GateQisGate: - """ - Attributes: - gate (QisGate): - target (int | Unset): - targets (list[float] | Unset): The qubits that a quantum gate is applied to - controls (list[float] | Unset): The qubits that determine whether the operation is applied to targets. - control (int | Unset): - rotation (float | Unset): Rotation angle for rx/ry/rz gates - """ - - gate: QisGate - target: int | Unset = UNSET - targets: list[float] | Unset = UNSET - controls: list[float] | Unset = UNSET - control: int | Unset = UNSET - rotation: float | Unset = UNSET - - - - - - def to_dict(self) -> dict[str, Any]: - gate: str = self.gate - - target = self.target - - targets: list[float] | Unset = UNSET - if not isinstance(self.targets, Unset): - targets = self.targets - - - - controls: list[float] | Unset = UNSET - if not isinstance(self.controls, Unset): - controls = self.controls - - - - control = self.control - - rotation = self.rotation - - - field_dict: dict[str, Any] = {} - - field_dict.update({ - "gate": gate, - }) - if target is not UNSET: - field_dict["target"] = target - if targets is not UNSET: - field_dict["targets"] = targets - if controls is not UNSET: - field_dict["controls"] = controls - if control is not UNSET: - field_dict["control"] = control - if rotation is not UNSET: - field_dict["rotation"] = rotation - - return field_dict - - - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - gate = check_qis_gate(d.pop("gate")) - - - - - target = d.pop("target", UNSET) - - targets = cast(list[float], d.pop("targets", UNSET)) - - - controls = cast(list[float], d.pop("controls", UNSET)) - - - control = d.pop("control", UNSET) - - rotation = d.pop("rotation", UNSET) - - gate_qis_gate = cls( - gate=gate, - target=target, - targets=targets, - controls=controls, - control=control, - rotation=rotation, - ) - - return gate_qis_gate - diff --git a/ionq_core/models/gate_rx.py b/ionq_core/models/gate_rx.py new file mode 100644 index 0000000..7f738b9 --- /dev/null +++ b/ionq_core/models/gate_rx.py @@ -0,0 +1,102 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +from ..models.gate_rx_gate import check_gate_rx_gate +from ..models.gate_rx_gate import GateRxGate +from ..types import UNSET, Unset +from typing import cast + + + + + + +T = TypeVar("T", bound="GateRx") + + + +@_attrs_define +class GateRx: + """ + Attributes: + gate (GateRxGate): + targets (list[int]): The single qubit the gate acts on. + rotation (float): Rotation angle in radians. + controls (list[int] | Unset): Optional control qubits. + """ + + gate: GateRxGate + targets: list[int] + rotation: float + controls: list[int] | Unset = UNSET + + + + + + def to_dict(self) -> dict[str, Any]: + gate: str = self.gate + + targets = self.targets + + + + rotation = self.rotation + + controls: list[int] | Unset = UNSET + if not isinstance(self.controls, Unset): + controls = self.controls + + + + + field_dict: dict[str, Any] = {} + + field_dict.update({ + "gate": gate, + "targets": targets, + "rotation": rotation, + }) + if controls is not UNSET: + field_dict["controls"] = controls + + return field_dict + + + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + gate = check_gate_rx_gate(d.pop("gate")) + + + + + targets = cast(list[int], d.pop("targets")) + + + rotation = d.pop("rotation") + + controls = cast(list[int], d.pop("controls", UNSET)) + + + gate_rx = cls( + gate=gate, + targets=targets, + rotation=rotation, + controls=controls, + ) + + return gate_rx + diff --git a/ionq_core/models/gate_rx_gate.py b/ionq_core/models/gate_rx_gate.py new file mode 100644 index 0000000..54cbb49 --- /dev/null +++ b/ionq_core/models/gate_rx_gate.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from typing import Literal, cast + +GateRxGate = Literal['rx'] + +GATE_RX_GATE_VALUES: set[GateRxGate] = { 'rx', } + +def check_gate_rx_gate(value: str) -> GateRxGate: + if value in GATE_RX_GATE_VALUES: + return cast(GateRxGate, value) + raise TypeError(f"Unexpected value {value!r}. Expected one of {GATE_RX_GATE_VALUES!r}") diff --git a/ionq_core/models/gate_ry.py b/ionq_core/models/gate_ry.py new file mode 100644 index 0000000..d5fdd00 --- /dev/null +++ b/ionq_core/models/gate_ry.py @@ -0,0 +1,102 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +from ..models.gate_ry_gate import check_gate_ry_gate +from ..models.gate_ry_gate import GateRyGate +from ..types import UNSET, Unset +from typing import cast + + + + + + +T = TypeVar("T", bound="GateRy") + + + +@_attrs_define +class GateRy: + """ + Attributes: + gate (GateRyGate): + targets (list[int]): The single qubit the gate acts on. + rotation (float): Rotation angle in radians. + controls (list[int] | Unset): Optional control qubits. + """ + + gate: GateRyGate + targets: list[int] + rotation: float + controls: list[int] | Unset = UNSET + + + + + + def to_dict(self) -> dict[str, Any]: + gate: str = self.gate + + targets = self.targets + + + + rotation = self.rotation + + controls: list[int] | Unset = UNSET + if not isinstance(self.controls, Unset): + controls = self.controls + + + + + field_dict: dict[str, Any] = {} + + field_dict.update({ + "gate": gate, + "targets": targets, + "rotation": rotation, + }) + if controls is not UNSET: + field_dict["controls"] = controls + + return field_dict + + + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + gate = check_gate_ry_gate(d.pop("gate")) + + + + + targets = cast(list[int], d.pop("targets")) + + + rotation = d.pop("rotation") + + controls = cast(list[int], d.pop("controls", UNSET)) + + + gate_ry = cls( + gate=gate, + targets=targets, + rotation=rotation, + controls=controls, + ) + + return gate_ry + diff --git a/ionq_core/models/gate_ry_gate.py b/ionq_core/models/gate_ry_gate.py new file mode 100644 index 0000000..dda816d --- /dev/null +++ b/ionq_core/models/gate_ry_gate.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from typing import Literal, cast + +GateRyGate = Literal['ry'] + +GATE_RY_GATE_VALUES: set[GateRyGate] = { 'ry', } + +def check_gate_ry_gate(value: str) -> GateRyGate: + if value in GATE_RY_GATE_VALUES: + return cast(GateRyGate, value) + raise TypeError(f"Unexpected value {value!r}. Expected one of {GATE_RY_GATE_VALUES!r}") diff --git a/ionq_core/models/gate_rz.py b/ionq_core/models/gate_rz.py new file mode 100644 index 0000000..df9ad18 --- /dev/null +++ b/ionq_core/models/gate_rz.py @@ -0,0 +1,102 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +from ..models.gate_rz_gate import check_gate_rz_gate +from ..models.gate_rz_gate import GateRzGate +from ..types import UNSET, Unset +from typing import cast + + + + + + +T = TypeVar("T", bound="GateRz") + + + +@_attrs_define +class GateRz: + """ + Attributes: + gate (GateRzGate): + targets (list[int]): The single qubit the gate acts on. + rotation (float): Rotation angle in radians. + controls (list[int] | Unset): Optional control qubits. + """ + + gate: GateRzGate + targets: list[int] + rotation: float + controls: list[int] | Unset = UNSET + + + + + + def to_dict(self) -> dict[str, Any]: + gate: str = self.gate + + targets = self.targets + + + + rotation = self.rotation + + controls: list[int] | Unset = UNSET + if not isinstance(self.controls, Unset): + controls = self.controls + + + + + field_dict: dict[str, Any] = {} + + field_dict.update({ + "gate": gate, + "targets": targets, + "rotation": rotation, + }) + if controls is not UNSET: + field_dict["controls"] = controls + + return field_dict + + + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + gate = check_gate_rz_gate(d.pop("gate")) + + + + + targets = cast(list[int], d.pop("targets")) + + + rotation = d.pop("rotation") + + controls = cast(list[int], d.pop("controls", UNSET)) + + + gate_rz = cls( + gate=gate, + targets=targets, + rotation=rotation, + controls=controls, + ) + + return gate_rz + diff --git a/ionq_core/models/gate_rz_gate.py b/ionq_core/models/gate_rz_gate.py new file mode 100644 index 0000000..95948cd --- /dev/null +++ b/ionq_core/models/gate_rz_gate.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from typing import Literal, cast + +GateRzGate = Literal['rz'] + +GATE_RZ_GATE_VALUES: set[GateRzGate] = { 'rz', } + +def check_gate_rz_gate(value: str) -> GateRzGate: + if value in GATE_RZ_GATE_VALUES: + return cast(GateRzGate, value) + raise TypeError(f"Unexpected value {value!r}. Expected one of {GATE_RZ_GATE_VALUES!r}") diff --git a/ionq_core/models/gate_s.py b/ionq_core/models/gate_s.py new file mode 100644 index 0000000..92f4678 --- /dev/null +++ b/ionq_core/models/gate_s.py @@ -0,0 +1,94 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +from ..models.gate_s_gate import check_gate_s_gate +from ..models.gate_s_gate import GateSGate +from ..types import UNSET, Unset +from typing import cast + + + + + + +T = TypeVar("T", bound="GateS") + + + +@_attrs_define +class GateS: + """ + Attributes: + gate (GateSGate): + targets (list[int]): The single qubit the gate acts on. + controls (list[int] | Unset): Optional control qubits. + """ + + gate: GateSGate + targets: list[int] + controls: list[int] | Unset = UNSET + + + + + + def to_dict(self) -> dict[str, Any]: + gate: str = self.gate + + targets = self.targets + + + + controls: list[int] | Unset = UNSET + if not isinstance(self.controls, Unset): + controls = self.controls + + + + + field_dict: dict[str, Any] = {} + + field_dict.update({ + "gate": gate, + "targets": targets, + }) + if controls is not UNSET: + field_dict["controls"] = controls + + return field_dict + + + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + gate = check_gate_s_gate(d.pop("gate")) + + + + + targets = cast(list[int], d.pop("targets")) + + + controls = cast(list[int], d.pop("controls", UNSET)) + + + gate_s = cls( + gate=gate, + targets=targets, + controls=controls, + ) + + return gate_s + diff --git a/ionq_core/models/gate_s_gate.py b/ionq_core/models/gate_s_gate.py new file mode 100644 index 0000000..503d1ee --- /dev/null +++ b/ionq_core/models/gate_s_gate.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from typing import Literal, cast + +GateSGate = Literal['s'] + +GATE_S_GATE_VALUES: set[GateSGate] = { 's', } + +def check_gate_s_gate(value: str) -> GateSGate: + if value in GATE_S_GATE_VALUES: + return cast(GateSGate, value) + raise TypeError(f"Unexpected value {value!r}. Expected one of {GATE_S_GATE_VALUES!r}") diff --git a/ionq_core/models/gate_si.py b/ionq_core/models/gate_si.py new file mode 100644 index 0000000..eb192f6 --- /dev/null +++ b/ionq_core/models/gate_si.py @@ -0,0 +1,95 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +from ..models.gate_si_gate import check_gate_si_gate +from ..models.gate_si_gate import GateSiGate +from ..types import UNSET, Unset +from typing import cast + + + + + + +T = TypeVar("T", bound="GateSi") + + + +@_attrs_define +class GateSi: + """ S-dagger (inverse of S). + + Attributes: + gate (GateSiGate): + targets (list[int]): The single qubit the gate acts on. + controls (list[int] | Unset): Optional control qubits. + """ + + gate: GateSiGate + targets: list[int] + controls: list[int] | Unset = UNSET + + + + + + def to_dict(self) -> dict[str, Any]: + gate: str = self.gate + + targets = self.targets + + + + controls: list[int] | Unset = UNSET + if not isinstance(self.controls, Unset): + controls = self.controls + + + + + field_dict: dict[str, Any] = {} + + field_dict.update({ + "gate": gate, + "targets": targets, + }) + if controls is not UNSET: + field_dict["controls"] = controls + + return field_dict + + + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + gate = check_gate_si_gate(d.pop("gate")) + + + + + targets = cast(list[int], d.pop("targets")) + + + controls = cast(list[int], d.pop("controls", UNSET)) + + + gate_si = cls( + gate=gate, + targets=targets, + controls=controls, + ) + + return gate_si + diff --git a/ionq_core/models/gate_si_gate.py b/ionq_core/models/gate_si_gate.py new file mode 100644 index 0000000..0705075 --- /dev/null +++ b/ionq_core/models/gate_si_gate.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from typing import Literal, cast + +GateSiGate = Literal['si'] + +GATE_SI_GATE_VALUES: set[GateSiGate] = { 'si', } + +def check_gate_si_gate(value: str) -> GateSiGate: + if value in GATE_SI_GATE_VALUES: + return cast(GateSiGate, value) + raise TypeError(f"Unexpected value {value!r}. Expected one of {GATE_SI_GATE_VALUES!r}") diff --git a/ionq_core/models/gate_swap.py b/ionq_core/models/gate_swap.py new file mode 100644 index 0000000..53b659b --- /dev/null +++ b/ionq_core/models/gate_swap.py @@ -0,0 +1,80 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +from ..models.gate_swap_gate import check_gate_swap_gate +from ..models.gate_swap_gate import GateSwapGate +from typing import cast + + + + + + +T = TypeVar("T", bound="GateSwap") + + + +@_attrs_define +class GateSwap: + """ Two-qubit SWAP. + + Attributes: + gate (GateSwapGate): + targets (list[int]): The two qubits the gate acts on. + """ + + gate: GateSwapGate + targets: list[int] + + + + + + def to_dict(self) -> dict[str, Any]: + gate: str = self.gate + + targets = self.targets + + + + + field_dict: dict[str, Any] = {} + + field_dict.update({ + "gate": gate, + "targets": targets, + }) + + return field_dict + + + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + gate = check_gate_swap_gate(d.pop("gate")) + + + + + targets = cast(list[int], d.pop("targets")) + + + gate_swap = cls( + gate=gate, + targets=targets, + ) + + return gate_swap + diff --git a/ionq_core/models/gate_swap_gate.py b/ionq_core/models/gate_swap_gate.py new file mode 100644 index 0000000..b8b56fc --- /dev/null +++ b/ionq_core/models/gate_swap_gate.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from typing import Literal, cast + +GateSwapGate = Literal['swap'] + +GATE_SWAP_GATE_VALUES: set[GateSwapGate] = { 'swap', } + +def check_gate_swap_gate(value: str) -> GateSwapGate: + if value in GATE_SWAP_GATE_VALUES: + return cast(GateSwapGate, value) + raise TypeError(f"Unexpected value {value!r}. Expected one of {GATE_SWAP_GATE_VALUES!r}") diff --git a/ionq_core/models/gate_t.py b/ionq_core/models/gate_t.py new file mode 100644 index 0000000..26de790 --- /dev/null +++ b/ionq_core/models/gate_t.py @@ -0,0 +1,94 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +from ..models.gate_t_gate import check_gate_t_gate +from ..models.gate_t_gate import GateTGate +from ..types import UNSET, Unset +from typing import cast + + + + + + +T = TypeVar("T", bound="GateT") + + + +@_attrs_define +class GateT: + """ + Attributes: + gate (GateTGate): + targets (list[int]): The single qubit the gate acts on. + controls (list[int] | Unset): Optional control qubits. + """ + + gate: GateTGate + targets: list[int] + controls: list[int] | Unset = UNSET + + + + + + def to_dict(self) -> dict[str, Any]: + gate: str = self.gate + + targets = self.targets + + + + controls: list[int] | Unset = UNSET + if not isinstance(self.controls, Unset): + controls = self.controls + + + + + field_dict: dict[str, Any] = {} + + field_dict.update({ + "gate": gate, + "targets": targets, + }) + if controls is not UNSET: + field_dict["controls"] = controls + + return field_dict + + + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + gate = check_gate_t_gate(d.pop("gate")) + + + + + targets = cast(list[int], d.pop("targets")) + + + controls = cast(list[int], d.pop("controls", UNSET)) + + + gate_t = cls( + gate=gate, + targets=targets, + controls=controls, + ) + + return gate_t + diff --git a/ionq_core/models/gate_t_gate.py b/ionq_core/models/gate_t_gate.py new file mode 100644 index 0000000..b0279d4 --- /dev/null +++ b/ionq_core/models/gate_t_gate.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from typing import Literal, cast + +GateTGate = Literal['t'] + +GATE_T_GATE_VALUES: set[GateTGate] = { 't', } + +def check_gate_t_gate(value: str) -> GateTGate: + if value in GATE_T_GATE_VALUES: + return cast(GateTGate, value) + raise TypeError(f"Unexpected value {value!r}. Expected one of {GATE_T_GATE_VALUES!r}") diff --git a/ionq_core/models/gate_ti.py b/ionq_core/models/gate_ti.py new file mode 100644 index 0000000..cea785e --- /dev/null +++ b/ionq_core/models/gate_ti.py @@ -0,0 +1,95 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +from ..models.gate_ti_gate import check_gate_ti_gate +from ..models.gate_ti_gate import GateTiGate +from ..types import UNSET, Unset +from typing import cast + + + + + + +T = TypeVar("T", bound="GateTi") + + + +@_attrs_define +class GateTi: + """ T-dagger (inverse of T). + + Attributes: + gate (GateTiGate): + targets (list[int]): The single qubit the gate acts on. + controls (list[int] | Unset): Optional control qubits. + """ + + gate: GateTiGate + targets: list[int] + controls: list[int] | Unset = UNSET + + + + + + def to_dict(self) -> dict[str, Any]: + gate: str = self.gate + + targets = self.targets + + + + controls: list[int] | Unset = UNSET + if not isinstance(self.controls, Unset): + controls = self.controls + + + + + field_dict: dict[str, Any] = {} + + field_dict.update({ + "gate": gate, + "targets": targets, + }) + if controls is not UNSET: + field_dict["controls"] = controls + + return field_dict + + + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + gate = check_gate_ti_gate(d.pop("gate")) + + + + + targets = cast(list[int], d.pop("targets")) + + + controls = cast(list[int], d.pop("controls", UNSET)) + + + gate_ti = cls( + gate=gate, + targets=targets, + controls=controls, + ) + + return gate_ti + diff --git a/ionq_core/models/gate_ti_gate.py b/ionq_core/models/gate_ti_gate.py new file mode 100644 index 0000000..7f96fb3 --- /dev/null +++ b/ionq_core/models/gate_ti_gate.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from typing import Literal, cast + +GateTiGate = Literal['ti'] + +GATE_TI_GATE_VALUES: set[GateTiGate] = { 'ti', } + +def check_gate_ti_gate(value: str) -> GateTiGate: + if value in GATE_TI_GATE_VALUES: + return cast(GateTiGate, value) + raise TypeError(f"Unexpected value {value!r}. Expected one of {GATE_TI_GATE_VALUES!r}") diff --git a/ionq_core/models/gate_v.py b/ionq_core/models/gate_v.py new file mode 100644 index 0000000..5d33dc0 --- /dev/null +++ b/ionq_core/models/gate_v.py @@ -0,0 +1,95 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +from ..models.gate_v_gate import check_gate_v_gate +from ..models.gate_v_gate import GateVGate +from ..types import UNSET, Unset +from typing import cast + + + + + + +T = TypeVar("T", bound="GateV") + + + +@_attrs_define +class GateV: + """ Square root of X. + + Attributes: + gate (GateVGate): + targets (list[int]): The single qubit the gate acts on. + controls (list[int] | Unset): Optional control qubits. + """ + + gate: GateVGate + targets: list[int] + controls: list[int] | Unset = UNSET + + + + + + def to_dict(self) -> dict[str, Any]: + gate: str = self.gate + + targets = self.targets + + + + controls: list[int] | Unset = UNSET + if not isinstance(self.controls, Unset): + controls = self.controls + + + + + field_dict: dict[str, Any] = {} + + field_dict.update({ + "gate": gate, + "targets": targets, + }) + if controls is not UNSET: + field_dict["controls"] = controls + + return field_dict + + + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + gate = check_gate_v_gate(d.pop("gate")) + + + + + targets = cast(list[int], d.pop("targets")) + + + controls = cast(list[int], d.pop("controls", UNSET)) + + + gate_v = cls( + gate=gate, + targets=targets, + controls=controls, + ) + + return gate_v + diff --git a/ionq_core/models/gate_v_gate.py b/ionq_core/models/gate_v_gate.py new file mode 100644 index 0000000..8ba383f --- /dev/null +++ b/ionq_core/models/gate_v_gate.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from typing import Literal, cast + +GateVGate = Literal['v'] + +GATE_V_GATE_VALUES: set[GateVGate] = { 'v', } + +def check_gate_v_gate(value: str) -> GateVGate: + if value in GATE_V_GATE_VALUES: + return cast(GateVGate, value) + raise TypeError(f"Unexpected value {value!r}. Expected one of {GATE_V_GATE_VALUES!r}") diff --git a/ionq_core/models/gate_vi.py b/ionq_core/models/gate_vi.py new file mode 100644 index 0000000..618d95b --- /dev/null +++ b/ionq_core/models/gate_vi.py @@ -0,0 +1,95 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +from ..models.gate_vi_gate import check_gate_vi_gate +from ..models.gate_vi_gate import GateViGate +from ..types import UNSET, Unset +from typing import cast + + + + + + +T = TypeVar("T", bound="GateVi") + + + +@_attrs_define +class GateVi: + """ V-dagger (inverse of V). + + Attributes: + gate (GateViGate): + targets (list[int]): The single qubit the gate acts on. + controls (list[int] | Unset): Optional control qubits. + """ + + gate: GateViGate + targets: list[int] + controls: list[int] | Unset = UNSET + + + + + + def to_dict(self) -> dict[str, Any]: + gate: str = self.gate + + targets = self.targets + + + + controls: list[int] | Unset = UNSET + if not isinstance(self.controls, Unset): + controls = self.controls + + + + + field_dict: dict[str, Any] = {} + + field_dict.update({ + "gate": gate, + "targets": targets, + }) + if controls is not UNSET: + field_dict["controls"] = controls + + return field_dict + + + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + gate = check_gate_vi_gate(d.pop("gate")) + + + + + targets = cast(list[int], d.pop("targets")) + + + controls = cast(list[int], d.pop("controls", UNSET)) + + + gate_vi = cls( + gate=gate, + targets=targets, + controls=controls, + ) + + return gate_vi + diff --git a/ionq_core/models/gate_vi_gate.py b/ionq_core/models/gate_vi_gate.py new file mode 100644 index 0000000..21850f4 --- /dev/null +++ b/ionq_core/models/gate_vi_gate.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from typing import Literal, cast + +GateViGate = Literal['vi'] + +GATE_VI_GATE_VALUES: set[GateViGate] = { 'vi', } + +def check_gate_vi_gate(value: str) -> GateViGate: + if value in GATE_VI_GATE_VALUES: + return cast(GateViGate, value) + raise TypeError(f"Unexpected value {value!r}. Expected one of {GATE_VI_GATE_VALUES!r}") diff --git a/ionq_core/models/gate_x.py b/ionq_core/models/gate_x.py new file mode 100644 index 0000000..74ebab6 --- /dev/null +++ b/ionq_core/models/gate_x.py @@ -0,0 +1,97 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +from ..models.gate_x_gate import check_gate_x_gate +from ..models.gate_x_gate import GateXGate +from ..types import UNSET, Unset +from typing import cast + + + + + + +T = TypeVar("T", bound="GateX") + + + +@_attrs_define +class GateX: + """ Pauli-X. With `controls`, this is the canonical multi-controlled + NOT (Gate_Cnot for the single-control case, Gate_Not for the + explicit form). + + Attributes: + gate (GateXGate): + targets (list[int]): The single qubit the gate acts on. + controls (list[int] | Unset): Optional control qubits. + """ + + gate: GateXGate + targets: list[int] + controls: list[int] | Unset = UNSET + + + + + + def to_dict(self) -> dict[str, Any]: + gate: str = self.gate + + targets = self.targets + + + + controls: list[int] | Unset = UNSET + if not isinstance(self.controls, Unset): + controls = self.controls + + + + + field_dict: dict[str, Any] = {} + + field_dict.update({ + "gate": gate, + "targets": targets, + }) + if controls is not UNSET: + field_dict["controls"] = controls + + return field_dict + + + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + gate = check_gate_x_gate(d.pop("gate")) + + + + + targets = cast(list[int], d.pop("targets")) + + + controls = cast(list[int], d.pop("controls", UNSET)) + + + gate_x = cls( + gate=gate, + targets=targets, + controls=controls, + ) + + return gate_x + diff --git a/ionq_core/models/gate_x_gate.py b/ionq_core/models/gate_x_gate.py new file mode 100644 index 0000000..03c2d02 --- /dev/null +++ b/ionq_core/models/gate_x_gate.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from typing import Literal, cast + +GateXGate = Literal['x'] + +GATE_X_GATE_VALUES: set[GateXGate] = { 'x', } + +def check_gate_x_gate(value: str) -> GateXGate: + if value in GATE_X_GATE_VALUES: + return cast(GateXGate, value) + raise TypeError(f"Unexpected value {value!r}. Expected one of {GATE_X_GATE_VALUES!r}") diff --git a/ionq_core/models/gate_xx.py b/ionq_core/models/gate_xx.py new file mode 100644 index 0000000..caf13d0 --- /dev/null +++ b/ionq_core/models/gate_xx.py @@ -0,0 +1,88 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +from ..models.gate_xx_gate import check_gate_xx_gate +from ..models.gate_xx_gate import GateXXGate +from typing import cast + + + + + + +T = TypeVar("T", bound="GateXX") + + + +@_attrs_define +class GateXX: + """ Two-qubit XX (Ising-XX) rotation, exp(-i theta/2 X⊗X). + + Attributes: + gate (GateXXGate): + targets (list[int]): The two qubits the gate acts on. + rotation (float): Rotation angle in radians. + """ + + gate: GateXXGate + targets: list[int] + rotation: float + + + + + + def to_dict(self) -> dict[str, Any]: + gate: str = self.gate + + targets = self.targets + + + + rotation = self.rotation + + + field_dict: dict[str, Any] = {} + + field_dict.update({ + "gate": gate, + "targets": targets, + "rotation": rotation, + }) + + return field_dict + + + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + gate = check_gate_xx_gate(d.pop("gate")) + + + + + targets = cast(list[int], d.pop("targets")) + + + rotation = d.pop("rotation") + + gate_xx = cls( + gate=gate, + targets=targets, + rotation=rotation, + ) + + return gate_xx + diff --git a/ionq_core/models/gate_xx_gate.py b/ionq_core/models/gate_xx_gate.py new file mode 100644 index 0000000..3eb3514 --- /dev/null +++ b/ionq_core/models/gate_xx_gate.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from typing import Literal, cast + +GateXXGate = Literal['xx'] + +GATE_XX_GATE_VALUES: set[GateXXGate] = { 'xx', } + +def check_gate_xx_gate(value: str) -> GateXXGate: + if value in GATE_XX_GATE_VALUES: + return cast(GateXXGate, value) + raise TypeError(f"Unexpected value {value!r}. Expected one of {GATE_XX_GATE_VALUES!r}") diff --git a/ionq_core/models/gate_y.py b/ionq_core/models/gate_y.py new file mode 100644 index 0000000..2ff59f0 --- /dev/null +++ b/ionq_core/models/gate_y.py @@ -0,0 +1,94 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +from ..models.gate_y_gate import check_gate_y_gate +from ..models.gate_y_gate import GateYGate +from ..types import UNSET, Unset +from typing import cast + + + + + + +T = TypeVar("T", bound="GateY") + + + +@_attrs_define +class GateY: + """ + Attributes: + gate (GateYGate): + targets (list[int]): The single qubit the gate acts on. + controls (list[int] | Unset): Optional control qubits. + """ + + gate: GateYGate + targets: list[int] + controls: list[int] | Unset = UNSET + + + + + + def to_dict(self) -> dict[str, Any]: + gate: str = self.gate + + targets = self.targets + + + + controls: list[int] | Unset = UNSET + if not isinstance(self.controls, Unset): + controls = self.controls + + + + + field_dict: dict[str, Any] = {} + + field_dict.update({ + "gate": gate, + "targets": targets, + }) + if controls is not UNSET: + field_dict["controls"] = controls + + return field_dict + + + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + gate = check_gate_y_gate(d.pop("gate")) + + + + + targets = cast(list[int], d.pop("targets")) + + + controls = cast(list[int], d.pop("controls", UNSET)) + + + gate_y = cls( + gate=gate, + targets=targets, + controls=controls, + ) + + return gate_y + diff --git a/ionq_core/models/gate_y_gate.py b/ionq_core/models/gate_y_gate.py new file mode 100644 index 0000000..9327dfd --- /dev/null +++ b/ionq_core/models/gate_y_gate.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from typing import Literal, cast + +GateYGate = Literal['y'] + +GATE_Y_GATE_VALUES: set[GateYGate] = { 'y', } + +def check_gate_y_gate(value: str) -> GateYGate: + if value in GATE_Y_GATE_VALUES: + return cast(GateYGate, value) + raise TypeError(f"Unexpected value {value!r}. Expected one of {GATE_Y_GATE_VALUES!r}") diff --git a/ionq_core/models/gate_yy.py b/ionq_core/models/gate_yy.py new file mode 100644 index 0000000..eb1b5a7 --- /dev/null +++ b/ionq_core/models/gate_yy.py @@ -0,0 +1,88 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +from ..models.gate_yy_gate import check_gate_yy_gate +from ..models.gate_yy_gate import GateYYGate +from typing import cast + + + + + + +T = TypeVar("T", bound="GateYY") + + + +@_attrs_define +class GateYY: + """ Two-qubit YY (Ising-YY) rotation, exp(-i theta/2 Y⊗Y). + + Attributes: + gate (GateYYGate): + targets (list[int]): The two qubits the gate acts on. + rotation (float): Rotation angle in radians. + """ + + gate: GateYYGate + targets: list[int] + rotation: float + + + + + + def to_dict(self) -> dict[str, Any]: + gate: str = self.gate + + targets = self.targets + + + + rotation = self.rotation + + + field_dict: dict[str, Any] = {} + + field_dict.update({ + "gate": gate, + "targets": targets, + "rotation": rotation, + }) + + return field_dict + + + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + gate = check_gate_yy_gate(d.pop("gate")) + + + + + targets = cast(list[int], d.pop("targets")) + + + rotation = d.pop("rotation") + + gate_yy = cls( + gate=gate, + targets=targets, + rotation=rotation, + ) + + return gate_yy + diff --git a/ionq_core/models/gate_yy_gate.py b/ionq_core/models/gate_yy_gate.py new file mode 100644 index 0000000..ae2688c --- /dev/null +++ b/ionq_core/models/gate_yy_gate.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from typing import Literal, cast + +GateYYGate = Literal['yy'] + +GATE_YY_GATE_VALUES: set[GateYYGate] = { 'yy', } + +def check_gate_yy_gate(value: str) -> GateYYGate: + if value in GATE_YY_GATE_VALUES: + return cast(GateYYGate, value) + raise TypeError(f"Unexpected value {value!r}. Expected one of {GATE_YY_GATE_VALUES!r}") diff --git a/ionq_core/models/gate_z.py b/ionq_core/models/gate_z.py new file mode 100644 index 0000000..f976abc --- /dev/null +++ b/ionq_core/models/gate_z.py @@ -0,0 +1,94 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +from ..models.gate_z_gate import check_gate_z_gate +from ..models.gate_z_gate import GateZGate +from ..types import UNSET, Unset +from typing import cast + + + + + + +T = TypeVar("T", bound="GateZ") + + + +@_attrs_define +class GateZ: + """ + Attributes: + gate (GateZGate): + targets (list[int]): The single qubit the gate acts on. + controls (list[int] | Unset): Optional control qubits. + """ + + gate: GateZGate + targets: list[int] + controls: list[int] | Unset = UNSET + + + + + + def to_dict(self) -> dict[str, Any]: + gate: str = self.gate + + targets = self.targets + + + + controls: list[int] | Unset = UNSET + if not isinstance(self.controls, Unset): + controls = self.controls + + + + + field_dict: dict[str, Any] = {} + + field_dict.update({ + "gate": gate, + "targets": targets, + }) + if controls is not UNSET: + field_dict["controls"] = controls + + return field_dict + + + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + gate = check_gate_z_gate(d.pop("gate")) + + + + + targets = cast(list[int], d.pop("targets")) + + + controls = cast(list[int], d.pop("controls", UNSET)) + + + gate_z = cls( + gate=gate, + targets=targets, + controls=controls, + ) + + return gate_z + diff --git a/ionq_core/models/gate_z_gate.py b/ionq_core/models/gate_z_gate.py new file mode 100644 index 0000000..16322c4 --- /dev/null +++ b/ionq_core/models/gate_z_gate.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from typing import Literal, cast + +GateZGate = Literal['z'] + +GATE_Z_GATE_VALUES: set[GateZGate] = { 'z', } + +def check_gate_z_gate(value: str) -> GateZGate: + if value in GATE_Z_GATE_VALUES: + return cast(GateZGate, value) + raise TypeError(f"Unexpected value {value!r}. Expected one of {GATE_Z_GATE_VALUES!r}") diff --git a/ionq_core/models/gate_zz.py b/ionq_core/models/gate_zz.py new file mode 100644 index 0000000..5350677 --- /dev/null +++ b/ionq_core/models/gate_zz.py @@ -0,0 +1,90 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +from ..models.gate_zz_gate import check_gate_zz_gate +from ..models.gate_zz_gate import GateZZGate +from typing import cast + + + + + + +T = TypeVar("T", bound="GateZZ") + + + +@_attrs_define +class GateZZ: + """ Two-qubit ZZ (Ising-ZZ) rotation, exp(-i theta/2 Z⊗Z), with + `rotation` in radians. Distinct from the native-gateset `zz`, + which takes a `phase` parameter in turns. + + Attributes: + gate (GateZZGate): + targets (list[int]): The two qubits the gate acts on. + rotation (float): Rotation angle in radians. + """ + + gate: GateZZGate + targets: list[int] + rotation: float + + + + + + def to_dict(self) -> dict[str, Any]: + gate: str = self.gate + + targets = self.targets + + + + rotation = self.rotation + + + field_dict: dict[str, Any] = {} + + field_dict.update({ + "gate": gate, + "targets": targets, + "rotation": rotation, + }) + + return field_dict + + + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + gate = check_gate_zz_gate(d.pop("gate")) + + + + + targets = cast(list[int], d.pop("targets")) + + + rotation = d.pop("rotation") + + gate_zz = cls( + gate=gate, + targets=targets, + rotation=rotation, + ) + + return gate_zz + diff --git a/ionq_core/models/gate_zz_gate.py b/ionq_core/models/gate_zz_gate.py new file mode 100644 index 0000000..551c91f --- /dev/null +++ b/ionq_core/models/gate_zz_gate.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2026 IonQ, Inc. +# SPDX-License-Identifier: Apache-2.0 +# @generated + +from typing import Literal, cast + +GateZZGate = Literal['zz'] + +GATE_ZZ_GATE_VALUES: set[GateZZGate] = { 'zz', } + +def check_gate_zz_gate(value: str) -> GateZZGate: + if value in GATE_ZZ_GATE_VALUES: + return cast(GateZZGate, value) + raise TypeError(f"Unexpected value {value!r}. Expected one of {GATE_ZZ_GATE_VALUES!r}") diff --git a/ionq_core/models/qis_circuit.py b/ionq_core/models/qis_circuit.py index d4c08df..9c7bf5c 100644 --- a/ionq_core/models/qis_circuit.py +++ b/ionq_core/models/qis_circuit.py @@ -18,7 +18,26 @@ from typing import cast if TYPE_CHECKING: - from ..models.gate_qis_gate import GateQisGate + from ..models.gate_cnot import GateCnot + from ..models.gate_h import GateH + from ..models.gate_not import GateNot + from ..models.gate_pauliexp import GatePauliexp + from ..models.gate_rx import GateRx + from ..models.gate_ry import GateRy + from ..models.gate_rz import GateRz + from ..models.gate_s import GateS + from ..models.gate_si import GateSi + from ..models.gate_swap import GateSwap + from ..models.gate_t import GateT + from ..models.gate_ti import GateTi + from ..models.gate_v import GateV + from ..models.gate_vi import GateVi + from ..models.gate_x import GateX + from ..models.gate_xx import GateXX + from ..models.gate_y import GateY + from ..models.gate_yy import GateYY + from ..models.gate_z import GateZ + from ..models.gate_zz import GateZZ from ..models.registers import Registers @@ -33,8 +52,9 @@ class QISCircuit: """ Attributes: - circuit (list[GateQisGate]): Circuit gates. Can be either QIS gates or Native gates depending on the gateset - property. + circuit (list[GateCnot | GateH | GateNot | GatePauliexp | GateRx | GateRy | GateRz | GateS | GateSi | GateSwap | + GateT | GateTi | GateV | GateVi | GateX | GateXX | GateY | GateYY | GateZ | GateZZ]): Circuit gates. Can be + either QIS gates or Native gates depending on the gateset property. name (str | Unset): qubits (int | Unset): registers (Registers | Unset): @@ -43,7 +63,7 @@ class QISCircuit: When set, the circuit must use the appropriate gate format (QIS). """ - circuit: list[GateQisGate] + circuit: list[GateCnot | GateH | GateNot | GatePauliexp | GateRx | GateRy | GateRz | GateS | GateSi | GateSwap | GateT | GateTi | GateV | GateVi | GateX | GateXX | GateY | GateYY | GateZ | GateZZ] name: str | Unset = UNSET qubits: int | Unset = UNSET registers: Registers | Unset = UNSET @@ -54,11 +74,71 @@ class QISCircuit: def to_dict(self) -> dict[str, Any]: - from ..models.gate_qis_gate import GateQisGate + from ..models.gate_cnot import GateCnot + from ..models.gate_h import GateH + from ..models.gate_not import GateNot + from ..models.gate_pauliexp import GatePauliexp + from ..models.gate_rx import GateRx + from ..models.gate_ry import GateRy + from ..models.gate_rz import GateRz + from ..models.gate_s import GateS + from ..models.gate_si import GateSi + from ..models.gate_swap import GateSwap + from ..models.gate_t import GateT + from ..models.gate_ti import GateTi + from ..models.gate_v import GateV + from ..models.gate_vi import GateVi + from ..models.gate_x import GateX + from ..models.gate_xx import GateXX + from ..models.gate_y import GateY + from ..models.gate_yy import GateYY + from ..models.gate_z import GateZ + from ..models.gate_zz import GateZZ from ..models.registers import Registers circuit = [] for circuit_item_data in self.circuit: - circuit_item = circuit_item_data.to_dict() + circuit_item: dict[str, Any] + if isinstance(circuit_item_data, GatePauliexp): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateCnot): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateSwap): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateRx): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateRy): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateRz): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateXX): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateYY): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateZZ): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateNot): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateX): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateY): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateZ): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateH): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateS): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateSi): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateT): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateTi): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateV): + circuit_item = circuit_item_data.to_dict() + else: + circuit_item = circuit_item_data.to_dict() + circuit.append(circuit_item) @@ -97,15 +177,231 @@ def to_dict(self) -> dict[str, Any]: @classmethod def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - from ..models.gate_qis_gate import GateQisGate + from ..models.gate_cnot import GateCnot + from ..models.gate_h import GateH + from ..models.gate_not import GateNot + from ..models.gate_pauliexp import GatePauliexp + from ..models.gate_rx import GateRx + from ..models.gate_ry import GateRy + from ..models.gate_rz import GateRz + from ..models.gate_s import GateS + from ..models.gate_si import GateSi + from ..models.gate_swap import GateSwap + from ..models.gate_t import GateT + from ..models.gate_ti import GateTi + from ..models.gate_v import GateV + from ..models.gate_vi import GateVi + from ..models.gate_x import GateX + from ..models.gate_xx import GateXX + from ..models.gate_y import GateY + from ..models.gate_yy import GateYY + from ..models.gate_z import GateZ + from ..models.gate_zz import GateZZ from ..models.registers import Registers d = dict(src_dict) circuit = [] _circuit = d.pop("circuit") for circuit_item_data in (_circuit): - circuit_item = GateQisGate.from_dict(circuit_item_data) + def _parse_circuit_item(data: object) -> GateCnot | GateH | GateNot | GatePauliexp | GateRx | GateRy | GateRz | GateS | GateSi | GateSwap | GateT | GateTi | GateV | GateVi | GateX | GateXX | GateY | GateYY | GateZ | GateZZ: + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_0 = GatePauliexp.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_1 = GateCnot.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_1 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_2 = GateSwap.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_2 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_3 = GateRx.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_3 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_4 = GateRy.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_4 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_5 = GateRz.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_5 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_6 = GateXX.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_6 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_7 = GateYY.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_7 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_8 = GateZZ.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_8 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_9 = GateNot.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_9 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_10 = GateX.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_10 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_11 = GateY.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_11 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_12 = GateZ.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_12 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_13 = GateH.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_13 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_14 = GateS.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_14 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_15 = GateSi.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_15 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_16 = GateT.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_16 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_17 = GateTi.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_17 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_18 = GateV.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_18 + except (TypeError, ValueError, AttributeError, KeyError): + pass + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_19 = GateVi.from_dict(data) + + + return componentsschemas_gate_qis_gate_type_19 + circuit_item = _parse_circuit_item(circuit_item_data) circuit.append(circuit_item) diff --git a/ionq_core/models/qis_circuit_input.py b/ionq_core/models/qis_circuit_input.py index 358b3c5..0f98439 100644 --- a/ionq_core/models/qis_circuit_input.py +++ b/ionq_core/models/qis_circuit_input.py @@ -17,7 +17,26 @@ from typing import cast if TYPE_CHECKING: - from ..models.gate_qis_gate import GateQisGate + from ..models.gate_cnot import GateCnot + from ..models.gate_h import GateH + from ..models.gate_not import GateNot + from ..models.gate_pauliexp import GatePauliexp + from ..models.gate_rx import GateRx + from ..models.gate_ry import GateRy + from ..models.gate_rz import GateRz + from ..models.gate_s import GateS + from ..models.gate_si import GateSi + from ..models.gate_swap import GateSwap + from ..models.gate_t import GateT + from ..models.gate_ti import GateTi + from ..models.gate_v import GateV + from ..models.gate_vi import GateVi + from ..models.gate_x import GateX + from ..models.gate_xx import GateXX + from ..models.gate_y import GateY + from ..models.gate_yy import GateYY + from ..models.gate_z import GateZ + from ..models.gate_zz import GateZZ @@ -32,12 +51,13 @@ class QisCircuitInput: """ Attributes: qubits (int): - circuit (list[GateQisGate]): + circuit (list[GateCnot | GateH | GateNot | GatePauliexp | GateRx | GateRy | GateRz | GateS | GateSi | GateSwap | + GateT | GateTi | GateV | GateVi | GateX | GateXX | GateY | GateYY | GateZ | GateZZ]): gateset (QisCircuitInputGateset): """ qubits: int - circuit: list[GateQisGate] + circuit: list[GateCnot | GateH | GateNot | GatePauliexp | GateRx | GateRy | GateRz | GateS | GateSi | GateSwap | GateT | GateTi | GateV | GateVi | GateX | GateXX | GateY | GateYY | GateZ | GateZZ] gateset: QisCircuitInputGateset @@ -45,12 +65,72 @@ class QisCircuitInput: def to_dict(self) -> dict[str, Any]: - from ..models.gate_qis_gate import GateQisGate + from ..models.gate_cnot import GateCnot + from ..models.gate_h import GateH + from ..models.gate_not import GateNot + from ..models.gate_pauliexp import GatePauliexp + from ..models.gate_rx import GateRx + from ..models.gate_ry import GateRy + from ..models.gate_rz import GateRz + from ..models.gate_s import GateS + from ..models.gate_si import GateSi + from ..models.gate_swap import GateSwap + from ..models.gate_t import GateT + from ..models.gate_ti import GateTi + from ..models.gate_v import GateV + from ..models.gate_vi import GateVi + from ..models.gate_x import GateX + from ..models.gate_xx import GateXX + from ..models.gate_y import GateY + from ..models.gate_yy import GateYY + from ..models.gate_z import GateZ + from ..models.gate_zz import GateZZ qubits = self.qubits circuit = [] for circuit_item_data in self.circuit: - circuit_item = circuit_item_data.to_dict() + circuit_item: dict[str, Any] + if isinstance(circuit_item_data, GatePauliexp): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateCnot): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateSwap): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateRx): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateRy): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateRz): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateXX): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateYY): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateZZ): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateNot): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateX): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateY): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateZ): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateH): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateS): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateSi): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateT): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateTi): + circuit_item = circuit_item_data.to_dict() + elif isinstance(circuit_item_data, GateV): + circuit_item = circuit_item_data.to_dict() + else: + circuit_item = circuit_item_data.to_dict() + circuit.append(circuit_item) @@ -72,16 +152,232 @@ def to_dict(self) -> dict[str, Any]: @classmethod def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - from ..models.gate_qis_gate import GateQisGate + from ..models.gate_cnot import GateCnot + from ..models.gate_h import GateH + from ..models.gate_not import GateNot + from ..models.gate_pauliexp import GatePauliexp + from ..models.gate_rx import GateRx + from ..models.gate_ry import GateRy + from ..models.gate_rz import GateRz + from ..models.gate_s import GateS + from ..models.gate_si import GateSi + from ..models.gate_swap import GateSwap + from ..models.gate_t import GateT + from ..models.gate_ti import GateTi + from ..models.gate_v import GateV + from ..models.gate_vi import GateVi + from ..models.gate_x import GateX + from ..models.gate_xx import GateXX + from ..models.gate_y import GateY + from ..models.gate_yy import GateYY + from ..models.gate_z import GateZ + from ..models.gate_zz import GateZZ d = dict(src_dict) qubits = d.pop("qubits") circuit = [] _circuit = d.pop("circuit") for circuit_item_data in (_circuit): - circuit_item = GateQisGate.from_dict(circuit_item_data) + def _parse_circuit_item(data: object) -> GateCnot | GateH | GateNot | GatePauliexp | GateRx | GateRy | GateRz | GateS | GateSi | GateSwap | GateT | GateTi | GateV | GateVi | GateX | GateXX | GateY | GateYY | GateZ | GateZZ: + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_0 = GatePauliexp.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_1 = GateCnot.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_1 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_2 = GateSwap.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_2 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_3 = GateRx.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_3 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_4 = GateRy.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_4 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_5 = GateRz.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_5 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_6 = GateXX.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_6 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_7 = GateYY.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_7 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_8 = GateZZ.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_8 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_9 = GateNot.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_9 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_10 = GateX.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_10 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_11 = GateY.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_11 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_12 = GateZ.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_12 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_13 = GateH.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_13 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_14 = GateS.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_14 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_15 = GateSi.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_15 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_16 = GateT.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_16 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_17 = GateTi.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_17 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_18 = GateV.from_dict(data) + + + + return componentsschemas_gate_qis_gate_type_18 + except (TypeError, ValueError, AttributeError, KeyError): + pass + if not isinstance(data, dict): + raise TypeError() + componentsschemas_gate_qis_gate_type_19 = GateVi.from_dict(data) + + + return componentsschemas_gate_qis_gate_type_19 + circuit_item = _parse_circuit_item(circuit_item_data) circuit.append(circuit_item) diff --git a/openapi-overlay.yaml b/openapi-overlay.yaml index 00c0976..6ce81b5 100644 --- a/openapi-overlay.yaml +++ b/openapi-overlay.yaml @@ -1,14 +1,48 @@ overlay: 1.0.0 info: title: ionq-core-python local OpenAPI fixes - version: 0.1.0 + version: 0.2.0 description: | - Patches applied to openapi.json before client generation. The upstream - spec marks QisCircuitInput.qubits as optional and floating-point, but - the simulator preflight rejects payloads without it (surfacing as - UnexpectedCompilationError) and qubit counts are non-negative integers. + Patches applied to openapi.json before client generation by oas-patch. + + Patch 1 - QisCircuitInput.qubits + + Mark `qubits` required and type it as a non-negative integer. + Upstream marks it optional and floating-point. + + Patch 2 - Gate_QisGate restructure (oneOf + discriminator) + + Upstream Gate_QisGate is a single flat object allowing any + combination of {gate, target, targets, control, controls, rotation} + with additionalProperties: false. Three problems: + + (a) `pauliexp` needs terms/coefficients/time fields the schema + does not declare, so every pauliexp payload violates it. + (b) targets/controls are typed number/double, but qubit indices + are non-negative integers. + (c) The flat-bag shape lets nonsensical combinations validate + (e.g. {gate: "h", control: 0, controls: [1], rotation: 1.5}). + + Replace with a oneOf + discriminator(propertyName: gate) tagged + union, one variant per gate. This is OpenAPI's standard pattern + for polymorphic types, also used by AWS Braket JAQCD. + + openapi-python-client 0.28.3 emits a Union[Gate_X, Gate_Y, ...] + alias and tries each variant's from_dict in order. With each + variant pinning `gate` to `enum: []` (and `literal_enums: + true` in the generator config), each class gets `Literal["x"]` + typing and mismatches reject cleanly. Variants are listed most- + constrained first (pauliexp -> parametric -> 2-qubit -> 1-qubit) + so payloads resolve to the most specific variant. + + Once upstream openapi.json at api.ionq.co adopts these fixes, prune + the corresponding actions here. actions: + # =========================================================================== + # Patch 1 - QisCircuitInput.qubits required + integer + # =========================================================================== + - target: $.components.schemas.QisCircuitInput.required remove: true - target: $.components.schemas.QisCircuitInput @@ -21,3 +55,356 @@ actions: update: type: integer format: int32 + minimum: 0 + + # =========================================================================== + # Patch 2 - Replace Gate_QisGate with discriminated union of per-gate variants + # =========================================================================== + + - target: $.components.schemas.Gate_QisGate + remove: true + + - target: $.components.schemas + update: + + # ---- single-target Pauli/Clifford/T-family gates -------------------- + + Gate_X: + type: object + additionalProperties: false + required: [gate, targets] + description: | + Pauli-X. With `controls`, this is the canonical multi-controlled + NOT (Gate_Cnot for the single-control case, Gate_Not for the + explicit form). + properties: + gate: { type: string, enum: [x] } + targets: &single_target + type: array + minItems: 1 + maxItems: 1 + items: &qubit_index + type: integer + format: int32 + minimum: 0 + description: The single qubit the gate acts on. + controls: &controls + type: array + items: *qubit_index + description: Optional control qubits. + + Gate_Y: + type: object + additionalProperties: false + required: [gate, targets] + properties: + gate: { type: string, enum: [y] } + targets: *single_target + controls: *controls + + Gate_Z: + type: object + additionalProperties: false + required: [gate, targets] + properties: + gate: { type: string, enum: [z] } + targets: *single_target + controls: *controls + + Gate_H: + type: object + additionalProperties: false + required: [gate, targets] + properties: + gate: { type: string, enum: [h] } + targets: *single_target + controls: *controls + + Gate_S: + type: object + additionalProperties: false + required: [gate, targets] + properties: + gate: { type: string, enum: [s] } + targets: *single_target + controls: *controls + + Gate_Si: + type: object + additionalProperties: false + required: [gate, targets] + description: S-dagger (inverse of S). + properties: + gate: { type: string, enum: [si] } + targets: *single_target + controls: *controls + + Gate_T: + type: object + additionalProperties: false + required: [gate, targets] + properties: + gate: { type: string, enum: [t] } + targets: *single_target + controls: *controls + + Gate_Ti: + type: object + additionalProperties: false + required: [gate, targets] + description: T-dagger (inverse of T). + properties: + gate: { type: string, enum: [ti] } + targets: *single_target + controls: *controls + + Gate_V: + type: object + additionalProperties: false + required: [gate, targets] + description: Square root of X. + properties: + gate: { type: string, enum: [v] } + targets: *single_target + controls: *controls + + Gate_Vi: + type: object + additionalProperties: false + required: [gate, targets] + description: V-dagger (inverse of V). + properties: + gate: { type: string, enum: [vi] } + targets: *single_target + controls: *controls + + # ---- multi-controlled NOT -------------------------------------------- + + Gate_Not: + type: object + additionalProperties: false + required: [gate, targets, controls] + description: | + Multi-controlled NOT with one or more controls. Functionally + equivalent to Gate_X with `controls`; kept as an explicit + alternative. + properties: + gate: { type: string, enum: [not] } + targets: *single_target + controls: + type: array + minItems: 1 + items: *qubit_index + description: One or more control qubits. + + # ---- two-qubit non-parametric gates --------------------------------- + + Gate_Cnot: + type: object + additionalProperties: false + required: [gate, targets, controls] + description: Controlled-NOT with one control and one target. + properties: + gate: { type: string, enum: [cnot] } + targets: *single_target + controls: + type: array + minItems: 1 + maxItems: 1 + items: *qubit_index + description: The single control qubit. + + Gate_Swap: + type: object + additionalProperties: false + required: [gate, targets] + description: Two-qubit SWAP. + properties: + gate: { type: string, enum: [swap] } + targets: &two_targets + type: array + minItems: 2 + maxItems: 2 + items: *qubit_index + description: The two qubits the gate acts on. + + # ---- single-qubit parametric rotations ------------------------------ + + Gate_Rx: + type: object + additionalProperties: false + required: [gate, targets, rotation] + properties: + gate: { type: string, enum: [rx] } + targets: *single_target + rotation: &rotation_radians + type: number + format: double + description: Rotation angle in radians. + controls: *controls + + Gate_Ry: + type: object + additionalProperties: false + required: [gate, targets, rotation] + properties: + gate: { type: string, enum: [ry] } + targets: *single_target + rotation: *rotation_radians + controls: *controls + + Gate_Rz: + type: object + additionalProperties: false + required: [gate, targets, rotation] + properties: + gate: { type: string, enum: [rz] } + targets: *single_target + rotation: *rotation_radians + controls: *controls + + # ---- two-qubit parametric Pauli (Ising) rotations ------------------- + + Gate_XX: + type: object + additionalProperties: false + required: [gate, targets, rotation] + description: Two-qubit XX (Ising-XX) rotation, exp(-i theta/2 X⊗X). + properties: + gate: { type: string, enum: [xx] } + targets: *two_targets + rotation: *rotation_radians + + Gate_YY: + type: object + additionalProperties: false + required: [gate, targets, rotation] + description: Two-qubit YY (Ising-YY) rotation, exp(-i theta/2 Y⊗Y). + properties: + gate: { type: string, enum: [yy] } + targets: *two_targets + rotation: *rotation_radians + + Gate_ZZ: + type: object + additionalProperties: false + required: [gate, targets, rotation] + description: | + Two-qubit ZZ (Ising-ZZ) rotation, exp(-i theta/2 Z⊗Z), with + `rotation` in radians. Distinct from the native-gateset `zz`, + which takes a `phase` parameter in turns. + properties: + gate: { type: string, enum: [zz] } + targets: *two_targets + rotation: *rotation_radians + + # ---- Pauli exponential (sparse Hamiltonian time evolution) ---------- + + Gate_Pauliexp: + type: object + additionalProperties: false + required: [gate, targets, terms, coefficients, time] + description: | + Sparse Pauli exponential gate. Trotter-decomposed per term: + + U = prod_k exp(-i * coefficients[k] * time * P_k) + + where P_k is the tensor product of single-qubit Paulis encoded + as `terms[k]`, and `terms[k][i]` (a character in {I,X,Y,Z}) acts + on the qubit at `targets[i]`. + + `time` is a global multiplier on every coefficient. + + Constraints: + * `terms[k]` has length equal to `len(targets)` for every k. + * `coefficients` has the same length as `terms`. + * `coefficients` are real numbers. + * `time` is strictly positive. + * Endianness: `terms[k][0]` acts on `targets[0]` (big-endian + by position). + + Because the formula is a Trotter decomposition, non-commuting + terms yield an approximation rather than the exact exp(-i t H). + properties: + gate: { type: string, enum: [pauliexp] } + targets: + type: array + minItems: 1 + items: *qubit_index + description: Qubits the Pauli operators act on, in order. + terms: + type: array + minItems: 1 + items: + type: string + pattern: '^[IXYZ]+$' + description: | + Pauli words in {I, X, Y, Z}. `terms[k][i]` acts on + `targets[i]`. Every term has length equal to `len(targets)`. + coefficients: + type: array + minItems: 1 + items: + type: number + format: double + description: Real coefficient for each Pauli term, parallel to `terms`. + time: + type: number + format: double + minimum: 0 + exclusiveMinimum: true + description: | + Strictly-positive global multiplier. The kth term's + effective rotation is `coefficients[k] * time`. + + # ---- discriminated union -------------------------------------------- + + Gate_QisGate: + description: | + A single QIS-gateset instruction. Tagged union discriminated by + the `gate` field. Variants are listed most-constrained first + (see Patch 2 notes). + oneOf: + - { $ref: '#/components/schemas/Gate_Pauliexp' } + - { $ref: '#/components/schemas/Gate_Cnot' } + - { $ref: '#/components/schemas/Gate_Swap' } + - { $ref: '#/components/schemas/Gate_Rx' } + - { $ref: '#/components/schemas/Gate_Ry' } + - { $ref: '#/components/schemas/Gate_Rz' } + - { $ref: '#/components/schemas/Gate_XX' } + - { $ref: '#/components/schemas/Gate_YY' } + - { $ref: '#/components/schemas/Gate_ZZ' } + - { $ref: '#/components/schemas/Gate_Not' } + - { $ref: '#/components/schemas/Gate_X' } + - { $ref: '#/components/schemas/Gate_Y' } + - { $ref: '#/components/schemas/Gate_Z' } + - { $ref: '#/components/schemas/Gate_H' } + - { $ref: '#/components/schemas/Gate_S' } + - { $ref: '#/components/schemas/Gate_Si' } + - { $ref: '#/components/schemas/Gate_T' } + - { $ref: '#/components/schemas/Gate_Ti' } + - { $ref: '#/components/schemas/Gate_V' } + - { $ref: '#/components/schemas/Gate_Vi' } + discriminator: + propertyName: gate + mapping: + pauliexp: '#/components/schemas/Gate_Pauliexp' + cnot: '#/components/schemas/Gate_Cnot' + swap: '#/components/schemas/Gate_Swap' + rx: '#/components/schemas/Gate_Rx' + ry: '#/components/schemas/Gate_Ry' + rz: '#/components/schemas/Gate_Rz' + xx: '#/components/schemas/Gate_XX' + yy: '#/components/schemas/Gate_YY' + zz: '#/components/schemas/Gate_ZZ' + not: '#/components/schemas/Gate_Not' + x: '#/components/schemas/Gate_X' + y: '#/components/schemas/Gate_Y' + z: '#/components/schemas/Gate_Z' + h: '#/components/schemas/Gate_H' + s: '#/components/schemas/Gate_S' + si: '#/components/schemas/Gate_Si' + t: '#/components/schemas/Gate_T' + ti: '#/components/schemas/Gate_Ti' + v: '#/components/schemas/Gate_V' + vi: '#/components/schemas/Gate_Vi' diff --git a/tests/integration/test_simulator_job.py b/tests/integration/test_simulator_job.py index 602535d..1385d95 100644 --- a/tests/integration/test_simulator_job.py +++ b/tests/integration/test_simulator_job.py @@ -27,8 +27,8 @@ "gateset": "qis", "qubits": 2, "circuit": [ - {"gate": "h", "target": 0}, - {"gate": "cnot", "control": 0, "target": 1}, + {"gate": "h", "targets": [0]}, + {"gate": "cnot", "targets": [1], "controls": [0]}, ], }, } diff --git a/tests/test_api.py b/tests/test_api.py index 176829a..b3c0955 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -112,7 +112,7 @@ def test_sync(self, httpx_mock, auth_client): "type": "ionq.circuit.v1", "backend": "simulator", "shots": 100, - "input": {"gateset": "qis", "qubits": 1, "circuit": [{"gate": "h", "target": 0}]}, + "input": {"gateset": "qis", "qubits": 1, "circuit": [{"gate": "h", "targets": [0]}]}, } ) result = create_job.sync(client=auth_client, body=body)