From 31bdedc3a1fdd0acdfed1d815bdb2a257541c4c4 Mon Sep 17 00:00:00 2001 From: "Blake R. Johnson" Date: Mon, 1 Aug 2016 16:31:05 -0400 Subject: [PATCH 1/8] Add basic meta program output. --- QGL/Compiler.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/QGL/Compiler.py b/QGL/Compiler.py index bfcefa6d..dddd8b19 100644 --- a/QGL/Compiler.py +++ b/QGL/Compiler.py @@ -23,6 +23,7 @@ from copy import copy from functools import reduce from importlib import import_module +import json from . import config from . import PatternUtils @@ -380,7 +381,7 @@ def compile_to_hardware(seqs, awgData = bundle_wires(physWires, wfs) # convert to hardware formats - fileList = [] + files = {} for awgName, data in awgData.items(): # create the target folder if it does not exist targetFolder = os.path.split(os.path.normpath(os.path.join( @@ -392,10 +393,25 @@ def compile_to_hardware(seqs, 'seqFileExt'])) data['translator'].write_sequence_file(data, fullFileName) - fileList.append(fullFileName) + files[awgName] = fullFileName + + # create meta output + axis_descriptor = { + 'name': 'segment', + 'unit': None, + 'points': list(range(1, 1+len(seqs))) + } + meta = { + 'instruments': files, + 'num_sequences': len(seqs), + 'axis_descriptor': axis_descriptor + } + metafilepath = os.path.join(config.AWGDir, fileName + '-meta.json') + with open(metafilepath, 'w') as FID: + json.dump(meta, FID, indent=2, sort_keys=True) # Return the filenames we wrote - return fileList + return list(files.values()) def compile_sequences(seqs, channels=set(), qgl2=False): From dfd74bc5048ec67c5335c13ff6fab12db41271f8 Mon Sep 17 00:00:00 2001 From: "Blake R. Johnson" Date: Tue, 2 Aug 2016 16:48:10 -0400 Subject: [PATCH 2/8] Add axis_descriptor and cal_descriptor kwargs to compile_to_hardware. --- QGL/Compiler.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/QGL/Compiler.py b/QGL/Compiler.py index dddd8b19..3e234fff 100644 --- a/QGL/Compiler.py +++ b/QGL/Compiler.py @@ -287,6 +287,8 @@ def collect_specializations(seqs): def compile_to_hardware(seqs, fileName, suffix='', + axis_descriptor=None, + cal_descriptor=None, qgl2=False, addQGL2SlaveTrigger=False): ''' @@ -396,15 +398,20 @@ def compile_to_hardware(seqs, files[awgName] = fullFileName # create meta output - axis_descriptor = { - 'name': 'segment', - 'unit': None, - 'points': list(range(1, 1+len(seqs))) - } + if not axis_descriptor: + axis_descriptor = { + 'name': 'segment', + 'unit': None, + 'points': list(range(1, 1+len(seqs))) + } + if not cal_descriptor: + # contains a dictionary of states and a list of associated indices + cal_descriptor = {} meta = { 'instruments': files, 'num_sequences': len(seqs), - 'axis_descriptor': axis_descriptor + 'axis_descriptor': axis_descriptor, + 'cal_descriptor': cal_descriptor } metafilepath = os.path.join(config.AWGDir, fileName + '-meta.json') with open(metafilepath, 'w') as FID: From b545084da15602b5bbb50827f56087ec2cf74edc Mon Sep 17 00:00:00 2001 From: "Blake R. Johnson" Date: Tue, 2 Aug 2016 16:48:33 -0400 Subject: [PATCH 3/8] Update basic sequences to provide axis descriptors. --- QGL/BasicSequences/CR.py | 30 +++++++++++---- QGL/BasicSequences/Decoupling.py | 14 ++++--- QGL/BasicSequences/Rabi.py | 39 ++++++++++++++++--- QGL/BasicSequences/T1T2.py | 64 ++++++++++++++++---------------- QGL/BasicSequences/helpers.py | 16 ++++++++ 5 files changed, 111 insertions(+), 52 deletions(-) diff --git a/QGL/BasicSequences/CR.py b/QGL/BasicSequences/CR.py index cefd53c0..ee90c55d 100644 --- a/QGL/BasicSequences/CR.py +++ b/QGL/BasicSequences/CR.py @@ -2,7 +2,7 @@ from ..Compiler import compile_to_hardware from ..ChannelLibrary import EdgeFactory from ..PulseSequencePlotter import plot_pulse_files -from .helpers import create_cal_seqs +from .helpers import create_cal_seqs, time_descriptor def PiRabi(controlQ, @@ -22,7 +22,7 @@ def PiRabi(controlQ, 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 + amp : amplitude of the CR pulse phase : phase of the CR pulse (rad) showPlot : whether to plot (boolean) """ @@ -37,7 +37,8 @@ def PiRabi(controlQ, MEAS(targetQ)*MEAS(controlQ)] for l in lengths] + \ create_cal_seqs([targetQ,controlQ], calRepeats, measChans=(targetQ,controlQ)) - fileNames = compile_to_hardware(seqs, 'PiRabi/PiRabi') + fileNames = compile_to_hardware(seqs, 'PiRabi/PiRabi', + axis_descriptor=time_descriptor(lengths)) print(fileNames) if showPlot: @@ -61,7 +62,7 @@ def EchoCRLen(controlQ, 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 + 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 showPlot : whether to plot (boolean) @@ -70,7 +71,8 @@ def EchoCRLen(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)) - fileNames = compile_to_hardware(seqs, 'EchoCR/EchoCR') + fileNames = compile_to_hardware(seqs, 'EchoCR/EchoCR', + axis_descriptor=time_descriptor(lengths)) print(fileNames) if showPlot: @@ -94,7 +96,7 @@ def EchoCRPhase(controlQ, CRchan: 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 + 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 showPlot : whether to plot (boolean) @@ -103,7 +105,13 @@ def EchoCRPhase(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)) - fileNames = compile_to_hardware(seqs, 'EchoCR/EchoCR') + axis_descriptor = { + 'name': 'phase', + 'unit': 'radians', + 'points': list(phases) + } + + fileNames = compile_to_hardware(seqs, 'EchoCR/EchoCR', axis_descriptor=axis_descriptor) print(fileNames) if showPlot: @@ -136,7 +144,13 @@ def EchoCRAmp(controlQ, for a in amps]+ [[X(controlQ)] + echoCR(controlQ, targetQ, length=length, phase= phase, riseFall=riseFall,amp=a) + [X(controlQ), MEAS(targetQ)*MEAS(controlQ)]\ for a in amps] + create_cal_seqs((targetQ,controlQ), calRepeats, measChans=(targetQ,controlQ)) - fileNames = compile_to_hardware(seqs, 'EchoCR/EchoCR') + axis_descriptor = { + 'name': 'amplitude', + 'unit': None, + 'points': list(amps) + } + + fileNames = compile_to_hardware(seqs, 'EchoCR/EchoCR', axis_descriptor=axis_descriptor) print(fileNames) if showPlot: diff --git a/QGL/BasicSequences/Decoupling.py b/QGL/BasicSequences/Decoupling.py index aa8e4eda..91d4e8f1 100644 --- a/QGL/BasicSequences/Decoupling.py +++ b/QGL/BasicSequences/Decoupling.py @@ -1,16 +1,16 @@ from ..PulsePrimitives import * from ..Compiler import compile_to_hardware from ..PulseSequencePlotter import plot_pulse_files -from .helpers import create_cal_seqs +from .helpers import create_cal_seqs, time_descriptor def HahnEcho(qubit, pulseSpacings, periods=0, calRepeats=2, showPlot=False): """ - A single pulse Hahn echo with variable phase of second pi/2 pulse. + A single pulse Hahn echo with variable phase of second pi/2 pulse. Parameters ---------- - qubit : logical channel to implement sequence (LogicalChannel) + 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) @@ -28,7 +28,8 @@ def HahnEcho(qubit, pulseSpacings, periods=0, calRepeats=2, showPlot=False): #Tack on the calibration scalings seqs += create_cal_seqs((qubit, ), calRepeats) - fileNames = compile_to_hardware(seqs, 'Echo/Echo') + fileNames = compile_to_hardware(seqs, 'Echo/Echo', + axis_descriptor=time_descriptor(2 * pulseSpacings)) print(fileNames) if showPlot: @@ -42,7 +43,7 @@ def CPMG(qubit, numPulses, pulseSpacing, calRepeats=2, showPlot=False): Parameters ---------- - qubit : logical channel to implement sequence (LogicalChannel) + qubit : logical channel to implement sequence (LogicalChannel) numPulses : number of 180 pulses; should be even (iterable) pulseSpacing : spacing between the 180's (seconds) calRepeats : how many times to repeat calibration scalings (default 2) @@ -63,7 +64,8 @@ def CPMG(qubit, numPulses, pulseSpacing, calRepeats=2, showPlot=False): #Tack on the calibration scalings seqs += create_cal_seqs((qubit, ), calRepeats) - fileNames = compile_to_hardware(seqs, 'CPMG/CPMG') + fileNames = compile_to_hardware(seqs, 'CPMG/CPMG', + axis_descriptor=time_descriptor(pulseSpacing * numPulses)) print(fileNames) if showPlot: diff --git a/QGL/BasicSequences/Rabi.py b/QGL/BasicSequences/Rabi.py index df78d4ba..4fb2dd27 100644 --- a/QGL/BasicSequences/Rabi.py +++ b/QGL/BasicSequences/Rabi.py @@ -2,7 +2,7 @@ from ..Compiler import compile_to_hardware from ..PulseSequencePlotter import plot_pulse_files import QGL.PulseShapes -from .helpers import create_cal_seqs +from .helpers import create_cal_seqs, time_descriptor from functools import reduce @@ -24,7 +24,13 @@ def RabiAmp(qubit, amps, phase=0, showPlot=False): """ seqs = [[Utheta(qubit, amp=amp, phase=phase), MEAS(qubit)] for amp in amps] - fileNames = compile_to_hardware(seqs, 'Rabi/Rabi') + axis_descriptor = { + 'name': 'amplitude', + 'unit': None, + 'points': list(amps) + } + + fileNames = compile_to_hardware(seqs, 'Rabi/Rabi', axis_descriptor=axis_descriptor) print(fileNames) if showPlot: @@ -59,7 +65,8 @@ def RabiWidth(qubit, phase=phase, shapeFun=shapeFun), MEAS(qubit)] for l in widths] - fileNames = compile_to_hardware(seqs, 'Rabi/Rabi') + fileNames = compile_to_hardware(seqs, 'Rabi/Rabi', + axis_descriptor=time_descriptor(widths)) print(fileNames) if showPlot: @@ -101,7 +108,13 @@ def RabiAmp_NQubits(qubits, if docals: seqs += create_cal_seqs(qubits, calRepeats, measChans=measChans) - fileNames = compile_to_hardware(seqs, 'Rabi/Rabi') + axis_descriptor = { + 'name': 'amplitude', + 'unit': None, + 'points': list(amps) + } + + fileNames = compile_to_hardware(seqs, 'Rabi/Rabi', axis_descriptor=axis_descriptor) print(fileNames) if showPlot: @@ -127,7 +140,13 @@ def RabiAmpPi(qubit, mqubit, amps, phase=0, showPlot=False): seqs = [[X(mqubit), Utheta(qubit, amp=amp, phase=phase), X(mqubit), MEAS(mqubit)] for amp in amps] - fileNames = compile_to_hardware(seqs, 'Rabi/Rabi') + axis_descriptor = { + 'name': 'amplitude', + 'unit': None, + 'points': list(amps) + } + + fileNames = compile_to_hardware(seqs, 'Rabi/Rabi', axis_descriptor=axis_descriptor) print(fileNames) if showPlot: @@ -140,6 +159,13 @@ def SingleShot(qubit, showPlot=False): 2-segment sequence with qubit prepared in |0> and |1>, useful for single-shot fidelity measurements and kernel calibration """ seqs = [[Id(qubit), MEAS(qubit)], [X(qubit), MEAS(qubit)]] + + axis_descriptor = { + 'name': 'state', + 'unit': None, + 'points': [0, 1] + } + filenames = compile_to_hardware(seqs, 'SingleShot/SingleShot') print(filenames) @@ -181,7 +207,8 @@ def Swap(qubit, mqubit, delays, showPlot=False): (mqubit, qubit), 2, measChans=(mqubit, qubit)) - fileNames = compile_to_hardware(seqs, 'Rabi/Rabi') + fileNames = compile_to_hardware(seqs, 'Rabi/Rabi', + time_descriptor=time_descriptor(delays)) print(fileNames) if showPlot: diff --git a/QGL/BasicSequences/T1T2.py b/QGL/BasicSequences/T1T2.py index 5d438961..df687c43 100644 --- a/QGL/BasicSequences/T1T2.py +++ b/QGL/BasicSequences/T1T2.py @@ -2,7 +2,7 @@ from ..Compiler import compile_to_hardware from ..PulseSequencePlotter import plot_pulse_files from scipy.constants import pi -from .helpers import create_cal_seqs +from .helpers import create_cal_seqs, time_descriptor def InversionRecovery(qubit, @@ -11,20 +11,19 @@ def InversionRecovery(qubit, 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) - - Returns - ------- - plotHandle : handle to plot window to prevent destruction - """ + 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) + + Returns + ------- + plotHandle : handle to plot window to prevent destruction + """ #Create the basic sequences seqs = [[X(qubit), Id(qubit, d), MEAS(qubit)] for d in delays] @@ -34,7 +33,8 @@ def InversionRecovery(qubit, fileNames = compile_to_hardware(seqs, 'T1' + ('_' + qubit.label) * suffix + '/T1' + - ('_' + qubit.label) * suffix) + ('_' + qubit.label) * suffix, + axis_descriptor=time_descriptor(delays)) print(fileNames) if showPlot: @@ -48,21 +48,20 @@ def Ramsey(qubit, 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) - - Returns - ------- - plotHandle : handle to plot window to prevent destruction - """ + 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) + + Returns + ------- + plotHandle : handle to plot window to prevent destruction + """ #Create the phases for the TPPI phases = 2 * pi * TPPIFreq * pulseSpacings @@ -76,7 +75,8 @@ def Ramsey(qubit, fileNames = compile_to_hardware(seqs, 'Ramsey' + ('_' + qubit.label) * suffix + '/Ramsey' + - ('_' + qubit.label) * suffix) + ('_' + qubit.label) * suffix, + axis_descriptor=time_descriptor(pulseSpacings)) print(fileNames) if showPlot: diff --git a/QGL/BasicSequences/helpers.py b/QGL/BasicSequences/helpers.py index 9338056a..3f117343 100644 --- a/QGL/BasicSequences/helpers.py +++ b/QGL/BasicSequences/helpers.py @@ -28,3 +28,19 @@ def create_cal_seqs(qubits, numRepeats, measChans=None, waitcmp=False): measBlock = reduce(operator.mul, [MEAS(q) for q in qubits]) return [[seq, measBlock, qwait('CMP')] if waitcmp else [seq, measBlock] for seq in calSeqs] + +def time_descriptor(times, desired_units="us"): + if desired_units == "s": + scale = 1 + elif desired_units == "ms": + scale = 1e3 + elif desired_units == "us" or desired_units == "μs": + scale = 1e6 + elif desired_units == "ns": + scale = 1e9 + axis_descriptor = { + 'name': 'time', + 'unit': desired_units, + 'points': list(scale * times) + } + return axis_descriptor From 0e9c60b5e95549c85f5d165ab333af2c9b6bceed Mon Sep 17 00:00:00 2001 From: "Blake R. Johnson" Date: Tue, 2 Aug 2016 16:54:05 -0400 Subject: [PATCH 4/8] Add number of measurements to meta info. --- QGL/Compiler.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/QGL/Compiler.py b/QGL/Compiler.py index 3e234fff..4367f04f 100644 --- a/QGL/Compiler.py +++ b/QGL/Compiler.py @@ -398,11 +398,13 @@ def compile_to_hardware(seqs, files[awgName] = fullFileName # create meta output + num_measurements = sum(PatternUtils.contains_measurement(e) + for e in flatten(seqs)) if not axis_descriptor: axis_descriptor = { 'name': 'segment', 'unit': None, - 'points': list(range(1, 1+len(seqs))) + 'points': list(range(1, 1 + num_measurements)) } if not cal_descriptor: # contains a dictionary of states and a list of associated indices @@ -410,6 +412,7 @@ def compile_to_hardware(seqs, meta = { 'instruments': files, 'num_sequences': len(seqs), + 'num_measurements': num_measurements, 'axis_descriptor': axis_descriptor, 'cal_descriptor': cal_descriptor } From cc2cc77e5f73821d359a7f173c9729f3cacc6ad5 Mon Sep 17 00:00:00 2001 From: "Blake R. Johnson" Date: Tue, 2 Aug 2016 17:13:07 -0400 Subject: [PATCH 5/8] Add cal_descriptor helper And use it in most of the basic sequences. --- QGL/BasicSequences/CR.py | 16 +++++++++++----- QGL/BasicSequences/Decoupling.py | 8 +++++--- QGL/BasicSequences/Rabi.py | 9 ++++++--- QGL/BasicSequences/T1T2.py | 18 +++++++++--------- QGL/BasicSequences/helpers.py | 10 +++++++++- 5 files changed, 40 insertions(+), 21 deletions(-) diff --git a/QGL/BasicSequences/CR.py b/QGL/BasicSequences/CR.py index ee90c55d..80a27510 100644 --- a/QGL/BasicSequences/CR.py +++ b/QGL/BasicSequences/CR.py @@ -2,7 +2,7 @@ from ..Compiler import compile_to_hardware from ..ChannelLibrary import EdgeFactory from ..PulseSequencePlotter import plot_pulse_files -from .helpers import create_cal_seqs, time_descriptor +from .helpers import create_cal_seqs, time_descriptor, cal_descriptor def PiRabi(controlQ, @@ -38,7 +38,8 @@ def PiRabi(controlQ, create_cal_seqs([targetQ,controlQ], calRepeats, measChans=(targetQ,controlQ)) fileNames = compile_to_hardware(seqs, 'PiRabi/PiRabi', - axis_descriptor=time_descriptor(lengths)) + axis_descriptor=time_descriptor(lengths), + cal_descriptor=cal_descriptor((controlQ, targetQ), calRepeats, len(lengths)+1)) print(fileNames) if showPlot: @@ -72,7 +73,8 @@ def EchoCRLen(controlQ, for l in lengths] + create_cal_seqs((targetQ,controlQ), calRepeats, measChans=(targetQ,controlQ)) fileNames = compile_to_hardware(seqs, 'EchoCR/EchoCR', - axis_descriptor=time_descriptor(lengths)) + axis_descriptor=time_descriptor(lengths), + cal_descriptor=cal_descriptor((controlQ, targetQ), calRepeats, len(lengths)+1)) print(fileNames) if showPlot: @@ -111,7 +113,9 @@ def EchoCRPhase(controlQ, 'points': list(phases) } - fileNames = compile_to_hardware(seqs, 'EchoCR/EchoCR', axis_descriptor=axis_descriptor) + fileNames = compile_to_hardware(seqs, 'EchoCR/EchoCR', + axis_descriptor=axis_descriptor, + cal_descriptor=cal_descriptor((controlQ, targetQ), calRepeats, len(phases)+1)) print(fileNames) if showPlot: @@ -150,7 +154,9 @@ def EchoCRAmp(controlQ, 'points': list(amps) } - fileNames = compile_to_hardware(seqs, 'EchoCR/EchoCR', axis_descriptor=axis_descriptor) + fileNames = compile_to_hardware(seqs, 'EchoCR/EchoCR', + axis_descriptor=axis_descriptor, + cal_descriptor=cal_descriptor((controlQ, targetQ), calRepeats, len(amps)+1)) print(fileNames) if showPlot: diff --git a/QGL/BasicSequences/Decoupling.py b/QGL/BasicSequences/Decoupling.py index 91d4e8f1..a3714314 100644 --- a/QGL/BasicSequences/Decoupling.py +++ b/QGL/BasicSequences/Decoupling.py @@ -1,7 +1,7 @@ from ..PulsePrimitives import * from ..Compiler import compile_to_hardware from ..PulseSequencePlotter import plot_pulse_files -from .helpers import create_cal_seqs, time_descriptor +from .helpers import create_cal_seqs, time_descriptor, cal_descriptor def HahnEcho(qubit, pulseSpacings, periods=0, calRepeats=2, showPlot=False): @@ -29,7 +29,8 @@ def HahnEcho(qubit, pulseSpacings, periods=0, calRepeats=2, showPlot=False): seqs += create_cal_seqs((qubit, ), calRepeats) fileNames = compile_to_hardware(seqs, 'Echo/Echo', - axis_descriptor=time_descriptor(2 * pulseSpacings)) + axis_descriptor=time_descriptor(2 * pulseSpacings), + cal_descriptor=cal_descriptor((qubit,), calRepeats, len(pulseSpacings)+1)) print(fileNames) if showPlot: @@ -65,7 +66,8 @@ def CPMG(qubit, numPulses, pulseSpacing, calRepeats=2, showPlot=False): seqs += create_cal_seqs((qubit, ), calRepeats) fileNames = compile_to_hardware(seqs, 'CPMG/CPMG', - axis_descriptor=time_descriptor(pulseSpacing * numPulses)) + axis_descriptor=time_descriptor(pulseSpacing * numPulses), + cal_descriptor=cal_descriptor((qubit,), calRepeats, len(numPulses)+1)) print(fileNames) if showPlot: diff --git a/QGL/BasicSequences/Rabi.py b/QGL/BasicSequences/Rabi.py index 4fb2dd27..68fa869e 100644 --- a/QGL/BasicSequences/Rabi.py +++ b/QGL/BasicSequences/Rabi.py @@ -2,7 +2,7 @@ from ..Compiler import compile_to_hardware from ..PulseSequencePlotter import plot_pulse_files import QGL.PulseShapes -from .helpers import create_cal_seqs, time_descriptor +from .helpers import create_cal_seqs, time_descriptor, cal_descriptor from functools import reduce @@ -114,7 +114,9 @@ def RabiAmp_NQubits(qubits, 'points': list(amps) } - fileNames = compile_to_hardware(seqs, 'Rabi/Rabi', axis_descriptor=axis_descriptor) + fileNames = compile_to_hardware(seqs, 'Rabi/Rabi', + axis_descriptor=axis_descriptor, + cal_descriptor=cal_descriptor(qubits, calRepeats, len(amps)+1)) print(fileNames) if showPlot: @@ -208,7 +210,8 @@ def Swap(qubit, mqubit, delays, showPlot=False): measChans=(mqubit, qubit)) fileNames = compile_to_hardware(seqs, 'Rabi/Rabi', - time_descriptor=time_descriptor(delays)) + time_descriptor=time_descriptor(delays), + cal_descriptor=cal_descriptor((mqubit, qubit), 2, len(delays)+1)) print(fileNames) if showPlot: diff --git a/QGL/BasicSequences/T1T2.py b/QGL/BasicSequences/T1T2.py index df687c43..e9f1a558 100644 --- a/QGL/BasicSequences/T1T2.py +++ b/QGL/BasicSequences/T1T2.py @@ -2,7 +2,7 @@ from ..Compiler import compile_to_hardware from ..PulseSequencePlotter import plot_pulse_files from scipy.constants import pi -from .helpers import create_cal_seqs, time_descriptor +from .helpers import create_cal_seqs, time_descriptor, cal_descriptor def InversionRecovery(qubit, @@ -31,10 +31,10 @@ def InversionRecovery(qubit, #Tack on the calibration scalings seqs += create_cal_seqs((qubit, ), calRepeats) - fileNames = compile_to_hardware(seqs, 'T1' + - ('_' + qubit.label) * suffix + '/T1' + - ('_' + qubit.label) * suffix, - axis_descriptor=time_descriptor(delays)) + fileNames = compile_to_hardware(seqs, + 'T1' + ('_' + qubit.label) * suffix + '/T1' + ('_' + qubit.label) * suffix, + axis_descriptor=time_descriptor(delays), + cal_descriptor=cal_descriptor((qubit,), calRepeats, len(delays)+1)) print(fileNames) if showPlot: @@ -73,10 +73,10 @@ def Ramsey(qubit, #Tack on the calibration scalings seqs += create_cal_seqs((qubit, ), calRepeats) - fileNames = compile_to_hardware(seqs, 'Ramsey' + - ('_' + qubit.label) * suffix + '/Ramsey' + - ('_' + qubit.label) * suffix, - axis_descriptor=time_descriptor(pulseSpacings)) + fileNames = compile_to_hardware(seqs, + 'Ramsey' + ('_' + qubit.label) * suffix + '/Ramsey' + ('_' + qubit.label) * suffix, + axis_descriptor=time_descriptor(pulseSpacings), + cal_descriptor=cal_descriptor((qubit,), calRepeats, len(pulseSpacings)+1)) print(fileNames) if showPlot: diff --git a/QGL/BasicSequences/helpers.py b/QGL/BasicSequences/helpers.py index 3f117343..b7d94df8 100644 --- a/QGL/BasicSequences/helpers.py +++ b/QGL/BasicSequences/helpers.py @@ -1,3 +1,5 @@ +# coding=utf-8 + from itertools import product import operator from ..PulsePrimitives import Id, X, MEAS @@ -29,12 +31,18 @@ def create_cal_seqs(qubits, numRepeats, measChans=None, waitcmp=False): return [[seq, measBlock, qwait('CMP')] if waitcmp else [seq, measBlock] for seq in calSeqs] +def cal_descriptor(qubits, numRepeats, startIdx): + states = ['0', '1'] + state_set = [reduce(operator.add, s) for s in product(states, repeat=len(qubits))] + descriptor = {state: startIdx + (ct * numRepeats) for ct, state in enumerate(state_set)} + return descriptor + def time_descriptor(times, desired_units="us"): if desired_units == "s": scale = 1 elif desired_units == "ms": scale = 1e3 - elif desired_units == "us" or desired_units == "μs": + elif desired_units == "us" or desired_units == u"μs": scale = 1e6 elif desired_units == "ns": scale = 1e9 From f3d6c0c26e537403464f68ecb7cf55b5ab8b45f2 Mon Sep 17 00:00:00 2001 From: "Blake R. Johnson" Date: Wed, 3 Aug 2016 14:15:22 -0400 Subject: [PATCH 6/8] Fix cal_descriptor helper to return lists of cal points. --- QGL/BasicSequences/helpers.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/QGL/BasicSequences/helpers.py b/QGL/BasicSequences/helpers.py index b7d94df8..09d41b58 100644 --- a/QGL/BasicSequences/helpers.py +++ b/QGL/BasicSequences/helpers.py @@ -33,8 +33,12 @@ def create_cal_seqs(qubits, numRepeats, measChans=None, waitcmp=False): def cal_descriptor(qubits, numRepeats, startIdx): states = ['0', '1'] + # generate state set in same order as we do above in create_cal_seqs() state_set = [reduce(operator.add, s) for s in product(states, repeat=len(qubits))] - descriptor = {state: startIdx + (ct * numRepeats) for ct, state in enumerate(state_set)} + descriptor = {} + cal_range = range(startIdx, startIdx + numRepeats*len(state_set)) + for ct, state in enumerate(state_set): + descriptor[state] = list(cal_range[ct*numRepeats : (ct+1)*numRepeats]) return descriptor def time_descriptor(times, desired_units="us"): @@ -46,9 +50,9 @@ def time_descriptor(times, desired_units="us"): scale = 1e6 elif desired_units == "ns": scale = 1e9 - axis_descriptor = { + axis_descriptor = [{ 'name': 'time', 'unit': desired_units, 'points': list(scale * times) - } + }] return axis_descriptor From 6db034d4167c1a0c9ab4b26bdffe97820039d18e Mon Sep 17 00:00:00 2001 From: "Blake R. Johnson" Date: Wed, 3 Aug 2016 14:15:41 -0400 Subject: [PATCH 7/8] Make axis_descriptor an array of DataAxis descriptions. Incorporating feedback from @grahamrow --- QGL/BasicSequences/CR.py | 8 ++++---- QGL/BasicSequences/Rabi.py | 12 ++++++------ QGL/Compiler.py | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/QGL/BasicSequences/CR.py b/QGL/BasicSequences/CR.py index 80a27510..a3d4068a 100644 --- a/QGL/BasicSequences/CR.py +++ b/QGL/BasicSequences/CR.py @@ -107,11 +107,11 @@ def EchoCRPhase(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)) - axis_descriptor = { + axis_descriptor = [{ 'name': 'phase', 'unit': 'radians', 'points': list(phases) - } + }] fileNames = compile_to_hardware(seqs, 'EchoCR/EchoCR', axis_descriptor=axis_descriptor, @@ -148,11 +148,11 @@ def EchoCRAmp(controlQ, for a in amps]+ [[X(controlQ)] + echoCR(controlQ, targetQ, length=length, phase= phase, riseFall=riseFall,amp=a) + [X(controlQ), MEAS(targetQ)*MEAS(controlQ)]\ for a in amps] + create_cal_seqs((targetQ,controlQ), calRepeats, measChans=(targetQ,controlQ)) - axis_descriptor = { + axis_descriptor = [{ 'name': 'amplitude', 'unit': None, 'points': list(amps) - } + }] fileNames = compile_to_hardware(seqs, 'EchoCR/EchoCR', axis_descriptor=axis_descriptor, diff --git a/QGL/BasicSequences/Rabi.py b/QGL/BasicSequences/Rabi.py index 68fa869e..8005fd16 100644 --- a/QGL/BasicSequences/Rabi.py +++ b/QGL/BasicSequences/Rabi.py @@ -24,11 +24,11 @@ def RabiAmp(qubit, amps, phase=0, showPlot=False): """ seqs = [[Utheta(qubit, amp=amp, phase=phase), MEAS(qubit)] for amp in amps] - axis_descriptor = { + axis_descriptor = [{ 'name': 'amplitude', 'unit': None, 'points': list(amps) - } + }] fileNames = compile_to_hardware(seqs, 'Rabi/Rabi', axis_descriptor=axis_descriptor) print(fileNames) @@ -108,11 +108,11 @@ def RabiAmp_NQubits(qubits, if docals: seqs += create_cal_seqs(qubits, calRepeats, measChans=measChans) - axis_descriptor = { + axis_descriptor = [{ 'name': 'amplitude', 'unit': None, 'points': list(amps) - } + }] fileNames = compile_to_hardware(seqs, 'Rabi/Rabi', axis_descriptor=axis_descriptor, @@ -142,11 +142,11 @@ def RabiAmpPi(qubit, mqubit, amps, phase=0, showPlot=False): seqs = [[X(mqubit), Utheta(qubit, amp=amp, phase=phase), X(mqubit), MEAS(mqubit)] for amp in amps] - axis_descriptor = { + axis_descriptor = [{ 'name': 'amplitude', 'unit': None, 'points': list(amps) - } + }] fileNames = compile_to_hardware(seqs, 'Rabi/Rabi', axis_descriptor=axis_descriptor) print(fileNames) diff --git a/QGL/Compiler.py b/QGL/Compiler.py index 4367f04f..811caa4e 100644 --- a/QGL/Compiler.py +++ b/QGL/Compiler.py @@ -401,11 +401,11 @@ def compile_to_hardware(seqs, num_measurements = sum(PatternUtils.contains_measurement(e) for e in flatten(seqs)) if not axis_descriptor: - axis_descriptor = { + axis_descriptor = [{ 'name': 'segment', 'unit': None, 'points': list(range(1, 1 + num_measurements)) - } + }] if not cal_descriptor: # contains a dictionary of states and a list of associated indices cal_descriptor = {} From ae0fa7cfa9325cccb5acdca9c4e18d4f32ffb049 Mon Sep 17 00:00:00 2001 From: "Blake R. Johnson" Date: Wed, 3 Aug 2016 14:23:07 -0400 Subject: [PATCH 8/8] Document new arguments to compile_to_hardware. [ci skip] --- QGL/Compiler.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/QGL/Compiler.py b/QGL/Compiler.py index 811caa4e..dec861c6 100644 --- a/QGL/Compiler.py +++ b/QGL/Compiler.py @@ -292,8 +292,17 @@ def compile_to_hardware(seqs, qgl2=False, addQGL2SlaveTrigger=False): ''' - Compiles 'seqs' to a hardware description and saves it to 'fileName'. Other inputs: - suffix : string to append to end of fileName (e.g. with fileNames = 'test' and suffix = 'foo' might save to test-APSfoo.h5) + Compiles 'seqs' to a hardware description and saves it to 'fileName'. + Other inputs: + suffix (optional): string to append to end of fileName, e.g. with + fileNames = 'test' and suffix = 'foo' might save to test-APSfoo.h5 + axis_descriptor (optional): a list of dictionaries describing the effective + axes of the measurements that the sequence will yield. For instance, + if `seqs` generates a Ramsey experiment, axis_descriptor would describe + the time delays between pulses. + cal_descriptor (optional): a dictionary of labels and indices for calibration + experiments within `seqs` + qgl2 (optional): Launch compiler in QGL2 mode ''' logger.debug("Compiling %d sequence(s)", len(seqs))