# Copyright 2020-2024 Quantinuum## Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at## http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing, software# 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."""public api for qir conversion from pytket"""fromenumimportEnumfromtypingimportTYPE_CHECKING,Unionimportpyqirfrompytket.circuitimportCircuitfrompytket.passesimport(scratch_reg_resize_pass,)from.baseprofileqirgeneratorimportBaseProfileQirGeneratorfrom.moduleimporttketqirModulefrom.profileqirgeneratorimportAdaptiveProfileQirGeneratorfrom.pytketqirgeneratorimportPytketQirGeneratorifTYPE_CHECKING:from.qirgeneratorimportAbstractQirGenerator
[docs]classQIRFormat(Enum):"""Return types qir, options are BINARY for a binary output and STRING for a string output """BINARY=0STRING=1
[docs]classQIRProfile(Enum):"""Profile for the QIR generation"""BASE=0ADAPTIVE=1ADAPTIVE_CREGSIZE=2PYTKET=3
[docs]defpytket_to_qir(circ:Circuit,name:str="Generated from input pytket circuit",qir_format:QIRFormat=QIRFormat.BINARY,int_type:int=64,cut_pytket_register:bool=False,profile:QIRProfile=QIRProfile.PYTKET,)->Union[str,bytes,None]:"""converts given pytket circuit to qir :param circ: given circuit :param name: name for the qir module created :param qir_format: format of the generated qir, default value is binary :param wfh: wasm file handler used when creating the circuit. Only needed when there are wasm calls in the circuit. :param int_type: size of each integer, allowed value 32 and 64 :param cut_pytket_register: breaks up the internal scratch bit registers into smaller registers, default value false :param profile: generates QIR corresponding to the selected profile: Use QIRProfile.BASE for the base profile, see: https://github.com/qir-alliance/qir-spec/blob/main/specification/under_development/profiles/Base_Profile.md Use QIRProfile.ADAPTIVE for the adaptive profile, see: https://github.com/qir-alliance/qir-spec/tree/main/specification/under_development/profiles/Adaptive_Profile.md Use QIRProfile.ADAPTIVE_CREGSIZE for the adaptive profile with additional truncation operation to assure that integers matching the classical registers have no unexpected set bits, see: https://github.com/qir-alliance/qir-spec/tree/main/specification/under_development/profiles/Adaptive_Profile.md Use QIRProfile.PYTKET for QIR with additonal function for classical registers. """ifcut_pytket_register:cpass=scratch_reg_resize_pass(int_type)cpass.apply(circ)check_circuit(circ,int_type)m=tketqirModule(name=name,num_qubits=circ.n_qubits,num_results=circ.n_qubits,)trunc=Falseifprofile==QIRProfile.ADAPTIVE_CREGSIZE:trunc=Trueifprofile==QIRProfile.BASE:qir_generator:AbstractQirGenerator=BaseProfileQirGenerator(circuit=circ,module=m,wasm_int_type=int_type,qir_int_type=int_type,)elifprofile==QIRProfile.PYTKET:qir_generator=PytketQirGenerator(circuit=circ,module=m,wasm_int_type=int_type,qir_int_type=int_type,)elifprofile==QIRProfile.ADAPTIVEorprofile==QIRProfile.ADAPTIVE_CREGSIZE:qir_generator=AdaptiveProfileQirGenerator(circuit=circ,module=m,wasm_int_type=int_type,qir_int_type=int_type,trunc=trunc,)else:raiseNotImplementedError("unexpected profile")populated_module=qir_generator.circuit_to_module(qir_generator.circuit,True)ifqir_generator.has_wasm:wasm_sar_dict:dict[str,str]=qir_generator.get_wasm_sar()initial_result=str(populated_module.module.ir())forwfinwasm_sar_dict:initial_result=initial_result.replace(wf,wasm_sar_dict[wf])result=initial_resultbitcode=pyqir.Module.from_ir(pyqir.Context(),result).bitcodeifqir_format==QIRFormat.BINARY:returnbitcodeelifqir_format==QIRFormat.STRING:returnresultelse:assertnot"unsupported return type"# type: ignoreelse:ifqir_format==QIRFormat.BINARY:returnpopulated_module.module.bitcode()elifqir_format==QIRFormat.STRING:returnpopulated_module.module.ir()else:assertnot"unsupported return type"# type: ignore
defcheck_circuit(circuit:Circuit,int_type:int=64,)->None:"""Checks the validity of the circuit. Running this check before conversion is recommended for big circuits that take a long time to be converted. :param circuit: given circuit :param int_type: integer bit width (32 or 64) :raises ValueError: with a suggestion on how to resolve the problems """iflen(circuit.q_registers)>1or(len(circuit.q_registers)==1andcircuit.q_registers[0].name!="q"):raiseValueError("""The circuit that should be converted should only have the default quantum register. You can convert it using the pytket compiler pass `FlattenRelabelRegistersPass`.""")ifint_type!=32andint_type!=64:raiseValueError("the integer size must be 32 or 64")forcregincircuit.c_registers:ifcreg.size>int_type:raiseValueError(f"""classical registers must not have more than {int_type} bits, \you could try to set cut_pytket_register=True in the conversion""")set_circ_register=set([creg.nameforcregincircuit.c_registers])forbinset([b.reg_nameforbincircuit.bits]):ifbnotinset_circ_register:raiseValueError(f"Used register {b} in not a valid register")