def qreset_full(q: qreg, delay, measSign): m = MEAS(q) Id(q, delay) if m == measSign: X(q) else: Id(q)
def CRtomo_seq(controlQ: qreg, targetQ: qreg, lengths, ph, amp=0.8, riseFall=20e-9): """ Variable length CX experiment, for Hamiltonian tomography. Parameters ---------- controlQ : logical channel for the control qubit (LogicalChannel) targetQ: logical channel for the target qubit (LogicalChannel) lengths : pulse lengths of the CR pulse to sweep over (iterable) riseFall : rise/fall time of the CR pulse (s) ph : phase of the CR pulse (rad) """ # Rather than do EdgeFactory and regular flat_top_gaussian, # define a new QGL2 stub where the QGL1 implementation does that, # so QGL2 can avoid dealing with the edge # CRchan = EdgeFactory(controlQ, targetQ) # flat_top_gaussian is an addition of 3 UTheta pulses cNt = QRegister(controlQ, targetQ) tomo_pulses = [Y90m, X90, Id] # Sequence 1 for l, tomo_pulse in product(lengths, tomo_pulses): init(cNt) Id(controlQ) flat_top_gaussian_edge(controlQ, targetQ, riseFall=riseFall, length=l, amp=amp, phase=ph, label="CR") Barrier(cNt) Id(controlQ) tomo_pulse(targetQ) MEAS(targetQ) # Sequence 2 for l, tomo_pulse in product(lengths, tomo_pulses): init(cNt) X(controlQ) flat_top_gaussian_edge(controlQ, targetQ, riseFall=riseFall, length=l, amp=amp, phase=ph, label="CR") Barrier(cNt) X(controlQ) tomo_pulse(targetQ) MEAS(targetQ) create_cal_seqs(targetQ, 2)
def EchoCRAmp(controlQ: qreg, targetQ: qreg, amps, riseFall=40e-9, length=50e-9, phase=0, calRepeats=2): """ Variable amplitude CX experiment, with echo pulse sandwiched between two CR opposite-phase pulses. Parameters ---------- controlQ : logical channel for the control qubit (LogicalChannel) targetQ: logical channel for the target qubit (LogicalChannel) amps : pulse amplitudes of the CR pulse to sweep over (iterable) riseFall : rise/fall time of the CR pulse (s) length : duration of each of the two flat parts of the CR pulse (s) phase : phase of the CR pulse (rad) calRepeats : number of repetitions of readout calibrations for each 2-qubit state """ cNt = QRegister(controlQ, targetQ) # Sequence 1 for a in amps: init(cNt) Id(controlQ) echoCR(controlQ, targetQ, length=length, phase=phase, riseFall=riseFall, amp=a) Id(controlQ) measConcurrently(cNt) # Sequence 2 for a in amps: init(cNt) X(controlQ) echoCR(controlQ, targetQ, length=length, phase=phase, riseFall=riseFall, amp=a) X(controlQ) measConcurrently(cNt) # Then do calRepeats calibration sequences create_cal_seqs(cNt, calRepeats)
def multiQbitTest2(): qs = QRegister('q1', 'q2') Id(qs) X(qs) Barrier(qs) MEAS(qs)
def qreset_with_delay(q: qreg, delay): m = MEAS(q) # Wait to make branching time deterministic, and to allow residual # measurement photons to decay Id(q, delay) if m == 1: X(q)
def anotherMulti(): qs = QRegister(2) Id(qs) X(qs) Barrier(qs) MEAS(qs) Y(qs)
def doPulsedSpec(q: qreg, specOn): init(q) if specOn: X(q) else: Id(q) MEAS(q)
def doSingleShot(q: qreg): init(q) Id(q) MEAS(q) init(q) X(q) MEAS(q)
def InversionRecovery(qubit: qreg, delays, calRepeats=2): """ Inversion recovery experiment to measure qubit T1 Parameters ---------- qubit : logical channel to implement sequence (LogicalChannel) delays : delays after inversion before measurement (iterable; seconds) calRepeats : how many repetitions of calibration pulses (int) """ # Original: # # Create the basic sequences # seqs = [[X(qubit), Id(qubit, d), MEAS(qubit)] for d in delays] # # Tack on the calibration scalings # seqs += create_cal_seqs((qubit,), calRepeats) # fileNames = compile_to_hardware(seqs, 'T1'+('_'+qubit.label)*suffix+'/T1'+('_'+qubit.label)*suffix) # print(fileNames) # if showPlot: # plot_pulse_files(fileNames) for d in delays: init(qubit) X(qubit) Id(qubit, length=d) MEAS(qubit) # Tack on calibration create_cal_seqs(qubit, calRepeats)
def settle(q: qreg) -> pulse: init(q) while True: MEAS(q) if vmeas: break Id(q)
def EchoCRPhase(controlQ: qreg, targetQ: qreg, phases, riseFall=40e-9, amp=1, length=100e-9, calRepeats=2, canc_amp=0, canc_phase=np.pi/2): """ Variable phase CX experiment, with echo pulse sandwiched between two CR opposite-phase pulses. Parameters ---------- controlQ : logical channel for the control qubit (LogicalChannel) targetQ : logical channel for the cross-resonance pulse (LogicalChannel) phases : pulse phases of the CR pulse to sweep over (iterable) riseFall : rise/fall time of the CR pulse (s) amp : amplitude of the CR pulse length : duration of each of the two flat parts of the CR pulse (s) calRepeats : number of repetitions of readout calibrations for each 2-qubit state """ # Original: # seqs = [[Id(controlQ)] + echoCR(controlQ, targetQ, length=length, phase=ph, riseFall=riseFall) + [X90(targetQ)*Id(controlQ), MEAS(targetQ)*MEAS(controlQ)] \ # for ph in phases]+[[X(controlQ)] + echoCR(controlQ, targetQ, length=length, phase= ph, riseFall = riseFall) + [X90(targetQ)*X(controlQ), MEAS(targetQ)*MEAS(controlQ)] \ # for ph in phases]+create_cal_seqs((targetQ,controlQ), calRepeats, measChans=(targetQ,controlQ)) cNt = QRegister(controlQ, targetQ) # Sequence 1 for ph in phases: init(cNt) Id(controlQ) echoCR(controlQ, targetQ, length=length, phase=ph, riseFall=riseFall, canc_amp=canc_amp, canc_phase=canc_phase) Barrier(cNt) X90(targetQ) Id(controlQ) measConcurrently(cNt) # Sequence 2 for ph in phases: init(cNt) X(controlQ) echoCR(controlQ, targetQ, length=length, phase=ph, riseFall=riseFall, canc_amp=canc_amp, canc_phase=canc_phase) Barrier(cNt) X90(targetQ) X(controlQ) measConcurrently(cNt) # Then do calRepeats calibration sequences create_cal_seqs(cNt, calRepeats)
def PiRabi(controlQ: qreg, targetQ: qreg, lengths, riseFall=40e-9, amp=1, phase=0, calRepeats=2): """ Variable length CX experiment. Parameters ---------- controlQ : logical channel for the control qubit (LogicalChannel) targetQ: logical channel for the target qubit (LogicalChannel) lengths : pulse lengths of the CR pulse to sweep over (iterable) riseFall : rise/fall time of the CR pulse (s) amp : amplitude of the CR pulse phase : phase of the CR pulse (rad) calRepeats : number repetitions of calibration sequences (int) """ # Rather than do EdgeFactory and regular flat_top_gaussian, # define a new QGL2 stub where the QGL1 implementation does that, # so QGL2 can avoid dealing with the edge # CRchan = EdgeFactory(controlQ, targetQ) # flat_top_gaussian is an addition of 3 UTheta pulses cNt = QRegister(controlQ, targetQ) # Sequence 1: Id(control), gaussian(l), measure both for l in lengths: init(cNt) Id(controlQ) flat_top_gaussian_edge(controlQ, targetQ, riseFall, length=l, amp=amp, phase=phase) measConcurrently(cNt) # Sequence 2: X(control), gaussian(l), X(control), measure both for l in lengths: init(cNt) X(controlQ) flat_top_gaussian_edge(controlQ, targetQ, riseFall, length=l, amp=amp, phase=phase) X(controlQ) measConcurrently(cNt) # Then do calRepeats calibration sequences create_cal_seqs(cNt, calRepeats)
def doInversionRecovery(q:qreg, delays, calRepeats): for d in delays: init(q) X(q) Id(q, length=d) MEAS(q) # Tack on calibration create_cal_seqs(q, calRepeats)
def doSwap(qr: qreg, delays): for d in delays: init(qr) X(qr) Id(qr[1], length=d) Barrier(qr) MEAS(qr) create_cal_seqs(qr, 2)
def FlipFlop(qubit: qreg, dragParamSweep, maxNumFFs=10): """ Flip-flop sequence (X90-X90m)**n to determine off-resonance or DRAG parameter optimization. Parameters ---------- qubit : logical channel to implement sequence (LogicalChannel) dragParamSweep : drag parameter values to sweep over (iterable) maxNumFFs : maximum number of flip-flop pairs to do """ # Original: # def flipflop_seqs(dragScaling): # """ Helper function to create a list of sequences with a specified drag parameter. """ # qubit.pulse_params['dragScaling'] = dragScaling # return [[X90(qubit)] + [X90(qubit), X90m(qubit)]*rep + [Y90(qubit)] for rep in range(maxNumFFs)] # # Insert an identity at the start of every set to mark them off # originalScaling = qubit.pulse_params['dragScaling'] # seqs = list(chain.from_iterable([[[Id(qubit)]] + flipflop_seqs(dragParam) for dragParam in dragParamSweep])) # qubit.pulse_params['dragScaling'] = originalScaling # # Add a final pi for reference # seqs.append([X(qubit)]) # # Add the measurment block to every sequence # measBlock = MEAS(qubit) # for seq in seqs: # seq.append(measBlock) # fileNames = compile_to_hardware(seqs, 'FlipFlop/FlipFlop') # print(fileNames) # if showPlot: # plot_pulse_files(fileNames) # Insert an identity at the start of every set to mark them off # Want a result something like: # [['Id'], ['X9', 'Y9'], ['X9', 'X9', 'X9m', 'Y9'], ['X9', 'X9', 'X9m', 'X9', 'X9m', 'Y9'], ['Id'], ['X9', 'Y9'], ['X9', 'X9', 'X9m', 'Y9'], ['X9', 'X9', 'X9m', 'X9', 'X9m', 'Y9'], ['Id'], ['X9', 'Y9'], ['X9', 'X9', 'X9m', 'Y9'], ['X9', 'X9', 'X9m', 'X9', 'X9m', 'Y9']] # QGL2 qubits are read only, so can't modify qubit.pulse_params[dragScaling], # Instead of modifying qubit, we'll just supply the drag param explicitly to each pulse # So no need to save this off and reset afterwards # originalScaling = qubit.pulse_params['dragScaling'] for dragParam in dragParamSweep: init(qubit) Id(qubit) MEAS(qubit) flipflop_seqs(dragParam, maxNumFFs, qubit) # qubit.pulse_params['dragScaling'] = originalScaling # Add a final pi for reference init(qubit) X(qubit) MEAS(qubit)
def edgeTest3(): q1 = QRegister('q1') q2 = QRegister('q2') for q in [q1, q2]: init(q) echoCR(q1, q2) X(q2) Y(q2) Id(q2) X(q2)
def anotherMulti2(): qs = QRegister(3) qsub = QRegister(qs[0], qs[1]) Id(qsub) X(qs[0:2]) # equivalent to calling with qsub argument Barrier(qs) MEAS(qsub) Barrier(qs) Y(qs[0]) Y(qs[2])
def SingleShot(qubit: qreg): """ 2-segment sequence with qubit prepared in |0> and |1>, useful for single-shot fidelity measurements and kernel calibration """ init(qubit) Id(qubit) MEAS(qubit) init(qubit) X(qubit) MEAS(qubit)
def PulsedSpec(qubit: qreg, specOn=True): """ Measurement preceded by a X pulse if specOn """ init(qubit) if specOn: X(qubit) else: Id(qubit) MEAS(qubit)
def anotherMulti3(): qs = QRegister(3) # create the QRegister with slicing qsub = QRegister(qs[0:2]) Id(qsub) X(qsub) Barrier(qs) MEAS(qsub) Barrier(qs) Y(qs[0]) Y(qs[2])
def SingleShotNoArg(): """ Sample 0-argument 2-segment sequence with qubit prepared in |0> and |1>, useful for single-shot fidelity measurements and kernel calibration """ qubit = QRegister(1) init(qubit) Id(qubit) MEAS(qubit) init(qubit) X(qubit) MEAS(qubit)
def EchoCRLen(controlQ: qreg, targetQ: qreg, lengths, riseFall=40e-9, amp=1, phase=0, calRepeats=2, canc_amp=0, canc_phase=np.pi/2): """ Variable length CX experiment, with echo pulse sandwiched between two CR opposite-phase pulses. Parameters ---------- controlQ : logical channel for the control qubit (LogicalChannel) targetQ: logical channel for the target qubit (LogicalChannel) lengths : pulse lengths of the CR pulse to sweep over (iterable) riseFall : rise/fall time of the CR pulse (s) amp : amplitude of the CR pulse phase : phase of the CR pulse (rad) calRepeats : number of repetitions of readout calibrations for each 2-qubit state """ # Original: # seqs = [[Id(controlQ)] + echoCR(controlQ, targetQ, length=l, phase=phase, riseFall=riseFall) + [Id(controlQ), MEAS(targetQ)*MEAS(controlQ)] \ # for l in lengths]+ [[X(controlQ)] + echoCR(controlQ, targetQ, length=l, phase= phase, riseFall=riseFall) + [X(controlQ), MEAS(targetQ)*MEAS(controlQ)] \ # for l in lengths] + create_cal_seqs((targetQ,controlQ), calRepeats, measChans=(targetQ,controlQ)) cNt = QRegister(controlQ, targetQ) # Sequence1: for l in lengths: init(cNt) Id(controlQ) echoCR(controlQ, targetQ, length=l, phase=phase, amp=amp, riseFall=riseFall, canc_amp=canc_amp, canc_phase=canc_phase) Id(controlQ) measConcurrently(cNt) # Sequence 2 for l in lengths: init(cNt) X(controlQ) echoCR(controlQ, targetQ, length=l, phase=phase, amp=amp, riseFall=riseFall, canc_amp=canc_amp, canc_phase=canc_phase) X(controlQ) measConcurrently(cNt) # Then do calRepeats calibration sequences create_cal_seqs(cNt, calRepeats)
def doSPAM(q: qreg, angleSweep, maxSpamBlocks): # Insert an identity at the start of every set to mark them off for angle in angleSweep: init(q) Id(q) MEAS(q) spam_seqs(angle, q, maxSpamBlocks) # Add a final pi for reference init(q) X(q) MEAS(q)
def create_cal_seqs(qubits: qreg, numRepeats, measChans=None, waitcmp=False, delay=None): """ Helper function to create a set of calibration sequences. Parameters ---------- qubits : a QRegister of channels to calibrate numRepeats : number of times to repeat calibration sequences (int) measChans : QRegister of channels to measure; default is to use qubits waitcmp = True if the sequence contains branching; default False delay: optional time between state preparation and measurement (s) """ # Allows supplying a tuple as is usually done in QGL1 qubitreg = QRegister(qubits) # QGL2 will warn here: # warning: parameter [measChans] overwritten by assignment if measChans is None: measChans = qubitreg # Make all combinations for qubit calibration states for n qubits and repeat # Assuming numRepeats=2 and qubits are q1, q2 # Produces 2 ^ #qubits * numRepeats sequences of Id, X, MEAS, # something like # [[Id(q1)*Id(q2), M(q1)*M(q2)], [Id(q1)*Id(q2), M(q1)*M(q2)], # [Id(q1)*X(q2), M(q1)*M(q2)], [Id(q1)*X(q2), M(q1)*M(q2)], # [X(q1)*Id(q2), M(q1)*M(q2)], [X(q1)*Id(q2), M(q1)*M(q2)], # [X(q1)*X(q2), M(q1)*M(q2)], [X(q1)*X(q2), M(q1)*M(q2)]] # Calibrate using Id and X pulses calSet = [Id, X] for pulseSet in product(calSet, repeat=len(qubitreg)): # Repeat each calibration numRepeats times for _ in range(numRepeats): init(qubitreg) for pulse, qubit in zip(pulseSet, qubitreg): pulse(qubit) if delay: # Add optional delay before measurement Id(qubitreg(0), length=delay) Barrier(measChans) MEAS(measChans) # If branching do wait if waitcmp: qwait(kind='CMP')
def HahnEcho(qubit: qreg, pulseSpacings, periods=0, calRepeats=2): """ A single pulse Hahn echo with variable phase of second pi/2 pulse. Parameters ---------- qubit : logical channel to implement sequence (LogicalChannel) pulseSpacings : pulse spacings to sweep over; the t in 90-t-180-t-180 (iterable) periods: number of artificial oscillations calRepeats : how many times to repeat calibration scalings (default 2) """ # Original: # seqs=[]; # for k in range(len(pulseSpacings)): # seqs.append([X90(qubit), Id(qubit, pulseSpacings[k]), Y(qubit), Id(qubit,pulseSpacings[k]), \ # U90(qubit,phase=2*pi*periods/len(pulseSpacings)*k), MEAS(qubit)]) # # Tack on the calibration scalings # seqs += create_cal_seqs((qubit,), calRepeats) # fileNames = compile_to_hardware(seqs, 'Echo/Echo') # print(fileNames) # if showPlot: # plot_pulse_files(fileNames) for k in range(len(pulseSpacings)): init(qubit) X90(qubit) # FIXME 9/28/16: Must name the length arg (issue #45) Id(qubit, length=pulseSpacings[k]) Y(qubit) Id(qubit, length=pulseSpacings[k]) U90(qubit, phase=2 * pi * periods / len(pulseSpacings) * k) MEAS(qubit) create_cal_seqs(qubit, calRepeats)
def doRamsey(q:qreg, delays, TPPIFreq, calRepeats): # Create the phases for the TPPI phases = 2*pi*TPPIFreq*delays # Create the basic Ramsey sequence for d,phase in zip(delays, phases): init(q) X90(q) Id(q, length=d) U90(q, phase=phase) MEAS(q) # Tack on calibration create_cal_seqs(q, calRepeats)
def doFlipFlop(qubit: qreg, dragParamSweep, maxNumFFs): # QGL2 qubits are read only, so can't modify qubit.pulse_params[dragScaling], # So no need to save this off and reset afterwards for dragParam in dragParamSweep: # Id sequence for reference init(qubit) Id(qubit) MEAS(qubit) # then a flip flop sequence for a particular DRAG parameter flipflop_seqs(dragParam, maxNumFFs, qubit) # Final pi for reference init(qubit) X(qubit) MEAS(qubit)
def Ramsey(qubit: qreg, pulseSpacings, TPPIFreq=0, calRepeats=2): """ Variable pulse spacing Ramsey (pi/2 - tau - pi/2) with optional TPPI. Parameters ---------- qubit : logical channel to implement sequence (LogicalChannel) pulseSpacings : pulse spacings (iterable; seconds) TPPIFreq : frequency for TPPI phase updates of second Ramsey pulse (Hz) calRepeats : how many repetitions of calibration pulses (int) """ # Original: # # Create the phases for the TPPI # phases = 2*pi*TPPIFreq*pulseSpacings # # Create the basic Ramsey sequence # seqs = [[X90(qubit), Id(qubit, d), U90(qubit, phase=phase), MEAS(qubit)] # for d,phase in zip(pulseSpacings, phases)] # # Tack on the calibration scalings # seqs += create_cal_seqs((qubit,), calRepeats) # fileNames = compile_to_hardware(seqs, 'Ramsey'+('_'+qubit.label)*suffix+'/Ramsey'+('_'+qubit.label)*suffix) # print(fileNames) # if showPlot: # plot_pulse_files(fileNames) # Create the phases for the TPPI phases = 2*pi*TPPIFreq*pulseSpacings # Creating sequences that look like this: # [['X90', 'Id', 'U90', 'M'], ['X90', 'Id', 'U90', 'M']] # Create the basic Ramsey sequence for d,phase in zip(pulseSpacings, phases): init(qubit) X90(qubit) Id(qubit, length=d) U90(qubit, phase=phase) MEAS(qubit) # Tack on calibration create_cal_seqs(qubit, calRepeats)
def SPAM(qubit: qreg, angleSweep, maxSpamBlocks=10): """ X-Y sequence (X-Y-X-Y)**n to determine quadrature angles or mixer correction. Parameters ---------- qubit : logical channel to implement sequence (LogicalChannel) angleSweep : angle shift to sweep over maxSpamBlocks : maximum number of XYXY block to do """ # Original: # def spam_seqs(angle): # """ Helper function to create a list of sequences increasing SPAM blocks with a given angle. """ # SPAMBlock = [X(qubit), U(qubit, phase=pi/2+angle), X(qubit), U(qubit, phase=pi/2+angle)] # return [[Y90(qubit)] + SPAMBlock*rep + [X90(qubit)] for rep in range(maxSpamBlocks)] # # Insert an identity at the start of every set to mark them off # seqs = list(chain.from_iterable([[[Id(qubit)]] + spam_seqs(angle) for angle in angleSweep])) # # Add a final pi for reference # seqs.append([X(qubit)]) # # Add the measurment block to every sequence # measBlock = MEAS(qubit) # for seq in seqs: # seq.append(measBlock) # fileNames = compile_to_hardware(seqs, 'SPAM/SPAM') # print(fileNames) # if showPlot: # plot_pulse_files(fileNames) # Insert an identity at the start of every set to mark them off for angle in angleSweep: init(qubit) Id(qubit) MEAS(qubit) spam_seqs(angle, qubit, maxSpamBlocks) # Add a final pi for reference init(qubit) X(qubit) MEAS(qubit)
def SingleQubitRB_DiAC(qubit, seqs, compiled=True, purity=False, add_cals=True): """Single qubit randomized benchmarking using diatomic Clifford pulses. Parameters ---------- qubit : logical channel to implement sequence (LogicalChannel) seqFile : file containing sequence strings compiled : if True, compile Z90(m)-X90-Z90(m) to Y90(m) pulses purity : measure <Z>,<X>,<Y> of final state, to measure purity. See J.J. Wallman et al., New J. Phys. 17, 113020 (2015) """ op = [Id, Y90m, X90] for ct in range(3 if purity else 1): for seq in seqs: init(qubit) for c in seq: DiAC(qubit, c, compiled) # append tomography pulse to measure purity if ct == 0: op[ct](qubit, length=0) else: op[ct](qubit) # append measurement MEAS(qubit) # axis_descriptor = [{ # 'name': 'length', # 'unit': None, # 'points': list(map(len, seqs)), # 'partition': 1 # }] # Tack on the calibration sequences if add_cals: for _ in range(2): init(qubit) Id(qubit) MEAS(qubit) for _ in range(2): init(qubit) X90(qubit) X90(qubit) MEAS(qubit)