def transcoding_cliffords(self, other): r""" Returns an iterator onto all :class:`qecc.Clifford` objects which take states specified by ``self``, and return states specified by ``other``. :arg other: :class:`qecc.StabilizerCode` """ #Preliminaries: stab_in = self.group_generators stab_out = other.group_generators xs_in = self.logical_xs xs_out = other.logical_xs zs_in = self.logical_zs zs_out = other.logical_zs nq_in = len(stab_in[0]) nq_out = len(stab_out[0]) nq_anc = abs(nq_in - nq_out) #Decide left side: if nq_in < nq_out: stab_left = stab_out xs_left = xs_out zs_left = zs_out stab_right = stab_in xs_right = xs_in zs_right = zs_in else: stab_right = stab_out xs_right = xs_out zs_right = zs_out stab_left = stab_in xs_left = xs_in zs_left = zs_in cliff_xouts_left = stab_left + xs_left cliff_zouts_left = [Unspecified] * len(stab_left) + zs_left cliff_left = next( c.Clifford(cliff_xouts_left, cliff_zouts_left).constraint_completions()) list_left = cliff_left.xout + cliff_left.zout for mcset in p.mutually_commuting_sets(n_elems=len(stab_left) - len(stab_right), n_bits=nq_anc): temp_xouts_right = p.pad(stab_right, lower_right=mcset) + [ elem & p.eye_p(nq_anc) for elem in xs_right ] temp_zouts_right = [Unspecified] * len(stab_left) + [ elem & p.eye_p(nq_anc) for elem in zs_right ] for completion in c.Clifford( temp_xouts_right, temp_zouts_right).constraint_completions(): if nq_in < nq_out: yield c.gen_cliff(completion.xout + completion.zout, list_left) else: yield c.gen_cliff(list_left, completion.xout + completion.zout)
def encoding_cliffords(self): r""" Returns an iterator onto all Clifford operators that encode into this stabilizer code, starting from an input register such that the state to be encoded is a state of the first :math:`k` qubits, and such that the rest of the qubits in the input register are initialized to :math:`\left|0\right\rangle`. :yields: instances ``C`` of :class:`qecc.Clifford` such that ``C(q.StabilizerCode.unencoded_state(k, n - k))`` equals this code. """ C = c.Clifford(self.logical_xs + ([Unspecified] * self.n_constraints), self.logical_zs + self.group_generators) return C.constraint_completions()
def as_clifford(self): """ Converts a Pauli into a Clifford which changes the signs of input Paulis. :returns: A Clifford representing conjugation by this Pauli operator. :rtype: :class:`qecc.Clifford` """ Xs, Zs = elem_gens(len(self)) for P in chain(Xs, Zs): if com(self, P) == 1: P.mul_phase(2) return cc.Clifford(Xs, Zs)
def star_decoder(self, for_enc=None, as_dict=False): r""" Returns a tuple of a decoding Clifford and a :class:`qecc.PauliList` specifying the recovery operation to perform as a function of the result of a :math:`Z^{\otimes{n - k}}` measurement on the ancilla register. For syndromes corresponding to errors of weight greater than the distance, the relevant element of the recovery list will be set to :obj:`qecc.Unspecified`. :param for_enc: If not ``None``, specifies to use a given Clifford operator as the encoder, instead of the first element yielded by :meth:`encoding_cliffords`. :param bool as_dict: If ``True``, returns a dictionary from recovery operators to syndromes that indicate that recovery. """ def error_to_pauli(error): if error == p.I.as_clifford(): return "I" if error == p.X.as_clifford(): return "X" if error == p.Y.as_clifford(): return "Y" if error == p.Z.as_clifford(): return "Z" if for_enc is None: encoder = next(self.encoding_cliffords()) else: encoder = for_enc decoder = encoder.inv() errors = pc.PauliList(p.eye_p(self.nq)) + pc.PauliList( p.paulis_by_weight(self.nq, self.n_correctable)) syndrome_dict = defaultdict(lambda: Unspecified) syndrome_meas = [ p.elem_gen(self.nq, idx, 'Z') for idx in range(self.nq_logical, self.nq) ] for error in errors: effective_gate = decoder * error.as_clifford() * encoder # FIXME: the following line emulates measurement until we have a real # measurement simulation method. syndrome = tuple( [effective_gate(meas).ph / 2 for meas in syndrome_meas]) recovery = "".join([ # FIXME: the following is a broken hack to get the phases on the logical qubit register. error_to_pauli( c.Clifford([effective_gate.xout[idx][idx]], [effective_gate.zout[idx][idx]])) for idx in range(self.nq_logical) ]) # For degenerate codes, the syndromes can collide, so long as we # correct the same way for each. if syndrome in syndrome_dict and syndrome_dict[ syndrome] != recovery: raise RuntimeError( 'Syndrome {} has collided.'.format(syndrome)) syndrome_dict[syndrome] = recovery if as_dict: outdict = dict() keyfn = lambda syndrome_recovery: syndrome_recovery[1] data = sorted(list(syndrome_dict.items()), key=keyfn) for recovery, syndrome_group in it.groupby(data, keyfn): outdict[recovery] = [syn[0] for syn in syndrome_group] return decoder, outdict else: recovery_list = pc.PauliList( syndrome_dict[syndrome] for syndrome in it.product(list(range(2)), repeat=self.n_constraints)) return decoder, recovery_list