from __future__ import annotations
from typing import TYPE_CHECKING, Optional
if TYPE_CHECKING:
from cirq.sim.state_vector_simulator import StateVectorTrialResult
from cirq.study.result import Result as cirq_result
from cirq.work.observable_measurement_data import ObservableMeasuredResult
from typeguard import typechecked
from mpqp import Language
from mpqp.core.instruction.measurement import ComputationalBasis
from mpqp.core.instruction.measurement.basis_measure import BasisMeasure
from mpqp.core.instruction.measurement.expectation_value import ExpectationMeasure
from mpqp.execution.devices import GOOGLEDevice
from mpqp.execution.job import Job, JobType
from mpqp.execution.result import Result, Sample, StateVector
[docs]@typechecked
def run_google(job: Job) -> Result:
"""Executes the job on the right Google device precised in the job in
parameter.
Args:
job: Job to be executed.
Returns:
A Result after submission and execution of the job.
Note:
Note:
This function is not meant to be used directly, please use
:func:``run<mpqp.execution.runner.run>`` instead.
"""
return run_local(job) if not job.device.is_remote() else run_google_remote(job)
[docs]@typechecked
def run_google_remote(job: Job) -> Result:
"""
Executes the job remotely on a Google quantum device. At present, only IonQ devices are supported.
Args:
job: job to be executed.
Returns:
Result: The result after submission and execution of the job.
Raises:
ValueError: If the job's device is not an instance of GOOGLEDevice.
NotImplementedError: If the job's device is not supported (only IonQ
devices are supported currently).
NotImplementedError: If the job type or basis measure is not supported.
"""
import cirq_ionq as ionq
from cirq.circuits.circuit import Circuit as Cirq_circuit
from cirq.devices.line_qubit import LineQubit
from cirq.transformers.optimize_for_target_gateset import (
optimize_for_target_gateset,
)
from cirq_ionq.ionq_gateset import IonQTargetGateset
assert type(job.device) == GOOGLEDevice
job_cirq_circuit = job.circuit.to_other_language(Language.CIRQ)
assert isinstance(job_cirq_circuit, Cirq_circuit)
if job.device.is_ionq():
from mpqp.execution.connection.env_manager import load_env_variables
load_env_variables()
if job.job_type != JobType.SAMPLE:
raise ValueError(
f"{job.device}: job_type must be {JobType.SAMPLE} but got job type {job.job_type}"
)
assert isinstance(job.measure, BasisMeasure)
if isinstance(job.measure.basis, ComputationalBasis):
service = ionq.Service(default_target=job.device.value)
job_cirq_circuit = optimize_for_target_gateset(
job_cirq_circuit, gateset=IonQTargetGateset()
)
job_cirq_circuit = job_cirq_circuit.transform_qubits(
{qb: LineQubit(i) for i, qb in enumerate(job_cirq_circuit.all_qubits())}
)
result_sim = service.run(
circuit=job_cirq_circuit, repetitions=job.measure.shots
)
else:
raise NotImplementedError(
"Does not handle other basis than the ComputationalBasis for the moment"
)
else:
raise NotImplementedError(
f"{job.device} is not handled for the moment. Only IonQ is supported"
)
return extract_result(result_sim, job, job.device)
[docs]@typechecked
def run_local(job: Job) -> Result:
"""
Executes the job locally.
Args:
job : The job to be executed.
Returns:
Result: The result after submission and execution of the job.
Raises:
ValueError: If the job device is not GOOGLEDevice.
"""
from cirq.circuits.circuit import Circuit as Cirq_circuit
from cirq.ops.linear_combinations import PauliSum as Cirq_PauliSum
from cirq.sim.sparse_simulator import Simulator
from cirq.work.observable_measurement import (
RepetitionsStoppingCriteria,
measure_observables,
)
assert type(job.device) == GOOGLEDevice
if job.device.is_processor():
return run_local_processor(job)
job_cirq_circuit = job.circuit.to_other_language(Language.CIRQ)
assert isinstance(job_cirq_circuit, Cirq_circuit)
simulator = Simulator(noise=None)
if job.job_type == JobType.STATE_VECTOR:
result_sim = simulator.simulate(job_cirq_circuit)
elif job.job_type == JobType.SAMPLE:
assert isinstance(job.measure, BasisMeasure)
if isinstance(job.measure.basis, ComputationalBasis):
result_sim = simulator.run(job_cirq_circuit, repetitions=job.measure.shots)
else:
raise NotImplementedError(
"Does not handle other basis than the ComputationalBasis for the moment"
)
elif job.job_type == JobType.OBSERVABLE:
assert isinstance(job.measure, ExpectationMeasure)
cirq_obs = job.measure.observable.to_other_language(
language=Language.CIRQ, circuit=job_cirq_circuit
)
assert type(cirq_obs) == Cirq_PauliSum
if job.measure.shots == 0:
result_sim = simulator.simulate_expectation_values(
job_cirq_circuit, observables=cirq_obs
)
else:
result_sim = measure_observables(
job_cirq_circuit,
cirq_obs, # type: ignore[reportArgumentType]
simulator,
stopping_criteria=RepetitionsStoppingCriteria(job.measure.shots),
)
else:
raise ValueError(f"Job type {job.job_type} not handled")
return extract_result(result_sim, job, job.device)
[docs]@typechecked
def run_local_processor(job: Job) -> Result:
"""
Executes the job locally on processor.
Args:
job : The job to be executed.
Returns:
Result: The result after submission and execution of the job.
"""
from cirq.circuits.circuit import Circuit as Cirq_circuit
from cirq_google.engine.simulated_local_engine import SimulatedLocalEngine
from cirq_google.engine.simulated_local_processor import SimulatedLocalProcessor
from cirq_google.engine.virtual_engine_factory import (
create_device_from_processor_id,
load_median_device_calibration,
)
from qsimcirq.qsim_simulator import QSimSimulator
assert type(job.device) == GOOGLEDevice
calibration = load_median_device_calibration(job.device.value)
device = create_device_from_processor_id(job.device.value)
# noise_props = noise_properties_from_calibration(cal)
# noise_model = NoiseModelFromGoogleNoiseProperties(noise_props)
simulator = QSimSimulator(noise=None)
sim_processor = SimulatedLocalProcessor(
processor_id=job.device.value,
sampler=simulator,
device=device,
calibrations={calibration.timestamp // 1000: calibration},
)
simulator = SimulatedLocalEngine([sim_processor])
job_cirq_circuit = job.circuit.to_other_language(
Language.CIRQ, cirq_proc_id=job.device.value
)
assert isinstance(job_cirq_circuit, Cirq_circuit)
if job.job_type == JobType.STATE_VECTOR:
raise NotImplementedError(
f"Does not handle {job.job_type} for processor for the moment"
)
elif job.job_type == JobType.OBSERVABLE:
raise NotImplementedError(
f"Does not handle {job.job_type} for processor for the moment"
)
elif job.job_type == JobType.SAMPLE:
assert isinstance(job.measure, BasisMeasure)
if isinstance(job.measure.basis, ComputationalBasis):
result_sim = simulator.get_sampler(job.device.value).run(
job_cirq_circuit, repetitions=job.measure.shots
)
else:
raise NotImplementedError(
"Does not handle other basis than the ComputationalBasis for the moment"
)
else:
raise ValueError(f"Job type {job.job_type} not handled")
return extract_result(result_sim, job, job.device)