GRID_STAGGERED_PATTERN = (
    GridInteractionLayer(col_offset=0, vertical=True, stagger=True),  # A
    GridInteractionLayer(col_offset=1, vertical=True, stagger=True),  # B
    GridInteractionLayer(col_offset=1, vertical=False, stagger=True),  # C
    GridInteractionLayer(col_offset=0, vertical=False, stagger=True),  # D
    GridInteractionLayer(col_offset=1, vertical=False, stagger=True),  # C
    GridInteractionLayer(col_offset=0, vertical=False, stagger=True),  # D
    GridInteractionLayer(col_offset=0, vertical=True, stagger=True),  # A
    GridInteractionLayer(col_offset=1, vertical=True, stagger=True),  # B
)
document(
    GRID_STAGGERED_PATTERN,
    """A pattern of two-qubit gates that is hard to simulate.

    This pattern of gates was used in the paper
    https://www.nature.com/articles/s41586-019-1666-5
    to demonstrate quantum supremacy.
    """,
)

HALF_GRID_STAGGERED_PATTERN = (
    GridInteractionLayer(col_offset=0, vertical=True, stagger=True),  # A
    GridInteractionLayer(col_offset=1, vertical=True, stagger=True),  # B
    GridInteractionLayer(col_offset=1, vertical=False, stagger=True),  # C
    GridInteractionLayer(col_offset=0, vertical=False, stagger=True),  # D
)
document(
    HALF_GRID_STAGGERED_PATTERN,
    """A pattern that is half of GRID_STAGGERED_PATTERN.
Exemple #2
0
from typing import List, Optional, Type, Union, cast, TYPE_CHECKING

import numpy as np

from cirq import circuits, protocols, study, devices, ops, value
from cirq._doc import document
from cirq.sim import sparse_simulator, density_matrix_simulator
from cirq.sim.clifford import clifford_simulator

if TYPE_CHECKING:
    import cirq

CIRCUIT_LIKE = Union[circuits.Circuit, ops.Gate, ops.OP_TREE]
document(
    CIRCUIT_LIKE,  # type: ignore
    """A `circuits.Circuit` or a value that can be trivially converted into it:
        a gate, an operation, and a list or tree of operations.
    """,
)


def _is_clifford_circuit(program: 'cirq.Circuit') -> bool:
    return all(
        clifford_simulator.CliffordSimulator.is_supported_operation(op)
        for op in program.all_operations()
    )


def sample(
    program: 'cirq.Circuit',
    *,
    noise: 'cirq.NOISE_MODEL_LIKE' = None,
Exemple #3
0
    import cirq

DEFAULT_COMPLEX_DTYPE = np.complex64

STATE_VECTOR_LIKE = Union[
    # Full big-endian computational basis state index.
    int,
    # Per-qudit computational basis values.
    Sequence[int],
    # Explicit state vector or state tensor.
    np.ndarray,
    Sequence[Union[int, float, complex]],
    # Product state object
    'cirq.ProductState',
]
document(STATE_VECTOR_LIKE, """An object representing a state vector.""")  # type: ignore

QUANTUM_STATE_LIKE = Union[
    # state vector
    STATE_VECTOR_LIKE,
    # density matrix
    np.ndarray,
    # quantum state object
    'cirq.QuantumState',
]
document(QUANTUM_STATE_LIKE, """An object representing a quantum state.""")  # type: ignore


class QuantumState:
    """A quantum state.
Exemple #4
0
    def __new__(cls, qubits: Sequence['cirq.Qid']):
        return IdentityGate(qid_shape=protocols.qid_shape(qubits)).on(*qubits)

    @property
    def qubits(self) -> Tuple['cirq.Qid', ...]:
        raise NotImplementedError('deprecated')

    def with_qubits(self, *new_qubits: 'cirq.Qid') -> 'cirq.Operation':
        raise NotImplementedError('deprecated')


I = IdentityGate(num_qubits=1)
document(
    I, """The one qubit identity gate.

    Matrix:

        [[1, 0],
         [0, 1]]
    """)


def identity_each(*qubits: 'cirq.Qid') -> 'cirq.Operation':
    """Returns a single IdentityGate applied to all the given qubits.

    Args:
        *qubits: The qubits that the identity gate will apply to.

    Returns:
        An identity operation on the given qubits.

    Raises:
Exemple #5
0
        SYC_SERIALIZER,
        *SINGLE_QUBIT_SERIALIZERS,
        *SINGLE_QUBIT_HALF_PI_SERIALIZERS,
        MEASUREMENT_SERIALIZER,
        WAIT_GATE_SERIALIZER,
    ],
    deserializers=[
        SYC_DESERIALIZER,
        *SINGLE_QUBIT_DESERIALIZERS,
        *SINGLE_QUBIT_HALF_PI_DESERIALIZERS,
        MEASUREMENT_DESERIALIZER,
        WAIT_GATE_DESERIALIZER,
    ],
)
document(
    SYC_GATESET,
    """Gate set with fsim(pi/4, pi/6) as the core 2 qubit interaction.""")

SQRT_ISWAP_GATESET = serializable_gate_set.SerializableGateSet(
    gate_set_name='sqrt_iswap',
    serializers=[
        *SQRT_ISWAP_SERIALIZERS,
        *SINGLE_QUBIT_SERIALIZERS,
        MEASUREMENT_SERIALIZER,
        WAIT_GATE_SERIALIZER,
    ],
    deserializers=[
        *SQRT_ISWAP_DESERIALIZERS,
        *SINGLE_QUBIT_DESERIALIZERS,
        MEASUREMENT_DESERIALIZER,
        WAIT_GATE_DESERIALIZER,
Exemple #6
0
    @property
    def keys(self) -> List[str]:
        return []

    def __len__(self) -> int:
        return 1

    def param_tuples(self) -> Iterator[Params]:
        yield ()

    def __repr__(self):
        return 'cirq.UnitSweep'


UnitSweep = _Unit()
document(UnitSweep, """The singleton sweep with no parameters.""")


class Product(Sweep):
    """Cartesian product of one or more sweeps.

    If one sweep assigns 'a' to the values 0, 1, 2, and the second sweep
    assigns 'b' to the values 2, 3, then the product is a sweep that
    assigns the tuple ('a','b') to all possible combinations of these
    assignments: (0, 2), (1, 2), (2, 2), (0, 3), (1, 3), (2, 3).
    """

    def __init__(self, *factors: Sweep) -> None:
        _check_duplicate_keys(factors)
        self.factors = factors
Exemple #7
0
    @property
    def basis(self: '_PauliZ') -> Dict[int, '_ZEigenState']:
        from cirq.value.product_state import _ZEigenState

        return {
            +1: _ZEigenState(+1),
            -1: _ZEigenState(-1),
        }


X = _PauliX()
document(
    X,
    """The Pauli X gate.

    Matrix:

        [[0, 1],
         [1, 0]]
    """,
)

Y = _PauliY()
document(
    Y,
    """The Pauli Y gate.

    Matrix:

        [[0, -i],
         [i, 0]]
    """,
from typing import Dict, Tuple

import numpy as np

from cirq import value
from cirq._doc import document

PAULI_BASIS = {
    'I': np.eye(2),
    'X': np.array([[0., 1.], [1., 0.]]),
    'Y': np.array([[0., -1j], [1j, 0.]]),
    'Z': np.diag([1., -1]),
}
document(
    PAULI_BASIS,
    """The four Pauli matrices (including identity) keyed by character.""")


def kron_bases(*bases: Dict[str, np.ndarray],
               repeat: int = 1) -> Dict[str, np.ndarray]:
    """Creates tensor product of bases."""
    product_basis = {'': 1}
    for basis in bases * repeat:
        product_basis = {
            name1 + name2: np.kron(matrix1, matrix2)
            for name1, matrix1 in product_basis.items()
            for name2, matrix2 in basis.items()
        }
    return product_basis
from typing import Any, cast, Dict, NamedTuple, Optional, Sequence, Tuple, TYPE_CHECKING, Union

import numpy as np

from cirq import protocols, value, linalg
from cirq._doc import document
from cirq.ops import common_gates, gate_features, named_qubit, pauli_gates
from cirq.ops.pauli_gates import Pauli
from cirq.type_workarounds import NotImplementedType

if TYPE_CHECKING:
    import cirq

PauliTransform = NamedTuple('PauliTransform', [('to', Pauli), ('flip', bool)])
document(PauliTransform, """+X, -X, +Y, -Y, +Z, or -Z.""")


def _to_pauli_transform(matrix: np.ndarray) -> Optional[PauliTransform]:
    """Converts matrix to PauliTransform.

    If matrix is not ±Pauli matrix, returns None.
    """
    for pauli in Pauli._XYZ:
        p = protocols.unitary(pauli)
        if np.allclose(matrix, p):
            return PauliTransform(pauli, False)
        if np.allclose(matrix, -p):
            return PauliTransform(pauli, True)
    return None
        # coverage: ignore
        raise ValueError("Bad eigenvalue: {}".format(self.eigenvalue))

    def stabilized_by(self) -> Tuple[int, 'cirq.Pauli']:
        from cirq import ops

        return self.eigenvalue, ops.Z


KET_PLUS = _XEigenState(eigenvalue=+1)
document(
    KET_PLUS,
    """The |+⟩ State

    This is the state such that X|+⟩ = +1 |+⟩

    Vector:

        [1, 1] / sqrt(2)
    """,
)

KET_MINUS = _XEigenState(eigenvalue=-1)
document(
    KET_MINUS,
    """The |-⟩ State

    This is the state such that X|-⟩ = -1 |-⟩

    Vector:
Exemple #11
0
from cirq import protocols
from cirq._compat import proper_repr
from cirq._doc import document

if TYPE_CHECKING:
    import cirq

DURATION_LIKE = Union[None, datetime.timedelta, 'cirq.Duration']
document(
    DURATION_LIKE,  # type: ignore
    """A `cirq.Duration` or value that can trivially converted to one.

    A `datetime.timedelta` is a `cirq.DURATION_LIKE`. It is converted while
    preserving its duration.

    `None` is a `cirq.DURATION_LIKE` that converts into a zero-length duration.

    Note that 0 is a `DURATION_LIKE`, despite the fact that `int` is not listed,
    because 0 is the only integer where the physical unit doesn't matter.
    """,
)


class Duration:
    """A time delta that supports symbols and picosecond accuracy."""
    def __init__(
        self,
        value: DURATION_LIKE = None,
        *,  # Force keyword args.
        picos: Union[int, float, sympy.Basic] = 0,
Exemple #12
0
from cirq import protocols, value
from cirq._doc import document
from cirq.linalg import operator_spaces
from cirq.ops import identity, raw_types, pauli_gates, pauli_string
from cirq.ops.pauli_string import PauliString, _validate_qubit_mapping
from cirq.value.linear_dict import _format_terms

if TYPE_CHECKING:
    import cirq

UnitPauliStringT = FrozenSet[Tuple[raw_types.Qid, pauli_gates.Pauli]]
PauliSumLike = Union[int, float, complex, PauliString, 'PauliSum',
                     pauli_string.SingleQubitPauliStringGateOperation]
document(
    PauliSumLike,  # type: ignore
    """Any value that can be easily translated into a sum of Pauli products.
    """)


class LinearCombinationOfGates(value.LinearDict[raw_types.Gate]):
    """Represents linear operator defined by a linear combination of gates.

    Suppose G1, G2, ..., Gn are gates and b1, b2, ..., bn are complex
    numbers. Then

        LinearCombinationOfGates({G1: b1, G2: b2, ..., Gn: bn})

    represents the linear operator

        A = b1 G1 + b2 G2 + ... + bn Gn
Exemple #13
0
            moment,
            ops.Moment([
                # TODO: Replace with "VirtualTag" class instance.
                self.qubit_noise_gate(q).with_tags(ops.VirtualTag())
                for q in system_qubits
            ])
        ]

    def _json_dict_(self):
        return protocols.obj_to_dict_helper(self, ['qubit_noise_gate'])


NO_NOISE: 'cirq.NoiseModel' = _NoNoiseModel()
document(
    NO_NOISE, """The trivial noise model with no effects.

    This is the noise model used when a `NOISE_MODEL_LIKE` noise parameter is
    set to `None`.
    """)

NOISE_MODEL_LIKE = Union[None, 'cirq.NoiseModel', 'cirq.SingleQubitGate']
document(
    NOISE_MODEL_LIKE,  # type: ignore
    """A `cirq.NoiseModel` or a value that can be trivially converted into one.

    `None` is a `NOISE_MODEL_LIKE`. It will be replaced by the `cirq.NO_NOISE`
    noise model.

    A single qubit gate is a `NOISE_MODEL_LIKE`. It will be wrapped inside of a
    `cirq.ConstantQubitNoiseModel`.
    """)
from cirq.protocols import json_serializable_dataclass
from cirq.work.observable_measurement_data import BitstringAccumulator
from cirq.work.observable_settings import (
    InitObsSetting,
    _MeasurementSpec,
)

if TYPE_CHECKING:
    import cirq
    from cirq.value.product_state import _NamedOneQubitState

MAX_REPETITIONS_PER_JOB = 3_000_000
document(
    MAX_REPETITIONS_PER_JOB,
    """The maximum repetitions allowed in a single batch job.

    This depends on the Sampler executing your batch job. It is set to be
    tens of minutes assuming ~kilosamples per second.
    """,
)


def _with_parameterized_layers(
    circuit: 'cirq.Circuit',
    qubits: Sequence['cirq.Qid'],
    needs_init_layer: bool,
) -> 'cirq.Circuit':
    """Return a copy of the input circuit with parameterized single-qubit rotations.

    These rotations flank the circuit: the initial two layers of X and Y gates
    are given parameter names "{qubit}-Xi" and "{qubit}-Yi" and are used
    to set up the initial state. If `needs_init_layer` is False,
Exemple #15
0
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Defines which types are Sweepable."""

from typing import Dict, Iterable, Iterator, List, Sequence, Union, cast
import warnings

from cirq._doc import document
from cirq.study.resolver import ParamResolver, ParamResolverOrSimilarType
from cirq.study.sweeps import ListSweep, Points, Sweep, UnitSweep, Zip, dict_to_product_sweep

SweepLike = Union[ParamResolverOrSimilarType, Sweep]
document(SweepLike,
         """An object similar to an iterable of parameter resolvers."""
         )  # type: ignore

Sweepable = Union[SweepLike, Iterable[SweepLike]]
document(
    Sweepable,  # type: ignore
    """An object or collection of objects representing a parameter sweep.""",
)


def to_resolvers(sweepable: Sweepable) -> Iterator[ParamResolver]:
    """Convert a Sweepable to a list of ParamResolvers."""
    for sweep in to_sweeps(sweepable):
        yield from sweep

Exemple #16
0
    def _value_equality_values_(self) -> Any:
        return self.phi

    def _circuit_diagram_info_(
        self, args: 'cirq.CircuitDiagramInfoArgs'
    ) -> Union[str, 'protocols.CircuitDiagramInfo']:
        return protocols.CircuitDiagramInfo(
            wire_symbols=(f'GPI({self.phase!r})', ))


GPI = GPIGate(phi=0)
document(
    GPI,
    r"""The GPI gate is a single qubit gate.
    The unitary of this gate is
        [[0, e^{-i*2*\pi*\phi}],
         [e^{-i*2*\pi*\phi}, 0]]
    It is driven by Rabi laser.
    https://ionq.com/best-practices
    """,
)


@cirq.value.value_equality
class GPI2Gate(cirq.Gate):
    r"""The GPI2 gate is a single qubit gate.
    The unitary of this gate is
        \frac{1}{/\sqrt{2}}[[1, -i*e^{-i\phi}],
         [-i*e^{-i\phi}, 1]]
    """
    def __init__(self, *, phi):
        self.phi = phi
Exemple #17
0

def riswap(rads: value.TParamVal) -> ISwapPowGate:
    """Returns gate with matrix exp(+i angle_rads (X⊗X + Y⊗Y) / 2)."""
    pi = sympy.pi if protocols.is_parameterized(rads) else np.pi
    return ISwapPowGate()**(2 * rads / pi)


SWAP = SwapPowGate()
document(
    SWAP,
    """The swap gate.

    Matrix:

    ```
        [[1, 0, 0, 0],
         [0, 0, 1, 0],
         [0, 1, 0, 0],
         [0, 0, 0, 1]]
    ```
    """,
)

ISWAP = ISwapPowGate()
document(
    ISWAP,
    """The iswap gate.

    Matrix:
    ```
        [[1, 0, 0, 0],
Exemple #18
0
def riswap(rads: value.TParamVal) -> ISwapPowGate:
    """Returns gate with matrix exp(+i angle_rads (X⊗X + Y⊗Y) / 2)."""
    pi = sympy.pi if protocols.is_parameterized(rads) else np.pi
    return ISwapPowGate()**(2 * rads / pi)


SWAP = SwapPowGate()
document(
    SWAP,
    r"""The swap gate.

    This gate will swap two qubits (in any basis).

    The unitary matrix of this gate is:
    $$
        \begin{bmatrix}
            1 & 0 & 0 & 0 \\
            & 0 & 1 & 0 \\
            & 1 & 0 & 0 \\
            0 & 0 & 0 & 1
        \end{bmatrix}
    $$
    """,
)

ISWAP = ISwapPowGate()
document(
    ISWAP,
    r"""The iswap gate.

    The unitary matrix of this gate is:
Exemple #19
0
               formatter: 'cirq.QuilFormatter') -> Optional[str]:
        return ''.join(formatter.format('I {0}\n', qubit) for qubit in qubits)

    @classmethod
    def _from_json_dict_(cls, num_qubits, qid_shape=None, **kwargs):
        return cls(num_qubits=num_qubits,
                   qid_shape=None if qid_shape is None else tuple(qid_shape))


I = IdentityGate(num_qubits=1)
document(
    I,
    """The one qubit identity gate.

    Matrix:
    ```
        [[1, 0],
         [0, 1]]
    ```
    """,
)


def identity_each(*qubits: 'cirq.Qid') -> 'cirq.Operation':
    """Returns a single IdentityGate applied to all the given qubits.

    Args:
        *qubits: The qubits that the identity gate will apply to.

    Returns:
        An identity operation on the given qubits.
Exemple #20
0
            determines the behavior of the empty kron product.

    Returns:
        The kronecker product of all the inputs.
    """
    product = np.ones(shape=(1, ) * shape_len)
    for m in factors:
        product = np.kron(product, m)
    return np.array(product)


CONTROL_TAG = np.array([[float('nan'), 0], [0, 1]])
document(
    CONTROL_TAG,
    """A special indicator value for `cirq.kron_with_controls`.

    This value is a stand-in for "control operations on the other qubits based
    on the value of this qubit", which otherwise doesn't have a proper matrix.
    """,
)


def kron_with_controls(
        *factors: Union[np.ndarray, complex, float]) -> np.ndarray:
    """Computes the kronecker product of a sequence of values and control tags.

    Use `cirq.CONTROL_TAG` to represent controls. Any entry of the output
    corresponding to a situation where the control is not satisfied will
    be overwritten by identity matrix elements.

    The control logic works by imbuing NaN with the meaning "failed to meet one
    or more controls". The normal kronecker product then spreads the per-item
Exemple #21
0
    pi = sympy.pi if protocols.is_parameterized(rads) else np.pi
    return ZPowGate(exponent=rads / pi, global_shift=-0.5)


@deprecated(deadline='v0.8.0', fix='Use cirq.rz, instead.')
def Rz(rads: value.TParamVal) -> ZPowGate:
    """Returns a gate with the matrix e^{-i Z rads / 2}."""
    return rz(rads)


H = HPowGate()
document(
    H, """The Hadamard gate.

    The `exponent=1` instance of `cirq.HPowGate`.

    Matrix:
        [[s, s],
         [s, -s]]
        where s = sqrt(0.5).
    """)

S = ZPowGate(exponent=0.5)
document(
    S, """The Clifford S gate.

    The `exponent=0.5` instance of `cirq.ZPowGate`.

    Matrix:
        [[1, 0],
         [0, i]]
    """)
Exemple #22
0
            'constant': self._repr,
        }


Foxtail = _NamedConstantXmonDevice(
    'cirq_google.Foxtail',
    measurement_duration=cirq.Duration(nanos=4000),
    exp_w_duration=cirq.Duration(nanos=20),
    exp_11_duration=cirq.Duration(nanos=50),
    qubits=_parse_device(_FOXTAIL_GRID)[0],
)
document(
    Foxtail,
    f"""72 xmon qubit device.

**Qubit grid**:
```
{str(Foxtail)}
```
""",
)

# Duration dict in picoseconds
_DURATIONS_FOR_XMON = {
    'cz': 45_000,
    'xy': 15_000,
    'z': 0,
    'meas': 4_000_000,  # 1000ns for readout, 3000ns for "ring down"
}

FOXTAIL_PROTO = create_device_proto_from_diagram(_FOXTAIL_GRID,
                                                 [gate_sets.XMON],
Exemple #23
0
                                qubits[0], qubits[1])


def riswap(rads: value.TParamVal) -> ISwapPowGate:
    """Returns gate with matrix exp(+i angle_rads (X⊗X + Y⊗Y) / 2)."""
    pi = sympy.pi if protocols.is_parameterized(rads) else np.pi
    return ISwapPowGate()**(2 * rads / pi)


SWAP = SwapPowGate()
document(
    SWAP,
    """The swap gate.

    Matrix:

        [[1, 0, 0, 0],
         [0, 0, 1, 0],
         [0, 1, 0, 0],
         [0, 0, 0, 1]]
    """,
)

ISWAP = ISwapPowGate()
document(
    ISWAP,
    """The iswap gate.

    Matrix:

        [[1, 0, 0, 0],
         [0, 0, i, 0],
Exemple #24
0

GRID_STAGGERED_PATTERN = (
    GridInteractionLayer(col_offset=0, vertical=True, stagger=True),  # A
    GridInteractionLayer(col_offset=1, vertical=True, stagger=True),  # B
    GridInteractionLayer(col_offset=1, vertical=False, stagger=True),  # C
    GridInteractionLayer(col_offset=0, vertical=False, stagger=True),  # D
    GridInteractionLayer(col_offset=1, vertical=False, stagger=True),  # C
    GridInteractionLayer(col_offset=0, vertical=False, stagger=True),  # D
    GridInteractionLayer(col_offset=0, vertical=True, stagger=True),  # A
    GridInteractionLayer(col_offset=1, vertical=True, stagger=True),  # B
)
document(
    GRID_STAGGERED_PATTERN,
    """A pattern of two-qubit gates that is hard to simulate.

    This pattern of gates was used in the paper
    https://www.nature.com/articles/s41586-019-1666-5
    to demonstrate quantum supremacy.
    """)

GRID_ALIGNED_PATTERN = (
    GridInteractionLayer(col_offset=0, vertical=False, stagger=False),  # E
    GridInteractionLayer(col_offset=1, vertical=False, stagger=False),  # F
    GridInteractionLayer(col_offset=0, vertical=True, stagger=False),  # G
    GridInteractionLayer(col_offset=1, vertical=True, stagger=False),  # H
)
document(
    GRID_ALIGNED_PATTERN,
    """A pattern of two-qubit gates that is easy to simulate.

    This pattern of gates was used in the paper
Exemple #25
0
            control_values=control_values,
            control_qid_shape=control_qid_shape,
        )


CCZ = CCZPowGate()
document(
    CCZ,
    """The Controlled-Controlled-Z gate.

    The `exponent=1` instance of `cirq.CCZPowGate`.

    Matrix:

    ```
        [[1 . . . . . . .],
         [. 1 . . . . . .],
         [. . 1 . . . . .],
         [. . . 1 . . . .],
         [. . . . 1 . . .],
         [. . . . . 1 . .],
         [. . . . . . 1 .],
         [. . . . . . . -1]]
    ```
    """,
)

CCNotPowGate = CCXPowGate
CCX = TOFFOLI = CCNOT = CCXPowGate()
document(
    CCX,
    """The TOFFOLI gate, also known as the Controlled-Controlled-X gate.
Exemple #26
0
class Job:
    """A job created on the IonQ API.

    Note that this is mutable, when calls to get status or results are made
    the job updates itself to the results returned from the API.

    If a job is canceled or deleted, only the job id and the status remain
    valid.
    """

    TERMINAL_STATES = ('completed', 'canceled', 'failed', 'deleted')
    document(
        TERMINAL_STATES,
        'States of the IonQ API job from which the job cannot transition. '
        'Note that deleted can only exist in a return call from a delete '
        '(subsequent calls will return not found).',
    )

    NON_TERMINAL_STATES = ('ready', 'submitted', 'running')
    document(
        NON_TERMINAL_STATES,
        'States of the IonQ API job which can transition to other states.')

    ALL_STATES = TERMINAL_STATES + NON_TERMINAL_STATES
    document(ALL_STATES, 'All states that an IonQ API job can exist in.')

    UNSUCCESSFUL_STATES = ('canceled', 'failed', 'deleted')
    document(
        UNSUCCESSFUL_STATES,
        'States of the IonQ API job when it was not successful and so does not have any '
        'data associated with it beyond an id and a status.',
    )

    def __init__(self, client: 'cirq_ionq.ionq_client._IonQClient',
                 job_dict: dict):
        """Construct an IonQJob.

        Users should not call this themselves. If you only know the `job_id`, use `get_job`
        on `cirq_ionq.Service`.

        Args:
            client: The client used for calling the API.
            job: A dict representing the response from a call to get_job on the client.
        """
        self._client = client
        self._job = job_dict

    def _refresh_job(self):
        """If the last fetched job is not terminal, gets the job from the API."""
        if self._job['status'] not in self.TERMINAL_STATES:
            self._job = self._client.get_job(self.job_id())

    def _check_if_unsuccessful(self):
        if self.status() in self.UNSUCCESSFUL_STATES:
            raise ionq_exceptions.IonQUnsuccessfulJobException(
                self.job_id(), self.status())

    def job_id(self) -> str:
        """Returns the job id (UID) for the job.

        This is the id used for identifying the job by the API.
        """
        return self._job['id']

    def status(self) -> str:
        """Gets the current status of the job.

        This will get a new job if the status of the job previously was determined to not be in
        a terminal state. A full list of states is given in `cirq_ionq.IonQJob.ALL_STATES`.

        Raises:
            IonQException: If the API is not able to get the status of the job.

        Returns:
            The job status.
        """
        self._refresh_job()
        return self._job['status']

    def target(self) -> str:
        """Returns the target where the job is to be run, or was run.

        Returns:
            'qpu' or 'simulator' depending on where the job was run or is running.

        Raises:
            IonQUnsuccessfulJob: If the job has failed, been canceled, or deleted.
            IonQException: If unable to get the status of the job from the API.
        """
        self._check_if_unsuccessful()
        return self._job['target']

    def name(self) -> str:
        """Returns the name of the job which was supplied during job creation.

        This is different than the `job_id`.

        Raises:
            IonQUnsuccessfulJob: If the job has failed, been canceled, or deleted.
            IonQException: If unable to get the status of the job from the API.
        """
        self._check_if_unsuccessful()
        return self._job['name']

    def num_qubits(self) -> int:
        """Returns the number of qubits for the job.

        Raises:
            IonQUnsuccessfulJob: If the job has failed, been canceled, or deleted.
            IonQException: If unable to get the status of the job from the API.
        """
        self._check_if_unsuccessful()
        return int(self._job['qubits'])

    def repetitions(self) -> int:
        """Returns the number of repetitions for the job.

        Raises:
            IonQUnsuccessfulJob: If the job has failed, been canceled, or deleted.
            IonQException: If unable to get the status of the job from the API.
        """
        self._check_if_unsuccessful()
        return int(self._job['metadata']['shots'])

    def measurement_dict(self) -> Dict[str, Sequence[int]]:
        """Returns a dictionary of measurement keys to target qubit index."""
        measurement_dict: Dict[str, Sequence[int]] = {}
        if 'metadata' in self._job:
            full_str = ''.join(value
                               for key, value in self._job['metadata'].items()
                               if key.startswith('measurement'))
            if full_str == '':
                return measurement_dict
            for key_value in full_str.split(chr(30)):
                key, value = key_value.split(chr(31))
                measurement_dict[key] = [int(t) for t in value.split(',')]
        return measurement_dict

    def results(
        self,
        timeout_seconds: int = 7200,
        polling_seconds: int = 1
    ) -> Union[results.QPUResult, results.SimulatorResult]:
        """Polls the IonQ api for results.

        Args:
            timeout_seconds: The total number of seconds to poll for.
            polling_seconds: The interval with which to poll.

        Returns:
            Either a `cirq_ionq.QPUResults` or `cirq_ionq.SimulatorResults` depending on whether
            the job was running on an actual quantum processor or a simulator.

        Raises:
            IonQUnsuccessfulJob: If the job has failed, been canceled, or deleted.
            IonQException: If unable to get the results from the API.
        """
        time_waited_seconds = 0
        while time_waited_seconds < timeout_seconds:
            # Status does a refresh.
            if self.status() in self.TERMINAL_STATES:
                break
            time.sleep(polling_seconds)
            time_waited_seconds += polling_seconds
        if self.status() != 'completed':
            if 'failure' in self._job and 'error' in self._job['failure']:
                error = self._job['failure']['error']
                raise RuntimeError(f'Job failed. Error message: {error}')
            raise RuntimeError(
                f'Job was not completed successful. Instead had status: {self.status()}'
            )
        # IonQ returns results in little endian, Cirq prefers to use big endian, so we convert.
        if self.target() == 'qpu':
            repetitions = self.repetitions()
            counts = {
                _little_endian_to_big(int(k), self.num_qubits()):
                int(repetitions * float(v))
                for k, v in self._job['data']['histogram'].items()
            }
            return results.QPUResult(
                counts=counts,
                num_qubits=self.num_qubits(),
                measurement_dict=self.measurement_dict(),
            )
        else:
            probabilities = {
                _little_endian_to_big(int(k), self.num_qubits()): float(v)
                for k, v in self._job['data']['histogram'].items()
            }
            return results.SimulatorResult(
                probabilities=probabilities,
                num_qubits=self.num_qubits(),
                measurement_dict=self.measurement_dict(),
                repetitions=self.repetitions(),
            )

    def cancel(self):
        """Cancel the given job.

        This mutates the job to only have a job id and status `canceled`.
        """
        self._job = self._client.cancel_job(job_id=self.job_id())

    def delete(self):
        """Delete the given job.

        This mutates the job to only have a job id and status `deleted`. Subsequence attempts to
        get the job with this job id will return not found.
        """
        self._job = self._client.delete_job(job_id=self.job_id())

    def __str__(self) -> str:
        return f'cirq_ionq.Job(job_id={self.job_id()})'
Exemple #27
0
    serializers=[
        SYC_SERIALIZER,
        *SINGLE_QUBIT_SERIALIZERS,
        *SINGLE_QUBIT_HALF_PI_SERIALIZERS,
        MEASUREMENT_SERIALIZER,
        WAIT_GATE_SERIALIZER,
    ],
    deserializers=[
        SYC_DESERIALIZER,
        *SINGLE_QUBIT_DESERIALIZERS,
        *SINGLE_QUBIT_HALF_PI_DESERIALIZERS,
        MEASUREMENT_DESERIALIZER,
        WAIT_GATE_DESERIALIZER,
    ],
)
document(SYC_GATESET,
         """Gate set with fsim(pi/2, pi/6) as the core 2 qubit interaction.""")

SQRT_ISWAP_GATESET = serializable_gate_set.SerializableGateSet(
    gate_set_name='sqrt_iswap',
    serializers=[
        *SQRT_ISWAP_SERIALIZERS,
        *SINGLE_QUBIT_SERIALIZERS,
        MEASUREMENT_SERIALIZER,
        WAIT_GATE_SERIALIZER,
    ],
    deserializers=[
        *SQRT_ISWAP_DESERIALIZERS,
        *SINGLE_QUBIT_DESERIALIZERS,
        MEASUREMENT_DESERIALIZER,
        WAIT_GATE_DESERIALIZER,
    ])
Exemple #28
0
if TYPE_CHECKING:
    import cirq

# A value that can be unambiguously converted into a `cirq.PauliString`.

PAULI_STRING_LIKE = Union[
    complex, 'cirq.OP_TREE', Mapping['cirq.Qid', 'cirq.PAULI_GATE_LIKE'],
    Iterable,  # of PAULI_STRING_LIKE, but mypy doesn't do recursive types yet.
]
document(
    PAULI_STRING_LIKE,  # type: ignore
    """A `cirq.PauliString` or a value that can easily be converted into one.

    Complex numbers turn into the coefficient of an empty Pauli string.

    Dictionaries from qubit to Pauli operation are wrapped into a Pauli string.
    Each Pauli operation can be specified as a cirq object (e.g. `cirq.X`) or as
    a string (e.g. `"X"`) or as an integer where 0=I, 1=X, 2=Y, 3=Z.

    Collections of Pauli operations are recrusively multiplied into a single
    Pauli string.
    """)

PAULI_GATE_LIKE = Union['cirq.Pauli', 'cirq.IdentityGate', str, int, ]
document(
    PAULI_GATE_LIKE,  # type: ignore
    """An object that can be interpreted as a Pauli gate.

    Allowed values are:

    1. Cirq gates: `cirq.I`, `cirq.X`, `cirq.Y`, `cirq.Z`.
Exemple #29
0
from typing import cast, Any

import numpy as np

from cirq._doc import document

RANDOM_STATE_LIKE = Any
document(
    RANDOM_STATE_LIKE,
    """A pseudorandom number generator or object that can be converted to one.

    If None, turns into the module `np.random`.

    If an integer, turns into a `np.random.RandomState` seeded with that
    integer.

    If none of the above, it is used unmodified. In this case, it is assumed
    that the object implements whatever methods are required for the use case
    at hand. For example, it might be an existing instance of
    `np.random.RandomState` or a custom pseudorandom number generator
    implementation.
    """)


def parse_random_state(random_state: RANDOM_STATE_LIKE
                      ) -> np.random.RandomState:
    """Interpret an object as a pseudorandom number generator.

    If `random_state` is None, returns the module `np.random`.
    If `random_state` is an integer, returns
Exemple #30
0
        return 'ZZ**{}'.format(self._exponent)

    def __repr__(self) -> str:
        if self._global_shift == 0:
            if self._exponent == 1:
                return 'cirq.ZZ'
            return '(cirq.ZZ**{})'.format(proper_repr(self._exponent))
        return ('cirq.ZZPowGate(exponent={}, '
                'global_shift={!r})').format(proper_repr(self._exponent),
                                             self._global_shift)


XX = XXPowGate()
document(
    XX, """The tensor product of two X gates.

    The `exponent=1` instance of `cirq.XXPowGate`.
    """)
YY = YYPowGate()
document(
    YY, """The tensor product of two Y gates.

    The `exponent=1` instance of `cirq.YYPowGate`.
    """)
ZZ = ZZPowGate()
document(
    ZZ, """The tensor product of two Z gates.

    The `exponent=1` instance of `cirq.ZZPowGate`.
    """)