def test_HahnEcho(self): q = QubitFactory('q1') qr = QRegister('q1') steps = 11 pulseSpacings = np.linspace(0, 5e-6, steps) periods = 0 calRepeats = 2 expectedseq = [] for k in range(len(pulseSpacings)): expectedseq += [ qwait(channels=(q, )), X90(q), Id(q, pulseSpacings[k]), Y(q), Id(q, pulseSpacings[k]), U90(q, phase=2 * pi * periods / len(pulseSpacings) * k), MEAS(q) ] # Add calibration cal = get_cal_seqs_1qubit(q, calRepeats) expectedseq += cal expectedseq = testable_sequence(expectedseq) resFunction = compile_function( "src/python/qgl2/basic_sequences/Decoupling.py", "HahnEcho", (qr, pulseSpacings, periods, calRepeats)) seqs = resFunction() seqs = testable_sequence(seqs) # import ipdb; ipdb.set_trace() assertPulseSequenceEqual(self, seqs, expectedseq)
def addt180t(q, pulseSpacingDiff, rep): t180t = [] for _ in range(rep): t180t += [ Id(q, pulseSpacingDiff / 2), Y(q), Id(q, pulseSpacingDiff / 2) ] return t180t
def test_FlipFlop(self): qubit = QubitFactory('q1') qr = QRegister('q1') dragParamSweep = np.linspace(0, 1, 11) maxNumFFs = 10 def addFFSeqs(dragParam, maxNumFFs, qubit): ffs = [] for rep in range(maxNumFFs): ffs += [ qwait(channels=(qubit, )), X90(qubit, dragScaling=dragParam) ] for _ in range(rep): ffs += [ X90(qubit, dragScaling=dragParam), X90m(qubit, dragScaling=dragParam) ] ffs += [Y90(qubit, dragScaling=dragParam), MEAS(qubit)] return ffs expectedseq = [] for dragParam in dragParamSweep: expectedseq += [qwait(channels=(qubit, )), Id(qubit), MEAS(qubit)] expectedseq += addFFSeqs(dragParam, maxNumFFs, qubit) expectedseq += [qwait(channels=(qubit, )), X(qubit), MEAS(qubit)] resFunction = compile_function( "src/python/qgl2/basic_sequences/FlipFlop.py", "FlipFlop", (qr, dragParamSweep, maxNumFFs)) seqs = resFunction() seqs = testable_sequence(seqs) assertPulseSequenceEqual(self, seqs, expectedseq)
def test_Swap(self): q = QubitFactory('q1') mq = QubitFactory('q2') qr = QRegister(q) mqr = QRegister(mq) delays = np.linspace(0, 5e-6, 11) expectedseq = [] for d in delays: expectedseq += [ qwait(channels=(q, mq)), X(q), X(mq), Id(mq, length=d), Barrier(q, mq), MEAS(q), MEAS(mq) ] # Add calibration cal_seqs = get_cal_seqs_2qubits(q, mq, 2) expectedseq += cal_seqs expectedseq = testable_sequence(expectedseq) resFunction = compile_function( "src/python/qgl2/basic_sequences/Rabi.py", "Swap", (qr, delays, mqr)) seqs = resFunction() seqs = testable_sequence(seqs) assertPulseSequenceEqual(self, seqs, expectedseq)
def test_SPAM(self): q = QubitFactory('q1') qr = QRegister('q1') angleSweep = np.linspace(0, pi / 2, 11) maxSpamBlocks = 10 expectedseq = [] def spam_seqs(angle, q, maxSpamBlocks): thisseq = [] for rep in range(maxSpamBlocks): thisseq += [qwait(channels=(q, )), Y90(q)] innerseq = [] for _ in range(rep): innerseq += [ X(q), U(q, phase=pi / 2 + angle), X(q), U(q, phase=pi / 2 + angle) ] thisseq += innerseq thisseq += [X90(q), MEAS(q)] return thisseq for angle in angleSweep: expectedseq += [qwait(channels=(q, )), Id(q), MEAS(q)] expectedseq += spam_seqs(angle, q, maxSpamBlocks) expectedseq += [qwait(channels=(q, )), X(q), MEAS(q)] resFunction = compile_function( "src/python/qgl2/basic_sequences/SPAM.py", "SPAM", (qr, angleSweep, maxSpamBlocks)) seqs = resFunction() seqs = testable_sequence(seqs) assertPulseSequenceEqual(self, seqs, expectedseq)
def doPulsedSpec(qubit: qreg, specOn): init(qubit) if specOn: X(qubit) else: Id(qubit) MEAS(qubit)
def test_Ramsey(self): q = QubitFactory('q1') qr = QRegister('q1') delays = np.arange(100e-9, 10e-6, 100e-9) TPPIFreq = 1e6 calRepeats = 2 expectedseq = [] # Create the phases for the TPPI phases = 2 * pi * TPPIFreq * delays # Create the basic Ramsey sequence for d, phase in zip(delays, phases): expectedseq += [ qwait(channels=(q, )), X90(q), Id(q, d), U90(q, phase=phase), MEAS(q) ] # Add calibration cal = get_cal_seqs_1qubit(q, calRepeats) expectedseq += cal expectedseq = testable_sequence(expectedseq) resFunction = compile_function( "src/python/qgl2/basic_sequences/T1T2.py", "Ramsey", (qr, delays, TPPIFreq, calRepeats)) seqs = resFunction() seqs = testable_sequence(seqs) assertPulseSequenceEqual(self, seqs, expectedseq)
def test_AllXY(self): # QGL1 uses QubitFactory, QGL2 uses QRegister q1 = QubitFactory('q1') qr = QRegister(q1) # Specify the QGL1 we expect QGL2 to generate # Note in this case we specify only a sample of the start expectedseq = [] # Expect a single sequence 4 * 2 * 21 pulses long # Expect it to start like this: expectedseq += [ qwait(channels=(q1, )), # aka init(q1) aka Wait(q1) Id(q1), Id(q1), MEAS(q1), qwait(channels=(q1, )), Id(q1), Id(q1), MEAS(q1) ] # To turn on verbose logging in compile_function # from pyqgl2.ast_util import NodeError # from pyqgl2.debugmsg import DebugMsg # NodeError.MUTE_ERR_LEVEL = NodeError.NODE_ERROR_NONE # DebugMsg.set_level(0) # Now compile the QGL2 to produce the function that would generate the expected sequence. # Supply the path to the QGL2, the main function in that file, and a list of the args to that function. # Can optionally supply saveOutput=True to save the qgl1.py # file, # and intermediate_output="path-to-output-file" to save # intermediate products resFunction = compile_function( "src/python/qgl2/basic_sequences/AllXY.py", "AllXY", (qr, )) # Run the QGL2. Note that the generated function takes no arguments itself seqs = resFunction() # Transform the returned sequences into the canonical form for comparing # to the explicit QGL1 version above. # EG, 'flatten' any embedded lists of sequences. seqs = testable_sequence(seqs) # Assert that the QGL1 is the same as the generated QGL2 self.assertEqual(len(seqs), 4 * 21 * 2) assertPulseSequenceEqual(self, seqs[:len(expectedseq)], expectedseq)
def test_PiRabi(self): controlQ = QubitFactory('q1') targetQ = QubitFactory('q2') controlQR = QRegister(controlQ) targetQR = QRegister(targetQ) edge = EdgeFactory(controlQ, targetQ) lengths = np.linspace(0, 4e-6, 11) riseFall = 40e-9 amp = 1 phase = 0 calRepeats = 2 expected_seq = [] # Seq1 for l in lengths: expected_seq += [ qwait(channels=(controlQ, targetQ)), Id(controlQ), flat_top_gaussian(edge, riseFall, length=l, amp=amp, phase=phase), Barrier(controlQ, targetQ), MEAS(controlQ), MEAS(targetQ) ] # Seq2 for l in lengths: expected_seq += [ qwait(channels=(controlQ, targetQ)), X(controlQ), flat_top_gaussian(edge, riseFall, length=l, amp=amp, phase=phase), X(controlQ), Barrier(controlQ, targetQ), MEAS(controlQ), MEAS(targetQ) ] # Add calibration calseq = get_cal_seqs_2qubits(controlQ, targetQ, calRepeats) expected_seq += calseq expected_seq = testable_sequence(expected_seq) resFunction = compile_function( "src/python/qgl2/basic_sequences/CR.py", "PiRabi", (controlQR, targetQR, lengths, riseFall, amp, phase, calRepeats)) seqs = resFunction() seqs = testable_sequence(seqs) self.maxDiff = None assertPulseSequenceEqual(self, seqs, expected_seq)
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 Ramseyq1(qubit: qreg, pulseSpacings, TPPIFreq=0, showPlot=False, calRepeats=2, suffix=False): """ 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) showPlot : whether to plot (boolean) 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 seqs = [] for d,phase in zip(pulseSpacings, phases): seq = [] seq.append(X90(qubit)) seq.append(Id(qubit, d)) seq.append(U90(qubit, phase=phase)) seq.append(MEAS(qubit)) seqs.append(seq) # Tack on calibration # seqs = addCalibration(seqs, (qubit,), calRepeats) # Calculate label label = 'Ramsey'+('_'+qubit.label)*suffix fullLabel = label + '/' + label
def doRamsey(): q = QubitFactory('q1') TPPIFreq=1e6 # FIXME: QGL2 doesn't deal well with the call to np.arange pulseS = [ 1.00000000e-07, 2.00000000e-07, 3.00000000e-07, 4.00000000e-07, 5.00000000e-07, 6.00000000e-07, 7.00000000e-07, 8.00000000e-07, 9.00000000e-07, 1.00000000e-06, 1.10000000e-06, 1.20000000e-06, 1.30000000e-06, 1.40000000e-06, 1.50000000e-06, 1.60000000e-06, 1.70000000e-06, 1.80000000e-06, 1.90000000e-06, 2.00000000e-06, 2.10000000e-06, 2.20000000e-06, 2.30000000e-06, 2.40000000e-06, 2.50000000e-06, 2.60000000e-06, 2.70000000e-06, 2.80000000e-06, 2.90000000e-06, 3.00000000e-06, 3.10000000e-06, 3.20000000e-06, 3.30000000e-06, 3.40000000e-06, 3.50000000e-06, 3.60000000e-06, 3.70000000e-06, 3.80000000e-06, 3.90000000e-06, 4.00000000e-06, 4.10000000e-06, 4.20000000e-06, 4.30000000e-06, 4.40000000e-06, 4.50000000e-06, 4.60000000e-06, 4.70000000e-06, 4.80000000e-06, 4.90000000e-06, 5.00000000e-06, 5.10000000e-06, 5.20000000e-06, 5.30000000e-06, 5.40000000e-06, 5.50000000e-06, 5.60000000e-06, 5.70000000e-06, 5.80000000e-06, 5.90000000e-06, 6.00000000e-06, 6.10000000e-06, 6.20000000e-06, 6.30000000e-06, 6.40000000e-06, 6.50000000e-06, 6.60000000e-06, 6.70000000e-06, 6.80000000e-06, 6.90000000e-06, 7.00000000e-06, 7.10000000e-06, 7.20000000e-06, 7.30000000e-06, 7.40000000e-06, 7.50000000e-06, 7.60000000e-06, 7.70000000e-06, 7.80000000e-06, 7.90000000e-06, 8.00000000e-06, 8.10000000e-06, 8.20000000e-06, 8.30000000e-06, 8.40000000e-06, 8.50000000e-06, 8.60000000e-06, 8.70000000e-06, 8.80000000e-06, 8.90000000e-06, 9.00000000e-06, 9.10000000e-06, 9.20000000e-06, 9.30000000e-06, 9.40000000e-06, 9.50000000e-06, 9.60000000e-06, 9.70000000e-06, 9.80000000e-06, 9.90000000e-06] #pulseSpacings=np.arange(100e-9, 10e-6, 100e-9) # Create the phases for the TPPI phases = 2*pi*TPPIFreq*pulseS # Create the basic Ramsey sequence # FIXME: QGL2 doesn't deal well with this call to zip for d,phase in zip(pulseS, phases): init(q) X90(q) Id(q, d) U90(q, phase=phase) MEAS(q) # Tack on calibration create_cal_seqs((q,), calRepeats)
def test_AllXY_alt2(self): q1 = QubitFactory('q1') qr = QRegister('q1') expectedseq = [] # Expect a single sequence 4 * 2 * 21 pulses long # Expect it to start like this: expectedseq += [ qwait(channels=(q1, )), Id(q1), Id(q1), MEAS(q1), qwait(channels=(q1, )), Id(q1), Id(q1), MEAS(q1) ] resFunction = compile_function("test/code/AllXY_alt.py", "doAllXY2", (qr, )) seqs = resFunction() seqs = testable_sequence(seqs) self.assertEqual(len(seqs), 4 * 21 * 2) assertPulseSequenceEqual(self, seqs[:len(expectedseq)], expectedseq)
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 test_SingleShot(self): q1 = QubitFactory('q1') qr = QRegister(q1) resFunction = compile_function( "src/python/qgl2/basic_sequences/Rabi.py", "SingleShot", (qr, )) seqs = resFunction() seqs = testable_sequence(seqs) expectedseq = [ qwait(channels=(q1, )), Id(q1), MEAS(q1), qwait(channels=(q1, )), X(q1), MEAS(q1) ] assertPulseSequenceEqual(self, seqs, expectedseq)
def testSingleQubitRB_AC(qubit, seqs, purit=False, add_cal=True): from QGL.PulsePrimitives import AC, MEAS, Id, Y90m, X90 from QGL.BasicSequences.helpers import create_cal_seqs from functools import reduce import operator seqsBis = [] op = [Id(qubit, length=0), Y90m(qubit), X90(qubit)] for ct in range(3 if purit else 1): for seq in seqs: seqsBis.append([AC(qubit, c) for c in seq]) # append tomography pulse to measure purity seqsBis[-1].append(op[ct]) # append measurement seqsBis[-1].append(MEAS(qubit)) # Tack on the calibration sequences if add_cals: seqsBis += create_cal_seqs((qubit, ), 2) return seqsBis
def testSingleQubitRB(qubit, rbseqs, purit=False, add_cal=True): from QGL.Cliffords import clifford_seq from QGL.BasicSequences.helpers import create_cal_seqs from functools import reduce import operator seqsBis = [] op = [Id(qubit, length=0), Y90m(qubit), X90(qubit)] for ct in range(3 if purit else 1): for seq in rbseqs: seqsBis.append( reduce(operator.add, [clifford_seq(c, qubit) for c in seq])) #append tomography pulse to measure purity seqsBis[-1].append(op[ct]) #append measurement seqsBis[-1].append(MEAS(qubit)) #Tack on the calibration sequences if add_cal: seqsBis += create_cal_seqs((qubit, ), 2) return seqsBis
def test_InversionRecovery(self): q = QubitFactory('q1') qr = QRegister('q1') delays = np.linspace(0, 5e-6, 11) calRepeats = 2 expectedseq = [] for d in delays: expectedseq += [qwait(channels=(q, )), X(q), Id(q, d), MEAS(q)] # Add calibration cal = get_cal_seqs_1qubit(q, calRepeats) expectedseq += cal expectedseq = testable_sequence(expectedseq) resFunction = compile_function( "src/python/qgl2/basic_sequences/T1T2.py", "InversionRecovery", (qr, delays, calRepeats)) seqs = resFunction() seqs = testable_sequence(seqs) assertPulseSequenceEqual(self, seqs, expectedseq)
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 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)
def idPulseCentered(qubit, pulseSpacing): return Id(qubit, length=(pulseSpacing - qubit.pulse_params["length"]) / 2)
def test_EchoCRLen(self): controlQ = QubitFactory('q1') targetQ = QubitFactory('q2') cR = QRegister('q1') # Equivalent to QRegister(controlQ) tR = QRegister('q2') # FIXME: Better values!? lengths = np.linspace(0, 2e-6, 11) riseFall = 40e-9 amp = 1 phase = 0 calRepeats = 2 canc_amp = 0 canc_phase = np.pi / 2 expected_seq = [] # Seq1 for l in lengths: expected_seq += [ qwait(channels=(controlQ, targetQ)), Id(controlQ), echoCR(controlQ, targetQ, length=l, phase=phase, amp=amp, riseFall=riseFall, canc_amp=canc_amp, canc_phase=canc_phase), Id(controlQ), Barrier(controlQ, targetQ), MEAS(controlQ), MEAS(targetQ) ] # Seq2 for l in lengths: expected_seq += [ qwait(channels=(controlQ, targetQ)), X(controlQ), echoCR(controlQ, targetQ, length=l, phase=phase, amp=amp, riseFall=riseFall, canc_amp=canc_amp, canc_phase=canc_phase), X(controlQ), Barrier(controlQ, targetQ), MEAS(controlQ), MEAS(targetQ) ] # Add calibration cal_seqs = get_cal_seqs_2qubits(controlQ, targetQ, calRepeats) expected_seq += cal_seqs expected_seq = testable_sequence(expected_seq) resFunction = compile_function("src/python/qgl2/basic_sequences/CR.py", "EchoCRLen", (cR, tR, lengths, riseFall, amp, phase, calRepeats, canc_amp, canc_phase)) seqs = resFunction() seqs = testable_sequence(seqs) self.maxDiff = None assertPulseSequenceEqual(self, seqs, expected_seq)
def test_EchoCRPhase(self): controlQ = QubitFactory('q1') targetQ = QubitFactory('q2') cR = QRegister('q1') tR = QRegister('q2') phases = np.linspace(0, pi / 2, 11) riseFall = 40e-9 amp = 1 length = 100e-9 calRepeats = 2 canc_amp = 0 canc_phase = np.pi / 2 expected_seq = [] # Seq1 for p in phases: expected_seq += [ qwait(channels=(controlQ, targetQ)), Id(controlQ), echoCR(controlQ, targetQ, length=length, phase=p, amp=amp, riseFall=riseFall, canc_amp=canc_amp, canc_phase=canc_phase), Barrier(controlQ, targetQ), X90(targetQ), Id(controlQ), Barrier(controlQ, targetQ), MEAS(controlQ), MEAS(targetQ) ] # Seq2 for p in phases: expected_seq += [ qwait(channels=(controlQ, targetQ)), X(controlQ), echoCR(controlQ, targetQ, length=length, phase=p, amp=amp, riseFall=riseFall, canc_amp=canc_amp, canc_phase=canc_phase), Barrier(controlQ, targetQ), X90(targetQ), X(controlQ), Barrier(controlQ, targetQ), MEAS(controlQ), MEAS(targetQ) ] # Add calibration cal_seqs = get_cal_seqs_2qubits(controlQ, targetQ, calRepeats) expected_seq += cal_seqs expected_seq = testable_sequence(expected_seq) resFunction = compile_function("src/python/qgl2/basic_sequences/CR.py", "EchoCRPhase", (cR, tR, phases, riseFall, amp, length, calRepeats, canc_amp, canc_phase)) seqs = resFunction() seqs = testable_sequence(seqs) self.maxDiff = None assertPulseSequenceEqual(self, seqs, expected_seq)