Example #1
0
def AllXY(q: qreg):
    # QGL2 version of QGL2 Basic Sequence
    # Must be compiled & given a QRegister
    # 6/12/19: Verified this looks same as QGL1 version
    
    twentyOnePulsePairs = [
            # no pulses to measure |0>
            (Id, Id),
            # pulse around same axis
            (X, X), (Y, Y),
            # pulse around orthogonal axes
            (X, Y), (Y, X),
            # These produce a |+> or |i> state
            (X90, Id), (Y90, Id),
            # pulse pairs around orthogonal axes with 1e error sensititivity
            (X90, Y90), (Y90, X90),
            # pulse pairs with 2e sensitivity
            (X90, Y), (Y90, X), (X, Y90), (Y, X90),
            # pulse pairs around common axis with 3e error sensitivity
            (X90, X), (X, X90), (Y90, Y), (Y, Y90),
            # These create the |1> state
            (X, Id), (Y, Id),
            (X90, X90), (Y90, Y90) ]

    # For each of the 21 pulse pairs
    for (f1, f2) in twentyOnePulsePairs:
        # Repeat it twice and do a MEAS at the end of each
        for i in range(2):
            init(q)
            f1(q)
            f2(q)
            MEAS(q)
Example #2
0
def InversionRecovery(qubit: qreg, delays, calRepeats=2):
    """
    Inversion recovery experiment to measure qubit T1

    Parameters
    ----------
    qubit : logical channel to implement sequence (LogicalChannel) 
    delays : delays after inversion before measurement (iterable; seconds)
    calRepeats : how many repetitions of calibration pulses (int)
    """

    # Original: 
    # # Create the basic sequences
    # seqs = [[X(qubit), Id(qubit, d), MEAS(qubit)] for d in delays]

    # # Tack on the calibration scalings
    # seqs += create_cal_seqs((qubit,), calRepeats)

    # fileNames = compile_to_hardware(seqs, 'T1'+('_'+qubit.label)*suffix+'/T1'+('_'+qubit.label)*suffix)
    # print(fileNames)

    # if showPlot:
    #     plot_pulse_files(fileNames)
    for d in delays:
        init(qubit)
        X(qubit)
        Id(qubit, length=d)
        MEAS(qubit)

    # Tack on calibration
    create_cal_seqs(qubit, calRepeats)
Example #3
0
def RabiAmp_NQubits(qubits: qreg,
                    amps,
                    phase=0,
                    measChans: qreg = None,
                    docals=False,
                    calRepeats=2):
    """
    Variable amplitude Rabi nutation experiment for an arbitrary number of qubits simultaneously

    Parameters
    ----------
    qubits : tuple of logical channels to implement sequence (LogicalChannel)
    amps : pulse amplitudes to sweep over for all qubits (iterable)
    phase : phase of the pulses (radians)
    measChans : tuple of qubits to be measured (use qubits if not specified) (LogicalChannel)
    docals, calRepeats: enable calibration sequences, repeated calRepeats times
    """
    if measChans is None:
        measChans = qubits
    allChans = QRegister(qubits, measChans)
    for amp in amps:
        init(allChans)
        Utheta(qubits, amp=amp, phase=phase)
        measConcurrently(measChans)

    if docals:
        create_cal_seqs(qubits, calRepeats, measChans)
Example #4
0
def doSingleShot(q: qreg):
    init(q)
    Id(q)
    MEAS(q)
    init(q)
    X(q)
    MEAS(q)
Example #5
0
def doPulsedSpec(q: qreg, specOn):
    init(q)
    if specOn:
        X(q)
    else:
        Id(q)
    MEAS(q)
Example #6
0
def doRabiWidth(q: qreg, widths):
    # FIXME: Note the local re-definition of tanh
    shapeFun = qgl2.basic_sequences.pulses.local_tanh
    for l in widths:
        init(q)
        Utheta(q, length=l, amp=1, phase=0, shapeFun=shapeFun)
        MEAS(q)
Example #7
0
def doRabiAmpPi(qr: qreg, amps):
    for l in amps:
        init(qr)
        X(qr[1])
        Utheta(qr[0], amp=l, phase=0)
        X(qr[1])
        MEAS(qr[1])
Example #8
0
def doPulsedSpec(qubit: qreg, specOn):
    init(qubit)
    if specOn:
        X(qubit)
    else:
        Id(qubit)
    MEAS(qubit)
Example #9
0
def CRtomo_seq(controlQ: qreg,
               targetQ: qreg,
               lengths,
               ph,
               amp=0.8,
               riseFall=20e-9):
    """
    Variable length CX experiment, for Hamiltonian tomography.

    Parameters
    ----------
    controlQ : logical channel for the control qubit (LogicalChannel)
    targetQ: logical channel for the target qubit (LogicalChannel)
    lengths : pulse lengths of the CR pulse to sweep over (iterable)
    riseFall : rise/fall time of the CR pulse (s)
    ph : phase of the CR pulse (rad)
    """
    # Rather than do EdgeFactory and regular flat_top_gaussian,
    # define a new QGL2 stub where the QGL1 implementation does that,
    # so QGL2 can avoid dealing with the edge
    # CRchan = EdgeFactory(controlQ, targetQ)

    # flat_top_gaussian is an addition of 3 UTheta pulses
    cNt = QRegister(controlQ, targetQ)
    tomo_pulses = [Y90m, X90, Id]

    # Sequence 1
    for l, tomo_pulse in product(lengths, tomo_pulses):
        init(cNt)
        Id(controlQ)
        flat_top_gaussian_edge(controlQ,
                               targetQ,
                               riseFall=riseFall,
                               length=l,
                               amp=amp,
                               phase=ph,
                               label="CR")
        Barrier(cNt)
        Id(controlQ)
        tomo_pulse(targetQ)
        MEAS(targetQ)

    # Sequence 2
    for l, tomo_pulse in product(lengths, tomo_pulses):
        init(cNt)
        X(controlQ)
        flat_top_gaussian_edge(controlQ,
                               targetQ,
                               riseFall=riseFall,
                               length=l,
                               amp=amp,
                               phase=ph,
                               label="CR")
        Barrier(cNt)
        X(controlQ)
        tomo_pulse(targetQ)
        MEAS(targetQ)

    create_cal_seqs(targetQ, 2)
Example #10
0
def settle(q: qreg) -> pulse:

    init(q)
    while True:
        MEAS(q)
        if vmeas:
            break
        Id(q)
Example #11
0
def func_a(a: qreg, b: qreg, c: qreg):

    with concur:
        for q in [a, b, c]:
            init(q)
            for x in [1, 2]:
                for f in [func_c, func_d]:
                    f(a, x)
Example #12
0
def doInversionRecovery(q:qreg, delays, calRepeats):
    for d in delays:
        init(q)
        X(q)
        Id(q, length=d)
        MEAS(q)

    # Tack on calibration
    create_cal_seqs(q, calRepeats)
Example #13
0
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)
Example #14
0
def PiRabi(controlQ: qreg,
           targetQ: qreg,
           lengths,
           riseFall=40e-9,
           amp=1,
           phase=0,
           calRepeats=2):
    """
    Variable length CX experiment.

    Parameters
    ----------
    controlQ : logical channel for the control qubit (LogicalChannel)
    targetQ: logical channel for the target qubit (LogicalChannel)
    lengths : pulse lengths of the CR pulse to sweep over (iterable)
    riseFall : rise/fall time of the CR pulse (s)
    amp : amplitude of the CR pulse
    phase : phase of the CR pulse (rad)
    calRepeats : number repetitions of calibration sequences (int)
    """

    # Rather than do EdgeFactory and regular flat_top_gaussian,
    # define a new QGL2 stub where the QGL1 implementation does that,
    # so QGL2 can avoid dealing with the edge
    # CRchan = EdgeFactory(controlQ, targetQ)

    # flat_top_gaussian is an addition of 3 UTheta pulses

    cNt = QRegister(controlQ, targetQ)

    # Sequence 1: Id(control), gaussian(l), measure both
    for l in lengths:
        init(cNt)
        Id(controlQ)
        flat_top_gaussian_edge(controlQ,
                               targetQ,
                               riseFall,
                               length=l,
                               amp=amp,
                               phase=phase)
        measConcurrently(cNt)

    # Sequence 2: X(control), gaussian(l), X(control), measure both
    for l in lengths:
        init(cNt)
        X(controlQ)
        flat_top_gaussian_edge(controlQ,
                               targetQ,
                               riseFall,
                               length=l,
                               amp=amp,
                               phase=phase)
        X(controlQ)
        measConcurrently(cNt)

    # Then do calRepeats calibration sequences
    create_cal_seqs(cNt, calRepeats)
Example #15
0
def doSwap(qr: qreg, delays):
    for d in delays:
        init(qr)
        X(qr)
        Id(qr[1], length=d)
        Barrier(qr)
        MEAS(qr)

    create_cal_seqs(qr, 2)
Example #16
0
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)
Example #17
0
def FlipFlop(qubit: qreg, dragParamSweep, maxNumFFs=10):
    """
    Flip-flop sequence (X90-X90m)**n to determine off-resonance or DRAG parameter optimization.

    Parameters
    ----------
    qubit : logical channel to implement sequence (LogicalChannel) 
    dragParamSweep : drag parameter values to sweep over (iterable)
    maxNumFFs : maximum number of flip-flop pairs to do
    """

    # Original:
    # def flipflop_seqs(dragScaling):
    #     """ Helper function to create a list of sequences with a specified drag parameter. """
    #     qubit.pulse_params['dragScaling'] = dragScaling
    #     return [[X90(qubit)] + [X90(qubit), X90m(qubit)]*rep + [Y90(qubit)] for rep in range(maxNumFFs)]

    # # Insert an identity at the start of every set to mark them off
    # originalScaling = qubit.pulse_params['dragScaling']
    # seqs = list(chain.from_iterable([[[Id(qubit)]] + flipflop_seqs(dragParam) for dragParam in dragParamSweep]))
    # qubit.pulse_params['dragScaling'] = originalScaling

    # # Add a final pi for reference
    # seqs.append([X(qubit)])

    # # Add the measurment block to every sequence
    # measBlock = MEAS(qubit)
    # for seq in seqs:
    #     seq.append(measBlock)

    # fileNames = compile_to_hardware(seqs, 'FlipFlop/FlipFlop')
    # print(fileNames)

    # if showPlot:
    #     plot_pulse_files(fileNames)

    # Insert an identity at the start of every set to mark them off
    # Want a result something like:
    # [['Id'], ['X9', 'Y9'], ['X9', 'X9', 'X9m', 'Y9'], ['X9', 'X9', 'X9m', 'X9', 'X9m', 'Y9'], ['Id'], ['X9', 'Y9'], ['X9', 'X9', 'X9m', 'Y9'], ['X9', 'X9', 'X9m', 'X9', 'X9m', 'Y9'], ['Id'], ['X9', 'Y9'], ['X9', 'X9', 'X9m', 'Y9'], ['X9', 'X9', 'X9m', 'X9', 'X9m', 'Y9']]

    # QGL2 qubits are read only, so can't modify qubit.pulse_params[dragScaling],
    # Instead of modifying qubit, we'll just supply the drag param explicitly to each pulse
    # So no need to save this off and reset afterwards
    # originalScaling = qubit.pulse_params['dragScaling']
    for dragParam in dragParamSweep:
        init(qubit)
        Id(qubit)
        MEAS(qubit)

        flipflop_seqs(dragParam, maxNumFFs, qubit)
    # qubit.pulse_params['dragScaling'] = originalScaling

    # Add a final pi for reference
    init(qubit)
    X(qubit)
    MEAS(qubit)
Example #18
0
def PulsedSpec(qubit: qreg, specOn=True):
    """
    Measurement preceded by a X pulse if specOn
    """
    init(qubit)
    if specOn:
        X(qubit)
    else:
        Id(qubit)
    MEAS(qubit)
Example #19
0
def SingleShot(qubit: qreg):
    """
    2-segment sequence with qubit prepared in |0> and |1>, useful for single-shot fidelity measurements and kernel calibration
    """
    init(qubit)
    Id(qubit)
    MEAS(qubit)
    init(qubit)
    X(qubit)
    MEAS(qubit)
Example #20
0
def doRabiAmp_NQubits(qr: qreg, amps, docals, calRepeats):
    p = 0

    for a in amps:
        init(qr)
        Utheta(qr, amp=a, phase=p)
        MEAS(qr)

    if docals:
        create_cal_seqs(qr, calRepeats)
Example #21
0
def doAllXY(q:qreg):
    # For each of the 21 pulse pairs
    for func in [IdId, XX, YY, XY, YX, X90Id, Y90Id,
                 X90Y90, Y90X90, X90Y, Y90X, XY90, YX90, X90X,
                 XX90, Y90Y, YY90, XId, YId, X90X90, Y90Y90]:
        # Repeat it twice and do a MEAS at the end of each
        for i in range(2):
            init(q)
            func(q)
            MEAS(q)
Example #22
0
def edgeTest3():
    q1 = QRegister('q1')
    q2 = QRegister('q2')
    for q in [q1, q2]:
        init(q)
    echoCR(q1, q2)
    X(q2)
    Y(q2)
    Id(q2)
    X(q2)
Example #23
0
def SimultaneousRB_AC(qubits: qreg, seqs, add_cals=True):
    """
    Simultaneous randomized benchmarking on multiple qubits using atomic Clifford pulses. 

    Parameters
    ----------
    qubits : QRegister of logical channels to implement seqs on
    seqs : a tuple of sequences created for each qubit in qubits

    Example
    -------
    >>> q1 = QubitFactory('q1')
    >>> q2 = QubitFactory('q2')
    >>> seqs1 = create_RB_seqs(1, [2, 4, 8, 16])
    >>> seqs2 = create_RB_seqs(1, [2, 4, 8, 16])
    >>> qr = QRegister(q1, q2)
    >>> SimultaneousRB_AC(qr, (seqs1, seqs2))
    """
    # Original:
    # seqsBis = []
    # for seq in zip(*seqs):
    #     seqsBis.append([reduce(operator.__mul__, [AC(q,c) for q,c in zip(qubits,
    #                                                                      pulseNums)]) for pulseNums in zip(*seq)])

    # # Add the measurement to all sequences
    # for seq in seqsBis:
    #     seq.append(reduce(operator.mul, [MEAS(q) for q in qubits]))

#    axis_descriptor = [{
#        'name': 'length',
#        'unit': None,
#        'points': list(map(len, seqs)),
#        'partition': 1
#    }]

    # # Tack on the calibration sequences
    # if add_cals:
    #   seqsBis += create_cal_seqs((qubits), 2)
    #   axis_descriptor.append(cal_descriptor((qubits), 2))

    # metafile = compile_to_hardware(seqsBis, 'RB/RB', axis_descriptor = axis_descriptor, extra_meta = {'sequences':seqs})

    for seq in zip(*seqs):
        # Start sequence
        init(qubits)
        for pulseNums in zip(*seq):
            Barrier(qubits)
            for q, c in zip(qubits, pulseNums):
                AC(q, c)
        # Measure at end of each sequence
        measConcurrently(qubits)

    if add_cals:
        # Tack on calibration
        create_cal_seqs(qubits, 2)
Example #24
0
def SingleQubitRB_AC(qubit: qreg, seqs, purity=False, add_cals=True):
    """
    Single qubit randomized benchmarking using atomic Clifford pulses. 

    Parameters
    ----------
    qubit : logical channel to implement sequence (LogicalChannel)
    seqFile : file containing sequence strings
    """

    # Original:
    # seqsBis = []
    # op = [Id(qubit, length=0), Y90m(qubit), X90(qubit)]
    # for ct in range(3 if purity 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)

#    axis_descriptor = [{
#        'name': 'length',
#        'unit': None,
#        'points': list(map(len, seqs)),
#        'partition': 1
#    }]
#    metafile = compile_to_hardware(seqsBis, 'RB/RB', axis_descriptor = axis_descriptor, extra_meta = {'sequences':seqs})

    # AC() gives a single pulse on qubit

    op = [Id, Y90m, X90]
    for ct in range(3 if purity else 1):
        for seq in seqs:
            init(qubit)
            for c in seq:
                AC(qubit, c)
            # append tomography pulse to measure purity
            # See issue #: 53
            func = op[ct]
            if ct == 0:
                func(qubit, length=0)
            else:
                func(qubit)
            # append measurement
            MEAS(qubit)

    if add_cals:
        # Tack on calibration sequences
        create_cal_seqs(qubit, 2)
Example #25
0
def SimultaneousRB_AC(qubits: qreg, seqs, showPlot=False):
    """
    Simultaneous randomized benchmarking on multiple qubits using atomic Clifford pulses. 

    Parameters
    ----------
    qubits : iterable of logical channels to implement seqs on (list or tuple) 
    seqs : a tuple of sequences created for each qubit in qubits
    showPlot : whether to plot (boolean)

    Example
    -------
    >>> q1 = QubitFactory('q1')
    >>> q2 = QubitFactory('q2')
    >>> seqs1 = create_RB_seqs(1, [2, 4, 8, 16])
    >>> seqs2 = create_RB_seqs(1, [2, 4, 8, 16])
    >>> SimultaneousRB_AC((q1, q2), (seqs1, seqs2), showPlot=False)
    """
    # Original:
    # seqsBis = []
    # for seq in zip(*seqs):
    #     seqsBis.append([reduce(operator.__mul__, [AC(q,c) for q,c in zip(qubits,
    #                                                                      pulseNums)]) for pulseNums in zip(*seq)])

    # # Add the measurement to all sequences
    # for seq in seqsBis:
    #     seq.append(reduce(operator.mul, [MEAS(q) for q in qubits]))

    # # Tack on the calibration sequences
    # seqsBis += create_cal_seqs((qubits), 2)

    # fileNames = compile_to_hardware(seqsBis, 'RB/RB')
    # print(fileNames)

    # if showPlot:
    #     plot_pulse_files(fileNames)

    for seq in zip(*seqs):
        # Start sequence
        with concur:
            for q in qubits:
                init(q)
        for pulseNums in zip(*seq):
            with concur:
                for q, c in zip(qubits, pulseNums):
                    AC(q, c)
        # Measure at end of each sequence
        with concur:
            for q in qubits:
                MEAS(q)

    # FIXME: Not working in QGL2 yet
    # Tack on calibration
    create_cal_seqs((qubits), 2)
Example #26
0
def spam_seqs(angle, q: qreg, maxSpamBlocks=10):
    for rep in range(maxSpamBlocks):
        init(q)
        Y90(q)
        for _ in range(rep):
            X(q)
            U(q, phase=pi / 2 + angle)
            X(q)
            U(q, phase=pi / 2 + angle)
        X90(q)
        MEAS(q)
Example #27
0
def SingleShotNoArg():
    """
    Sample 0-argument 2-segment sequence with qubit prepared in |0> and |1>, useful for single-shot fidelity measurements and kernel calibration
    """
    qubit = QRegister(1)
    init(qubit)
    Id(qubit)
    MEAS(qubit)
    init(qubit)
    X(qubit)
    MEAS(qubit)
Example #28
0
def doRabiAmp_NQubits(qubits: qreg, amps, phase,
                    measChans: qreg, docals, calRepeats):
    for amp in amps:
        with concur:
            for q in qubits:
                init(q)
                Utheta(q, amp=amp, phase=phase)
        with concur:
            for m in measChans:
                MEAS(m)

    if docals:
        create_cal_seqs(qubits, calRepeats, measChans)
Example #29
0
def doAllXY2(q:qreg):
    # one layer of indirection on "func" in the loop below
    twentyOnepulseFuncs = [IdId, XX, YY, XY, YX, X90Id, Y90Id,
                           X90Y90, Y90X90, X90Y, Y90X, XY90, YX90, X90X,
                           XX90, Y90Y, YY90, XId, YId, X90X90, Y90Y90]

    # For each of the 21 pulse pairs
    for func in twentyOnepulseFuncs:
        # Repeat it twice and do a MEAS at the end of each
        for i in range(2):
            init(q)
            func(q)
            MEAS(q)
Example #30
0
def flipflop_seqs(dragScaling, maxNumFFs, qubit: qreg):
    """ Helper function to create a list of sequences with a specified drag parameter. """
    # FIXME: cause qubit is a placeholder, can't access pulse_params
    # qubit.pulse_params['dragScaling'] = dragScaling
    for rep in range(maxNumFFs):
        init(qubit)
        X90(qubit, dragScaling=dragScaling)
        # FIXME: Original used [X90] + [X90, X90m]... is this right?
        for _ in range(rep):
            X90(qubit, dragScaling=dragScaling)
            X90m(qubi, dragScaling=dragScaling)
        Y90(qubit, dragScaling=dragScaling)
        MEAS(qubit)  # FIXME: Need original dragScaling?