def doRabiAmpPi(qubit: qreg, mqubit: qreg, amps, phase): for amp in amps: with concur: init(qubit) init(mqubit) X(mqubit) Utheta(qubit, amp=amp, phase=phase) X(mqubit) MEAS(mqubit)
def spam_seqs(angle, qubit: qreg, maxSpamBlocks=10): """ 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)] for rep in range(maxSpamBlocks): init(qubit) Y90(qubit) for _ in range(rep): X(qubit) U(qubit, phase=pi/2+angle) X(qubit) U(qubit, phase=pi/2+angle) X90(qubit) MEAS(qubit)
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)] seqs = [] for rep in range(maxSpamBlocks): seq = [] seq.append(Y90(qubit)) for _ in range(rep): seq.append(X(qubit)) seq.append(U(qubit, phase=pi/2+angle)) seq.append(X(qubit)) seq.append(U(qubit, phase=pi/2+angle)) seq.append(X90(qubit)) seqs.append(seq) return seqs
def doPulsedSpec(qubit: qreg, specOn): init(qubit) if specOn: X(qubit) else: Id(qubit) MEAS(qubit)
def FlipFlop(qubit: qreg, dragParamSweep, maxNumFFs=10, showPlot=False): """ 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 showPlot : whether to plot (boolean) """ # 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']] originalScaling = qubit.pulse_params['dragScaling'] for dragParam in dragParamSweep: init(qubit) Id(qubit) MEAS(qubit) # FIXME: Need original dragScaling? # FIXME: In original this was [[Id]] + flipflop - is this # right? flipflop_seqs(dragParam, maxNumFFs, qubit) qubit.pulse_params['dragScaling'] = originalScaling # Add a final pi for reference init(qubit) X(qubit) MEAS(qubit)
def doSingleShot(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 doSwap(qubit: qreg, mqubit: qreg, delays): # Original: # seqs = [[X(qubit), X(mqubit), Id(mqubit, d), MEAS(mqubit)*MEAS(qubit)] for d in delays] + create_cal_seqs((mqubit,qubit), 2, measChans=(mqubit,qubit)) # fileNames = compile_to_hardware(seqs, 'Rabi/Rabi') # print(fileNames) # if showPlot: # plotWin = plot_pulse_files(fileNames) # return plotWin for d in delays: with concur: init(qubit) init(mqubit) X(qubit) X(mqubit) Id(mqubit, d) with concur: MEAS(mqubit) MEAS(qubit) create_cal_seqs((mqubit, qubit), 2)
def SPAM(qubit: qreg, angleSweep, maxSpamBlocks=10, showPlot=False): """ 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 showPlot : whether to plot (boolean) """ # 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 InversionRecoveryq1(qubit: qreg, delays, showPlot=False, calRepeats=2, suffix=False): """ Inversion recovery experiment to measure qubit T1 Parameters ---------- qubit : logical channel to implement sequence (LogicalChannel) delays : delays after inversion before measurement (iterable; seconds) showPlot : whether to plot (boolean) 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) seqs = [] for d in delays: seq = [] seq.append(X(qubit)) seq.append(Id(qubit, d)) seq.append(MEAS(qubit)) seqs.append(seq) # Tack on calibration # seqs = addCalibration(seqs, (qubit,), calRepeats) # Calculate label label = 'T1'+('_'+qubit.label)*suffix fullLabel = label + '/' + label
def FlipFlopMin(): # FIXME: No args qubit = QubitFactory('q1') dragParamSweep = np.linspace(0, 5e-6, 11) # FIXME maxNumFFs = 10 # FIXME: cause qubit is a placeholder, can't access pulse_params # originalScaling = qubit.pulse_params['dragScaling'] for dragParam in dragParamSweep: init(qubit) Id(qubit) MEAS(qubit) # FIXME: Need original dragScaling? # FIXME: In original this was [[Id]] + flipflop - is this # right? flipflop_seqs(dragParam, maxNumFFs, qubit) # FIXME: cause qubit is a placeholder, can't access pulse_params # qubit.pulse_params['dragScaling'] = originalScaling # Add a final pi for reference init(qubit) X(qubit) MEAS(qubit)
def SingleQubitRBT(qubit: qreg, seqFileDir, analyzedPulse: pulse, showPlot=False): """ Single qubit randomized benchmarking using atomic Clifford pulses. Parameters ---------- qubit : logical channel to implement sequence (LogicalChannel) seqFile : file containing sequence strings showPlot : whether to plot (boolean) """ # Original: # # Setup a pulse library # pulseLib = [AC(qubit, cliffNum) for cliffNum in range(24)] # pulseLib.append(analyzedPulse) # measBlock = MEAS(qubit) # seqs = [] # for ct in range(10): # fileName = 'RBT_Seqs_fast_{0}_F1.txt'.format(ct+1) # tmpSeqs = [] # with open(os.path.join(seqFileDir, fileName),'r') as FID: # fileReader = reader(FID) # for pulseSeqStr in fileReader: # seq = [] # for pulseStr in pulseSeqStr: # seq.append(pulseLib[int(pulseStr)-1]) # seq.append(measBlock) # tmpSeqs.append(seq) # seqs += tmpSeqs[:12]*12 + tmpSeqs[12:-12] + tmpSeqs[-12:]*12 # seqsPerFile = 100 # numFiles = len(seqs)//seqsPerFile # for ct in range(numFiles): # chunk = seqs[ct*seqsPerFile:(ct+1)*seqsPerFile] # # Tack on the calibration scalings # numCals = 4 # chunk += [[Id(qubit), measBlock]]*numCals + [[X(qubit), measBlock]]*numCals # fileNames = compile_to_hardware(chunk, 'RBT/RBT', suffix='_{0}'.format(ct+1)) # if showPlot: # plot_pulse_files(fileNames) pulseSeqStrs = [] for ct in range(10): fileName = 'RBT_Seqs_fast_{0}_F1.txt'.format(ct + 1) tmpSeqs = [] with open(os.path.join(seqFileDir, fileName), 'r') as FID: fileReader = reader(FID) for pulseSeqStr in fileReader: tmpSeqs.append(pulseSeqStr) pulseSeqStrs = tmpSeqs[:12] * 12 + tmpSeqs[ 12:-12] + tmpSeqs[-12:] * 12 numSeqs = len(pulseSeqStrs) seqsPerFile = 100 numFiles = numSeqs // seqsPerFile numCals = 4 for ct in range(numFiles): for s in range(seqsPerFile): init(qubit) seqStr = pulseSeqStrs[ct * seqsPerFile + s] getPulseSeq(qubit, seqStr) # Add numCals calibration scalings for _ in range(numCals): init(qubit) Id(qubit) MEAS(qubit) init(qubit) X(qubit) MEAS(qubit) # FIXME: Then magically get the sequences here.... # This needs to get refactored.... # We need to split creating seqs from c_to_h fileNames = compile_to_hardware([], 'RBT/RBT', suffix='_{0}'.format(ct + 1), qgl2=True) # FIXME: Do this from calling function if showPlot: plot_pulse_files(fileNames)
def SingleQubitIRB_AC(qubit: qreg, seqFile, showPlot=False): """ Single qubit interleaved randomized benchmarking using atomic Clifford pulses. Parameters ---------- qubit : logical channel to implement sequence (LogicalChannel) seqFile : file containing sequence strings showPlot : whether to plot (boolean) """ # Original: # # Setup a pulse library # pulseLib = [AC(qubit, cliffNum) for cliffNum in range(24)] # pulseLib.append(pulseLib[0]) # measBlock = MEAS(qubit) # with open(seqFile,'r') as FID: # fileReader = reader(FID) # seqs = [] # for pulseSeqStr in fileReader: # seq = [] # for pulseStr in pulseSeqStr: # seq.append(pulseLib[int(pulseStr)]) # seq.append(measBlock) # seqs.append(seq) # # Hack for limited APS waveform memory and break it up into multiple files # # We've shuffled the sequences so that we loop through each gate length on the inner loop # numRandomizations = 36 # for ct in range(numRandomizations): # chunk = seqs[ct::numRandomizations] # chunk1 = chunk[::2] # chunk2 = chunk[1::2] # # Tack on the calibration scalings # chunk1 += [[Id(qubit), measBlock], [X(qubit), measBlock]] # fileNames = compile_to_hardware(chunk1, 'RB/RB', suffix='_{0}'.format(2*ct+1)) # chunk2 += [[Id(qubit), measBlock], [X(qubit), measBlock]] # fileNames = compile_to_hardware(chunk2, 'RB/RB', suffix='_{0}'.format(2*ct+2)) # if showPlot: # plot_pulse_files(fileNames) pulseSeqStrs = [] with open(seqFile, 'r') as FID: fileReader = reader(FID) # each line in the file is a sequence, but I don't know how many that is for pulseSeqStr in fileReader: pulseSeqStrs.append(pulseSeqStr) numSeqs = len(pulseSeqStrs) # Hack for limited APS waveform memory and break it up into multiple files # We've shuffled the sequences so that we loop through each gate length on the inner loop numRandomizations = 36 fileNames = [] for ct in range(numRandomizations): doCt = ct isOne = True while doCt < numSeqs: getPulseSeq(qubit, pulseSeqStrs[doCt]) # Tack on calibration scalings if isOne: init(qubit) Id(qubit) MEAS(qubit) init(qubit) X(qubit) meas(qubit) else: init(qubit) Id(qubit) meas(qubit) init(qubit) X(qubit) meas(qubit) # Now write these sequences # FIXME: Then magically get the sequences here.... # This needs to get refactored.... # We need to split creating seqs from c_to_h fileNames = compile_to_hardware( [], 'RB/RB', suffix='_{0}'.format(2 * ct + 1 + 1 * (not isOne)), qgl2=True) doCt += numRandomizations isOne = not isOne if showPlot: plot_pulse_Files(fileNames)