Source code for pytket.extensions.quantinuum.backends.leakage_gadget
# 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."""Methods for generating a leakage detection Pytket Circuit."""fromtypingimportList,Dict,Tuple,Counter,cast,SequencefrompytketimportCircuit,Qubit,Bit,OpType# type: ignorefrompytket.backends.backendresultimportBackendResultfrompytket.utils.outcomearrayimportOutcomeArrayLEAKAGE_DETECTION_BIT_NAME_="leakage_detection_bit"LEAKAGE_DETECTION_QUBIT_NAME_="leakage_detection_qubit"
[docs]defget_leakage_gadget_circuit(circuit_qubit:Qubit,postselection_qubit:Qubit,postselection_bit:Bit)->Circuit:""" Returns a two qubit Circuit for detecting leakage errors. :param circuit_qubit: Generated circuit detects whether leakage errors have occurred in this qubit. :param postselection_qubit: Measured qubit to detect leakage error. :param postselection_bit: Leakage detection result is written to this bit. :return: Circuit for detecting leakage errors for specified ids. """c=Circuit()c.add_qubit(circuit_qubit)c.add_qubit(postselection_qubit)c.add_gate(OpType.Reset,[postselection_qubit])c.add_bit(postselection_bit)c.X(postselection_qubit)c.add_barrier([circuit_qubit,postselection_qubit])c.H(postselection_qubit).ZZMax(postselection_qubit,circuit_qubit)c.add_barrier([circuit_qubit,postselection_qubit])c.ZZMax(postselection_qubit,circuit_qubit).H(postselection_qubit).Z(circuit_qubit)c.add_barrier([circuit_qubit,postselection_qubit])c.Measure(postselection_qubit,postselection_bit)returnc
[docs]defget_detection_circuit(circuit:Circuit,n_device_qubits:int)->Circuit:""" For a passed circuit, appends a leakage detection circuit for each end of circuit measurement using spare device qubits. All additional Qubit added for leakage detection are written to a new register "leakage_detection_qubit" and all additional Bit are written to a new register "leakage_detection_bit". :param circuit: Circuit to have leakage detection added. :param n_device_qubits: Total number of qubits supported by the device being compiled to. :return: Circuit with leakage detection circuitry added. """n_qubits:int=circuit.n_qubitsifn_qubits==0:raiseValueError("Circuit for Leakage Gadget Postselection must have at least one Qubit.")n_spare_qubits:int=n_device_qubits-n_qubits# N.b. even if n_spare_qubits == 0 , we will reuse measured data qubits# construct detection circuitdetection_circuit:Circuit=Circuit()postselection_qubits:List[Qubit]=[Qubit(LEAKAGE_DETECTION_QUBIT_NAME_,i)foriinrange(n_spare_qubits)]forqincircuit.qubits+postselection_qubits:detection_circuit.add_qubit(q)forbincircuit.bits:detection_circuit.add_bit(b)# construct a Circuit that is the original Circuit without# end of Circuit Measure gatesend_circuit_measures:Dict[Qubit,Bit]={}forcomincircuit:ifcom.op.type==OpType.Barrier:detection_circuit.add_barrier(com.args)continue# first check if a mid circuit measure needs to be readdedforqincom.qubits:# this condition only true if this Qubit has previously had a# "mid-circuit" measure operationifqinend_circuit_measures:detection_circuit.Measure(q,end_circuit_measures.pop(q))ifcom.op.type==OpType.Measure:# if this is "mid-circuit" then this will be rewritten laterend_circuit_measures[com.qubits[0]]=com.bits[0]elifcom.op.params:detection_circuit.add_gate(com.op.type,com.op.params,com.args)else:detection_circuit.add_gate(com.op.type,com.args)# for each entry in end_circuit_measures, we want to add a leakage_gadget_circuit# we try to use each free architecture qubit as few times as possibleps_q_index:int=0ps_b_index:int=0# if there are no spare qubits we measure the first qubit and then use it as# an ancilla qubit for leakage detectionifnotpostselection_qubits:qb:Qubit=next(iter(end_circuit_measures))bb:Bit=end_circuit_measures.pop(qb)detection_circuit.Measure(qb,bb)postselection_qubits.append(qb)forqinend_circuit_measures:ifq.reg_name==LEAKAGE_DETECTION_QUBIT_NAME_:raiseValueError("Leakage Gadget scheme makes a qubit register named ""'leakage_detection_qubit' but this already exists in"" the passed circuit.")ps_q_index=0ifps_q_index==len(postselection_qubits)elseps_q_indexleakage_detection_bit:Bit=Bit(LEAKAGE_DETECTION_BIT_NAME_,ps_b_index)ifleakage_detection_bitincircuit.bits:raiseValueError("Leakage Gadget scheme makes a new Bit named 'leakage_detection_bit'"" but this already exists in the passed circuit.")leakage_gadget_circuit:Circuit=get_leakage_gadget_circuit(q,postselection_qubits[ps_q_index],leakage_detection_bit)detection_circuit.append(leakage_gadget_circuit)# increment value for adding postselection tops_q_index+=1ps_b_index+=1detection_circuit.Measure(q,end_circuit_measures[q])# we can now add this qubit to the set of qubits used for postselectionpostselection_qubits.append(q)detection_circuit.remove_blank_wires()returndetection_circuit
[docs]defprune_shots_detected_as_leaky(result:BackendResult)->BackendResult:""" For all states with a Bit with name "leakage_detection_bit" in a state 1 sets the counts to 0. :param result: Shots returned from device. :type result: BackendResult :return: Shots with leakage cases removed. :rtype: BackendResult """regular_bits:List[Bit]=[bforbinresult.c_bitsifb.reg_name!=LEAKAGE_DETECTION_BIT_NAME_]leakage_bits:List[Bit]=[bforbinresult.c_bitsifb.reg_name==LEAKAGE_DETECTION_BIT_NAME_]received_counts:Counter[Tuple[int,...]]=result.get_counts(cbits=regular_bits+leakage_bits)discarded_counts:Counter[Tuple[int,...]]=Counter({tuple(state[:len(regular_bits)]):received_counts[state]forstateinreceived_countsifnotany(state[-len(leakage_bits):])})returnBackendResult(counts=Counter({OutcomeArray.from_readouts([key]):valforkey,valindiscarded_counts.items()}),c_bits=cast(Sequence[Bit],regular_bits),)