Source code for qleet.simulators.circuit_simulators

"""Module to draw samples from the circuit.
Used for computing properties of the circuit like Entanglability and Expressibility.
"""

import typing

import cirq
import numpy as np
import qiskit

from qiskit.providers.aer.noise import NoiseModel as qiskitNoiseModel
from cirq.devices.noise_model import NoiseModel as cirqNoiseModel
from pyquil.noise import NoiseModel as pyquilNoiseModel

from ..interface.circuit import CircuitDescriptor


[docs]class CircuitSimulator: """The interface for users to execute their CircuitDescriptor objects""" def __init__( self, circuit: CircuitDescriptor, noise_model: typing.Union[ cirqNoiseModel, qiskitNoiseModel, pyquilNoiseModel, None ] = None, ) -> None: """Initialize the state simulator :type circuit: CircuitDescriptor :param circuit: the target circuit to simulate :type noise_model: Noise model as a dict or in the library format :param noise_model: the noise model as dict or empty dict for density matrix simulations, None if performing state vector simulations """ self.circuit = circuit self.noise_model = noise_model self._result = None @property def result( self, ) -> typing.Optional[np.ndarray]: """Get the results stored from the circuit simulator :return: stored result of the circuit simulation if it has been performed, else None. :rtype: np.array or None """ return self._result
[docs] def simulate( self, param_resolver: typing.Dict[qiskit.circuit.Parameter, float], shots: int = 1024, ) -> np.ndarray: """Simulate to get the state vector or the density matrix :type param_resolver: Dict to resolve all parameters to a static float value :param param_resolver: a dictionary of all the symbols/parameters mapping to their values :type shots: int :param shots: number of times to run the qiskit density matrix simulator :returns: state vector or density matrix resulting from the simulation :rtype: np.array :raises NotImplementedError: if circuit simulation is not supported for a backend """ if self.circuit.default_backend == "qiskit": circuit = self.circuit.qiskit_circuit.bind_parameters(param_resolver) if self.noise_model is not None: circuit.snapshot("final", snapshot_type="density_matrix") result = qiskit.execute( circuit, qiskit.Aer.get_backend("qasm_simulator"), shots=shots, noise_model=self.noise_model, backend_options={"method": "density_matrix"}, ).result() result_data = result.data(0)["snapshots"]["density_matrix"]["final"][0][ "value" ] else: circuit.snapshot("final", snapshot_type="statevector") result = qiskit.execute( circuit, qiskit.Aer.get_backend("aer_simulator_statevector") ).result() result_data = result.data(0)["snapshots"]["statevector"]["final"][0] elif self.circuit.default_backend == "cirq": circuit = self.circuit.cirq_circuit non_unitary_flag = False for op in circuit.all_operations(): op_name = str(op).split("(")[0] if op_name in [ "phase_flip", "phase_damp", "amplitude_damp", "depolarize", "asymmetric_depolarize", ]: non_unitary_flag = True break if self.noise_model is None and not non_unitary_flag: simulator = cirq.Simulator() # type: ignore result = simulator.simulate(self.circuit.cirq_circuit, param_resolver) result_data = result.final_state_vector else: simulator = cirq.DensityMatrixSimulator(noise=self.noise_model) # type: ignore result = simulator.simulate(self.circuit.cirq_circuit, param_resolver) result_data = result.final_density_matrix else: raise NotImplementedError( "Parametrized circuit simulation is not implemented for this backend." ) self._result = result_data return result_data