예제 #1
0
    def linear_approximation_matrix(self):
        """
        Return linear approximation matrix ``A`` for this S-box.

        Let ``i_b`` be the ``b``-th bit of ``i`` and ``o_b`` the
        ``b``-th bit of ``o``. Then ``v = A[i,o]`` encodes the bias of
        the equation ``sum( i_b * x_i ) = sum( o_b * y_i )`` if
        ``x_i`` and ``y_i`` represent the input and output variables
        of the S-box.

        See [He2002]_ for an introduction to linear cryptanalysis.

        EXAMPLES::

            sage: from sage.crypto.sbox import SBox
            sage: S = SBox(7,6,0,4,2,5,1,3)
            sage: S.linear_approximation_matrix()
            [ 4  0  0  0  0  0  0  0]
            [ 0  0  0  0  2  2  2 -2]
            [ 0  0 -2 -2 -2  2  0  0]
            [ 0  0 -2  2  0  0 -2 -2]
            [ 0  2  0  2 -2  0  2  0]
            [ 0 -2  0  2  0  2  0  2]
            [ 0 -2 -2  0  0 -2  2  0]
            [ 0 -2  2  0 -2  0  0 -2]

        According to this matrix the first bit of the input is equal
        to the third bit of the output 6 out of 8 times::

            sage: for i in srange(8): print(S.to_bits(i)[0] == S.to_bits(S(i))[2])
            False
            True
            True
            True
            False
            True
            True
            True
        """
        m = self.m
        n = self.n

        nrows = 1<<m
        ncols = 1<<n

        B = BooleanFunction(self.m)
        L = []
        for j in range(ncols):
            for i in range(nrows):
                B[i] = ZZ(self(i)&j).popcount()
            L.append(B.walsh_hadamard_transform())

        A = Matrix(ZZ, ncols, nrows, L)
        A = -A.transpose()/2
        A.set_immutable()

        return A
예제 #2
0
파일: sbox.py 프로젝트: mcognetta/sage
    def linear_approximation_matrix(self):
        """
        Return linear approximation matrix ``A`` for this S-box.

        Let ``i_b`` be the ``b``-th bit of ``i`` and ``o_b`` the
        ``b``-th bit of ``o``. Then ``v = A[i,o]`` encodes the bias of
        the equation ``sum( i_b * x_i ) = sum( o_b * y_i )`` if
        ``x_i`` and ``y_i`` represent the input and output variables
        of the S-box.

        See [He2002]_ for an introduction to linear cryptanalysis.

        EXAMPLES::

            sage: from sage.crypto.sbox import SBox
            sage: S = SBox(7,6,0,4,2,5,1,3)
            sage: S.linear_approximation_matrix()
            [ 4  0  0  0  0  0  0  0]
            [ 0  0  0  0  2  2  2 -2]
            [ 0  0 -2 -2 -2  2  0  0]
            [ 0  0 -2  2  0  0 -2 -2]
            [ 0  2  0  2 -2  0  2  0]
            [ 0 -2  0  2  0  2  0  2]
            [ 0 -2 -2  0  0 -2  2  0]
            [ 0 -2  2  0 -2  0  0 -2]

        According to this matrix the first bit of the input is equal
        to the third bit of the output 6 out of 8 times::

            sage: for i in srange(8): print(S.to_bits(i)[0] == S.to_bits(S(i))[2])
            False
            True
            True
            True
            False
            True
            True
            True
        """
        m = self.m
        n = self.n

        nrows = 1<<m
        ncols = 1<<n

        B = BooleanFunction(self.m)
        L = []
        for j in range(ncols):
            for i in range(nrows):
                B[i] = ZZ(self(i)&j).popcount()
            L.append(B.walsh_hadamard_transform())

        A = Matrix(ZZ, ncols, nrows, L)
        A = -A.transpose()/2
        A.set_immutable()

        return A
예제 #3
0
class HarmonicCocycles(AmbientHeckeModule):
    Element=HarmonicCocycleElement
    r"""
    This object represents a space of Gamma invariant harmonic cocycles valued in
    a cofficient module.

    INPUT:

     - ``X`` - A BTQuotient object
     - ``k`` - integer - The weight.
     - ``prec`` - integer (Default: None). If specified, the precision for the coefficient module
     - ``basis_matrix`` - integer (Default: None)
     - ``base_field`` - (Default: None)

    EXAMPLES:

    ::

    AUTHORS:

    - Cameron Franc (2012-02-20)
    - Marc Masdeu
    """
    def __init__(self,X,k,prec=None,basis_matrix=None,base_field=None):
        self._k=k
        self._X=X
        self._E=self._X.get_edge_list()
        self._V=self._X.get_vertex_list()

        if prec is None:
            self._prec=None
            if base_field is None:
                try:
                    self._R= X.get_splitting_field()
                except AttributeError:
                    raise ValueError, "It looks like you are not using Magma as backend...and still we don't know how to compute splittings in that case!"
            else:
                pol=X.get_splitting_field().defining_polynomial().factor()[0][0]
                self._R=base_field.extension(pol,pol.variable_name()).absolute_field(name='r')
            self._U=OCVn(self._k-2,self._R)
        else:
            self._prec=prec
            if base_field is None:
                self._R=Qp(self._X._p,prec=prec)
            else:
                self._R=base_field
            self._U=OCVn(self._k-2,self._R,self._k-1)
        self.__rank = self._X.dimension_harmonic_cocycles(self._k)
        if basis_matrix is not None:
            self.__matrix=basis_matrix
            self.__matrix.set_immutable()
            assert self.__rank == self.__matrix.nrows()

        AmbientHeckeModule.__init__(self, self._R, self.__rank, self._X.prime()*self._X.Nplus()*self._X.Nminus(), weight=self._k)
        self._populate_coercion_lists_()

    def base_extend(self,base_ring):
        r"""
        This function extends the base ring of the coefficient module.
        
        INPUT:

        - ``base_ring`` - a ring that has a coerce map from the current base ring

        EXAMPLES:

        ::
        """
        if not base_ring.has_coerce_map_from(self.base_ring()):
            raise ValueError, "No coercion defined"
        else:
            return self.change_ring(base_ring)

    def change_ring(self, new_base_ring):
        r"""
        This function changes the base ring of the coefficient module.

        INPUT:

        - ``new_base_ring'' - a ring that has a coerce map from the current base ring

        EXAMPLES:
        ::

        """
        if not new_base_ring.has_coerce_map_from(self.base_ring()):
            raise ValueError, "No coercion defined"
        else:
            return self.__class__(self._X,self._k,prec=self._prec,basis_matrix=self.basis_matrix().change_ring(base_ring),base_field=new_base_ring)

    def rank(self):
        r"""
        The rank (dimension) of ``self``.
        
        EXAMPLES:
        ::

        """
        return self.__rank

    def submodule(self,v,check=False):
        r"""
        Return the submodule of ``self`` spanned by ``v``.

        EXAMPLES:
        """
        return HarmonicCocyclesSubmodule(self,v,dual=None,check=check)

    def is_simple(self):
        r"""
        Whether ``self`` is irreducible.

        EXAMPLES:
        ::

        """
        return self.rank()==1

    def _repr_(self):
        r"""
        This returns the representation of self as a string.
        """
        return 'Space of harmonic cocycles of weight %s on %s'%(self._k,self._X)

    def _latex_(self):
        r"""
        A LaTeX representation of ``self``.

        EXAMPLES:
        ::
        """
        s='\\text{Space of harmonic cocycles of weight }'+latex(self._k)+'\\text{ on }'+latex(self._X)
        return s

    def _an_element_(self):
        r"""

        """
        return self.basis()[0]


    def _coerce_map_from_(self, S):
        r"""
        Can coerce from other HarmonicCocycles or from pAutomorphicForms
        """
        if isinstance(S,(HarmonicCocycles,pAutomorphicForms)):
            if(S._k!=self._k):
                return False
            if(S._X!=self._X):
                return False
            return True
        return False

    def __cmp__(self,other):
        r"""

        """
        try:
            res=(self.base_ring()==other.base_ring() and self._X==other._X and self._k==other._k)
            return res
        except:
            return False

    def _element_constructor_(self,x):
        r"""

        """
        #Code how to coherce x into the space
        #Admissible values of x?
        if isinstance(x,HarmonicCocycleElement):
            return HarmonicCocycleElement(self,x)
        elif isinstance(x,pAutomorphicForm):
            tmp=[self._U.element_class(_parent._U,x._F[ii]).l_act_by(self._E[ii].rep) for ii in range(self._nE)]
            return HarmonicCocycleElement(self,tmp,from_values=True)
        else:
            return HarmonicCocycleElement(self,x)


    def free_module(self):
        r"""
        This function returns the underlying free module

        EXAMPLES:
        ::
        """
        try: return self.__free_module
        except AttributeError: pass
        V = self.base_ring()**self.dimension()
        self.__free_module = V
        return V

    def character(self):
        r"""
        Only implemented the trivial character so far.

        EXAMPLES:

        """
        return lambda x:x

    def embed_quaternion(self,g):
        r"""
        Embed the quaternion element ``g`` into the matrix algebra.

        EXAMPLES:
        ::
        """
        return self._X.embed_quaternion(g,exact = self._R.is_exact(), prec = self._prec)

    def basis_matrix(self):
        r"""
        Returns a basis of ``self`` in matrix form.

        If the coefficient module `M` is of finite rank then the space of Gamma invariant
        `M` valued harmonic cocycles can be represented as a subspace of the finite rank
        space of all functions from the finitely many edges in the corresponding 
        BTQuotient into `M`. This function computes this representation of the space of
        cocycles.

        OUTPUT:

          A basis matrix describing the cocycles in the spaced of all `M` valued Gamma
          invariant functions on the tree.

        EXAMPLES:

        ::

            sage: X = BTQuotient(3,19)
            sage: C = HarmonicCocycles(X,4,prec = 5)
            sage: B = C.basis()
            Traceback (most recent call last):
            ...
            RuntimeError: The computed dimension does not agree with the expectation. Consider increasing precision!

        We try increasing the precision:

        ::

            sage: C = HarmonicCocycles(X,4,prec = 20)
            sage: B = C.basis()
            sage: len(B) == X.dimension_harmonic_cocycles(4)
            True

        AUTHORS:

        - Cameron Franc (2012-02-20)
        - Marc Masdeu (2012-02-20)
        """
        try: return self.__matrix
        except AttributeError: pass
        nV=len(self._V)
        nE=len(self._E)
        stab_conds=[]
        S=self._X.get_edge_stabs()
        p=self._X._p
        d=self._k-1
        for e in self._E:
            try:
                g=filter(lambda g:g[2],S[e.label])[0]
                C=self._U.l_matrix_representation(self.embed_quaternion(g[0]))
                C-=self._U.l_matrix_representation(Matrix(QQ,2,2,p**g[1]))
                stab_conds.append([e.label,C])
            except IndexError: pass

        n_stab_conds=len(stab_conds)
        self._M=Matrix(self._R,(nV+n_stab_conds)*d,nE*d,0,sparse=True)
        for v in self._V:
            for e in filter(lambda e:e.parity==0,v.leaving_edges):
                C=sum([self._U.l_matrix_representation(self.embed_quaternion(x[0])) for x in e.links],Matrix(self._R,d,d,0))
                self._M.set_block(v.label*d,e.label*d,C)
            for e in filter(lambda e:e.parity==0,v.entering_edges):
                C=sum([self._U.l_matrix_representation(self.embed_quaternion(x[0])) for x in e.opposite.links],Matrix(self._R,d,d,0))
                self._M.set_block(v.label*d,e.opposite.label*d,C)

        for kk in range(n_stab_conds):
            v=stab_conds[kk]
            self._M.set_block((nV+kk)*d,v[0]*d,v[1])

        x1=self._M.right_kernel().matrix()

        if x1.nrows() != self.rank():
            raise RuntimeError, 'The computed dimension does not agree with the expectation. Consider increasing precision!'

        K=[c for c in x1.rows()]

        if not self._R.is_exact():
            for ii in range(len(K)):
                s=min([t.valuation() for t in K[ii]])
                for jj in range(len(K[ii])):
                    K[ii][jj]=(p**(-s))*K[ii][jj]

        self.__matrix=Matrix(self._R,len(K),nE*d,K)
        self.__matrix.set_immutable()
        return self.__matrix

    def __apply_atkin_lehner(self,q,f):
        r"""
        This function applies an Atkin-Lehner involution to a harmonic cocycle

        INPUT:

          - ``q`` - an integer dividing the full level p*Nminus*Nplus

          - ``f`` - a harmonic cocycle

        OUTPUT:

          The harmonic cocycle obtained by hitting f with the Atkin-Lehner at q

        EXAMPLES:
        ::
        """
        R=self._R
        Data=self._X._get_atkin_lehner_data(q)
        p=self._X._p
        tmp=[self._U.element_class(self._U,zero_matrix(self._R,self._k-1,1),quick=True) for jj in range(len(self._E))]
        d1=Data[1]
        mga=self.embed_quaternion(Data[0])
        for jj in range(len(self._E)):
            t=d1[jj]
            tmp[jj]+=(t.sign()*f._F[t.label]).l_act_by(p**(-t.power)*mga*t.igamma(self.embed_quaternion))
        return HarmonicCocycleElement(self,tmp,from_values=True)

    def __apply_hecke_operator(self,l,f):
        r"""
        This function applies a Hecke operator to a harmonic cocycle.

        INPUT:

          - ``l`` - an integer

          - ``f`` - a harmonic cocycle

        OUTPUT:

          A harmonic cocycle which is the result of applying the lth Hecke operator
          to f

        EXAMPLES:
        ::

        """
        R=self._R
        HeckeData,alpha=self._X._get_hecke_data(l)
        if(self.level()%l==0):
            factor=QQ(l**(Integer((self._k-2)/2))/(l+1))
        else:
            factor=QQ(l**(Integer((self._k-2)/2)))
        p=self._X._p
        alphamat=self.embed_quaternion(alpha)
        tmp=[self._U.element_class(self._U,zero_matrix(self._R,self._k-1,1),quick=True) for jj in range(len(self._E))]
        for ii in range(len(HeckeData)):
            d1=HeckeData[ii][1]
            mga=self.embed_quaternion(HeckeData[ii][0])*alphamat
            for jj in range(len(self._E)):
                t=d1[jj]
                tmp[jj]+=(t.sign()*f._F[t.label]).l_act_by(p**(-t.power)*mga*t.igamma(self.embed_quaternion))
        return HarmonicCocycleElement(self,[factor*x for x in tmp],from_values=True)

    def _compute_atkin_lehner_matrix(self,d):
        r"""
        When the underlying coefficient module is finite, this function computes the 
        matrix of an Atkin-Lehner involution in the basis provided by the function
        basis_matrix

        INPUT:

          - ``d`` - an integer dividing p*Nminus*Nplus

        OUTPUT:

          The matrix of the AL-involution at d in the basis given by self.basis_matrix

        EXAMPLES:
        ::

        """
        res=self.__compute_operator_matrix(lambda f:self.__apply_atkin_lehner(d,f))
        return res

    def _compute_hecke_matrix_prime(self,l):
        r"""
        When the underlying coefficient module is finite, this function computes the 
        matrix of a (prime) Hecke operator in the basis provided by the function
        basis_matrix

        INPUT:

          - ``l`` - an integer prime

        OUTPUT:

          The matrix of T_l acting on the cocycles in the basis given by 
          self.basis_matrix

        EXAMPLES:
        ::

        """
        res=self.__compute_operator_matrix(lambda f:self.__apply_hecke_operator(l,f))
        return res

    def __compute_operator_matrix(self,T):
        r"""
        Compute the matrix of the operator ``T``.

        EXAMPLES:
        ::

        """
        R=self._R
        A=self.basis_matrix().transpose()
        basis=self.basis()
        B=zero_matrix(R,len(self._E)*(self._k-1),self.dimension())
        for rr in range(len(basis)):
            g=T(basis[rr])
            B.set_block(0,rr,Matrix(R,len(self._E)*(self._k-1),1,[g._F[e]._val[ii,0]  for e in range(len(self._E)) for ii in range(self._k-1) ]))

        try:
            res=(A.solve_right(B)).transpose()
            res.set_immutable()
            return res
        except ValueError:
            print A
            print B
            raise ValueError
예제 #4
0
        def cartan_invariants_matrix(self):
            r"""
            Return the Cartan invariants matrix of the algebra.

            OUTPUT: a matrix of non negative integers

            Let `A` be this finite dimensional algebra and
            `(S_i)_{i\in I}` be representatives of the right simple
            modules of `A`. Note that their adjoints `S_i^*` are
            representatives of the left simple modules.

            Let `(P^L_i)_{i\in I}` and `(P^R_i)_{i\in I}` be
            respectively representatives of the corresponding
            indecomposable projective left and right modules of `A`.
            In particular, we assume that the indexing is consistent
            so that `S_i^*=\operatorname{top} P^L_i` and
            `S_i=\operatorname{top} P^R_i`.

            The *Cartan invariant matrix* `(C_{i,j})_{i,j\in I}` is a
            matrix of non negative integers that encodes much of the
            representation theory of `A`; namely:

            - `C_{i,j}` counts how many times `S_i^*\otimes S_j`
              appears as composition factor of `A` seen as a bimodule
              over itself;

            - `C_{i,j}=\dim Hom_A(P^R_j, P^R_i)`;

            - `C_{i,j}` counts how many times `S_j` appears as
              composition factor of `P^R_i`;

            - `C_{i,j}=\dim Hom_A(P^L_i, P^L_j)`;

            - `C_{i,j}` counts how many times `S_i^*` appears as
              composition factor of `P^L_j`.

            In the commutative case, the Cartan invariant matrix is
            diagonal. In the context of solving systems of
            multivariate polynomial equations of dimension zero, `A`
            is the quotient of the polynomial ring by the ideal
            generated by the equations, the simple modules correspond
            to the roots, and the numbers `C_{i,i}` give the
            multiplicities of those roots.

            .. NOTE::

                For simplicity, the current implementation assumes
                that the index set `I` is of the form
                `\{0,\dots,n-1\}`. Better indexations will be possible
                in the future.

            ALGORITHM:

            The Cartan invariant matrix of `A` is computed from the
            dimension of the summands of its peirce decomposition.

            .. SEEALSO::

                - :meth:`peirce_decomposition`
                - :meth:`isotypic_projective_modules`

            EXAMPLES:

            For a semisimple algebra, in particular for group algebras
            in chararacteristic zero, the Cartan invariants matrix is
            the identity::

                sage: A3 = SymmetricGroup(3).algebra(QQ)
                sage: A3.cartan_invariants_matrix()
                [1 0 0]
                [0 1 0]
                [0 0 1]

            For the path algebra of a quiver, the Cartan invariants
            matrix counts the number of paths between two vertices::

                sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example()
                sage: A.cartan_invariants_matrix()
                [1 2]
                [0 1]

            In the commutative case, the Cartan invariant matrix is diagonal::

                sage: Z12 = Monoids().Finite().example(); Z12
                An example of a finite multiplicative monoid: the integers modulo 12
                sage: A = Z12.algebra(QQ)
                sage: A.cartan_invariants_matrix()
                [1 0 0 0 0 0 0 0 0]
                [0 1 0 0 0 0 0 0 0]
                [0 0 2 0 0 0 0 0 0]
                [0 0 0 1 0 0 0 0 0]
                [0 0 0 0 2 0 0 0 0]
                [0 0 0 0 0 1 0 0 0]
                [0 0 0 0 0 0 1 0 0]
                [0 0 0 0 0 0 0 2 0]
                [0 0 0 0 0 0 0 0 1]

            With the algebra of the `0`-Hecke monoid::

                sage: from sage.monoids.hecke_monoid import HeckeMonoid
                sage: A = HeckeMonoid(SymmetricGroup(4)).algebra(QQ)
                sage: A.cartan_invariants_matrix()
                [1 0 0 0 0 0 0 0]
                [0 2 1 0 1 1 0 0]
                [0 1 1 0 1 0 0 0]
                [0 0 0 1 0 1 1 0]
                [0 1 1 0 1 0 0 0]
                [0 1 0 1 0 2 1 0]
                [0 0 0 1 0 1 1 0]
                [0 0 0 0 0 0 0 1]
            """
            from sage.rings.integer_ring import ZZ
            A_quo = self.semisimple_quotient()
            idempotents_quo = A_quo.central_orthogonal_idempotents()
            # Dimension of simple modules
            dim_simples = [A_quo.principal_ideal(e).dimension().sqrt()
                          for e in idempotents_quo]
            # Orthogonal idempotents
            idempotents = self.orthogonal_idempotents_central_mod_radical()
            def C(i,j):
                summand = self.peirce_summand(idempotents[i], idempotents[j])
                return summand.dimension() / (dim_simples[i]*dim_simples[j])
            m = Matrix(ZZ, len(idempotents), C)
            m.set_immutable()
            return m
        def cartan_invariants_matrix(self):
            r"""
            Return the Cartan invariants matrix of the algebra.

            OUTPUT: a matrix of non negative integers

            Let `A` be this finite dimensional algebra and
            `(S_i)_{i\in I}` be representatives of the right simple
            modules of `A`. Note that their adjoints `S_i^*` are
            representatives of the left simple modules.

            Let `(P^L_i)_{i\in I}` and `(P^R_i)_{i\in I}` be
            respectively representatives of the corresponding
            indecomposable projective left and right modules of `A`.
            In particular, we assume that the indexing is consistent
            so that `S_i^*=\operatorname{top} P^L_i` and
            `S_i=\operatorname{top} P^R_i`.

            The *Cartan invariant matrix* `(C_{i,j})_{i,j\in I}` is a
            matrix of non negative integers that encodes much of the
            representation theory of `A`; namely:

            - `C_{i,j}` counts how many times `S_i^*\otimes S_j`
              appears as composition factor of `A` seen as a bimodule
              over itself;

            - `C_{i,j}=\dim Hom_A(P^R_j, P^R_i)`;

            - `C_{i,j}` counts how many times `S_j` appears as
              composition factor of `P^R_i`;

            - `C_{i,j}=\dim Hom_A(P^L_i, P^L_j)`;

            - `C_{i,j}` counts how many times `S_i^*` appears as
              composition factor of `P^L_j`.

            In the commutative case, the Cartan invariant matrix is
            diagonal. In the context of solving systems of
            multivariate polynomial equations of dimension zero, `A`
            is the quotient of the polynomial ring by the ideal
            generated by the equations, the simple modules correspond
            to the roots, and the numbers `C_{i,i}` give the
            multiplicities of those roots.

            .. NOTE::

                For simplicity, the current implementation assumes
                that the index set `I` is of the form
                `\{0,\dots,n-1\}`. Better indexations will be possible
                in the future.

            ALGORITHM:

            The Cartan invariant matrix of `A` is computed from the
            dimension of the summands of its peirce decomposition.

            .. SEEALSO::

                - :meth:`peirce_decomposition`
                - :meth:`isotypic_projective_modules`

            EXAMPLES:

            For a semisimple algebra, in particular for group algebras
            in chararacteristic zero, the Cartan invariants matrix is
            the identity::

                sage: A3 = SymmetricGroup(3).algebra(QQ)
                sage: A3.cartan_invariants_matrix()
                [1 0 0]
                [0 1 0]
                [0 0 1]

            For the path algebra of a quiver, the Cartan invariants
            matrix counts the number of paths between two vertices::

                sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example()
                sage: A.cartan_invariants_matrix()
                [1 2]
                [0 1]

            In the commutative case, the Cartan invariant matrix is diagonal::

                sage: Z12 = Monoids().Finite().example(); Z12
                An example of a finite multiplicative monoid: the integers modulo 12
                sage: A = Z12.algebra(QQ)
                sage: A.cartan_invariants_matrix()
                [1 0 0 0 0 0 0 0 0]
                [0 1 0 0 0 0 0 0 0]
                [0 0 2 0 0 0 0 0 0]
                [0 0 0 1 0 0 0 0 0]
                [0 0 0 0 2 0 0 0 0]
                [0 0 0 0 0 1 0 0 0]
                [0 0 0 0 0 0 1 0 0]
                [0 0 0 0 0 0 0 2 0]
                [0 0 0 0 0 0 0 0 1]

            With the algebra of the `0`-Hecke monoid::

                sage: from sage.monoids.hecke_monoid import HeckeMonoid
                sage: A = HeckeMonoid(SymmetricGroup(4)).algebra(QQ)
                sage: A.cartan_invariants_matrix()
                [1 0 0 0 0 0 0 0]
                [0 2 1 0 1 1 0 0]
                [0 1 1 0 1 0 0 0]
                [0 0 0 1 0 1 1 0]
                [0 1 1 0 1 0 0 0]
                [0 1 0 1 0 2 1 0]
                [0 0 0 1 0 1 1 0]
                [0 0 0 0 0 0 0 1]
            """
            from sage.rings.integer_ring import ZZ

            A_quo = self.semisimple_quotient()
            idempotents_quo = A_quo.central_orthogonal_idempotents()
            # Dimension of simple modules
            dim_simples = [sqrt(A_quo.principal_ideal(e).dimension()) for e in idempotents_quo]
            # Orthogonal idempotents
            idempotents = self.orthogonal_idempotents_central_mod_radical()

            def C(i, j):
                summand = self.peirce_summand(idempotents[i], idempotents[j])
                return summand.dimension() / (dim_simples[i] * dim_simples[j])

            m = Matrix(ZZ, len(idempotents), C)
            m.set_immutable()
            return m