コード例 #1
0
ファイル: PauliClass.py プロジェクト: silky/python-quaec
    def centralizer_gens(self, group_gens=None):
        r"""
        Returns the generators of the centralizer group :math:`\mathrm{C}(P)`,
        where :math:`P` is the Pauli operator represented by this instance.
        If ``group_gens`` is specified, :math:`\mathrm{C}(P)` is taken to be
        a subgroup of the group :math:`G = \langle G_1, \dots, G_k\rangle`,
        where :math:`G_i` is the :math:`i^{\text{th}}` element of
        ``group_gens``.
        
        :param group_gens: Either ``None`` or a list of generators :math:`G_i`.
            If not ``None``, the returned centralizer :math:`\mathrm{C}(P)` is
            a subgroup of the group :math:`\langle G_i \rangle_{i=1}^k`.
        :type group_gens: list of :class:`qecc.Pauli` instances
        :returns: A list of elements :math:`P_i` of the Pauli group such that
            :math:`\mathrm{C}(P) = \langle P_i \rangle_{i=1}^{n}`, where
            :math:`n` is the number of unique generators of the centralizer.
        """
        if group_gens is None:
            Xs, Zs = elem_gens(len(self))
            group_gens = Xs + Zs

        if not group_gens:  # If group_gens is empty, it's false-y.
            return PauliList()

        if com(self, group_gens[0]) == 0:
            # That generator commutes, and so we pass it along
            # unmodified.
            return PauliList(group_gens[0],
                             *self.centralizer_gens(group_gens[1:]))
        else:
            # That generator anticommutes, and so we must modify it by
            # multiplication with another anticommuting generator, if one
            # exists.
            found = False
            for idx in range(1, len(group_gens)):
                if com(self, group_gens[idx]) == 1:
                    found = True
                    g_prime = group_gens[idx] * group_gens[0]
                    assert com(self, g_prime) == 0
                    return PauliList(g_prime,
                                     *self.centralizer_gens(group_gens[1:]))
            if not found:
                # Generator 0 anticommuted, and so we know two things
                # from our search:
                #     - All other generators commute.
                #     - The anticommuting generator (0) has no match, and must
                #       be excluded.
                return PauliList(*group_gens[1:])
コード例 #2
0
ファイル: PauliClass.py プロジェクト: silky/python-quaec
def clifford_bottoms(c_top):
    r"""
    This function yields the next set of nq paulis that mutually 
    commute, and anti-commute with selected elements from c_top. The intent
    behind this function is to begin with a list of mutually commuting Paulis, 
    and ifnd an associated set that share the same commutation relations as 
    :math:`\left[ X_1,\ldots,X_n \range]` and 
    :math:`\left[ Z_1,\ldots,Z_n \range]`. This allows the input and output of 
    this function can be thought of as the :math:`X` and :math:`Z` outputs of a
    Clifford operator. 
    
    :param c_top: list of :class:`qecc.Pauli` objects, which mutually commute. 
    """
    nq = len(c_top)
    possible_zs = []
    for jj in range(nq):
        applicable_centralizer_gens = PauliList(
            *(c_top[:jj] + c_top[jj + 1:])).centralizer_gens()
        possible_zs.append(
            filter(lambda a: com(a, c_top[jj]) == 1,
                   from_generators(applicable_centralizer_gens)))
    for possible_set in product(*possible_zs):
        if all(
                imap(
                    lambda twolist: pred.commutes_with(twolist[0])(twolist[1]),
                    combinations(possible_set, 2))):
            yield possible_set
コード例 #3
0
ファイル: CliffordClass.py プロジェクト: silky/python-quaec
    def __init__(self, xbars, zbars):
        # Require that all specified operators be Paulis.
        # Moreover, we should warn the caller if the output phase is not either
        # 0 or 2, since such operators are not automorphisms of the Pauli group.
        self.xout = PauliList(*xbars)
        self.zout = PauliList(*zbars)

        for output_xz in chain(self.xout, self.zout):
            if output_xz is not Unspecified and output_xz.ph not in [0, 2]:
                warnings.warn(
                    'The output phase of a Clifford operator has been specified as {}, such that the operator is not a valid automorphism.\n'
                    .format(output_xz.ph) +
                    'To avoid this warning, please choose all output phases to be from the set {0, 2}.'
                )

        # Prevent fully unspecified operators.
        if all([P is Unspecified for P in chain(xbars, zbars)]):
            raise ValueError("At least one output must be specified.")
コード例 #4
0
def elem_gens(nq):
    """
    Produces all weight-one :math:`X` and :math:`Z` operators on `nq` qubits.
    For example,
    
    >>> import qecc as q
    >>> Xgens, Zgens = q.elem_gens(2)
    >>> print Xgens[1]
    i^0 IX
    
    :param int nq: Number of qubits for each returned operator.
    
    :returns: a tuple of two lists, containing :math:`X` and :math:`Z`
        generators, respectively.
    """
    return tuple(PauliList(*[elem_gen(nq,idx,P) for idx in range(nq)]) for P in ['X','Z'])
コード例 #5
0
ファイル: CliffordClass.py プロジェクト: silky/python-quaec
    def __call__(self, other):
        if isinstance(other, Pauli):
            return self.conjugate_pauli(other)

        elif isinstance(other, str):
            return self.conjugate_pauli(Pauli(other))

        elif isinstance(other, PauliList):
            return PauliList(*map(self, other))

        elif isinstance(other, stab.StabilizerCode):
            return stab.StabilizerCode(self(other.group_generators),
                                       self(other.logical_xs),
                                       self(other.logical_zs))

        else:
            return NotImplemented
コード例 #6
0
def solve_commutation_constraints(
        commutation_constraints=[],
        anticommutation_constraints=[],
        search_in_gens=None,
        search_in_set=None
    ):
    r"""
    Given commutation constraints on a Pauli operator, yields an iterator onto
    all solutions of those constraints.
    
    :param commutation_constraints: A list of operators :math:`\{A_i\}` such
        that each solution :math:`P` yielded by this function must satisfy
        :math:`[A_i, P] = 0` for all :math:`i`.
    :param anticommutation_constraints: A list of operators :math:`\{B_i\}` such
        that each solution :math:`P` yielded by this function must satisfy
        :math:`\{B_i, P\} = 0` for all :math:`i`.
    :param search_in_gens: A list of operators :math:`\{N_i\}` that generate
        the group in which to search for solutions. If ``None``, defaults to
        the elementary generators of the pc.Pauli group on :math:`n` qubits, where
        :math:`n` is given by the length of the commutation and anticommutation
        constraints.
    :param search_in_set: An iterable of operators to which the search for 
        satisfying assignments is restricted. This differs from ``search_in_gens``
        in that it specifies the entire set, not a generating set. When this
        parameter is specified, a brute-force search is executed. Use only
        when the search set is small, and cannot be expressed using its generating
        set. 
    :returns: An iterator ``it`` such that ``list(it)`` contains all operators
        within the group :math:`G = \langle N_1, \dots, N_k \rangle`
        given by ``search_in_gens``, consistent with the commutation and
        anticommutation constraints.
        
    This function is based on finding the generators of the centralizer groups 
    of each commutation constraint, and is thus faster than a predicate-based
    search over the entire group of interest. The resulting iterator can be
    used in conjunction with other filters, however.
    
    >>> import qecc as q
    >>> list(q.solve_commutation_constraints(q.PauliList('XXI', 'IZZ', 'IYI'), q.PauliList('YIY')))
    [i^0 XII, i^0 IIZ, i^0 YYX, i^0 ZYY]
    >>> from itertools import ifilter
    >>> list(ifilter(lambda P: P.wt <= 2, q.solve_commutation_constraints(q.PauliList('XXI', 'IZZ', 'IYI'), q.PauliList('YIY'))))
    [i^0 XII, i^0 IIZ]
    """
        
    # Normalize our arguments to be PauliLists, so that we can obtain
    # centralizers easily.
    if not isinstance(commutation_constraints, PauliList):
        commutation_constraints = PauliList(commutation_constraints)
    if not isinstance(anticommutation_constraints, PauliList):
        # This is probably not necessary, strictly speaking, but it keeps me
        # slightly more sane to have both constraints represented by the same
        # sequence type.
        anticommutation_constraints = PauliList(anticommutation_constraints)

    # Then check that the arguments make sense.
    if len(commutation_constraints) == 0 and len(anticommutation_constraints) == 0:

        raise ValueError("At least one constraint must be specified.")

    #We default to executing a brute-force search if the search set is
    #explicitly specified:
    if search_in_set is not None:
        commutation_predicate = AllPredicate(*map(
            lambda acc: (lambda P: pc.com(P, acc) == 0),
            commutation_constraints
            ))
        commuters = filter(commutation_predicate, search_in_set)
        anticommutation_predicate = AllPredicate(*map(
            lambda acc: (lambda P: pc.com(P, acc) == 1),
            anticommutation_constraints
            ))
        return filter(anticommutation_predicate, commuters)

    # We finish putting arguments in the right form by defaulting to searching
    # over the pc.Pauli group on $n$ qubits.
    if search_in_gens is None:
        nq = len(commutation_constraints[0] if len(commutation_constraints) > 0 else anticommutation_constraints[0])
        Xs, Zs = pc.elem_gens(nq)
        search_in_gens = Xs + Zs
    
    # Now we update our search by restricting to the centralizer of the
    # commutation constraints.
    search_in_gens = commutation_constraints.centralizer_gens(group_gens=search_in_gens)
    
    # Finally, we return a filter iterator on the elements of the given
    # centralizer that selects elements which anticommute appropriately.
    anticommutation_predicate = AllPredicate(*map(
        lambda acc: (lambda P: pc.com(P, acc) == 1),
        anticommutation_constraints
        ))
    assert len(search_in_gens) > 0
    return ifilter(anticommutation_predicate, pc.from_generators(search_in_gens))