"""Backend for DDSIM Unitary Simulator."""from__future__importannotationsimporttimefromtypingimportTYPE_CHECKING,Any,Sequenceimportnumpyasnpimportnumpy.typingasnptfromqiskitimportQiskitErrorfromqiskit.providersimportOptionsfromqiskit.result.modelsimportExperimentResult,ExperimentResultDatafromqiskit.transpilerimportTargetfrom.headerimportDDSIMHeaderfrom.pyddsimimportConstructionMode,UnitarySimulator,get_matrixfrom.qasmsimulatorimportQasmSimulatorBackendfrom.targetimportDDSIMTargetBuilderifTYPE_CHECKING:fromqiskitimportQuantumCircuit
[docs]classUnitarySimulatorBackend(QasmSimulatorBackend):"""Decision diagram-based unitary simulator."""_US_TARGET=Target(description="MQT DDSIM Unitary Simulator Target",num_qubits=15,# corresponds to 16GiB memory for storing the full matrix)@staticmethoddef_add_operations_to_target(target:Target)->None:DDSIMTargetBuilder.add_0q_gates(target)DDSIMTargetBuilder.add_1q_gates(target)DDSIMTargetBuilder.add_2q_gates(target)DDSIMTargetBuilder.add_3q_gates(target)DDSIMTargetBuilder.add_multi_qubit_gates(target)DDSIMTargetBuilder.add_barrier(target)def__init__(self)->None:super().__init__(name="unitary_simulator",description="MQT DDSIM Unitary Simulator")@classmethoddef_default_options(cls)->Options:returnOptions(shots=1,mode="recursive",parameter_binds=None)@propertydeftarget(self)->Target:returnself._US_TARGET@classmethoddef_run_experiment(cls,qc:QuantumCircuit,**options:Any)->ExperimentResult:start_time=time.time()seed=options.get("seed",-1)mode=options.get("mode","recursive")ifmode=="sequential":construction_mode=ConstructionMode.sequentialelifmode=="recursive":construction_mode=ConstructionMode.recursiveelse:msg=(f"Construction mode {mode} not supported by DDSIM unitary simulator. Available modes are ""'recursive' and 'sequential'")raiseQiskitError(msg)sim=UnitarySimulator(qc,seed=seed,mode=construction_mode)sim.construct()# Extract resulting matrix from final DD and write dataunitary:npt.NDArray[np.complex128]=np.zeros((2**qc.num_qubits,2**qc.num_qubits),dtype=np.complex128)get_matrix(sim,unitary)end_time=time.time()data=ExperimentResultData(unitary=unitary,construction_time=sim.get_construction_time(),max_dd_nodes=sim.get_max_node_count(),dd_nodes=sim.get_final_node_count(),time_taken=end_time-start_time,)returnExperimentResult(shots=1,success=True,status="DONE",seed=seed,data=data,metadata=qc.metadata,header=DDSIMHeader(qc),)def_validate(self,quantum_circuits:Sequence[QuantumCircuit])->None:"""Semantic validations of the quantum circuits which cannot be done via schemas. 1. No shots 2. No measurements in the middle. """forqcinquantum_circuits:name=qc.namen_qubits=qc.num_qubitsmax_qubits=self.target.num_qubitsifn_qubits>max_qubits:msg=f"Number of qubits {n_qubits} is greater than maximum ({max_qubits}) for '{self.name}'."raiseQiskitError(msg)ifqc.metadataisnotNoneand"shots"inqc.metadataandqc.metadata["shots"]!=1:qc.metadata["shots"]=1forobjinqc.data:ifobj[0].namein{"measure","reset"}:operation_name=obj[0].namemsg=f"Unsupported '{self.name}' instruction '{operation_name}' in circuit '{name}'."raiseQiskitError(msg)