예제 #1
0
        def central_form(self):
            r"""
            Return ``self`` expressed in the canonical basis of the center
            of the group algebra.

            INPUT:

            - ``self`` -- an element of the center of the group algebra

            OUTPUT:

            - A formal linear combination of the conjugacy class
              representatives representing its coordinates in the
              canonical basis of the center. See
              :meth:`Groups.Algebras.ParentMethods.center_basis` for
              details.

            .. WARNING::

                - This method requires the underlying group to
                  have a method ``conjugacy_classes_representatives``
                  (every permutation group has one, thanks GAP!).
                - This method does not check that the element is
                  indeed central. Use the method
                  :meth:`Monoids.Algebras.ElementMethods.is_central`
                  for this purpose.
                - This function has a complexity linear in the
                  number of conjugacy classes of the group. One
                  could easily implement a function whose
                  complexity is linear in the size of the support
                  of ``self``.

            EXAMPLES::

                sage: QS3 = SymmetricGroup(3).algebra(QQ)
                sage: A = QS3([2,3,1]) + QS3([3,1,2])
                sage: A.central_form()
                B[(1,2,3)]
                sage: QS4 = SymmetricGroup(4).algebra(QQ)
                sage: B = sum(len(s.cycle_type())*QS4(s) for s in Permutations(4))
                sage: B.central_form()
                4*B[()] + 3*B[(1,2)] + 2*B[(1,2)(3,4)] + 2*B[(1,2,3)] + B[(1,2,3,4)]

            The following test fails due to a bug involving combinatorial free modules and
            the coercion system (see :trac:`28544`)::

                sage: QG = GroupAlgebras(QQ).example(PermutationGroup([[(1,2,3),(4,5)],[(3,4)]]))
                sage: s = sum(i for i in QG.basis())
                sage: s.central_form()   # not tested
                B[()] + B[(4,5)] + B[(3,4,5)] + B[(2,3)(4,5)] + B[(2,3,4,5)] + B[(1,2)(3,4,5)] + B[(1,2,3,4,5)]

            .. SEEALSO::

                - :meth:`Groups.Algebras.ParentMethods.center_basis`
                - :meth:`Monoids.Algebras.ElementMethods.is_central`
            """
            from sage.combinat.free_module import CombinatorialFreeModule
            conj_classes_reps = self.parent().basis().keys().conjugacy_classes_representatives()
            Z = CombinatorialFreeModule(self.base_ring(), conj_classes_reps)
            return sum(self[i] * Z.basis()[i] for i in Z.basis().keys())
예제 #2
0
파일: groups.py 프로젝트: sampadsaha5/sage
            def central_form(self):
                r"""
                Return ``self`` expressed in the canonical basis of the center
                of the group algebra.

                INPUT:

                - ``self`` -- an element of the center of the group algebra

                OUTPUT:

                - A formal linear combination of the conjugacy class
                  representatives representing its coordinates in the
                  canonical basis of the center. See
                  :meth:`Groups.Algebras.ParentMethods.center_basis` for
                  details.

                .. WARNING::

                    - This method requires the underlying group to
                      have a method ``conjugacy_classes_representatives``
                      (every permutation group has one, thanks GAP!).
                    - This method does not check that the element is
                      indeed central. Use the method
                      :meth:`Monoids.Algebras.ElementMethods.is_central`
                      for this purpose.
                    - This function has a complexity linear in the
                      number of conjugacy classes of the group. One
                      could easily implement a function whose
                      complexity is linear in the size of the support
                      of ``self``.

                EXAMPLES::

                    sage: QS3 = SymmetricGroup(3).algebra(QQ)
                    sage: A = QS3([2,3,1]) + QS3([3,1,2])
                    sage: A.central_form()
                    B[(1,2,3)]
                    sage: QS4 = SymmetricGroup(4).algebra(QQ)
                    sage: B = sum(len(s.cycle_type())*QS4(s) for s in Permutations(4))
                    sage: B.central_form()
                    4*B[()] + 3*B[(1,2)] + 2*B[(1,2)(3,4)] + 2*B[(1,2,3)] + B[(1,2,3,4)]

                    sage: QG = GroupAlgebras(QQ).example(PermutationGroup([[(1,2,3),(4,5)],[(3,4)]]))
                    sage: sum(i for i in QG.basis()).central_form()
                    B[()] + B[(4,5)] + B[(3,4,5)] + B[(2,3)(4,5)] + B[(2,3,4,5)] + B[(1,2)(3,4,5)] + B[(1,2,3,4,5)]

                .. SEEALSO::

                    - :meth:`Groups.Algebras.ParentMethods.center_basis`
                    - :meth:`Monoids.Algebras.ElementMethods.is_central`
                """
                from sage.combinat.free_module import CombinatorialFreeModule

                conj_classes_reps = self.parent().basis().keys().conjugacy_classes_representatives()
                Z = CombinatorialFreeModule(self.base_ring(), conj_classes_reps)
                return sum(self[i] * Z.basis()[i] for i in Z.basis().keys())
예제 #3
0
파일: chomp.py 프로젝트: mcognetta/sage
    def __call__(self, program, complex, subcomplex=None, **kwds):
        """
        Call a CHomP program to compute the homology of a chain
        complex, simplicial complex, or cubical complex.

        See :class:`CHomP` for full documentation.

        EXAMPLES::

            sage: from sage.interfaces.chomp import CHomP
            sage: T = cubical_complexes.Torus()
            sage: CHomP()('homcubes', T) # indirect doctest, optional - CHomP
            {0: 0, 1: Z x Z, 2: Z}
        """
        from sage.misc.temporary_file import tmp_filename
        from sage.homology.all import CubicalComplex, cubical_complexes
        from sage.homology.all import SimplicialComplex, Simplex
        from sage.homology.chain_complex import HomologyGroup
        from subprocess import Popen, PIPE
        from sage.rings.all import QQ, ZZ
        from sage.modules.all import VectorSpace, vector
        from sage.combinat.free_module import CombinatorialFreeModule

        if not have_chomp(program):
            raise OSError("Program %s not found" % program)

        verbose = kwds.get('verbose', False)
        generators = kwds.get('generators', False)
        extra_opts = kwds.get('extra_opts', '')
        base_ring = kwds.get('base_ring', ZZ)

        if extra_opts:
            extra_opts = extra_opts.split()
        else:
            extra_opts = []

        # type of complex:
        cubical = False
        simplicial = False
        chain = False
        # CHomP seems to have problems with cubical complexes if the
        # first interval in the first cube defining the complex is
        # degenerate.  So replace the complex X with [0,1] x X.
        if isinstance(complex, CubicalComplex):
            cubical = True
            edge = cubical_complexes.Cube(1)
            original_complex = complex
            complex = edge.product(complex)
            if verbose:
                print("Cubical complex")
        elif isinstance(complex, SimplicialComplex):
            simplicial = True
            if verbose:
                print("Simplicial complex")
        else:
            chain = True
            base_ring = kwds.get('base_ring', complex.base_ring())
            if verbose:
                print("Chain complex over %s" % base_ring)

        if base_ring == QQ:
            raise ValueError("CHomP doesn't compute over the rationals, only over Z or F_p.")
        if base_ring.is_prime_field():
            p = base_ring.characteristic()
            extra_opts.append('-p%s' % p)
            mod_p = True
        else:
            mod_p = False

        #
        #    complex
        #
        try:
            data = complex._chomp_repr_()
        except AttributeError:
            raise AttributeError("Complex can not be converted to use with CHomP.")

        datafile = tmp_filename()
        f = open(datafile, 'w')
        f.write(data)
        f.close()

        #
        #    subcomplex
        #
        if subcomplex is None:
            if cubical:
                subcomplex = CubicalComplex([complex.n_cells(0)[0]])
            elif simplicial:
                m = re.search(r'\(([^,]*),', data)
                v = int(m.group(1))
                subcomplex = SimplicialComplex([[v]])
        else:
            # replace subcomplex with [0,1] x subcomplex.
            if cubical:
                subcomplex = edge.product(subcomplex)
        #
        #    generators
        #
        if generators:
            genfile = tmp_filename()
            extra_opts.append('-g%s' % genfile)

        #
        #    call program
        #
        if subcomplex is not None:
            try:
                sub = subcomplex._chomp_repr_()
            except AttributeError:
                raise AttributeError("Subcomplex can not be converted to use with CHomP.")
            subfile = tmp_filename()
            f = open(subfile, 'w')
            f.write(sub)
            f.close()
        else:
            subfile = ''
        if verbose:
            print("Popen called with arguments", end="")
            print([program, datafile, subfile] + extra_opts)
            print("")
            print("CHomP output:")
            print("")
        # output = Popen([program, datafile, subfile, extra_opts],
        cmd = [program, datafile]
        if subfile:
            cmd.append(subfile)
        if extra_opts:
            cmd.extend(extra_opts)
        output = Popen(cmd, stdout=PIPE).communicate()[0]
        if verbose:
            print(output)
            print("End of CHomP output")
            print("")
        if generators:
            gens = open(genfile, 'r').read()
            if verbose:
                print("Generators:")
                print(gens)
        #
        #    process output
        #
        if output.find('ERROR') != -1:
            raise RuntimeError('error inside CHomP')
        # output contains substrings of one of the forms
        # "H_1 = Z", "H_1 = Z_2 + Z", "H_1 = Z_2 + Z^2",
        # "H_1 = Z + Z_2 + Z"
        if output.find('trivial') != -1:
            if mod_p:
                return {0: VectorSpace(base_ring, 0)}
            else:
                return {0: HomologyGroup(0, ZZ)}
        d = {}
        h = re.compile("^H_([0-9]*) = (.*)$", re.M)
        tors = re.compile("Z_([0-9]*)")
        #
        #    homology groups
        #
        for m in h.finditer(output):
            if verbose:
                print(m.groups())
            # dim is the dimension of the homology group
            dim = int(m.group(1))
            # hom_str is the right side of the equation "H_n = Z^r + Z_k + ..."
            hom_str = m.group(2)
            # need to read off number of summands and their invariants
            if hom_str.find("0") == 0:
                if mod_p:
                    hom = VectorSpace(base_ring, 0)
                else:
                    hom = HomologyGroup(0, ZZ)
            else:
                rk = 0
                if hom_str.find("^") != -1:
                    rk_srch = re.search(r'\^([0-9]*)\s?', hom_str)
                    rk = int(rk_srch.group(1))
                rk += len(re.findall("(Z$)|(Z\s)", hom_str))
                if mod_p:
                    rk = rk if rk != 0 else 1
                    if verbose:
                        print("dimension = %s, rank of homology = %s" % (dim, rk))
                    hom = VectorSpace(base_ring, rk)
                else:
                    n = rk
                    invts = []
                    for t in tors.finditer(hom_str):
                        n += 1
                        invts.append(int(t.group(1)))
                    for i in range(rk):
                        invts.append(0)
                    if verbose:
                        print("dimension = %s, number of factors = %s, invariants = %s" % (dim, n, invts))
                    hom = HomologyGroup(n, ZZ, invts)

            #
            #    generators
            #
            if generators:
                if cubical:
                    g = process_generators_cubical(gens, dim)
                    if verbose:
                        print("raw generators: %s" % g)
                    if g:
                        module = CombinatorialFreeModule(base_ring,
                                                         original_complex.n_cells(dim),
                                                         prefix="",
                                                         bracket=True)
                        basis = module.basis()
                        output = []
                        for x in g:
                            v = module(0)
                            for term in x:
                                v += term[0] * basis[term[1]]
                            output.append(v)
                        g = output
                elif simplicial:
                    g = process_generators_simplicial(gens, dim, complex)
                    if verbose:
                        print("raw generators: %s" % gens)
                    if g:
                        module = CombinatorialFreeModule(base_ring,
                                                         complex.n_cells(dim),
                                                         prefix="",
                                                         bracket=False)
                        basis = module.basis()
                        output = []
                        for x in g:
                            v = module(0)
                            for term in x:
                                if complex._is_numeric():
                                    v += term[0] * basis[term[1]]
                                else:
                                    translate = complex._translation_from_numeric()
                                    simplex = Simplex([translate[a] for a in term[1]])
                                    v += term[0] * basis[simplex]
                            output.append(v)
                        g = output
                elif chain:
                    g = process_generators_chain(gens, dim, base_ring)
                    if verbose:
                        print("raw generators: %s" % gens)
                if g:
                    if not mod_p:
                        # sort generators to match up with corresponding invariant
                        g = [_[1] for _ in sorted(zip(invts, g), key=lambda x: x[0])]
                    d[dim] = (hom, g)
                else:
                    d[dim] = hom
            else:
                d[dim] = hom

        if chain:
            new_d = {}
            diff = complex.differential()
            if len(diff) == 0:
                return {}
            bottom = min(diff)
            top = max(diff)
            for dim in d:
                if complex._degree_of_differential == -1:  # chain complex
                    new_dim = bottom + dim
                else: # cochain complex
                    new_dim = top - dim
                if isinstance(d[dim], tuple):
                    # generators included.
                    group = d[dim][0]
                    gens = d[dim][1]
                    new_gens = []
                    dimension = complex.differential(new_dim).ncols()
                    # make sure that each vector is embedded in the
                    # correct ambient space: pad with a zero if
                    # necessary.
                    for v in gens:
                        v_dict = v.dict()
                        if dimension - 1 not in v.dict():
                            v_dict[dimension - 1] = 0
                            new_gens.append(vector(base_ring, v_dict))
                        else:
                            new_gens.append(v)
                    new_d[new_dim] = (group, new_gens)
                else:
                    new_d[new_dim] = d[dim]
            d = new_d
        return d
예제 #4
0
파일: chomp.py 프로젝트: timgates42/sage
    def __call__(self, program, complex, subcomplex=None, **kwds):
        """
        Call a CHomP program to compute the homology of a chain
        complex, simplicial complex, or cubical complex.

        See :class:`CHomP` for full documentation.

        EXAMPLES::

            sage: from sage.interfaces.chomp import CHomP
            sage: T = cubical_complexes.Torus()
            sage: CHomP()('homcubes', T) # indirect doctest, optional - CHomP
            {0: 0, 1: Z x Z, 2: Z}
        """
        from sage.misc.temporary_file import tmp_filename
        from sage.homology.all import CubicalComplex, cubical_complexes
        from sage.homology.all import SimplicialComplex, Simplex
        from sage.homology.chain_complex import HomologyGroup
        from subprocess import Popen, PIPE
        from sage.rings.all import QQ, ZZ
        from sage.modules.all import VectorSpace, vector
        from sage.combinat.free_module import CombinatorialFreeModule

        if not have_chomp(program):
            raise OSError("Program %s not found" % program)

        verbose = kwds.get('verbose', False)
        generators = kwds.get('generators', False)
        extra_opts = kwds.get('extra_opts', '')
        base_ring = kwds.get('base_ring', ZZ)

        if extra_opts:
            extra_opts = extra_opts.split()
        else:
            extra_opts = []

        # type of complex:
        cubical = False
        simplicial = False
        chain = False
        # CHomP seems to have problems with cubical complexes if the
        # first interval in the first cube defining the complex is
        # degenerate.  So replace the complex X with [0,1] x X.
        if isinstance(complex, CubicalComplex):
            cubical = True
            edge = cubical_complexes.Cube(1)
            original_complex = complex
            complex = edge.product(complex)
            if verbose:
                print("Cubical complex")
        elif isinstance(complex, SimplicialComplex):
            simplicial = True
            if verbose:
                print("Simplicial complex")
        else:
            chain = True
            base_ring = kwds.get('base_ring', complex.base_ring())
            if verbose:
                print("Chain complex over %s" % base_ring)

        if base_ring == QQ:
            raise ValueError(
                "CHomP doesn't compute over the rationals, only over Z or F_p."
            )
        if base_ring.is_prime_field():
            p = base_ring.characteristic()
            extra_opts.append('-p%s' % p)
            mod_p = True
        else:
            mod_p = False

        #
        #    complex
        #
        try:
            data = complex._chomp_repr_()
        except AttributeError:
            raise AttributeError(
                "Complex cannot be converted to use with CHomP.")

        datafile = tmp_filename()
        with open(datafile, 'w') as f:
            f.write(data)

        #
        #    subcomplex
        #
        if subcomplex is None:
            if cubical:
                subcomplex = CubicalComplex([complex.n_cells(0)[0]])
            elif simplicial:
                m = re.search(r'\(([^,]*),', data)
                v = int(m.group(1))
                subcomplex = SimplicialComplex([[v]])
        else:
            # replace subcomplex with [0,1] x subcomplex.
            if cubical:
                subcomplex = edge.product(subcomplex)
        #
        #    generators
        #
        if generators:
            genfile = tmp_filename()
            extra_opts.append('-g%s' % genfile)

        #
        #    call program
        #
        if subcomplex is not None:
            try:
                sub = subcomplex._chomp_repr_()
            except AttributeError:
                raise AttributeError(
                    "Subcomplex cannot be converted to use with CHomP.")
            subfile = tmp_filename()
            with open(subfile, 'w') as f:
                f.write(sub)
        else:
            subfile = ''
        if verbose:
            print("Popen called with arguments", end="")
            print([program, datafile, subfile] + extra_opts)
            print("")
            print("CHomP output:")
            print("")
        # output = Popen([program, datafile, subfile, extra_opts],
        cmd = [program, datafile]
        if subfile:
            cmd.append(subfile)
        if extra_opts:
            cmd.extend(extra_opts)
        output = Popen(cmd, stdout=PIPE).communicate()[0]
        if verbose:
            print(output)
            print("End of CHomP output")
            print("")
        if generators:
            with open(genfile, 'r') as f:
                gens = f.read()
            if verbose:
                print("Generators:")
                print(gens)
        #
        #    process output
        #
        if output.find('ERROR') != -1:
            raise RuntimeError('error inside CHomP')
        # output contains substrings of one of the forms
        # "H_1 = Z", "H_1 = Z_2 + Z", "H_1 = Z_2 + Z^2",
        # "H_1 = Z + Z_2 + Z"
        if output.find('trivial') != -1:
            if mod_p:
                return {0: VectorSpace(base_ring, 0)}
            else:
                return {0: HomologyGroup(0, ZZ)}
        d = {}
        h = re.compile("^H_([0-9]*) = (.*)$", re.M)
        tors = re.compile("Z_([0-9]*)")
        #
        #    homology groups
        #
        for m in h.finditer(output):
            if verbose:
                print(m.groups())
            # dim is the dimension of the homology group
            dim = int(m.group(1))
            # hom_str is the right side of the equation "H_n = Z^r + Z_k + ..."
            hom_str = m.group(2)
            # need to read off number of summands and their invariants
            if hom_str.find("0") == 0:
                if mod_p:
                    hom = VectorSpace(base_ring, 0)
                else:
                    hom = HomologyGroup(0, ZZ)
            else:
                rk = 0
                if hom_str.find("^") != -1:
                    rk_srch = re.search(r'\^([0-9]*)\s?', hom_str)
                    rk = int(rk_srch.group(1))
                rk += len(re.findall(r"(Z$)|(Z\s)", hom_str))
                if mod_p:
                    rk = rk if rk != 0 else 1
                    if verbose:
                        print("dimension = %s, rank of homology = %s" %
                              (dim, rk))
                    hom = VectorSpace(base_ring, rk)
                else:
                    n = rk
                    invts = []
                    for t in tors.finditer(hom_str):
                        n += 1
                        invts.append(int(t.group(1)))
                    for i in range(rk):
                        invts.append(0)
                    if verbose:
                        print(
                            "dimension = %s, number of factors = %s, invariants = %s"
                            % (dim, n, invts))
                    hom = HomologyGroup(n, ZZ, invts)

            #
            #    generators
            #
            if generators:
                if cubical:
                    g = process_generators_cubical(gens, dim)
                    if verbose:
                        print("raw generators: %s" % g)
                    if g:
                        module = CombinatorialFreeModule(
                            base_ring,
                            original_complex.n_cells(dim),
                            prefix="",
                            bracket=True)
                        basis = module.basis()
                        output = []
                        for x in g:
                            v = module(0)
                            for term in x:
                                v += term[0] * basis[term[1]]
                            output.append(v)
                        g = output
                elif simplicial:
                    g = process_generators_simplicial(gens, dim, complex)
                    if verbose:
                        print("raw generators: %s" % gens)
                    if g:
                        module = CombinatorialFreeModule(base_ring,
                                                         complex.n_cells(dim),
                                                         prefix="",
                                                         bracket=False)
                        basis = module.basis()
                        output = []
                        for x in g:
                            v = module(0)
                            for term in x:
                                if complex._is_numeric():
                                    v += term[0] * basis[term[1]]
                                else:
                                    translate = complex._translation_from_numeric(
                                    )
                                    simplex = Simplex(
                                        [translate[a] for a in term[1]])
                                    v += term[0] * basis[simplex]
                            output.append(v)
                        g = output
                elif chain:
                    g = process_generators_chain(gens, dim, base_ring)
                    if verbose:
                        print("raw generators: %s" % gens)
                if g:
                    if not mod_p:
                        # sort generators to match up with corresponding invariant
                        g = [
                            _[1]
                            for _ in sorted(zip(invts, g), key=lambda x: x[0])
                        ]
                    d[dim] = (hom, g)
                else:
                    d[dim] = hom
            else:
                d[dim] = hom

        if chain:
            new_d = {}
            diff = complex.differential()
            if len(diff) == 0:
                return {}
            bottom = min(diff)
            top = max(diff)
            for dim in d:
                if complex._degree_of_differential == -1:  # chain complex
                    new_dim = bottom + dim
                else:  # cochain complex
                    new_dim = top - dim
                if isinstance(d[dim], tuple):
                    # generators included.
                    group = d[dim][0]
                    gens = d[dim][1]
                    new_gens = []
                    dimension = complex.differential(new_dim).ncols()
                    # make sure that each vector is embedded in the
                    # correct ambient space: pad with a zero if
                    # necessary.
                    for v in gens:
                        v_dict = v.dict()
                        if dimension - 1 not in v.dict():
                            v_dict[dimension - 1] = 0
                            new_gens.append(vector(base_ring, v_dict))
                        else:
                            new_gens.append(v)
                    new_d[new_dim] = (group, new_gens)
                else:
                    new_d[new_dim] = d[dim]
            d = new_d
        return d