def four_qubit_off_on(q0_pulse_pars,
                      q1_pulse_pars,
                      q2_pulse_pars,
                      q3_pulse_pars,
                      RO_pars,
                      return_seq=False, verbose=False):

    seq_name = '4_qubit_OffOn_sequence'
    seq = sequence.Sequence(seq_name)
    station.pulsar.update_channel_settings()
    el_list = []
    # Create a dict with the parameters for all the pulses
    q0_pulses = add_suffix_to_dict_keys(
        get_pulse_dict_from_pars(q0_pulse_pars), ' q0')
    q1_pulses = add_suffix_to_dict_keys(
        get_pulse_dict_from_pars(q1_pulse_pars), ' q1')
    q2_pulses = add_suffix_to_dict_keys(
        get_pulse_dict_from_pars(q2_pulse_pars), ' q2')
    q3_pulses = add_suffix_to_dict_keys(
        get_pulse_dict_from_pars(q3_pulse_pars), ' q3')
    RO_dict = {'RO': RO_pars}

    pulse_dict = {}
    pulse_dict.update(q0_pulses)
    pulse_dict.update(q1_pulses)
    pulse_dict.update(q2_pulses)
    pulse_dict.update(q3_pulses)
    pulse_dict.update(RO_dict)

    # N.B. Identities not needed in all cases
    pulse_combinations = [['I q0', 'I q1', 'I q2', 'I q3', 'RO'],
                          ['X180 q0', 'I q1', 'I q2', 'I q3', 'RO'],
                          ['I q0', 'X180 q1', 'I q2', 'I q3', 'RO'],
                          ['X180 q0', 'X180 q1', 'I q2', 'I q3', 'RO'],
                          ['I q0', 'I q1', 'X180 q2', 'I q3', 'RO'],
                          ['X180 q0', 'I q1', 'X180 q2', 'I q3', 'RO'],
                          ['I q0', 'X180 q1', 'X180 q2',  'I q3', 'RO'],
                          ['X180 q0', 'X180 q1', 'X180 q2',  'I q3', 'RO'],
                          ['I q0', 'I q1', 'I q2', 'X180 q3', 'RO'],
                          ['X180 q0', 'I q1', 'I q2', 'X180 q3', 'RO'],
                          ['I q0', 'X180 q1', 'I q2', 'X180 q3', 'RO'],
                          ['X180 q0', 'X180 q1', 'I q2', 'X180 q3', 'RO'],
                          ['I q0', 'I q1', 'X180 q2', 'X180 q3', 'RO'],
                          ['X180 q0', 'I q1', 'X180 q2', 'X180 q3', 'RO'],
                          ['I q0', 'X180 q1', 'X180 q2',  'X180 q3', 'RO'],
                          ['X180 q0', 'X180 q1', 'X180 q2',  'X180 q3', 'RO']]

    for i, pulse_comb in enumerate(pulse_combinations):
        pulses = []
        for p in pulse_comb:
            pulses += [pulse_dict[p]]

        el = multi_pulse_elt(i, station, pulses)
        el_list.append(el)
        seq.append_element(el, trigger_wait=True)
    station.pulsar.program_awgs(seq, *el_list, verbose=verbose)
    if return_seq:
        return seq, el_list
    else:
        return seq_name
def four_qubit_off_on(
    q0_pulse_pars, q1_pulse_pars, q2_pulse_pars, q3_pulse_pars, RO_pars, return_seq=False, verbose=False
):

    seq_name = "4_qubit_OffOn_sequence"
    seq = sequence.Sequence(seq_name)
    station.pulsar.update_channel_settings()
    el_list = []
    # Create a dict with the parameters for all the pulses
    q0_pulses = add_suffix_to_dict_keys(get_pulse_dict_from_pars(q0_pulse_pars), " q0")
    q1_pulses = add_suffix_to_dict_keys(get_pulse_dict_from_pars(q1_pulse_pars), " q1")
    q2_pulses = add_suffix_to_dict_keys(get_pulse_dict_from_pars(q2_pulse_pars), " q2")
    q3_pulses = add_suffix_to_dict_keys(get_pulse_dict_from_pars(q3_pulse_pars), " q3")
    RO_dict = {"RO": RO_pars}

    pulse_dict = {}
    pulse_dict.update(q0_pulses)
    pulse_dict.update(q1_pulses)
    pulse_dict.update(q2_pulses)
    pulse_dict.update(q3_pulses)
    pulse_dict.update(RO_dict)

    # N.B. Identities not needed in all cases
    pulse_combinations = [
        ["I q0", "I q1", "I q2", "I q3", "RO"],
        ["X180 q0", "I q1", "I q2", "I q3", "RO"],
        ["I q0", "X180 q1", "I q2", "I q3", "RO"],
        ["X180 q0", "X180 q1", "I q2", "I q3", "RO"],
        ["I q0", "I q1", "X180 q2", "I q3", "RO"],
        ["X180 q0", "I q1", "X180 q2", "I q3", "RO"],
        ["I q0", "X180 q1", "X180 q2", "I q3", "RO"],
        ["X180 q0", "X180 q1", "X180 q2", "I q3", "RO"],
        ["I q0", "I q1", "I q2", "X180 q3", "RO"],
        ["X180 q0", "I q1", "I q2", "X180 q3", "RO"],
        ["I q0", "X180 q1", "I q2", "X180 q3", "RO"],
        ["X180 q0", "X180 q1", "I q2", "X180 q3", "RO"],
        ["I q0", "I q1", "X180 q2", "X180 q3", "RO"],
        ["X180 q0", "I q1", "X180 q2", "X180 q3", "RO"],
        ["I q0", "X180 q1", "X180 q2", "X180 q3", "RO"],
        ["X180 q0", "X180 q1", "X180 q2", "X180 q3", "RO"],
    ]

    for i, pulse_comb in enumerate(pulse_combinations):
        pulses = []
        for p in pulse_comb:
            pulses += [pulse_dict[p]]

        el = multi_pulse_elt(i, station, pulses)
        el_list.append(el)
        seq.append_element(el, trigger_wait=True)
    station.components["AWG"].stop()
    station.pulsar.program_awg(seq, *el_list, verbose=verbose)
    if return_seq:
        return seq, el_list
    else:
        return seq_name
def n_qubit_off_on(pulse_pars_list, RO_pars, return_seq=False, verbose=False,
                   parallel_pulses=False, preselection=False,
                   RO_spacing=200e-9):
    n = len(pulse_pars_list)
    seq_name = '{}_qubit_OffOn_sequence'.format(n)
    seq = sequence.Sequence(seq_name)
    el_list = []

    # Create a dict with the parameters for all the pulses
    pulse_dict = {'RO': RO_pars}
    for i, pulse_pars in enumerate(pulse_pars_list):
        pars = pulse_pars.copy()
        if i != 0 and parallel_pulses:
            pars['refpoint'] = 'start'
        pulses = add_suffix_to_dict_keys(
            get_pulse_dict_from_pars(pars), ' {}'.format(i))
        pulse_dict.update(pulses)
    spacerpulse = {'pulse_type': 'SquarePulse',
                   'channel': RO_pars['acq_marker_channel'],
                   'amplitude': 0.0,
                   'length': RO_spacing,
                   'pulse_delay': 0}
    pulse_dict.update({'spacer': spacerpulse})

    # Create a list of required pulses
    pulse_combinations = []
    for pulse_list in itertools.product(*(n*[['I', 'X180']])):
        pulse_comb = (n+1)*['']
        for i, pulse in enumerate(pulse_list):
            pulse_comb[i] = pulse + ' {}'.format(i)
        pulse_comb[-1] = 'RO'
        if preselection:
            pulse_comb = ['RO', 'spacer'] + pulse_comb
        pulse_combinations.append(pulse_comb)

    for i, pulse_comb in enumerate(pulse_combinations):
        pulses = []
        for j, p in enumerate(pulse_comb):
            pulses += [pulse_dict[p]]
        el = multi_pulse_elt(i, station, pulses)
        el_list.append(el)
        seq.append_element(el, trigger_wait=True)
    station.pulsar.program_awgs(seq, *el_list, verbose=verbose)
    if return_seq:
        return seq, el_list
    else:
        return seq_name
    def get_pulse_dict(self, pulse_dict={}):
        '''
        Returns a dictionary containing the pulse parameters of the qubit.
        This function is intended to replace the old get_pulse_pars.
        Dictionary contains the keys formatted as follows:
            operation self.name

        Input args:
            pulse_dict (dict):  Optionally specify an existing pulse dict to update

        (currently only contains single qubit pulses)
        '''
        drive_pars, RO_pars = self.get_pulse_pars()
        pulse_dict.update(add_suffix_to_dict_keys(
            sq.get_pulse_dict_from_pars(drive_pars), ' ' + self.name))
        pulse_dict.update({'RO {}'.format(self.name): RO_pars})

        spec_pars, RO_pars = self.get_spec_pars()
        pulse_dict.update({'Spec {}'.format(self.name): spec_pars})

        return pulse_dict
def swap_CP_swap_2Qubits(mw_pulse_pars_qCP, mw_pulse_pars_qS,
                         flux_pulse_pars_qCP, flux_pulse_pars_qS,
                         RO_pars,
                         distortion_dict,
                         CPhase=True,
                         excitations='both',
                         inter_swap_wait=100e-9,
                         phases=np.linspace(0, 720, 41),
                         verbose=False,
                         upload=True,
                         cal_points=True):
    '''
    Sequence that swaps qS with the bus and does CPhase between qCP and the bus
        X180 qS - Ym90 qCP - swap qS,B - CPhase qCP,B - swap qS,B - fphi90 qCP
        - X180 qS - RO

    qS is the "swap qubit"
    qCP is the "CPhase qubit"

    mw_pulse_pars qCP:    (dict) qubit control pulse pars
    mw_pulse_pars qS:     (dict) qubit control pulse pars
    flux_pulse_pars qCP:  (dict) flux puplse pars
    flux_pulse_pars qS:   (dict) flux puplse pars
    RO_pars:              (dict) qubit RO pars, ideally a multiplexed readout
    distortion_dict=None: (dict) flux_pulse predistortion kernels

    CPhase:               (bool) if False replaces CPhase with an identity
    excitations:          (enum) [0, 1, 'both'] whether to put an excitation in
                          the swap qubit, both does the sequence both ways.
    phases                (list) phases used for the recovery pulse
    inter_swap_wait       (float) wait time in seconds between the two swaps
    verbose=False:        (bool) used for verbosity printing in the pulsar
    upload=True:          (bool) uploads to AWG, set False for testing purposes
    cal_points=True:      (bool) wether to use calibration points

    TODO:
        - move getting the pulse dict to a single function
        - default to the single qubit swap-wait-swap sequence if no pulse pars
          for qCP
        - Add all four calibration points
    '''

    # ############ This getting pulse dict should be a single function
    mw_pulses_qCP = add_suffix_to_dict_keys(
        get_pulse_dict_from_pars(mw_pulse_pars_qCP), ' qCP')
    mw_pulses_qS = add_suffix_to_dict_keys(
        get_pulse_dict_from_pars(mw_pulse_pars_qS), ' qS')
    # This should come out of this dict in a smarter way
    swap_qCP = {'CPhase qCP': flux_pulse_pars_qCP}
    swap_qS = {'swap qS': flux_pulse_pars_qS}
    RO_dict = {'RO': RO_pars}
    pulse_dict = {}
    pulse_dict.update(mw_pulses_qCP)
    pulse_dict.update(mw_pulses_qS)
    pulse_dict.update(swap_qCP)
    pulse_dict.update(swap_qS)
    pulse_dict.update(RO_dict)
    ## End of the getting pulse dict

    # Preloading should be almost instant (no preloading here)
    preloaded_kernels_vec = preload_kernels_func(distortion_dict)
    # renamed as the dict contains the pulse directly

    # Getting the minus flux pulses should also be in the get pulse dict
    minus_flux_pulse_pars = deepcopy(flux_pulse_pars_qCP)
    pulse_dict['mCPhase qCP'] = deepcopy(pulse_dict['CPhase qCP'])
    pulse_dict['mswap qS'] = deepcopy(pulse_dict['swap qS'])
    pulse_dict['mCPhase qCP']['amplitude'] = -pulse_dict['CPhase qCP']['amplitude']
    pulse_dict['mswap qS']['amplitude'] = -pulse_dict['swap qS']['amplitude']

    pulse_dict.update({'mFlux_pulse': minus_flux_pulse_pars})
    pulse_dict.update({'dead_time_pulse':
                       {'pulse_type': 'SquarePulse',
                        'pulse_delay': flux_pulse_pars_qCP['dead_time'],
                        'channel': flux_pulse_pars_qCP['channel'],
                        'amplitude': 0,
                        'length': 0.}})

    # Pulse is used to set the starting refpoint for the compensation pulses

    seq_name = 'swap_CP_swap_2Qubits'
    seq = sequence.Sequence(seq_name)
    station.pulsar.update_channel_settings()
    el_list = []

    recovery_swap = deepcopy(pulse_dict['swap qS'])

    if not CPhase:
        pulse_dict['CPhase qCP']['amplitude'] = 0
        pulse_dict['mCPhase qCP']['amplitude'] = 0

    recovery_swap['pulse_delay'] = inter_swap_wait/2
    pulse_dict['recovery swap qS'] = recovery_swap
    pulse_dict['CPhase qCP']['pulse_delay'] = inter_swap_wait/2

    # seq has to have at least 2 elts
    for i, phase in enumerate(phases):
        if excitations == 'both':
            if (i < (len(phases)-4*cal_points)/2):
                excitation = False
            else:
                excitation = True
        elif excitations == 0:
            excitation = False
        elif excitations == 1:
            excitation = True
        else:
            raise ValueError(
                'excitations {} not recognized'.format(excitations))
        if cal_points and (i == (len(phases)-4)):
            pulse_combinations = ['I qCP', 'I qS', 'RO']
        elif cal_points and (i == (len(phases)-3)):
            pulse_combinations = ['I qCP', 'X180 qS', 'RO']
        elif cal_points and ((i == len(phases)-2)):
            pulse_combinations = ['X180 qCP', 'I qS', 'RO']
        elif cal_points and (i == (len(phases)-1)):
            pulse_combinations = ['X180 qCP', 'X180 qS', 'RO']
        else:
            rphi90_qCP = deepcopy(pulse_dict['X90 qCP'])
            rphi90_qCP['phase'] = phase
            pulse_dict['rphi90 qCP'] = rphi90_qCP

            if excitation:
                pulse_combinations = ['X180 qS', 'mY90 qCP', 'swap qS'] + \
                    ['CPhase qCP'] + \
                    ['recovery swap qS', 'rphi90 qCP', 'X180 qS', 'RO'] + \
                    ['dead_time_pulse']+['mswap qS']*2+['mCPhase qCP']
            else:
                pulse_combinations = ['I qS', 'mY90 qCP', 'swap qS'] + \
                    ['CPhase qCP'] + \
                    ['recovery swap qS', 'rphi90 qCP', 'I qS', 'RO'] + \
                    ['dead_time_pulse']+['mswap qS']*2+['mCPhase qCP']
                # correcting timings
        pulses = []
        for p in pulse_combinations:
            pulses += [pulse_dict[p]]

        el = multi_pulse_elt(i, station, pulses)
        if distortion_dict is not None:
            el = distort_and_compensate(
                el, distortion_dict, preloaded_kernels_vec)
        el_list.append(el)
        seq.append_element(el, trigger_wait=True)

    if upload:
        station.components['AWG'].stop()
        station.pulsar.program_awg(seq, *el_list, verbose=verbose)

    return seq, el_list
def cphase_fringes(phases, q0_pulse_pars, q1_pulse_pars, RO_pars,
                   swap_pars_q0, cphase_pars_q1, timings_dict,
                   distortion_dict, verbose=False, upload=True, return_seq=False):
    '''
    '''
    preloaded_kernels_vec = preload_kernels_func(distortion_dict)
    original_delay = deepcopy(RO_pars)[0]['pulse_delay']
    seq_name = 'CPhase'
    seq = sequence.Sequence(seq_name)
    station.pulsar.update_channel_settings()
    el_list = []
    # print(q0_pulse_pars)
    q0_pulses = add_suffix_to_dict_keys(
        get_pulse_dict_from_pars(q0_pulse_pars[0]), ' q0')
    q1_pulses = add_suffix_to_dict_keys(
        get_pulse_dict_from_pars(q1_pulse_pars[0]), ' q1')

    pulse_dict = {}
    pulse_dict.update(q0_pulses)
    pulse_dict.update(q1_pulses)
    pulse_dict.update({'RO': RO_pars[0]})
    # print({'RO': RO_pars})

    # Timings
    buffer_mw_flux = timings_dict[0]['buffer_mw_flux']
    buffer_flux_mw = timings_dict[0]['buffer_flux_mw']
    msmt_buffer = timings_dict[0]['msmt_buffer']
    dead_time = timings_dict[0]['dead_time']
    # print(buffer_mw_flux,buffer_flux_mw,msmt_buffer,dead_time)

    # defining main pulses
    exc_pulse = deepcopy(pulse_dict['X180 q0'])
    exc_pulse['pulse_delay'] += 0.01e-6
    swap_pulse_1 = deepcopy(swap_pars_q0[0])
    # print(swap_pulse_1)
    swap_pulse_1['pulse_delay'] = buffer_mw_flux + \
        exc_pulse['sigma']*exc_pulse['nr_sigma']

    ramsey_1 = deepcopy(pulse_dict['Y90 q1'])
    ramsey_1['pulse_delay'] = buffer_flux_mw + swap_pulse_1['length']
    cphase_pulse = cphase_pars_q1[0]
    cphase_amp = cphase_pulse['amplitude']
    cphase_pulse['pulse_delay'] = buffer_mw_flux + \
        ramsey_1['sigma']*ramsey_1['nr_sigma']
    ramsey_2 = deepcopy(pulse_dict['X90 q1'])
    ramsey_2['pulse_delay'] = buffer_flux_mw + cphase_pulse['length']

    swap_pulse_2 = deepcopy(swap_pars_q0[0])
    swap_pulse_2['pulse_delay'] = buffer_mw_flux + \
        ramsey_2['sigma']*ramsey_2['nr_sigma']
    RO_pars[0]['pulse_delay'] = msmt_buffer + swap_pulse_2['length']

    # defining compensation pulses
    swap_comp_1 = deepcopy(swap_pulse_1)
    swap_pulse_1['pulse_delay'] = RO_pars[0]['length'] + dead_time
    cphase_comp = deepcopy(cphase_pulse)
    swap_comp_2 = deepcopy(swap_pulse_2)

    dead_time_pulse = {'pulse_type': 'SquarePulse',
                       'pulse_delay': RO_pars[0]['pulse_delay'],
                       'channel': swap_pars_q0[0]['channel'],
                       'amplitude': 0,
                       'length': dead_time}

    for i, ph2 in enumerate(phases[0]):
        # print(ph2)
        ramsey_2['phase'] = ph2

        cphase_pulse['amplitude'] = cphase_amp
        pulse_list = [exc_pulse,
                      swap_pulse_1,
                      ramsey_1,
                      cphase_pulse,
                      ramsey_2,
                      swap_pulse_2,
                      RO_pars[0],
                      swap_comp_1,
                      cphase_comp,
                      swap_comp_2,
                      dead_time_pulse]
        el = multi_pulse_elt(2*i, station, pulse_list)
        el_list.append(el)

        cphase_pulse['amplitude'] = 0.
        pulse_list = [exc_pulse,
                      swap_pulse_1,
                      ramsey_1,
                      cphase_pulse,
                      ramsey_2,
                      swap_pulse_2,
                      RO_pars[0],
                      swap_comp_1,
                      cphase_comp,
                      swap_comp_2,
                      dead_time_pulse]
        el = multi_pulse_elt(2*i+1, station, pulse_list)
        el_list.append(el)

    # Compensations
    for i, el in enumerate(el_list):
        if distortion_dict is not None:
            el = distort_and_compensate(
                el, distortion_dict, preloaded_kernels_vec)
            el_list[i] = el
        seq.append_element(el, trigger_wait=True)
    cal_points = 4
    RO_pars[0]['pulse_delay'] = original_delay

    # Calibration points
    cal_points = [['I q0', 'I q1', 'RO'],
                  ['I q0', 'I q1', 'RO'],
                  ['X180 q0', 'I q1', 'RO'],
                  ['X180 q0', 'I q1', 'RO'],
                  ['I q0', 'X180 q1', 'RO'],
                  ['I q0', 'X180 q1', 'RO'],
                  ['X180 q0', 'X180 q1', 'RO'],
                  ['X180 q0', 'X180 q1', 'RO']]

    for i, pulse_comb in enumerate(cal_points):
        pulses = []
        for p in pulse_comb:
            pulses += [pulse_dict[p]]
        pulses[0]['pulse_delay'] += 0.01e-6

        el = multi_pulse_elt(2*len(phases)+i, station, pulses)
        el_list.append(el)
        seq.append_element(el, trigger_wait=True)

    # upload
    if upload:
        station.pulsar.program_awgs(seq, *el_list, verbose=verbose)
    if return_seq:
        return seq, el_list
    else:
        return seq
def two_qubit_tomo_cardinal(cardinal,
                            q0_pulse_pars,
                            q1_pulse_pars,
                            RO_pars,
                            timings_dict,
                            verbose=False,
                            upload=True,
                            return_seq=False):

    seq_name = '2_qubit_Card_%d_seq' % cardinal
    seq = sequence.Sequence(seq_name)
    station.pulsar.update_channel_settings()
    el_list = []
    # Create a dict with the parameters for all the pulses
    q0_pulses = add_suffix_to_dict_keys(
        get_pulse_dict_from_pars(q0_pulse_pars), ' q0')
    q1_pulses = add_suffix_to_dict_keys(
        get_pulse_dict_from_pars(q1_pulse_pars), ' q1')
    RO_dict = {'RO': RO_pars}

    pulse_dict = {}
    pulse_dict.update(q0_pulses)
    pulse_dict.update(q1_pulses)
    pulse_dict.update(RO_dict)

    # Timings
    # FIXME: This dictionary should not be required? -MAR
    # NOTE: required in the CPhase tomo as input but not used
    QQ_buffer = timings_dict['QQ_buffer']
    wait_time = timings_dict['wait_time']
    msmt_buffer = timings_dict['msmt_buffer']

    tomo_list_q0 = ['I q0', 'X180 q0', 'Y90 q0',
                    'mY90 q0', 'X90 q0', 'mX90 q0']
    tomo_list_q1 = ['I q1', 'X180 q1', 'Y90 q1',
                    'mY90 q1', 'X90 q1', 'mX90 q1']

    # inner loop on q0
    prep_idx_q0 = int(cardinal % 6)
    prep_idx_q1 = int(((cardinal - prep_idx_q0)/6) % 6)

    prep_pulse_q0 = pulse_dict[tomo_list_q0[prep_idx_q0]]
    prep_pulse_q1 = pulse_dict[tomo_list_q1[prep_idx_q1]]

    prep_pulse_q1['pulse_delay'] = QQ_buffer + (prep_pulse_q0['sigma'] *
                                                prep_pulse_q0['nr_sigma'])

    RO_pars['pulse_delay'] += msmt_buffer - (prep_pulse_q1['sigma'] *
                                             prep_pulse_q1['nr_sigma'])

    # Calibration points
    cal_points = [['I q0', 'I q1', 'RO'],
                  ['I q0', 'I q1', 'RO'],
                  ['I q0', 'I q1', 'RO'],
                  ['I q0', 'I q1', 'RO'],
                  ['I q0', 'I q1', 'RO'],
                  ['I q0', 'I q1', 'RO'],
                  ['I q0', 'I q1', 'RO'],
                  ['X180 q0', 'I q1', 'RO'],
                  ['X180 q0', 'I q1', 'RO'],
                  ['X180 q0', 'I q1', 'RO'],
                  ['X180 q0', 'I q1', 'RO'],
                  ['X180 q0', 'I q1', 'RO'],
                  ['X180 q0', 'I q1', 'RO'],
                  ['X180 q0', 'I q1', 'RO'],
                  ['I q0', 'X180 q1', 'RO'],
                  ['I q0', 'X180 q1', 'RO'],
                  ['I q0', 'X180 q1', 'RO'],
                  ['I q0', 'X180 q1', 'RO'],
                  ['I q0', 'X180 q1', 'RO'],
                  ['I q0', 'X180 q1', 'RO'],
                  ['I q0', 'X180 q1', 'RO'],
                  ['X180 q0', 'X180 q1', 'RO'],
                  ['X180 q0', 'X180 q1', 'RO'],
                  ['X180 q0', 'X180 q1', 'RO'],
                  ['X180 q0', 'X180 q1', 'RO'],
                  ['X180 q0', 'X180 q1', 'RO'],
                  ['X180 q0', 'X180 q1', 'RO'],
                  ['X180 q0', 'X180 q1', 'RO']]

    for i in range(36):
        tomo_idx_q0 = int(i % 6)
        tomo_idx_q1 = int(((i - tomo_idx_q0)/6) % 6)

        # print(i,tomo_idx_q0,tomo_idx_q1)

        tomo_pulse_q0 = pulse_dict[tomo_list_q0[tomo_idx_q0]]
        tomo_pulse_q1 = pulse_dict[tomo_list_q1[tomo_idx_q1]]

        tomo_pulse_q0['pulse_delay'] = wait_time + (prep_pulse_q1['sigma'] *
                                                    prep_pulse_q1['nr_sigma'])

        tomo_pulse_q1['pulse_delay'] = QQ_buffer + (tomo_pulse_q0['sigma'] *
                                                    tomo_pulse_q0['nr_sigma'])
        pulse_list = [prep_pulse_q0,
                      prep_pulse_q1,
                      tomo_pulse_q0,
                      tomo_pulse_q1,
                      RO_pars]
        el = multi_pulse_elt(i, station, pulse_list)
        el_list.append(el)
        seq.append_element(el, trigger_wait=True)

    for i, pulse_comb in enumerate(cal_points):
        pulses = []
        for p in pulse_comb:
            pulses += [pulse_dict[p]]

        el = multi_pulse_elt(35+i, station, pulses)
        el_list.append(el)
        seq.append_element(el, trigger_wait=True)

    station.pulsar.program_awgs(seq, *el_list, verbose=verbose)
    if return_seq:
        return seq, el_list
    else:
        return seq_name
def cphase_fringes(
    phases,
    q0_pulse_pars,
    q1_pulse_pars,
    RO_pars,
    swap_pars_q0,
    cphase_pars_q1,
    timings_dict,
    distortion_dict,
    verbose=False,
    upload=True,
    return_seq=False,
):
    """
    """
    preloaded_kernels_vec = preload_kernels_func(distortion_dict)
    original_delay = deepcopy(RO_pars)[0]["pulse_delay"]
    seq_name = "CPhase"
    seq = sequence.Sequence(seq_name)
    station.pulsar.update_channel_settings()
    el_list = []
    # print(q0_pulse_pars)
    q0_pulses = add_suffix_to_dict_keys(get_pulse_dict_from_pars(q0_pulse_pars[0]), " q0")
    q1_pulses = add_suffix_to_dict_keys(get_pulse_dict_from_pars(q1_pulse_pars[0]), " q1")

    pulse_dict = {}
    pulse_dict.update(q0_pulses)
    pulse_dict.update(q1_pulses)
    pulse_dict.update({"RO": RO_pars[0]})
    # print({'RO': RO_pars})

    # Timings
    buffer_mw_flux = timings_dict[0]["buffer_mw_flux"]
    buffer_flux_mw = timings_dict[0]["buffer_flux_mw"]
    msmt_buffer = timings_dict[0]["msmt_buffer"]
    dead_time = timings_dict[0]["dead_time"]
    # print(buffer_mw_flux,buffer_flux_mw,msmt_buffer,dead_time)

    # defining main pulses
    exc_pulse = deepcopy(pulse_dict["X180 q0"])
    exc_pulse["pulse_delay"] += 0.01e-6
    swap_pulse_1 = deepcopy(swap_pars_q0[0])
    # print(swap_pulse_1)
    swap_pulse_1["pulse_delay"] = buffer_mw_flux + exc_pulse["sigma"] * exc_pulse["nr_sigma"]

    ramsey_1 = deepcopy(pulse_dict["Y90 q1"])
    ramsey_1["pulse_delay"] = buffer_flux_mw + swap_pulse_1["length"]
    cphase_pulse = cphase_pars_q1[0]
    cphase_amp = cphase_pulse["amplitude"]
    cphase_pulse["pulse_delay"] = buffer_mw_flux + ramsey_1["sigma"] * ramsey_1["nr_sigma"]
    ramsey_2 = deepcopy(pulse_dict["X90 q1"])
    ramsey_2["pulse_delay"] = buffer_flux_mw + cphase_pulse["length"]

    swap_pulse_2 = deepcopy(swap_pars_q0[0])
    swap_pulse_2["pulse_delay"] = buffer_mw_flux + ramsey_2["sigma"] * ramsey_2["nr_sigma"]
    RO_pars[0]["pulse_delay"] = msmt_buffer + swap_pulse_2["length"]

    # defining compensation pulses
    swap_comp_1 = deepcopy(swap_pulse_1)
    swap_pulse_1["pulse_delay"] = RO_pars[0]["length"] + dead_time
    cphase_comp = deepcopy(cphase_pulse)
    swap_comp_2 = deepcopy(swap_pulse_2)

    dead_time_pulse = {
        "pulse_type": "SquarePulse",
        "pulse_delay": RO_pars[0]["pulse_delay"],
        "channel": swap_pars_q0[0]["channel"],
        "amplitude": 0,
        "length": dead_time,
    }

    for i, ph2 in enumerate(phases[0]):
        # print(ph2)
        ramsey_2["phase"] = ph2

        cphase_pulse["amplitude"] = cphase_amp
        pulse_list = [
            exc_pulse,
            swap_pulse_1,
            ramsey_1,
            cphase_pulse,
            ramsey_2,
            swap_pulse_2,
            RO_pars[0],
            swap_comp_1,
            cphase_comp,
            swap_comp_2,
            dead_time_pulse,
        ]
        el = multi_pulse_elt(2 * i, station, pulse_list)
        el_list.append(el)

        cphase_pulse["amplitude"] = 0.0
        pulse_list = [
            exc_pulse,
            swap_pulse_1,
            ramsey_1,
            cphase_pulse,
            ramsey_2,
            swap_pulse_2,
            RO_pars[0],
            swap_comp_1,
            cphase_comp,
            swap_comp_2,
            dead_time_pulse,
        ]
        el = multi_pulse_elt(2 * i + 1, station, pulse_list)
        el_list.append(el)

    # Compensations
    for i, el in enumerate(el_list):
        if distortion_dict is not None:
            el = distort_and_compensate(el, distortion_dict, preloaded_kernels_vec)
            el_list[i] = el
        seq.append_element(el, trigger_wait=True)
    cal_points = 4
    RO_pars[0]["pulse_delay"] = original_delay

    # Calibration points
    cal_points = [
        ["I q0", "I q1", "RO"],
        ["I q0", "I q1", "RO"],
        ["X180 q0", "I q1", "RO"],
        ["X180 q0", "I q1", "RO"],
        ["I q0", "X180 q1", "RO"],
        ["I q0", "X180 q1", "RO"],
        ["X180 q0", "X180 q1", "RO"],
        ["X180 q0", "X180 q1", "RO"],
    ]

    for i, pulse_comb in enumerate(cal_points):
        pulses = []
        for p in pulse_comb:
            pulses += [pulse_dict[p]]
        pulses[0]["pulse_delay"] += 0.01e-6

        el = multi_pulse_elt(2 * len(phases) + i, station, pulses)
        el_list.append(el)
        seq.append_element(el, trigger_wait=True)

    # upload
    if upload:
        station.components["AWG"].stop()
        station.pulsar.program_awg(seq, *el_list, verbose=verbose)
    if return_seq:
        return seq, el_list
    else:
        return seq
def two_qubit_tomo_cardinal(
    cardinal, q0_pulse_pars, q1_pulse_pars, RO_pars, timings_dict, verbose=False, upload=True, return_seq=False
):

    seq_name = "2_qubit_Card_%d_seq" % cardinal
    seq = sequence.Sequence(seq_name)
    station.pulsar.update_channel_settings()
    el_list = []
    # Create a dict with the parameters for all the pulses
    q0_pulses = add_suffix_to_dict_keys(get_pulse_dict_from_pars(q0_pulse_pars), " q0")
    q1_pulses = add_suffix_to_dict_keys(get_pulse_dict_from_pars(q1_pulse_pars), " q1")
    RO_dict = {"RO": RO_pars}

    pulse_dict = {}
    pulse_dict.update(q0_pulses)
    pulse_dict.update(q1_pulses)
    pulse_dict.update(RO_dict)

    # Timings
    QQ_buffer = timings_dict["QQ_buffer"]
    wait_time = timings_dict["wait_time"]
    msmt_buffer = timings_dict["msmt_buffer"]

    tomo_list_q0 = ["I q0", "X180 q0", "Y90 q0", "mY90 q0", "X90 q0", "mX90 q0"]
    tomo_list_q1 = ["I q1", "X180 q1", "Y90 q1", "mY90 q1", "X90 q1", "mX90 q1"]

    # inner loop on q0
    prep_idx_q0 = int(cardinal % 6)
    prep_idx_q1 = int(((cardinal - prep_idx_q0) / 6) % 6)

    prep_pulse_q0 = pulse_dict[tomo_list_q0[prep_idx_q0]]
    prep_pulse_q1 = pulse_dict[tomo_list_q1[prep_idx_q1]]

    prep_pulse_q1["pulse_delay"] = QQ_buffer + (prep_pulse_q0["sigma"] * prep_pulse_q0["nr_sigma"])

    RO_pars["pulse_delay"] += msmt_buffer - (prep_pulse_q1["sigma"] * prep_pulse_q1["nr_sigma"])

    # Calibration points
    cal_points = [
        ["I q0", "I q1", "RO"],
        ["I q0", "I q1", "RO"],
        ["I q0", "I q1", "RO"],
        ["I q0", "I q1", "RO"],
        ["I q0", "I q1", "RO"],
        ["I q0", "I q1", "RO"],
        ["I q0", "I q1", "RO"],
        ["X180 q0", "I q1", "RO"],
        ["X180 q0", "I q1", "RO"],
        ["X180 q0", "I q1", "RO"],
        ["X180 q0", "I q1", "RO"],
        ["X180 q0", "I q1", "RO"],
        ["X180 q0", "I q1", "RO"],
        ["X180 q0", "I q1", "RO"],
        ["I q0", "X180 q1", "RO"],
        ["I q0", "X180 q1", "RO"],
        ["I q0", "X180 q1", "RO"],
        ["I q0", "X180 q1", "RO"],
        ["I q0", "X180 q1", "RO"],
        ["I q0", "X180 q1", "RO"],
        ["I q0", "X180 q1", "RO"],
        ["X180 q0", "X180 q1", "RO"],
        ["X180 q0", "X180 q1", "RO"],
        ["X180 q0", "X180 q1", "RO"],
        ["X180 q0", "X180 q1", "RO"],
        ["X180 q0", "X180 q1", "RO"],
        ["X180 q0", "X180 q1", "RO"],
        ["X180 q0", "X180 q1", "RO"],
    ]

    for i in range(36):
        tomo_idx_q0 = int(i % 6)
        tomo_idx_q1 = int(((i - tomo_idx_q0) / 6) % 6)

        # print(i,tomo_idx_q0,tomo_idx_q1)

        tomo_pulse_q0 = pulse_dict[tomo_list_q0[tomo_idx_q0]]
        tomo_pulse_q1 = pulse_dict[tomo_list_q1[tomo_idx_q1]]

        tomo_pulse_q0["pulse_delay"] = wait_time + (prep_pulse_q1["sigma"] * prep_pulse_q1["nr_sigma"])

        tomo_pulse_q1["pulse_delay"] = QQ_buffer + (tomo_pulse_q0["sigma"] * tomo_pulse_q0["nr_sigma"])
        pulse_list = [prep_pulse_q0, prep_pulse_q1, tomo_pulse_q0, tomo_pulse_q1, RO_pars]
        pulse_list[0]["pulse_delay"] += 0.01e-6
        el = multi_pulse_elt(i, station, pulse_list)
        el_list.append(el)
        seq.append_element(el, trigger_wait=True)

    for i, pulse_comb in enumerate(cal_points):
        pulses = []
        for p in pulse_comb:
            pulses += [pulse_dict[p]]
        pulses[0]["pulse_delay"] += 0.01e-6

        el = multi_pulse_elt(35 + i, station, pulses)
        el_list.append(el)
        seq.append_element(el, trigger_wait=True)

    station.components["AWG"].stop()
    station.pulsar.program_awg(seq, *el_list, verbose=verbose)
    if return_seq:
        return seq, el_list
    else:
        return seq_name
def two_qubit_AllXY(
    q0_pulse_pars, q1_pulse_pars, RO_pars, double_points=True, verbose=False, upload=True, return_seq=False
):
    """
    Performs an AllXY on the first qubit will doing a pi-pulse before
    and after the AllXY on the second qubit
    AllXY q0 - RO
    X180 q1 - AllXY q0 - X180 q1 - RO
    """
    seq_name = "2_qubit_AllXY_sequence"
    seq = sequence.Sequence(seq_name)
    station.pulsar.update_channel_settings()
    el_list = []
    # Create a dict with the parameters for all the pulses
    q0_pulses = add_suffix_to_dict_keys(get_pulse_dict_from_pars(q0_pulse_pars), " q0")
    q1_pulses = add_suffix_to_dict_keys(get_pulse_dict_from_pars(q1_pulse_pars), " q1")
    RO_dict = {"RO": RO_pars}

    pulse_dict = {}
    pulse_dict.update(q0_pulses)
    pulse_dict.update(q1_pulses)
    pulse_dict.update(RO_dict)
    AllXY_pulse_combinations = [
        ["I q0", "I q0"],
        ["X180 q0", "X180 q0"],
        ["Y180 q0", "Y180 q0"],
        ["X180 q0", "Y180 q0"],
        ["Y180 q0", "X180 q0"],
        ["X90 q0", "I q0"],
        ["Y90 q0", "I q0"],
        ["X90 q0", "Y90 q0"],
        ["Y90 q0", "X90 q0"],
        ["X90 q0", "Y180 q0"],
        ["Y90 q0", "X180 q0"],
        ["X180 q0", "Y90 q0"],
        ["Y180 q0", "X90 q0"],
        ["X90 q0", "X180 q0"],
        ["X180 q0", "X90 q0"],
        ["Y90 q0", "Y180 q0"],
        ["Y180 q0", "Y90 q0"],
        ["X180 q0", "I q0"],
        ["Y180 q0", "I q0"],
        ["X90 q0", "X90 q0"],
        ["Y90 q0", "Y90 q0"],
    ]

    if double_points:
        AllXY_pulse_combinations = [val for val in AllXY_pulse_combinations for _ in (0, 1)]
    pulse_list = []
    for pulse_comb in AllXY_pulse_combinations:
        pulse_list += [pulse_comb + ["RO"]]
    for pulse_comb in AllXY_pulse_combinations:
        pulse_list += [["X180 q1"] + pulse_comb + ["X180 q1", "RO"]]
    for i, pulse_comb in enumerate(pulse_list):
        pulses = []
        for p in pulse_comb:
            pulses += [pulse_dict[p]]
        el = multi_pulse_elt(i, station, pulses)
        el_list.append(el)
        seq.append_element(el, trigger_wait=True)

    station.components["AWG"].stop()
    station.pulsar.program_awg(seq, *el_list, verbose=verbose)
    if return_seq:
        return seq, el_list
    else:
        return seq_name
def n_qubit_off_on(pulse_pars_list,
                   RO_pars_list,
                   return_seq=False,
                   parallel_pulses=False,
                   preselection=False,
                   upload=True,
                   RO_spacing=2000e-9):
    n = len(pulse_pars_list)
    seq_name = '{}_qubit_OffOn_sequence'.format(n)
    seq = sequence.Sequence(seq_name)
    seg_list = []

    RO_pars_list_presel = deepcopy(RO_pars_list)

    for i, RO_pars in enumerate(RO_pars_list):
        RO_pars['name'] = 'RO_{}'.format(i)
        RO_pars['element_name'] = 'RO'
        if i != 0:
            RO_pars['ref_point'] = 'start'
    for i, RO_pars_presel in enumerate(RO_pars_list_presel):
        RO_pars_presel['ref_pulse'] = RO_pars_list[-1]['name']
        RO_pars_presel['ref_point'] = 'start'
        RO_pars_presel['element_name'] = 'RO_presel'
        RO_pars_presel['pulse_delay'] = -RO_spacing

    # Create a dict with the parameters for all the pulses
    pulse_dict = dict()
    for i, pulse_pars in enumerate(pulse_pars_list):
        pars = pulse_pars.copy()
        if i == 0 and parallel_pulses:
            pars['ref_pulse'] = 'segment_start'
        if i != 0 and parallel_pulses:
            pars['ref_point'] = 'start'
        pulses = add_suffix_to_dict_keys(get_pulse_dict_from_pars(pars),
                                         ' {}'.format(i))
        pulse_dict.update(pulses)

    # Create a list of required pulses
    pulse_combinations = []

    for pulse_list in itertools.product(*(n * [['I', 'X180']])):
        pulse_comb = (n) * ['']
        for i, pulse in enumerate(pulse_list):
            pulse_comb[i] = pulse + ' {}'.format(i)
        pulse_combinations.append(pulse_comb)
    for i, pulse_comb in enumerate(pulse_combinations):
        pulses = []
        for j, p in enumerate(pulse_comb):
            pulses += [pulse_dict[p]]
        pulses += RO_pars_list
        if preselection:
            pulses = pulses + RO_pars_list_presel

        seg = segment.Segment('segment_{}'.format(i), pulses)
        seg_list.append(seg)
        seq.add(seg)

    repeat_dict = {}
    repeat_pattern = ((1.0 + int(preselection)) * len(pulse_combinations), 1)
    for i, RO_pars in enumerate(RO_pars_list):
        repeat_dict = seq.repeat(RO_pars, None, repeat_pattern)

    if upload:
        ps.Pulsar.get_instance().program_awgs(seq)
    if return_seq:
        return seq, seg_list
    else:
        return seq_name