Example #1
0
def main():
    from pyqgl2.qreg import QRegister
    import pyqgl2.test_cl
    from pyqgl2.main import compile_function, qgl2_compile_to_hardware
    import numpy as np

    toHW = True
    plotPulses = False
    pyqgl2.test_cl.create_default_channelLibrary(toHW, True)

    #    # 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

    # Pass in QRegister(s) NOT real Qubits
    q1 = QRegister("q1")

    # FIXME: See issue #44: Must supply all args to qgl2main for now

    #    for func, args, label in [("HahnEcho", (q1, np.linspace(0, 5e-6, 11)), "HahnEcho"),
    #                              ("CPMG", (q1, [0, 2, 4, 5], 500e-9), "CPMG"),
    #                          ]:
    for func, args, label in [
        ("HahnEcho", (q1, np.linspace(0, 5e-6, 11), 0, 2), "HahnEcho"),
        ("CPMG", (q1, [0, 2, 4, 6], 500e-9, 2), "CPMG"),
    ]:

        print(f"\nRun {func}...")
        # Here we know the function is in the current file
        # You could use os.path.dirname(os.path.realpath(__file)) to find files relative to this script,
        # Or os.getcwd() to get files relative to where you ran from. Or always use absolute paths.
        resFunc = compile_function(__file__, func, args)
        # Run the QGL2. Note that the generated function takes no arguments itself
        seq = resFunc()
        if toHW:
            print(f"Compiling {func} sequences to hardware\n")
            fileNames = qgl2_compile_to_hardware(seq, f'{label}/{label}')
            print(f"Compiled sequences; metafile = {fileNames}")
            if plotPulses:
                from QGL.PulseSequencePlotter import plot_pulse_files
                # FIXME: As called, this returns a graphical object to display
                plot_pulse_files(fileNames)
        else:
            print(f"\nGenerated {func} sequences:\n")
            from QGL.Scheduler import schedule

            scheduled_seq = schedule(seq)
            from IPython.lib.pretty import pretty
            print(pretty(scheduled_seq))
Example #2
0
def main():
    from pyqgl2.qreg import QRegister
    import pyqgl2.test_cl
    from pyqgl2.main import compile_function, qgl2_compile_to_hardware
    import numpy as np

    toHW = True
    plotPulses = True
    pyqgl2.test_cl.create_default_channelLibrary(toHW, True)

    #    # 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

    # Pass in a QRegister NOT the real Qubit
    q = QRegister(1)

    # SPAM(q1, np.linspace(0, pi/2, 11))
    # - test_basic_mins uses np.linspace(0,1,11)

    # Here we know the function is in the current file
    # You could use os.path.dirname(os.path.realpath(__file)) to find files relative to this script,
    # Or os.getcwd() to get files relative to where you ran from. Or always use absolute paths.
    resFunction = compile_function(__file__, "SPAM",
                                   (q, np.linspace(0, pi / 2, 11), 10))
    # Run the QGL2. Note that the generated function takes no arguments itself
    sequences = resFunction()
    if toHW:
        print("Compiling sequences to hardware\n")
        fileNames = qgl2_compile_to_hardware(sequences, filename='SPAM/SPAM')
        print(f"Compiled sequences; metafile = {fileNames}")
        if plotPulses:
            from QGL.PulseSequencePlotter import plot_pulse_files
            # FIXME: As called, this returns a graphical object to display
            plot_pulse_files(fileNames)
    else:
        print("\nGenerated sequences:\n")
        from QGL.Scheduler import schedule

        scheduled_seq = schedule(sequences)
        from IPython.lib.pretty import pretty
        print(pretty(scheduled_seq))
Example #3
0
def main():
    from pyqgl2.qreg import QRegister
    import pyqgl2.test_cl
    from pyqgl2.main import compile_function, qgl2_compile_to_hardware
    import numpy as np

    toHW = True
    plotPulses = False  # This tries to produce graphics to display
    pyqgl2.test_cl.create_default_channelLibrary(toHW, True)

    #    # 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

    # Pass in QRegister(s) NOT real Qubits
    q1 = QRegister("q1")

    # Axis Descriptor generator functions here
    # This is ugly; they're method dependent, but I can't do them in the QGL2 itself
    # Additionally, each uses values from the args to the function
    # So here we make those arguments be constants so we can use them twice
    # without rewriting the values
    hahnSpacings = np.linspace(0, 5e-6, 11)
    tCalR = 2  # calRepeats
    cpmgNumPulses = [0, 2, 4, 6]
    cpmgSpacing = 500e-9

    def getHahnAxisDesc(pulseSpacings, calRepeats):
        return [
            delay_descriptor(2 * pulseSpacings),
            cal_descriptor(('qubit', ), calRepeats)
        ]

    def getCPMGAxisDesc(pulseSpacing, numPulses, calRepeats):
        return [
            # NOTE: numPulses is not a numpy array, so cannot multiply by a float
            # But thankfully, np.array(np.array) = np.array so this is always a good move here.
            delay_descriptor(pulseSpacing * np.array(numPulses)),
            cal_descriptor(('qubit', ), calRepeats)
        ]

    # FIXME: See issue #44: Must supply all args to qgl2main for now


#    for func, args, label, axisDesc in [("HahnEcho", (q1, hahnSpacings), "Echo", getHahnAxisDesc(hahnSpacings, tCalR)),
#                              ("CPMG", (q1, cpmgNumPulses, cpmgSpacing), "CPMG", getCPMGAxisDesc(cpmgSpacing, cpmgNumPulses, tCalR)),
#                          ]:
    for func, args, label, axisDesc in [
        ("HahnEcho", (q1, hahnSpacings, 0, tCalR), "Echo",
         getHahnAxisDesc(hahnSpacings, tCalR)),
        ("CPMG", (q1, cpmgNumPulses, cpmgSpacing, tCalR), "CPMG",
         getCPMGAxisDesc(cpmgSpacing, cpmgNumPulses, tCalR)),
    ]:

        print(f"\nRun {func}...")
        # Here we know the function is in the current file
        # You could use os.path.dirname(os.path.realpath(__file)) to find files relative to this script,
        # Or os.getcwd() to get files relative to where you ran from. Or always use absolute paths.
        resFunc = compile_function(__file__, func, args)
        # Run the QGL2. Note that the generated function takes no arguments itself
        seq = resFunc()
        if toHW:
            print(f"Compiling {func} sequences to hardware\n")
            fileNames = qgl2_compile_to_hardware(seq,
                                                 filename=f'{label}/{label}',
                                                 axis_descriptor=axisDesc)
            print(f"Compiled sequences; metafile = {fileNames}")
            if plotPulses:
                from QGL.PulseSequencePlotter import plot_pulse_files
                # FIXME: As called, this returns a graphical object to display
                plot_pulse_files(fileNames)
        else:
            print(f"\nGenerated {func} sequences:\n")
            from QGL.Scheduler import schedule

            scheduled_seq = schedule(seq)
            from IPython.lib.pretty import pretty
            print(pretty(scheduled_seq))
Example #4
0
def main():
    from pyqgl2.qreg import QRegister
    import pyqgl2.test_cl
    from pyqgl2.main import compile_function, qgl2_compile_to_hardware

    toHW = True
    plotPulses = False
    pyqgl2.test_cl.create_default_channelLibrary(toHW, True)

#    # 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

    # Pass in QRegister(s) NOT real Qubits
    q1 = QRegister("q1")
    q2 = QRegister("q2")

    # Axis Descriptor generator functions here
    # This is ugly; they're method dependent, but I can't do them in the QGL2 itself
    # Additionally, each uses values from the args to the function
    # So here we make those arguments be constants so we can use them twice
    # without rewriting the values
    pirlengths = np.linspace(0, 4e-6, 11) # Lengths arg to PiRabi
    eclLengths = np.linspace(0, 2e-6, 11) # Lengths arg to EchoCRLen
    trisefall = 40e-9 # riseFall arg for many
    tamp = 1 # amp arg for many
    t2amp = 0.8 # amp arg for CRTomo
    tphase = 0 # phase arg for many
    tcalr = 2 # calRepeats arg for many
    ecpPhases = np.linspace(0, np.pi/2, 11) # phases arg for EchoCRPhase
    ecaAmps = np.linspace(0, 5e-6, 11) # amps arg for echoCRAmp
    crtLengths = np.linspace(0, 2e-6, 11) # lengths arg for CRtomo_seq
    def getPRAxisDesc(lengths, calRepeats):
        return [
            delay_descriptor(np.concatenate((lengths, lengths))),
            # Hard code there are 2 qubits
            cal_descriptor(('c', 't'), calRepeats)
        ]
    def getECLAxisDesc(lengths, calRepeats):
        return [
            delay_descriptor(np.concatenate((lengths, lengths))),
            # Hard code there are 2 qubits
            cal_descriptor(('controlQ', 'targetQ'), calRepeats)
        ]
    def getECPAxisDesc(phases, calRepeats):
        return [
            {
                'name': 'phase',
                'unit': 'radians',
                'points': list(phases)+list(phases),
                'partition': 1
            },
            cal_descriptor(('controlQ', 'targetQ'), calRepeats)
        ]
    def getECAAxisDesc(amps, calRepeats):
        return [
            {
                'name': 'amplitude',
                'unit': None,
                'points': list(amps)+list(amps),
                'partition': 1
            },
            cal_descriptor(('controlQ', 'targetQ'), calRepeats)
        ]
    def getCRtAxisDesc(lengths):
        return [
            delay_descriptor(np.concatenate((np.repeat(lengths,3), np.repeat(lengths,3)))),
            cal_descriptor(('targetQ',), 2)
        ]

    # FIXME: See issue #44: Must supply all args to qgl2main for now

#    for func, args, label, axisDesc in [("PiRabi", (q1, q2, pirlengths), "PiRabi", getPRAxisDesc(pirlengths, tcalr)),
#                              ("EchoCRLen", (q1, q2, np.linspace(0, 2e-6, 11)), "EchoCR", getECLAxisDesc(eclLengths, tcalr)),
#                              ("EchoCRPhase", (q1, q2, np.linspace(0, np.pi/2, 11)), "EchoCR", getECPAxisDesc(ecpPhases, tcalr)),
#                              ("EchoCRAmp", (q1, q2, np.linspace(0, 5e-6, 11)), "EchoCR", getECAAxisDesc(ecaAmps, tcalr)), # FIXME: Right values?
#                              ("CRtomo_seq", (q1, q2, np.linspace(0, 2e-6, 11), 0), "CR", getCRtAxisDesc(crtLengths)) # FIXME: Right values?
#                          ]:
    for func, args, label, axisDesc in [("PiRabi", (q1, q2, pirlengths, trisefall,tamp,tphase,tcalr), "PiRabi", getPRAxisDesc(pirlengths, tcalr)),
                              ("EchoCRLen", (q1, q2, eclLengths, trisefall, tamp, tphase, tcalr, 0, np.pi/2), "EchoCR", getECLAxisDesc(eclLengths, tcalr)),
                              ("EchoCRPhase", (q1, q2, ecpPhases, trisefall,tamp,100e-9,tcalr,0,np.pi/2), "EchoCR", getECPAxisDesc(ecpPhases, tcalr)),
                              ("EchoCRAmp", (q1, q2, ecaAmps, trisefall,50e-9,tphase,tcalr), "EchoCR", getECAAxisDesc(ecaAmps, tcalr)), # FIXME: Right values?
                              ("CRtomo_seq", (q1, q2, crtLengths, 0, t2amp,20e-9), "CR", getCRtAxisDesc(crtLengths)) # FIXME: Right values?
                          ]:

        print(f"\nRun {func}...")
        # Here we know the function is in the current file
        # You could use os.path.dirname(os.path.realpath(__file)) to find files relative to this script,
        # Or os.getcwd() to get files relative to where you ran from. Or always use absolute paths.
        resFunc = compile_function(__file__, func, args)
        # Run the QGL2. Note that the generated function takes no arguments itself
        seq = resFunc()
        if toHW:
            print(f"Compiling {func} sequences to hardware\n")
            fileNames = qgl2_compile_to_hardware(seq, filename=f'{label}/{label}', axis_descriptor=axisDesc)
            print(f"Compiled sequences; metafile = {fileNames}")
            if plotPulses:
                from QGL.PulseSequencePlotter import plot_pulse_files
                # FIXME: As called, this returns a graphical object to display
                plot_pulse_files(fileNames)
        else:
            print(f"\nGenerated {func} sequences:\n")
            from QGL.Scheduler import schedule

            scheduled_seq = schedule(seq)
            from IPython.lib.pretty import pretty
            print(pretty(scheduled_seq))
Example #5
0
def main():
    from pyqgl2.qreg import QRegister
    import pyqgl2.test_cl
    from pyqgl2.main import compile_function, qgl2_compile_to_hardware

    toHW = True
    plotPulses = False # Don't try creating graphics objects
    suffix = False # change generated filename to include qbit name
    pyqgl2.test_cl.create_default_channelLibrary(toHW, True)

#    # 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

    # Pass in QRegister(s) NOT real Qubits
    qbitName = "q1"
    q1 = QRegister(qbitName)

    # FIXME: See issue #44: Must supply all args to qgl2main for now

    # InversionRecovery(q1,  np.linspace(0, 5e-6, 11))
    # Ramsey(q1, np.linspace(0, 5e-6, 11))

    irDelays = np.linspace(0, 5e-6, 11)
    rSpacings = np.linspace(0, 5e-6, 11)
    tCalR = 2

    def irAD(delays, calRepeats):
        return [
            delay_descriptor(delays),
            cal_descriptor(('qubit',), calRepeats)
            ]

    def rAD(pulseSpacings, calRepeats):
        return [
            delay_descriptor(pulseSpacings),
            cal_descriptor(('qubit',), calRepeats)
        ]

#    for func, args, label, axisDesc in [("InversionRecovery", (q1, irDelays), "T1", irAD(irDelays, tCalR)),
#                              ("Ramsey", (q1, rSpacings), "Ramsey", rAD(rSpacings, tCalR))
#                          ]:
    for func, args, label, axisDesc in [("InversionRecovery", (q1, irDelays, tCalR), "T1", irAD(irDelays, tCalR)),
                              ("Ramsey", (q1, rSpacings, 0, tCalR), "Ramsey", rAD(rSpacings, tCalR))
                          ]:

        print(f"\nRun {func}...")
        # Here we know the function is in the current file
        # You could use os.path.dirname(os.path.realpath(__file)) to find files relative to this script,
        # Or os.getcwd() to get files relative to where you ran from. Or always use absolute paths.
        resFunc = compile_function(__file__, func, args)
        # Run the QGL2. Note that the generated function takes no arguments itself
        seq = resFunc()
        if toHW:
            print(f"Compiling {func} sequences to hardware\n")

            # Generate proper filenames; for these, it isn't just the label Ramsey
            # T1T2 QGL functions take a suffix boolean default false. If true, then append to label "_qubit.label"; ie "_q1"
            if suffix:
                label = label + f"_{qbitName}"

            fileNames = qgl2_compile_to_hardware(seq, filename=f'{label}/{label}', axis_descriptor=axisDesc)
            print(f"Compiled sequences; metafile = {fileNames}")
            if plotPulses:
                from QGL.PulseSequencePlotter import plot_pulse_files
                # FIXME: As called, this returns a graphical object to display
                plot_pulse_files(fileNames)
        else:
            print(f"\nGenerated {func} sequences:\n")
            from QGL.Scheduler import schedule

            scheduled_seq = schedule(seq)
            from IPython.lib.pretty import pretty
            print(pretty(scheduled_seq))
Example #6
0
def main():
    from pyqgl2.qreg import QRegister
    import pyqgl2.test_cl
    from pyqgl2.main import compile_function, qgl2_compile_to_hardware
    import numpy as np
    import QGL.PulseShapes

    toHW = True
    plotPulses = False
    pyqgl2.test_cl.create_default_channelLibrary(toHW, True)

    #    # 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

    # Pass in QRegister(s) NOT real Qubits
    q1 = QRegister("q1")
    q2 = QRegister("q2")
    qr = QRegister(q1, q2)

    rAmpAmps = np.linspace(0, 1, 1)
    rWidthWidths = np.linspace(0, 5e-6, 11)
    ranqAmps = np.linspace(0, 5e-6, 11)
    tCalR = 2
    rAmpPiAmps = np.linspace(0, 1, 11)

    def getRAmpAD(amps):
        return [{
            'name': 'amplitude',
            'unit': None,
            'points': list(amps),
            'partition': 1
        }]

    def getRWidthAD(widths):
        return [delay_descriptor(widths)]

    def getRAmpNQAD(qubits, amps, calRepeats):
        return [{
            'name': 'amplitude',
            'unit': None,
            'points': list(amps),
            'partition': 1
        },
                cal_descriptor(qubits, calRepeats)]

    def getRAmpPiAD(amps):
        return [{
            'name': 'amplitude',
            'unit': None,
            'points': list(amps),
            'partition': 1
        }]

    # FIXME: See issue #44: Must supply all args to qgl2main for now


#    for func, args, label, axisDec in [("RabiAmp", (q1, rAmpAmps), "Rabi", getRAmpAD(rAmpAmps)),
#                              ("RabiWidth", (q1, rWidthWidths), "Rabi", getRWidthAD(rWidthWidths)),
#                              ("RabiAmpPi", (q1, q2, rAmpPiAmps), "Rabi", getRAmpPiAD(rAmpPiAmps)),
#                              ("SingleShow", (q1,), "SingleShot", None),
#                              ("PulsedSpec", (q1,), "Spec", None),
#                              ("RabiAmp_NQubits", (qr,ranqAmps), "Rabi", getRAmpNQAD(qr, ranqAmps, tCalR)),
#                              ("Swap", (q1, np.linspace(0, 5e-6, 11), "Swap", None),
#                          ]:

    for func, args, label, axisDesc in [
        ("RabiAmp", (q1, rAmpAmps, 0), "Rabi", getRAmpAD(rAmpAmps)),
        ("RabiWidth", (q1, rWidthWidths, 1, 0, QGL.PulseShapes.tanh), "Rabi",
         getRWidthAD(rWidthWidths)),
        ("RabiAmpPi", (q1, q2, rAmpPiAmps, 0), "Rabi",
         getRAmpPiAD(rAmpPiAmps)), ("SingleShot", (q1, ), "SingleShot", None),
        ("PulsedSpec", (q1, True), "Spec", None),
        ("RabiAmp_NQubits", (qr, ranqAmps, 0, qr, False, tCalR), "Rabi",
         getRAmpNQAD(qr, ranqAmps, tCalR)),
        ("Swap", (q1, np.linspace(0, 5e-6, 11), q2), "Swap", None)
    ]:

        print(f"\nRun {func}...")
        # Here we know the function is in the current file
        # You could use os.path.dirname(os.path.realpath(__file)) to find files relative to this script,
        # Or os.getcwd() to get files relative to where you ran from. Or always use absolute paths.
        resFunc = compile_function(__file__, func, args)
        # Run the QGL2. Note that the generated function takes no arguments itself
        seq = resFunc()
        if toHW:
            print(f"Compiling {func} sequences to hardware\n")
            # To get verbose logging including showing the compiled sequences:
            # QGL.Compiler.set_log_level()
            fileNames = qgl2_compile_to_hardware(seq,
                                                 filename=f'{label}/{label}',
                                                 axis_descriptor=axisDesc)
            print(f"Compiled sequences; metafile = {fileNames}")
            if plotPulses:
                from QGL.PulseSequencePlotter import plot_pulse_files
                # FIXME: As called, this returns a graphical object to display
                plot_pulse_files(fileNames)
        else:
            print(f"\nGenerated {func} sequences:\n")
            from QGL.Scheduler import schedule

            scheduled_seq = schedule(seq)
            from IPython.lib.pretty import pretty
            print(pretty(scheduled_seq))
Example #7
0
def main():
    from pyqgl2.qreg import QRegister
    import pyqgl2.test_cl
    from pyqgl2.main import compile_function, qgl2_compile_to_hardware
    import numpy as np
    import random

    toHW = True
    plotPulses = False
    pyqgl2.test_cl.create_default_channelLibrary(toHW, True)

#    # 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

    # Pass in QRegister(s) NOT real Qubits
    q1 = QRegister("q1")
    q2 = QRegister("q2")
    qr = QRegister(q1, q2)

    # FIXME: See issue #44: Must supply all args to qgl2main for now

    # Functions here have some extra code to run before running the compiled QGL2,
    # so define functions for those; random number seeding

    def beforeSingleRB():
        np.random.seed(20152606) # set seed for create_RB_seqs()
        random.seed(20152606) # set seed for random.choice()
    # SingleQubitRB(q1, create_RB_seqs(1, 2**np.arange(1,7)))

    # The original unit test had this comment:
    """  Fails on APS1, APS2, and Tek7000 due to:
    File "QGL/PatternUtils.py", line 129, in add_gate_pulses
    if has_gate(chan) and not pulse.isZero and not (chan.gate_chan
    AttributeError: 'CompositePulse' object has no attribute 'isZero'
    """
    def beforeTwoRB():
        np.random.seed(20152606) # set seed for create_RB_seqs()
    # TwoQubitRB(q2, q1, create_RB_seqs(2, [2, 4, 8, 16, 32], repeats=16))

    def beforeSimRBAC():
        np.random.seed(20151709) # set seed for create_RB_seqs
        #seqs1 = create_RB_seqs(1, 2**np.arange(1,7))
        #seqs2 = create_RB_seqs(1, 2**np.arange(1,7))
    # SimultaneousRB_AC((q1, q2), (seqs1, seqs2))

    def beforeSingleRBAC():
        np.random.seed(20152606) # set seed for create_RB_seqs
    # SingleQubitRB_AC(q1,create_RB_seqs(1, 2**np.arange(1,7)))

# FIXME: Add test of SingleQubitRB_DiAC

    sqCSeqs = create_RB_seqs(1, 2**np.arange(1,7))
    tqCSeqs = create_RB_seqs(2, [2, 4, 8, 16, 32], repeats=16)
    simCSeqs = (sqCSeqs, sqCSeqs)
    tAddCals = True
    def getSingleQubitRBAD(seqs, add_cals):
        ad = [{
            'name': 'length',
            'unit': None,
            'points': list(map(len, seqs)),
            'partition': 1
        }]
        if add_cals:
            ad.append(cal_descriptor(('qubit',), 2))
        return ad

    def getTwoQubitRBAD(seqs, add_cals):
        axis_descriptor = [{
            'name': 'length',
            'unit': None,
            'points': list(map(len, seqs)),
            'partition': 1
        }]
        if add_cals:
            axis_descriptor.append(cal_descriptor(('q1', 'q2'), 2))
        return axis_descriptor

    def getSingleQubitRBAC_AD(seqs, add_cals):
        axis_descriptor = [{
            'name': 'length',
            'unit': None,
            'points': list(map(len, seqs)),
            'partition': 1
        }]
        if add_cals:
            axis_descriptor.append(cal_descriptor(('qubit',), 2))
        return axis_descriptor

    def getSimRBACAD(seqs, add_cals, qubits):
        axis_descriptor = [{
            'name': 'length',
            'unit': None,
            'points': list(map(len, seqs)),
            'partition': 1
        }]
        if add_cals:
            axis_descriptor.append(cal_descriptor((qubits), 2))
        return axis_descriptor

# FIXME: SingleQubitIRB_AC filenames are more complex
# FIXME: SingleQubitRBT has complex suffix it should pass to compile_to_hardware

#    for func, args, label, beforeFunc, axisDesc, cseqs in [("SingleQubitRB", (q1, sqCSeqs), "RB", beforeSingleRB, getSingleQubitRBAD(sqCSeqs, tAddCals), sqCSeqs),
#                              ("TwoQubitRB", (q1, q2, tqCSeqs), "RB", beforeTwoRB, getTwoQubitRBAD(tqCSeqs, tAddCals), tqCSeqs),
#                              ("SingleQubitRB_AC", (q1,sqCSeqs), "RB", beforeSingleRBAC, getSingleQubitRBAC_AD(sqCSeqs, tAddCals), sqCSeqs),
#                              ("SimultaneousRB_AC", (qr, simCSeqs), "RB", beforeSimRBAC, getSimRBACAD(simCSeqs, tAddCals, qr), simCSeqs),
#                              ("SingleQubitIRB_AC", (q1,''), "RB", None, None, None),
# Comment says this next one relies on a specific file, so don't bother running
#                              ("SingleQubitRBT", (q1,'', fixmePulse), "RBT", None, None, None),
#                          ]:

    for func, args, label, beforeFunc, axisDesc, cseqs in [("SingleQubitRB", (q1, sqCSeqs, False, tAddCals), "RB", beforeSingleRB, getSingleQubitRBAD(sqCSeqs, tAddCals), sqCSeqs),
                              ("TwoQubitRB", (q1, q2, tqCSeqs, tAddCals), "RB", beforeTwoRB, getTwoQubitRBAD(tqCSeqs, tAddCals), tqCSeqs),
                              ("SingleQubitRB_AC", (q1,sqCSeqs, False, tAddCals), "RB", beforeSingleRBAC, getSingleQubitRBAC_AD(sqCSeqs, tAddCals), sqCSeqs),
# Warning: This next one is slow....
                              ("SimultaneousRB_AC", (qr, simCSeqs, tAddCals), "RB", beforeSimRBAC, getSimRBACAD(simCSeqs, tAddCals, qr), simCSeqs),
# This next one relies on a file of sequence strings, which I don't have
#                                          ("SingleQubitIRB_AC", (q1,None), "RB", None, None, None),
# Comment says this next one relies on a specific file, so don't bother running
#                              # ("SingleQubitRBT", (q1,'', fixmePulse, True), "RBT", None, None, None),
                           ]:

        print(f"\nRun {func}...")

        # This is typically setting random seed
        if beforeFunc is not None:
            beforeFunc()

        # Here we know the function is in the current file
        # You could use os.path.dirname(os.path.realpath(__file)) to find files relative to this script,
        # Or os.getcwd() to get files relative to where you ran from. Or always use absolute paths.
        resFunc = compile_function(__file__, func, args)
        # Run the QGL2. Note that the generated function takes no arguments itself
        seq = resFunc()
        if toHW:
            import QGL
            print(f"Compiling {func} sequences to hardware\n")
            # QGL.Compiler.set_log_level()
            em = None
            if cseqs:
                em = {'sequences':cseqs}
            fileNames = qgl2_compile_to_hardware(seq, filename=f'{label}/{label}', axis_descriptor=axisDesc, extra_meta = em)
            print(f"Compiled sequences; metafile = {fileNames}")
            if plotPulses:
                from QGL.PulseSequencePlotter import plot_pulse_files
                # FIXME: As called, this returns a graphical object to display
                plot_pulse_files(fileNames)
        else:
            print(f"\nGenerated {func} sequences:\n")
            from QGL.Scheduler import schedule

            scheduled_seq = schedule(seq)
            from IPython.lib.pretty import pretty
            print(pretty(scheduled_seq))