Exemple #1
0
    def dumb_correction(self, syndromes, origin=False):
        """
        Connects all detection events to the closest boundary of the
        appropriate type.
        Simple dumb decoder.
        Throughout this method, we will treat a Z syndrome as
        indicating a Z error.
        Note that these syndromes are supported on the X ancillas of
        the layout and vice versa.

        There's an optional argument, origin, that will just move
        all observed syndromes to the same corner of the lattice, near
        the origin.

        TODO: Make it work with toric BC?
        """
        corr_dict = {'Z': sp.Pauli(), 'X': sp.Pauli()}
        if origin:
            for err, synd, pt in zip('ZX', syndromes, [(0, 0), (2, 0)]):
                crds = [self.layout.map.inv[_] for _ in synd]
                corr_dict[err] *= product(
                    [self.path_pauli(_, pt, err) for _ in crds])
        else:
            for err, synd in zip('ZX', syndromes):
                crds = [self.layout.map.inv[_] for _ in synd]
                corr_dict[err] *= product([
                    self.path_pauli(_,
                                    self.bdy_info(_)[1], err) for _ in crds
                ])

        return corr_dict['X'], corr_dict['Z']
def add2check(extractor, err_synd, two_err, anc, check_tp, alph_order=True):
    tp = check_tp
    ntp = 'XZ'.replace(tp, '')

    for i in range(len(extractor[tp])):
        if len(list(extractor[tp][i])) == 3:
            # if it is a two-qubit gate
            for err in two_err:
                # add 16 kinds of pauli errors one by one
                error = sp.Pauli()
                if err[0] == 'X' or err[0] == 'Y':
                    error *= sp.Pauli({int(list(extractor[tp][i])[1])}, {})
                if err[0] == 'Z' or err[0] == 'Y':
                    error *= sp.Pauli({}, {int(list(extractor[tp][i])[1])})
                if err[1] == 'X' or err[1] == 'Y':
                    error *= sp.Pauli({int(list(extractor[tp][i])[-1])}, {})
                if err[1] == 'Z' or err[1] == 'Y':
                    error *= sp.Pauli({}, {int(list(extractor[tp][i])[-1])})

                synd1 = {'X': [], 'Z': []}

                synd1[tp], error = esm_apply_err(extractor[tp],
                                                 anc,
                                                 error,
                                                 rg=i + 1,
                                                 bk=True)
                # The execution breaks here because we assume if we see a syndrome or a flag,
                # we will stop this round and start a full of new round
                # if extractor[ntp]:
                #     synd1[ntp], error = esm_apply_err(extractor[ntp], anc, error)
                # synd1[ntp] = set()

                # apply these errors to the extractors to get the syndromes of next perfect round
                synd2 = {'X': [], 'Z': []}
                if alph_order:
                    synd2[tp], error = esm_apply_err(extractor[tp], anc, error)
                    if extractor[ntp]:
                        synd2[ntp], error = esm_apply_err(
                            extractor[ntp], anc, error)
                else:
                    synd2[ntp], error = esm_apply_err(extractor[ntp], anc,
                                                      error)
                    if extractor[tp]:
                        synd2[tp], error = esm_apply_err(
                            extractor[tp], anc, error)

                # define a tuple here, the first (last) two elements are the synds from the first(second) round of esm
                synd_list = (tuple(synd1['X']), tuple(synd1['Z']),
                             tuple(synd2['X']), tuple(synd2['Z']))
                if synd_list in err_synd.keys():
                    if (error.x_set, error.z_set) in err_synd[synd_list]:
                        pass
                    else:
                        err_synd[synd_list].append((error.x_set, error.z_set))
                else:
                    err_synd[synd_list] = [(error.x_set, error.z_set)]
        else:
            pass

    return err_synd
    def run(self):
        err_synds = self.generate_err_synd_pairs()
        ft_value = 0

        for synd_list in err_synds:
            for i in err_synds[synd_list]:

                
                if len(i[0]) == 2 or len(i[1]) == 2:
                    if (set(synd_list[0]) | set(synd_list[1])) & set(self.q_flag):
                        pass
                    else:
                        print('synds are', synd_list)
                        print('errs are', i)
                        raise('two errors but no flags')
               
            if len(err_synds[synd_list]) > 1:
                for i in range(len(err_synds[synd_list])-1):

                    for j in range(i+1, len(err_synds[synd_list])):
                        err1 = sp.Pauli()
                        err2 = sp.Pauli()
                        err1 *= sp.Pauli(err_synds[synd_list][i][0], err_synds[synd_list][i][1])
                        err2 *= sp.Pauli(err_synds[synd_list][j][0], err_synds[synd_list][j][1])
                        # check the fault-tolerance by checking whether the multiplication of two errors 
                        # is a logical. This should be ok for esm circuit checking, but how about logical gates

                        for stab in self.init_stabs:
                            
                            if (err1 * err2).com(stab):
                                print(err1,'err1')
                                print(err2,'err2')
                                ft_value = 0

                                print('One case that errors are going to be a logical,here')
                                print(synd_list,'synd_list')
                                print(synd_list, err_synds[synd_list])

                                return ft_value
                            else:
                                pass

                        if (err1 * err2).com(self.init_logs[0]):
                            ft_value = 0
                            print('One case that could cause a logical error')
                            print(synd_list, err_synds[synd_list])
                            return ft_value
                        elif (err1 * err2).com(self.init_logs[1]):
                            ft_value = 0
                            print('One case that could cause a logical error')
                            print(synd_list, err_synds[synd_list])
                            return ft_value
                        else:
                            ft_value = 1

            else:
                ft_value = 1

        return ft_value
 def logicals(self):
     x_set = [
         self.map[_] for _ in filter(lambda pr: pr[0] == 1, self.datas)
     ]
     z_set = [
         self.map[_] for _ in filter(lambda pr: pr[1] == 1, self.datas)
     ]
     return [sp.Pauli(x_set, []), sp.Pauli([], z_set)]
Exemple #5
0
def dist_7_single_sample():
    test_layout = cm.SCLayoutClass.SCLayout(7)
    x_stabs = list(test_layout.stabilisers()['X'].values())
    ds = [test_layout.map[d] for d in test_layout.datas]
    x_errs = [sp.Pauli({d}, set()) for d in ds]
    x_errs += [sp.Pauli(pr, set()) for pr in it.combinations(ds, r=2)]
    log = test_layout.logicals()[0]
    prob_dist = single_prob(weight_dist(x_stabs, x_errs[52], log, x_errs[52]),
                            0.01)
Exemple #6
0
def dist_5_check():
    """
    runs weight-1 and 2 errors for a dist-5 SC
    """
    test_layout = cm.SCLayoutClass.SCLayout(5)
    x_stabs = list(test_layout.stabilisers()['X'].values())
    ds = [test_layout.map[d] for d in test_layout.datas]
    x_errs = [sp.Pauli({d}, set()) for d in ds]
    x_errs += [sp.Pauli(pr, set()) for pr in it.combinations(ds, r=2)]
    log = test_layout.logicals()[0]
    for err in x_errs:
        prob_dist = single_prob(weight_dist(x_stabs, err, log, err), 0.01)
        if prob_dist[0] < 2.:  #dummy
            print(err, prob_dist)
    def half_err_synd_pairs(self,err_synd,f_c1,f_c2,one_type_ancillas):
        for i in range(len(f_c1)):
            
            if len(list(f_c1[i])) == 3:
            # if it is a two-qubit gate    

                for err in self.two_error:
                    # add 16 kinds of pauli errors one by one

                    error = sp.Pauli()
                    if err[0] == 'X' or err[0] == 'Y':
                        error *= sp.Pauli({int(list(f_c1[i])[1])}, {})
                    if err[0] == 'Z' or err[0] == 'Y':
                        error *= sp.Pauli({}, {int(list(f_c1[i])[1])})
                    if err[1] == 'X' or err[1] == 'Y':
                        error *= sp.Pauli({int(list(f_c1[i])[-1])}, {})
                    if err[1] == 'Z' or err[1] == 'Y':
                        error *= sp.Pauli({}, {int(list(f_c1[i])[-1])})
                        
                    syndromes1, error = esm_apply_err(f_c1, 
                                                      one_type_ancillas, 
                                                      error, 
                                                      rg=i+1, 
                                                      bk=False)
                    # The execution breaks here because we assume if we see a 
                    # syndrome or a flag, we will stop this round and start a full of
                    # new round 
                    syndromes2, error = esm_apply_err_skip_P(f_c2, self.ancillas, error)

                    syndromes1_x = (syndromes1 & self.x_ancillas)
                    syndromes1_z = (syndromes1 & self.z_ancillas)
                    syndromes2_x = (syndromes2 & self.x_ancillas)
                    syndromes2_z = (syndromes2 & self.z_ancillas)

                    synd_list = (tuple(syndromes1_x),tuple(syndromes1_z),tuple(syndromes2_x),tuple(syndromes2_z))

#                    if syndromes1_x == set() and syndromes1_z == set():
#                        pass 

                    if synd_list in err_synd.keys():
                        if (error.x_set, error.z_set) in err_synd[synd_list]:
                            pass
                        else:
                            err_synd[synd_list].append((error.x_set,error.z_set))
                    else:
                        err_synd[synd_list]= [(error.x_set,error.z_set)]
            else:
                pass

        return(err_synd)
def weight_dist(stab_gens, identity, log, coset_rep):
    """
    If we iterate over an entire stabiliser group, we can calculate
    the weight of each Pauli of the form c * l * s for c a coset
    representative for the normaliser of the stabiliser, l a choice of 
    logical operator, and s a stabiliser.
    Colloquially, c is generated by a one-to-one map from the
    syndromes.

    The weight will range from 0 to nq, where nq is the number of
    qubits in the system, and there'll be many Paulis with each weight.
    Therefore, we return an array full of counts.  
    """

    # First get nq
    nq = len(reduce(union, (s.support() for s in stab_gens)))

    wt_counts_I = np.zeros((nq + 1, ), dtype=np.int_)
    wt_counts_L = np.zeros((nq + 1, ), dtype=np.int_)

    i = 0
    for subset in powerset(stab_gens):
        i += 1
        s = reduce(mul, subset, sp.Pauli())
        wt_counts_I[(s * identity * coset_rep).weight()] += 1
        wt_counts_L[(s * log * coset_rep).weight()] += 1
        #if i % 1000 == 0:
        #    print(i)

    return [wt_counts_I, wt_counts_L]
Exemple #9
0
    def run_second_round(self, err, synd1, i):
        corr = sp.Pauli()
        synd2 = set()
        subcir = self.esm_circuits[i + 2]

        synd_err = circ2err(
            subcir, fowler_model(subcir, self.p1, self.p1, self.p1, self.pI),
            err, self.ancillas)
        synd2 |= synd_err[0]
        err = synd_err[1]

        # Choose lut decoder based on whether there is a flag, then find corrections
        flag_qs = synd1 & set(self.q_flag)
        synd_qx = sorted(synd2 & set(self.q_syndx))
        synd_qz = sorted(synd2 & set(self.q_syndz))

        if len(flag_qs):
            try:

                corr *= self.lut_flag[tuple(flag_qs)][tuple(synd_qx)]
                corr *= self.lut_flag[tuple(flag_qs)][tuple(synd_qz)]
            except KeyError:
                pass
        else:
            try:
                corr *= self.lut_synd[tuple(synd_qz)]
                corr *= self.lut_synd[tuple(synd_qx)]

            except KeyError:
                pass

        return (err, synd2, corr)
def check_hld(outputname, trials, qeccode):
    import tensorflow as tf

    with tf.device('/CPU:0'):
        model = tf.keras.models.load_model('nn_model/' + outputname + '.model')
        no_error = 0
        total_errors = 0
        for trial in range(trials):
            for key in qeccode.datas:
                qeccode.fnl_errsx[key] = 0
                qeccode.fnl_errsz[key] = 0
            synd_list = np.zeros((qeccode.num_anc * 2))
            synd_zeros = np.zeros((qeccode.num_anc * 2))
            corr = sp.Pauli()

            err, synd1 = qeccode.run_first_round()
            if len(synd1):
                err, synd2, corr = qeccode.run_second_round(err, synd1)
            else:
                synd2 = dict()
                no_error += 1

            err_fnl = err
            err *= corr

            synd_fnl = set()
            for i in range(len(qeccode.esm_circuits)):
                subcir = qeccode.esm_circuits[i]
                synd_err = circ2err(subcir, fowler_model(subcir, 0, 0, 0), err,
                                    qeccode.ancillas)
                synd_fnl |= synd_err[0]
                err = synd_err[1]
            err *= qeccode.lut_synd[tuple(
                sorted(synd_fnl & set(qeccode.q_syndx)))]
            err *= qeccode.lut_synd[tuple(
                sorted(synd_fnl & set(qeccode.q_syndz)))]

            err_tp = singlelogical_error_index(err, qeccode.init_logs)

            for key in err_fnl.x_set:
                qeccode.fnl_errsx[key] = 1
            for key in err_fnl.z_set:
                qeccode.fnl_errsz[key] = 1

            for i in range(qeccode.num_anc):
                if qeccode.ancillas[i] in synd1:
                    if qeccode.ancillas[i] in set(qeccode.q_flag):
                        synd_list[i] = 1

            for j in range(qeccode.num_anc):
                if qeccode.ancillas[j] in synd2:
                    synd_list[j + qeccode.num_anc] = 1

            if (synd_list != synd_zeros).any():
                synd_list = np.reshape(synd_list, (1, 16))
                pred = model.predict(synd_list)
                if err_tp != np.argmax(pred):
                    total_errors += 1
    print(total_errors)
    return (total_errors, no_error)
Exemple #11
0
    def run(self, trials=1):
        total_errors = 0
        no_synd = 0

        for trial in range(trials):
            corr = sp.Pauli()
            synd2 = set()
            err, synd1, break_point = self.run_first_round()

            if len(synd1):
                err, synd2, corr = self.run_second_round(
                    err, synd1, break_point)
            else:
                no_synd += 1

            err_fnl = err
            err *= corr

            # run another perfect round to clean the left errors
            synd_fnl = set()
            for i in range(2):
                subcir = self.esm_circuits[i]
                synd_err = circ2err(subcir, fowler_model(subcir, 0, 0, 0), err,
                                    self.ancillas)
                synd_fnl |= synd_err[0]
                err = synd_err[1]
            err *= self.lut_synd[tuple(sorted(synd_fnl & set(self.q_syndx)))]
            err *= self.lut_synd[tuple(sorted(synd_fnl & set(self.q_syndz)))]

            # # check logical errors
            err_tp = singlelogical_error(err, self.init_logs)
            self.errors[err_tp] += 1

        return (self.errors)
Exemple #12
0
def full_weight_dist(stab_gens, log_x, log_z, coset_rep):
    """
    I revert to full Pauli calculations in order to look at
    depolarizing errors.
    """

    # First get nq
    nq = len(reduce(union, (s.support() for s in stab_gens)))
    wt_counts = {
        'I': np.zeros((nq + 1, ), dtype=np.int_),
        'X': np.zeros((nq + 1, ), dtype=np.int_),
        'Y': np.zeros((nq + 1, ), dtype=np.int_),
        'Z': np.zeros((nq + 1, ), dtype=np.int_)
    }
    coset_rep_X = coset_rep * log_x
    coset_rep_Y = coset_rep * log_x * log_z
    coset_rep_Z = coset_rep * log_z

    for subset in powerset(stab_gens):
        s = reduce(mul, subset, sp.Pauli())
        wt_counts['I'][(s * coset_rep).weight()] += 1
        wt_counts['X'][(s * coset_rep_X).weight()] += 1
        wt_counts['Y'][(s * coset_rep_Y).weight()] += 1
        wt_counts['Z'][(s * coset_rep_Z).weight()] += 1

    return wt_counts
Exemple #13
0
    def run_hld(self, trials, ds):
        no_error = 0
        total_errors = 0
        for trial in range(trials):

            for key in self.datas:
                self.fnl_errsx[key] = 0
                self.fnl_errsz[key] = 0

            synd_list = ['0'] * self.num_anc * 2
            synd_zeros = '0' * self.num_anc * 2
            corr = sp.Pauli()

            err, synd1, breakpoint = self.run_first_round()
            if len(synd1):
                err, synd2, corr = self.run_second_round(
                    err, synd1, breakpoint)
            else:
                synd2 = dict()
                no_error += 1

            err_fnl = err
            err *= corr

            # run another perfect round to clean the left errors
            synd_fnl = set()
            for i in range(len(self.esm_circuits)):
                subcir = self.esm_circuits[i]
                synd_err = circ2err(subcir, fowler_model(subcir, 0, 0, 0), err,
                                    self.ancillas)
                synd_fnl |= synd_err[0]
                err = synd_err[1]
            err *= self.lut_synd[tuple(sorted(synd_fnl & set(self.q_syndx)))]
            err *= self.lut_synd[tuple(sorted(synd_fnl & set(self.q_syndz)))]

            # # check logical errors
            err_tp = self.singlelogical_error_index(err, self.init_logs)

            for key in err_fnl.x_set:
                self.fnl_errsx[key] = 1
            for key in err_fnl.z_set:
                self.fnl_errsz[key] = 1

            synd_str = self.set_to_list_with_syndromes(synd1, synd2, synd_list)
            if synd_str != synd_zeros:
                if synd_str in ds:
                    if err_tp != np.argmax(ds[synd_str]):
                        total_errors += 1
                elif err_tp != 0:
                    total_errors += 1
                    print(synd1, 'synd1')
                    print(synd2, 'synd2')
                    print(synd_str, 'synd_str')
                    print('not in dataset')

        return (total_errors, no_error)
Exemple #14
0
def mwe(sim, syndromes, stabs, logs):
    """
    Input: where XXXX and ZZZZ stabilisers are violated, respectively.
    Output: minimum-weight Pauli that matches the syndrome.
    """
    # Pauli must be a product of a dumb correction, a logical and a
    # stabiliser:
    dumb_corr = reduce(mul, sim.dumb_correction(syndromes), sp.Pauli())
    all_logs = [reduce(mul, _, sp.Pauli()) for _ in powerset(logs)]

    curr_corr = dumb_corr
    for stab_set in powerset(stabs):
        cs_prod = reduce(mul, stab_set, dumb_corr)
        for log in all_logs:
            test_corr = cs_prod * log
            if test_corr.weight() < curr_corr.weight():
                curr_corr = test_corr

    return curr_corr
Exemple #15
0
    def meas(self, op):
        """
        Here, we measure the eigenvalue of a new operator `op`, which
        we hope has eigenvalue +/- 1.
        This is Gottesman-Knill style. 
        If the new operator is a logical, we return a random bit,
        effectively assuming that the state is uniformly mixed over the
        stabiliser subspace. 
        """
        if type(op) != sp.Pauli:
            raise ValueError("op must be Pauli: " "{} entered.".format(op))

        acom_stabs = [_ for _ in self.stabs if _.com(op)]
        acom_logs = [_ for _ in self.logs if _.com(op)]

        if not (self.stabs) and not (self.logs):
            self.stabs.append(op)
        elif not (acom_stabs):
            try:
                aug_mat = self._augmented_matrix(op)
                # decomp = gf2.solve_augmented(aug_mat)
                decomp = _c_solve_augmented(aug_mat)
                s = prod([a for a, b in zip(self.stabs, decomp) if b])
                comparison = s * op
                assert comparison.weight() == 0
                return -1 if comparison.ph else 1  # UNSAFE
            except:  # inconsistent system, we assume
                # stab_log_mat = np.vstack(
                # [pauli2vec(s, self.qubits) for s in self.stabs + self.logs]
                # ).T
                # aug_mat = np.hstack([stab_log_mat, pauli2vec(op, self.qubits).T])
                # decomp = gf2.solve_augmented(aug_mat)
                meas_result = 2 * randint(2) - 1
                # eliminate the proper logicals from self.logs
                if len(self.logs) > 2:
                    raise NotImplementedError(
                        "Logical measurements in k > 1 codes not supported.")
                self.logs = []
                self.stabs.append(meas_result * op)
                return meas_result

        else:
            acom_p = (acom_stabs + acom_logs)[0]
            for p in acom_logs:
                self.logs.remove(p)
                if p != acom_p:
                    self.logs.append(acom_p * p)
            for p in acom_stabs:
                self.stabs.remove(p)
                if p != acom_p:
                    self.stabs.append(acom_p * p)
            meas_result = 2 * randint(2) - 1
            self.stabs.append(sp.Pauli(op.x_set, op.z_set, meas_result - 1))
            return meas_result
    def path_pauli(self, crd_0, crd_1, err_type):
        """
        Returns a minimum-length Pauli between two ancillas, given the
        type of error that joins the two.

        This function is awkward, because it works implicitly on the
        un-rotated surface code, first finding a "corner" (a place on
        the lattice for the path to turn 90 degrees), then producing
        two diagonal paths on the rotated lattice that go to and from
        this corner.
        """

        mid_v = diag_intersection(crd_0, crd_1, self.ancillas.values())

        pth_0, pth_1 = diag_pth(crd_0, mid_v), diag_pth(mid_v, crd_1)

        #path on lattice, uses idxs
        p = [self.map[crd] for crd in list(pth_0) + list(pth_1)]

        pl = sp.Pauli(p, []) if err_type == 'X' else sp.Pauli([], p)

        return pl
Exemple #17
0
def int_to_pauli(intgr, lbl_lst):
    """
    This one needs a little explaining. I convert every integer with
    an even number of bits to a Pauli by splitting the integer into a
    left (big) half and a right (small) half. 
    Locations where the left half is 1 are elements of the `x_set`.
    Locations where the right half is 1 are elements of the `z_set`.
    """
    bits = bin(intgr)[2:].zfill(2 * len(lbl_lst))
    xs, zs = bits[:len(lbl_lst)], bits[len(lbl_lst):]
    return sp.Pauli({l
                     for l, b in zip(lbl_lst, xs) if b == '1'},
                    {l
                     for l, b in zip(lbl_lst, zs) if b == '1'})
Exemple #18
0
    def run_first_round(self):
        err = sp.Pauli()
        synd1 = set()
        for i in range(2):

            subcir = self.esm_circuits[i]
            synd_err = circ2err(
                subcir, fowler_model(subcir, self.p1, self.p1, self.p1,
                                     self.pI), err, self.ancillas)
            synd1 |= synd_err[0]
            err = synd_err[1]
            if len(synd1):
                # if there is a syndrome or a flag, then stop this round
                break
        return (err, synd1, i)
    def stabilisers(self):
        """
        Sometimes it's convenient to have the stabilisers of a surface
        code, especially when doing a 2d example.
        """
        x_stabs, z_stabs = {}, {}

        #TODO: Fix Copypasta, PEP8 me.

        for crd_tag, shft_tag in zip(['x_sq', 'x_top', 'x_bot'],
                                     ['A', 'S', 'N']):
            for crd in self.ancillas[crd_tag]:
                pauli = sp.Pauli(
                    x_set=[self.map[ad(crd, dx)] for dx in SHIFTS[shft_tag]])
                x_stabs[self.map[crd]] = pauli

        for crd_tag, shft_tag in zip(['z_sq', 'z_left', 'z_right'],
                                     ['A', 'E', 'W']):
            for crd in self.ancillas[crd_tag]:
                pauli = sp.Pauli(
                    z_set=[self.map[ad(crd, dx)] for dx in SHIFTS[shft_tag]])
                z_stabs[self.map[crd]] = pauli

        return {'X': x_stabs, 'Z': z_stabs}
Exemple #20
0
    def err_synd_parallel(self):
        # reset all the syndromes and errs to be 0

        for key in self.ancillas:
            self.synds1[key] = 0
            self.synds2[key] = 0
        for key in self.datas:
            self.fnl_errsx[key] = 0
            self.fnl_errsz[key] = 0

        corr = sp.Pauli()
        synd2 = set()

        err, synd1 = self.run_first_round()

        if len(synd1):
            err, synd2, corr = self.run_second_round(err, synd1)

        err_fnl = err
        err *= corr
        # run another perfect round to clean the left errors
        synd_fnl = set()
        for i in range(len(self.esm_circuits)):
            subcir = self.esm_circuits[i]
            synd_err = circ2err(subcir, fowler_model(subcir, 0, 0, 0), err,
                                self.ancillas)
            synd_fnl |= synd_err[0]
            err = synd_err[1]

        err *= self.lut_synd[tuple(sorted(synd_fnl & set(self.q_syndx)))]
        err *= self.lut_synd[tuple(sorted(synd_fnl & set(self.q_syndz)))]

        err_tp = singlelogical_error_index(err, self.init_logs)

        for key in synd1:
            self.synds1[key] = 1
        for key in synd2:
            self.synds2[key] = 1

        for key in err_fnl.x_set:
            self.fnl_errsx[key] = 1
        for key in err_fnl.z_set:
            self.fnl_errsz[key] = 1

        fnl_synd = list(self.synds1.values()) + list(self.synds2.values())
        fnl_err = list(self.fnl_errsx.values()) + list(self.fnl_errsz.values())

        return np.array(fnl_synd), np.array(fnl_err), err_tp
Exemple #21
0
    def history(self, final_perfect_rnd=True):
        """
        Produces a list of sparse_pauli.Paulis that track the error 
        through the `n_meas` measurement rounds. 
        """

        #ancillas (for restricting error to data bits)
        ancs = {self.layout.map[anc]
                for anc in sum(self.layout.ancillas.values(), [])}
        err_hist = []
        synd_hist = {'X': [], 'Z': []}
        #perfect (quiescent state) initialization
        err = sp.Pauli() 
        for meas_dx in range(self.n_meas):
            #just the ones
            synd = {'X': set(), 'Z': set()}
            #run circuit
            for stp, mdl in zip(self.extractor, self.gate_error_model):
                #run timestep, then sample
                new_synds, err = cm.apply_step(stp, err)
                err *= product(_.sample() for _ in mdl)
                for ki in synd.keys():
                    synd[ki] |= new_synds[ki][1]
            
            #last round of circuit, because there are n-1 errs, n gates
            new_synds, err = cm.apply_step(self.extractor[-1], err)
            
            for ki in synd.keys():
                synd[ki] |= new_synds[ki][1]

            # remove remaining errors on ancilla qubits before append
            # (they contain no information)
            err.prep(ancs)
            for key in 'XZ':
                synd_hist[key].append(synd[key])
            err_hist.append(err)

        if final_perfect_rnd:
            synd = {'X': set(), 'Z': set()}
            for ki, val in synd.items():
                for idx, stab in self.layout.stabilisers()[ki].items():
                    if err.com(stab) == 1:
                        val |= {idx}
            for key in 'XZ':
                synd_hist[key].append(synd[key])

        return err_hist, synd_hist
Exemple #22
0
    def correction(self, synds, metric=None, bdy_info=None):
        """
        Given a set of recorded syndromes, returns a correction by
        minimum-weight perfect matching.
        In order to 'make room' for correlated decoders, X and Z 
        syndromes are passed in as a single object, and any splitting
        is performed inside this method.
        Also, a single correction Pauli is returned. 
        metric should be a function, so you'll have to wrap a matrix 
        in table-lookup if you want to use one.
        bdy_info is a function that takes a flip and returns the
        distance to the closest boundary point 
        """

        n = self.layout.n
        x = self.layout.map.inv

        if metric is None:
            metric = lambda flp_1, flp_2: self.manhattan_metric(flp_1, flp_2)
        
        if bdy_info is None:
            bdy_info = lambda flp: self.manhattan_bdy_tpl(flp)

        flip_idxs = flat_flips(synds, n)
        
        # Note: 'X' syndromes are XXXX stabiliser measurement results.
        corr = sp.Pauli()
        for stab in 'XZ':
            matching = mwpm(flip_idxs[stab], metric, bdy_info,
                            self.use_blossom, self.ffi, self.blossom)
            
            err = 'X' if stab == 'Z' else 'Z'

            for u, v in matching:
                if isinstance(u, int) & isinstance(v, int):
                    corr *= self.layout.path_pauli(x[u % n], x[v % n], err)
                elif isinstance(u, int) ^ isinstance(v, int):
                    vert = u if isinstance(u, int) else v
                    bdy_pt = bdy_info(vert)[1]
                    corr *= self.layout.path_pauli(bdy_pt, x[vert % n], err)
                else:
                    pass #both boundary points, no correction

        #TODO: Optional return syndrome correction, test inferred syndrome error rate
        return corr
Exemple #23
0
def unique_list():
    distance = 5
    x_anc_len = 12
    test_layout = SCLayoutClass.SCLayout(distance)
    x_stabs = list(test_layout.stabilisers()['X'].values())
    log = test_layout.logicals()[0]
    sim_test = dc.Sim2D(
        distance, distance,
        0.01)  # probability is irrelevant since we provide directly the error
    lst = []
    z_ancs_keys = list(sim_test.layout.z_ancs())
    cycles = 0
    store_s = []
    while len(lst) < 500:
        cycles += 1
        rnd_err = sim_test.random_error()
        #print(rnd_err)
        synds = sim_test.syndromes(rnd_err)
        #print(synds[1])
        dumb_x_corr, dumb_z_corr = sim_test.dumb_correction(synds)
        coset_rep = dumb_x_corr  #sp.Pauli({5,13,22,26,33,42,46},{})
        prob_dist = single_prob(
            weight_dist(x_stabs, sp.Pauli(), log, coset_rep), 0.01)

        list_z = [0] * len(z_ancs_keys)
        for k in synds[1]:
            key = sim_test.layout.map.inv[k]
            pos = z_ancs_keys.index(key)
            list_z[pos] = 1

        s = ''
        for i in range(x_anc_len):
            s += str(list_z[i])

        if s not in store_s:
            store_s.append(s)
            lst.append([s, prob_dist])

        if cycles % 20 == 0:
            print(len(lst), cycles)
            #print('store_s ', store_s)

    for i in range(len(lst)):
        print(lst[i])
Exemple #24
0
    def run_second_round_with_synd_lut(self, err, synd1):
        corr = sp.Pauli()
        synd2 = set()
        for i in range(len(self.esm_circuits)):
            subcir = self.esm_circuits[i]
            synd_err = circ2err(
                subcir, fowler_model(subcir, self.p1, self.p2, self.pm,
                                     self.pI), err, self.ancillas)
            synd2 |= synd_err[0]
            err = synd_err[1]

        # Choose lut decoder based on whether there is a flag, then find corrections
        synd_qx = sorted(synd2 & set(self.q_syndx))
        synd_qz = sorted(synd2 & set(self.q_syndz))

        corr *= self.lut_synd[tuple(synd_qz)]
        corr *= self.lut_synd[tuple(synd_qx)]

        return (err, synd2, corr)
Exemple #25
0
def dist_5_tabulate():
    """
    I only intend to run this function once, it's going to pickle all
    the weight_dist's for a distance-5 code correcting x errors.
    """
    anc_lst = [0, 1, 8, 10, 18, 20, 28, 30, 38, 40, 47, 48]
    sim_5 = dc.Sim2D(5, 5, 0.01)
    log_x, log_z = sim_5.layout.logicals()
    x_stabs = list(sim_5.layout.stabilisers()['X'].values())
    weight_dict = {}
    blsm_cosets = {}
    for subset in powerset(anc_lst):
        coset_rep = sim_5.dumb_correction([[], list(subset)], origin=True)[0]
        blsm_corr = sim_5.graphAndCorrection(subset, 'X')
        key = synd_to_bits(subset, anc_lst)
        val = weight_dist(x_stabs, sp.Pauli(), log_x, coset_rep)
        weight_dict[key] = val
        blsm_cosets[key] = (blsm_corr * coset_rep).com(log_z)

    with open('weight_counts_5.pkl', 'w') as phil:
        pkl.dump(weight_dict, phil)

    with open('blsm_cosets_5.pkl', 'w') as phil:
        pkl.dump(blsm_cosets, phil)
Exemple #26
0
    flp = [0] * no_anc
    flips_Z = [0] * (d + 1)
    for i in range(d + 1):
        flips_Z[i] = deepcopy(flp)
    no_samples = 10000
    sim_test2d = dc2.Sim2D(d, d, p)
    sim_test = dc3.Sim3D(d, d, ('fowler', p), True)
    #err = sim_test.run(no_samples, progress=False, metric=None, bdy_info=None, final_perfect_rnd=True)
    #print(err)

    #calc_parity_3d(dist, meas_rnds, model, use_blossom)

    for cycl in range(1000000):
        err, synd = sim_test.history(True)
        rnd_err = err[2].x_set
        rd_er = sp.Pauli(rnd_err, [])
        corr_blossom = sim_test.correction(synd, metric=None, bdy_info=None)
        mwpm_log_err = sim_test.logical_error(err[-1], corr_blossom)
        synds_2d = sim_test2d.syndromes(rd_er)
        dumb_x_corr, dumb_z_corr = sim_test2d.dumb_correction(synds_2d, False)
        dumb_log_err = sim_test2d.logical_error(rd_er, dumb_x_corr,
                                                dumb_z_corr)

        for j in range(d + 1):
            for i in range(no_anc):
                if (z_ancs[i] in synd['Z'][j] and z_ancs[i] in synd['Z'][j+1]) or \
                   (z_ancs[i] not in synd['Z'][j] and z_ancs[i] not in synd['Z'][j+1]):
                    flips_Z[j][i] = 0
                else:
                    flips_Z[j][i] = 1
    def __init__(self, cir_index=2, steane=True):

        self.cir_index = cir_index
        if cir_index == 'c1_l1' or cir_index == 'c1_l2':
            # for cir_steane2,3
            self.q_synd = [9, 11, 13, 80, 100, 120]
            self.q_flag = [8, 10, 12, 90, 110, 130]
        elif cir_index == 'c2_l1' or cir_index == 'c2_l2':
            # for cir_steane4,5,6
            self.q_synd = [8, 10, 12, 80, 100, 120]
            if cir_index == 'c2_l1':
                self.q_flag = [9, 13, 14, 90, 130, 140]
            else:
                self.q_flag = [9, 13, 90, 130]
        elif cir_index == 'c3_l2':
            # for cir_steane7,8
            self.q_synd = [8, 10, 12, 80, 100, 120]
            self.q_flag = [9, 90]

        self.ancillas = self.q_synd + self.q_flag

        self.init_stabs = [
            sp.Pauli(x_set=[1, 2, 4, 5]),
            sp.Pauli(x_set=[4, 5, 6, 7]),
            sp.Pauli(x_set=[1, 3, 4, 7]),
            sp.Pauli(z_set=[1, 2, 4, 5]),
            sp.Pauli(z_set=[4, 5, 6, 7]),
            sp.Pauli(z_set=[1, 3, 4, 7])
        ]
        self.init_logs = [
            sp.Pauli(x_set=[1, 2, 3, 4, 5, 6, 7]),
            sp.Pauli(z_set=[1, 2, 3, 4, 5, 6, 7])
        ]
        self.stabilisers = {
            'X': {
                8: sp.Pauli(x_set=[1, 2, 4, 5]),
                10: sp.Pauli(x_set=[1, 3, 4, 7]),
                12: sp.Pauli(x_set=[4, 5, 6, 7])
            },
            'Z': {
                80: sp.Pauli(z_set=[1, 2, 4, 5]),
                100: sp.Pauli(z_set=[1, 3, 4, 7]),
                120: sp.Pauli(z_set=[4, 5, 6, 7])
            }
        }

        self.two_error = [
            'IX', 'IZ', 'IY', 'XI', 'ZI', 'YI', 'XX', 'XZ', 'XY', 'ZX', 'ZZ',
            'ZY', 'YX', 'YZ', 'YY'
        ]
        self.one_error = ['IX', 'IZ', 'IY']
    def lut_gen(self):
        # generate the look-up-table decocder for steane code

        extractor_x = flatten(self.ft_circuit(tp='X'))
        extractor_z = flatten(self.ft_circuit(tp='Z'))
        print('timesteps number',
              len(self.ft_circuit(tp='X')) + len(self.ft_circuit(tp='Z')))
        print('gate number', len(extractor_x) + len(extractor_z))
        cnot_n = 0
        cnot_nd = 0
        for i in extractor_z + extractor_x:
            if i[0] == 'CNOT':
                cnot_n += 1
                if len(set(self.ancillas) & set(i[1:])) != 2:
                    cnot_nd += 1
        print('cnot number', cnot_n)
        print('cnot on data number', cnot_nd)

        err_synds = circuit_2err2(self.ancillas,
                                  extractor_z,
                                  extractor_x,
                                  two_err=self.two_error,
                                  one_err=None)

        lut_synd = dict()
        lut_flag = dict()
        for synd in err_synds.keys():
            if len(synd[0]) + len(synd[1]) == 0:
                pass
            else:
                synd_r1 = set(synd[0]) | set(synd[1])
                synd_r2 = set(synd[2]) | set(synd[3])
                err_minx = self.init_logs[0]
                err_minz = self.init_logs[1]
                for qbt in err_synds[synd]:
                    err = sp.Pauli(x_set=qbt[0])
                    if err.weight() < err_minx.weight():
                        err_minx = err
                for qbt in err_synds[synd]:
                    err = sp.Pauli(z_set=qbt[1])
                    if err.weight() < err_minz.weight():
                        err_minz = err
                synd_r2 = [set(synd[2]), set(synd[3])]
                err_mins = [err_minz, err_minx]
                if synd_r1 & set(self.q_flag):
                    # if flag1 flags
                    flag1 = tuple(synd_r1 & set(self.q_flag))
                    if flag1 not in lut_flag.keys():
                        lut_flag[flag1] = dict()

                    for i in range(len(synd_r2)):  # loop through X and Z
                        flag_key = tuple(sorted(synd_r2[i]))
                        if flag_key not in lut_flag[flag1]:
                            lut_flag[flag1][flag_key] = err_mins[i]
                        else:
                            if err_mins[i] != lut_flag[flag1][flag_key]:
                                for log in self.init_logs:
                                    if (err_mins[i] * lut_flag[flag1][flag_key]
                                        ).com(log):
                                        print('synd is', str(flag_key))
                                        print(err_mins[i])
                                        print(lut_flag[flag1][flag_key])
                                        print(err_synds)
                                        raise (
                                            'Possibly not distingushed syndromes'
                                        )
                            else:
                                pass
                elif synd_r1 & set(self.q_synd):

                    for i in range(len(synd_r2)):
                        #                        print(synd_r2,'synd_r2')
                        synd_key = tuple(sorted(synd_r2[i]))
                        #                        print(synd_key,'synd_key')
                        if synd_key not in lut_synd:
                            lut_synd[synd_key] = err_mins[i]
                        else:
                            for log in self.init_logs:
                                if err_mins[i] != lut_synd[synd_key]:

                                    if (err_mins[i] *
                                            lut_synd[synd_key]).com(log):
                                        print(err_synds)
                                        print('synd is', synd_key)
                                        print(err_mins[i])
                                        print(lut_synd[synd_key])
                                        raise (
                                            'Possibly not distingushed syndromes'
                                        )

        # Add other pairs of syndrome:error for flag cases
        for flag in lut_flag.keys():
            for synd in lut_synd.keys():
                if synd not in lut_flag[flag].keys():
                    lut_flag[flag][synd] = lut_synd[synd]

        return lut_synd, lut_flag
    def run(self):

        extractor_x = flatten(self.ft_circuit(tp='X'))
        extractor_z = flatten(self.ft_circuit(tp='Z'))
        err_synds = circuit_2err2(self.ancillas,
                                  extractor_z,
                                  extractor_x,
                                  two_err=self.two_error,
                                  one_err=None)
        ft_value = 0
        for synd_list in err_synds:
            for i in err_synds[synd_list]:
                if len(i[0]) == 2 or len(i[1]) == 2:

                    if (set(synd_list[0]) | set(synd_list[1])) & set(
                            self.q_flag):
                        pass
                    else:
                        print('synds are', synd_list)
                        print('errs are', i)
                        raise ('two errors but no flags')
                        # print((set(synd_list[0]) | set(synd_list[1])) & set(self.q_flag))

            if len(err_synds[synd_list]) > 1:
                for i in range(len(err_synds[synd_list]) - 1):
                    for j in range(i + 1, len(err_synds[synd_list])):
                        err1 = sp.Pauli()
                        err2 = sp.Pauli()
                        err1 *= sp.Pauli(err_synds[synd_list][i][0],
                                         err_synds[synd_list][i][1])
                        err2 *= sp.Pauli(err_synds[synd_list][j][0],
                                         err_synds[synd_list][j][1])

                        # check the fault-tolerance by checking whether the multiplication of two errors
                        # is a logical. This should be ok for esm circuit checking, but how about logical gates
                        for stab in self.init_stabs:
                            if (err1 * err2).com(stab):
                                ft_value = 0
                                print(
                                    'One case that errors are going to be a logical'
                                )
                                print(synd_list, err_synds[synd_list])
                                return ft_value
                            else:
                                pass

                        if (err1 * err2).com(self.init_logs[0]):
                            ft_value = 0
                            print('One case that could cause a logical error')
                            print(synd_list, err_synds[synd_list])
                            return ft_value
                        elif (err1 * err2).com(self.init_logs[1]):
                            ft_value = 0
                            print('One case that could cause a logical error')
                            print(synd_list, err_synds[synd_list])
                            return ft_value
                        else:
                            ft_value = 1
            else:
                ft_value = 1

        return ft_value
    def __init__(self, cir_index=2):

        self.stabilisers = {'X': {8: sp.Pauli(x_set=[1,2,4,5]),
                                  10: sp.Pauli(x_set=[1,3,4,7]),
                                  12:  sp.Pauli(x_set=[4,5,6,7])},
                            'Z': {80: sp.Pauli(z_set=[1,2,4,5]),
                                  100: sp.Pauli(z_set=[1,3,4,7]),
                                  120:  sp.Pauli(z_set=[4,5,6,7])}}

        if cir_index == 'IBM_11':
            self.q_synd = [8,9,10,80,90,100]
            self.q_flag = [11, 110]
            self.q_syndx = [80, 90, 100]
            self.q_syndz = [8, 9, 10]

        elif cir_index == 'IBM_12':
            self.q_synd = [8,10,12,80,100,120]
            self.q_flag = [9,11,90,110]
            self.q_syndx = [80,100,120]
            self.q_syndz = [8,10,12]

        elif cir_index == 'IBM_13':
            self.q_flag = [8,10,12,80,100,120]
            self.q_synd = [130, 110, 90, 9, 11, 13]
            self.q_syndx = [130,110,90]
            self.q_syndz = [9, 11, 13]

        elif cir_index == 's17_33':
            self.q_synd = [8,10,11, 80,100,110]
            self.q_flag = [90, 120, 130, 9, 12, 13]
            self.q_syndx = [80, 100, 110]
            self.q_syndz = [8, 10, 11]

        elif cir_index == 's17_222':
            self.q_synd = [9,11,13,90,110,130]
            self.q_flag = [80, 100, 120, 8, 10, 12]
            self.q_syndx = [90, 110, 130]
            self.q_syndz = [9, 11, 13]

        elif cir_index == 's17_13':
            self.q_synd = [9,11,13,90,110,130]
            self.q_flag = [80, 100, 120, 8, 10, 12]
            self.q_syndx = [9, 11, 13]
            self.q_syndz = [90, 110, 130]

        self.cir_index = cir_index

        self.ancillas = self.q_synd + self.q_flag

        self.init_stabs = [sp.Pauli(x_set=[1,2,4,5]), 
                           sp.Pauli(x_set=[4,5,6,7]), 
                           sp.Pauli(x_set=[1,3,4,7]), 
                           sp.Pauli(z_set=[1,2,4,5]), 
                           sp.Pauli(z_set=[4,5,6,7]), 
                           sp.Pauli(z_set=[1,3,4,7])]
        
        self.init_logs = [sp.Pauli(x_set=[1,2,3,4,5,6,7]),
                          sp.Pauli(z_set=[1,2,3,4,5,6,7])]

                
        
        self.two_error = ['IX', 'IZ', 'IY', 'XI', 'ZI', 'YI', 'XX', 'XZ', 
                          'XY','ZX', 'ZZ', 'ZY', 'YX', 'YZ', 'YY']
        self.one_error = ['IX', 'IZ', 'IY']

        self.flat_circuit = self.circuit_and_statistics()