[docs]@typecheckeddefrun_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:`~mpqp.execution.runner.run` instead. """returnrun_local(job)ifnotjob.device.is_remote()elserun_google_remote(job)
[docs]@typecheckeddefrun_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, it MUST be corresponding to a :class:`~mpqp.execution.devices.GOOGLEDevice`. Returns: 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. """ifnotisinstance(job.device,GOOGLEDevice):raiseValueError("`job` must correspond to an `GOOGLEDevice`, but corresponds to a "f"{job.device} instead")importcirq_ionqasionqfromcirq.circuits.circuitimportCircuitasCirqCircuitfromcirq.devices.line_qubitimportLineQubitfromcirq.transformers.optimize_for_target_gatesetimport(optimize_for_target_gateset,)fromcirq_ionq.ionq_gatesetimportIonQTargetGatesetjob_CirqCircuit=job.circuit.to_other_language(Language.CIRQ)ifTYPE_CHECKING:assertisinstance(job_CirqCircuit,CirqCircuit)ifjob.device.is_ionq():frommpqp.execution.connection.env_managerimportload_env_variablesload_env_variables()ifjob.job_type!=JobType.SAMPLE:raiseValueError(f"{job.device}: job_type must be {JobType.SAMPLE} but got job type {job.job_type}")service=ionq.Service(default_target=job.device.value)job_CirqCircuit=optimize_for_target_gateset(job_CirqCircuit,gateset=IonQTargetGateset())job_CirqCircuit=job_CirqCircuit.transform_qubits({qb:LineQubit(i)fori,qbinenumerate(job_CirqCircuit.all_qubits())})ifTYPE_CHECKING:assertisinstance(job.measure,BasisMeasure)returnextract_result_SAMPLE(service.run(circuit=job_CirqCircuit,repetitions=job.measure.shots),job)else:raiseNotImplementedError(f"{job.device} is not handled for the moment. Only IonQ is supported")
[docs]@typecheckeddefrun_local(job:Job)->Result:"""Executes the job locally. Args: job : Job to be executed, it MUST be corresponding to a :class:`~mpqp.execution.devices.GOOGLEDevice`. Returns: The result after submission and execution of the job. Raises: ValueError: If the job device is not GOOGLEDevice. """ifnotisinstance(job.device,GOOGLEDevice):raiseValueError("`job` must correspond to an `GOOGLEDevice`, but corresponds to a "f"{job.device} instead")fromcirq.circuits.circuitimportCircuitasCirqCircuitfromcirq.ops.pauli_stringimportPauliStringasCirqPauliStringfromcirq.sim.sparse_simulatorimportSimulatorfromcirq.work.observable_measurementimport(RepetitionsStoppingCriteria,measure_observables,)ifjob.device.is_processor():returnrun_local_processor(job)ifjob.job_type==JobType.STATE_VECTOR:# 3M-TODO: careful, if we ever support several measurements, the# line bellow will have to changercircuit=job.circuit.without_measurements()+job.circuit.pre_measure()cirq_circuit=circuit.to_other_language(Language.CIRQ)job.circuit.gphase=circuit.gphaseelse:cirq_circuit=job.circuit.to_other_language(Language.CIRQ)ifTYPE_CHECKING:assertisinstance(cirq_circuit,CirqCircuit)simulator=Simulator(noise=None)ifjob.job_type==JobType.STATE_VECTOR:returnextract_result_STATE_VECTOR(simulator.simulate(cirq_circuit),job)elifjob.job_type==JobType.SAMPLE:ifTYPE_CHECKING:assertisinstance(job.measure,BasisMeasure)returnextract_result_SAMPLE(simulator.run(cirq_circuit,repetitions=job.measure.shots),job)elifjob.job_type==JobType.OBSERVABLE:fromcirq.ops.linear_combinationsimportPauliSumasCirq_PauliSumfromcirq.ops.pauli_stringimportPauliStringasCirq_PauliStringifTYPE_CHECKING:assertisinstance(job.measure,ExpectationMeasure)cirq_obs=job.measure.observable.to_other_language(language=Language.CIRQ,circuit=cirq_circuit)ifTYPE_CHECKING:asserttype(cirq_obs)in(Cirq_PauliSum,Cirq_PauliString)ifjob.measure.shots==0:returnextract_result_OBSERVABLE_ideal(simulator.simulate_expectation_values(cirq_circuit,observables=cirq_obs),job,)else:returnextract_result_OBSERVABLE_shot_noise(measure_observables(cirq_circuit,observables=(# pyright: ignore[reportArgumentType][cirq_obs]ifisinstance(cirq_obs,CirqPauliString)elsecirq_obs),sampler=simulator,stopping_criteria=RepetitionsStoppingCriteria(job.measure.shots),),job,)else:raiseValueError(f"Job type {job.job_type} not handled")
[docs]@typecheckeddefrun_local_processor(job:Job)->Result:"""Executes the job locally on processor. Args: job : Job to be executed, it MUST be corresponding to a :class:`~mpqp.execution.devices.GOOGLEDevice`. Returns: The result after submission and execution of the job. """ifnotisinstance(job.device,GOOGLEDevice):raiseValueError("`job` must correspond to an `GOOGLEDevice`, but corresponds to a "f"{job.device} instead")fromcirq.circuits.circuitimportCircuitasCirqCircuitfromcirq_google.engine.simulated_local_engineimportSimulatedLocalEnginefromcirq_google.engine.simulated_local_processorimportSimulatedLocalProcessorfromcirq_google.engine.virtual_engine_factoryimport(create_device_from_processor_id,load_median_device_calibration,)fromqsimcirq.qsim_simulatorimportQSimSimulatorcalibration=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])cirq_circuit=job.circuit.to_other_language(Language.CIRQ,job.device.value)ifTYPE_CHECKING:assertisinstance(cirq_circuit,CirqCircuit)ifjob.job_type==JobType.STATE_VECTOR:raiseNotImplementedError(f"Does not handle {job.job_type} for processor for the moment")elifjob.job_type==JobType.OBSERVABLE:fromcirq.ops.linear_combinationsimportPauliSumasCirq_PauliSumfromcirq.ops.pauli_stringimportPauliStringasCirq_PauliStringifTYPE_CHECKING:assertisinstance(job.measure,ExpectationMeasure)cirq_obs=job.measure.observable.to_other_language(language=Language.CIRQ,circuit=cirq_circuit)ifTYPE_CHECKING:asserttype(cirq_obs)in(Cirq_PauliSum,Cirq_PauliString)ifjob.measure.shots==0:raiseDeviceJobIncompatibleError(f"Device {job.device.name} need shots != 0.")returnextract_result_OBSERVABLE_processors(simulator.get_sampler(job.device.value).sample_expectation_values(cirq_circuit,observables=cirq_obs,num_samples=job.measure.shots),job,)elifjob.job_type==JobType.SAMPLE:ifTYPE_CHECKING:assertisinstance(job.measure,BasisMeasure)returnextract_result_SAMPLE(simulator.get_sampler(job.device.value).run(cirq_circuit,repetitions=job.measure.shots),job,)else:raiseValueError(f"Job type {job.job_type} not handled")
[docs]defextract_result_SAMPLE(result:CirqResult,job:Job,)->Result:"""Extracts the result from a sample-based job. Args: result : The result of the simulation. job : The original job. Returns: The formatted result. """nb_qubits=job.circuit.nb_qubitskeys_in_order=sorted(result.records.keys())counts=result.multi_measurement_histogram(keys=keys_in_order)data=[Sample(bin_str="".join(map(bin,state)),count=count,nb_qubits=nb_qubits,)for(state,count)incounts.items()]shot=job.measure.shotsifjob.measureisnotNoneelse0returnResult(job,data,None,shot)
[docs]defextract_result_STATE_VECTOR(result:StateVectorTrialResult,job:Job,)->Result:"""Extracts the result from a state vector-based job. Args: result : The result of the simulation. job : The original job. Returns: The formatted result. """frommpqp.tools.mathsimportnormalizestate_vector=normalize(result.final_state_vector)state_vector=StateVector(state_vector,job.circuit.nb_qubits)returnResult(job,state_vector,0,0)
[docs]defextract_result_OBSERVABLE_processors(results:Sequence[Sequence[float]],job:Job,)->Result:"""Process measurement results for an observable from a quantum job. Args: results : A sequence of measurement results, where each inner sequence represents a set of results for a particular shot. job: The original job. Returns: The formatted result. Raises: NotImplementedError: If the job does not contain a measurement (i.e., ``job.measure`` is ``None``). """ifjob.measureisNone:raiseNotImplementedError("job.measure is None")mean=0forresultinresults:mean+=sum(result)/len(result)returnResult(job,mean,0,job.measure.shots)
[docs]defextract_result_OBSERVABLE_ideal(results:list[float],job:Job,)->Result:"""Extracts the result from an observable-based ideal job. The simulation from which the result to parse comes from can take in several observables, and each observable will have a corresponding value in the result. But since we only support a single measure per circuit for now, we could simplify this function by only returning the first value. Note: for some reason, the values we retrieve from cirq are not always float, but sometimes are complex. This is likely due to numerical approximation since the complex part is always extremely small, so we just remove it, but this might result in slightly unexpected results. Args: result : The result of the simulation. job : The original job. Returns: The formatted result. """ifjob.measureisNone:raiseNotImplementedError("job.measure is None")returnResult(job,sum(map(lambdar:r.real,results)),0,job.measure.shots)
[docs]defextract_result_OBSERVABLE_shot_noise(results:list[ObservableMeasuredResult],job:Job,)->Result:"""Extracts the result from an observable-based job. Args: result : The result of the simulation. job : The original job. Returns: The formatted result. """ifjob.measureisNone:raiseNotImplementedError("job.measure is None")pauli_mono=PauliString.from_other_language([r.observableforrinresults],job.measure.nb_qubits)ifTYPE_CHECKING:assertisinstance(pauli_mono,list)variances={pm:r.varianceforpm,rinzip(pauli_mono,results)}returnResult(job,sum(map(lambdar:r.mean,results)),variances,job.measure.shots,)