Example #1
0
    def reflection_group(self, type="matrix"):
        """
        Return the reflection group corresponding to ``self``.

        EXAMPLES::

            sage: C = CartanMatrix(['A',3])
            sage: C.reflection_group()
            Weyl Group of type ['A', 3] (as a matrix group acting on the root space)
        """
        from sage.groups.perm_gps.permgroup_named import SymmetricGroup
        RS = self.root_space()
        G = RS.weyl_group()
        if type == "matrix":
            return G
        elif type == "permutation":
            assert G.is_finite()
            Phi = RS.roots()
            gens = {}
            S = SymmetricGroup(len(Phi))
            for i in self.index_set():
                pi = S([ Phi.index( beta.simple_reflection(i) ) + 1 for beta in Phi ])
                gens[i] = pi
            return S.subgroup( gens[i] for i in gens )
        else:
            raise ValueError("The reflection group is only available as a matrix group or as a permutation group.")
Example #2
0
    def reflection_group(self, type="matrix"):
        """
        Return the reflection group corresponding to ``self``.

        EXAMPLES::

            sage: C = CartanMatrix(['A',3])
            sage: C.reflection_group()
            Weyl Group of type ['A', 3] (as a matrix group acting on the root space)
        """
        RS = self.root_space()

        if type == "matrix":
            return RS.weyl_group()

        if type == "permutation":
            if not self.is_finite():
                raise ValueError("only works for finite types")
            Phi = RS.roots()
            gens = {}
            from sage.groups.perm_gps.permgroup_named import SymmetricGroup
            S = SymmetricGroup(len(Phi))
            for i in self.index_set():
                pi = S(
                    [Phi.index(beta.simple_reflection(i)) + 1 for beta in Phi])
                gens[i] = pi
            return S.subgroup(gens[i] for i in gens)

        raise ValueError(
            "The reflection group is only available as a matrix group or as a permutation group."
        )
Example #3
0
def _generate_decreasing_hecke_factorizations(w,
                                              factors,
                                              ex,
                                              weight=None,
                                              parent=None):
    """
    Generate all decreasing factorizations of word ``w`` in a 0-Hecke monoid
    with fixed excess and number of factors.

    INPUT:

    - ``w`` -- a reduced word, expressed as an iterable

    - ``factors`` -- number of factors for each decreasing factorization

    - ``ex`` -- number of extra letters in each decreasing factorizations

    - ``weight`` -- (default: None) if None, returns all possible decreasing
                    factorizations, otherwise return all those with the
                    specified weight

    EXAMPLES::

        sage: from sage.combinat.crystals.fully_commutative_stable_grothendieck import _generate_decreasing_hecke_factorizations
        sage: _generate_decreasing_hecke_factorizations([1, 2, 1], 3, 1)
        [()(2, 1)(2, 1),
         (2)(1)(2, 1),
         (1)(2)(2, 1),
         (1)(1)(2, 1),
         (2, 1)()(2, 1),
         (2)(2, 1)(2),
         (1)(2, 1)(2),
         (1)(2, 1)(1),
         (2, 1)(2)(2),
         (2, 1)(2)(1),
         (2, 1)(1)(2),
         (2, 1)(2, 1)()]

        sage: _generate_decreasing_hecke_factorizations([1, 2, 1], 3, 1, weight=[1, 1, 2])
        [(2, 1)(2)(2), (2, 1)(2)(1), (2, 1)(1)(2)]
    """
    if parent is None:
        max_value = max(w) if w else 1
        S = SymmetricGroup(max_value + 1)
        v = S.from_reduced_word(w)
        parent = DecreasingHeckeFactorizations(v, factors, ex)

    _canonical_word = lambda w, ex: [list(w)[0]] * ex + list(w)
    wt = lambda t: [len(factor) for factor in reversed(t)]

    L = _list_equivalent_words(_canonical_word(w, ex))
    Factors = []
    for word in L:
        F = _list_all_decreasing_runs(word, factors)
        for f in F:
            t = [[word[j] for j in range(len(word)) if f[j] == i]
                 for i in range(factors, 0, -1)]
            if weight is None or weight == wt(t):
                Factors.append(parent.element_class(parent, t))
    return sorted(Factors, reverse=True)
    def __classcall_private__(self, t, max_value=None, parent=None):
        """
        Assign the correct parent for ``t`` and call ``t`` as an element of that parent

        EXAMPLES::

            sage: from sage.combinat.crystals.fully_commutative_stable_grothendieck import DecreasingHeckeFactorization
            sage: h1 = DecreasingHeckeFactorization([[3, 1], [], [3, 2]])
            sage: h1.parent()
            Fully commutative stable Grothendieck crystal of type A_2 associated to [1, 3, 2] with excess 1
            sage: h2 = DecreasingHeckeFactorization(h1)
            sage: h1 == h2
            True

            sage: h1 = DecreasingHeckeFactorization([[3, 1], [2, 1], [2, 1]])
            sage: F = h1.parent(); F
            Decreasing Hecke factorizations with 3 factors associated to [1, 3, 2, 1] with excess 2
            sage: h2 = F(h1)
            sage: h1 == h2
            True

        TESTS::

            sage: DecreasingHeckeFactorization([[]])
            ()
        """
        _check_decreasing_hecke_factorization(t)
        if isinstance(t, DecreasingHeckeFactorization):
            u = t.value
            if parent is None:
                parent = t.parent()
        else:
            u = t
            if parent is None:
                if max_value is None:
                    letters = [x for factor in t for x in factor]
                    max_value = max(letters) if letters else 1
                from sage.monoids.hecke_monoid import HeckeMonoid
                S = SymmetricGroup(max_value + 1)
                H = HeckeMonoid(S)
                word = H.from_reduced_word(x for factor in t
                                           for x in factor).reduced_word()
                factors = len(t)
                excess = sum(len(l) for l in t) - len(word)

                p = permutation.from_reduced_word(word)
                if p.has_pattern([3, 2, 1]):
                    word = S.from_reduced_word(word)
                    parent = DecreasingHeckeFactorizations(
                        word, factors, excess)
                else:
                    word = S.from_reduced_word(word)
                    parent = FullyCommutativeStableGrothendieckCrystal(
                        word, factors, excess)
        return parent.element_class(parent, u)
Example #5
0
def SymmetricPresentation(n):
    r"""
    Build the Symmetric group of order `n!` as a finitely presented group.

    INPUT:

    - ``n`` -- The size of the underlying set of arbitrary symbols being acted
      on by the Symmetric group of order `n!`.

    OUTPUT:

    Symmetric group as a finite presentation, implementation uses GAP to find an
    isomorphism from a permutation representation to a finitely presented group
    representation. Due to this fact, the exact output presentation may not be
    the same for every method call on a constant ``n``.

    EXAMPLES::

        sage: S4 = groups.presentation.Symmetric(4)
        sage: S4.as_permutation_group().is_isomorphic(SymmetricGroup(4))
        True

    TESTS::

        sage: S = [groups.presentation.Symmetric(i) for i in range(1,4)]; S[0].order()
        1
        sage: S[1].order(), S[2].as_permutation_group().is_isomorphic(DihedralGroup(3))
        (2, True)
        sage: S5 = groups.presentation.Symmetric(5)
        sage: perm_S5 = S5.as_permutation_group(); perm_S5.is_isomorphic(SymmetricGroup(5))
        True
        sage: groups.presentation.Symmetric(8).order()
        40320
    """
    from sage.groups.perm_gps.permgroup_named import SymmetricGroup
    from sage.groups.free_group import _lexi_gen

    n = Integer(n)
    perm_rep = SymmetricGroup(n)
    GAP_fp_rep = libgap.Image(
        libgap.IsomorphismFpGroupByGenerators(perm_rep, perm_rep.gens()))
    image_gens = GAP_fp_rep.FreeGeneratorsOfFpGroup()
    name_itr = _lexi_gen()  # Python generator object for variable names
    F = FreeGroup([next(name_itr) for x in perm_rep.gens()])
    ret_rls = tuple([
        F(rel_word.TietzeWordAbstractWord(image_gens).sage())
        for rel_word in GAP_fp_rep.RelatorsOfFpGroup()
    ])
    return FinitelyPresentedGroup(F, ret_rls)
Example #6
0
    def gens(self):
        r"""
        Return a tuple of generators of ``self``.

        EXAMPLES::

            sage: F.<a> = GF(4)
            sage: SemimonomialTransformationGroup(F, 3).gens()
            [((a, 1, 1); (), Ring endomorphism of Finite Field in a of size 2^2
              Defn: a |--> a), ((1, 1, 1); (1,2,3), Ring endomorphism of Finite Field in a of size 2^2
              Defn: a |--> a), ((1, 1, 1); (1,2), Ring endomorphism of Finite Field in a of size 2^2
              Defn: a |--> a), ((1, 1, 1); (), Ring endomorphism of Finite Field in a of size 2^2
              Defn: a |--> a + 1)]
        """
        from sage.groups.perm_gps.permgroup_named import SymmetricGroup
        R = self.base_ring()
        l = [
            self(v=([R.primitive_element()] + [R.one()] * (self.degree() - 1)))
        ]
        for g in SymmetricGroup(self.degree()).gens():
            l.append(self(perm=Permutation(g)))
        if R.is_field() and not R.is_prime_field():
            l.append(
                self(autom=R.hom([R.primitive_element()**R.characteristic()])))
        return l
Example #7
0
def antisymmetrized_coordinate_sums(dim, n):
    """
    Return formal anti-symmetrized sum of multi-indices

    INPUT:

    - ``dim`` -- integer. The dimension (range of each index).

    - ``n`` -- integer. The total number of indices.

    OUTPUT:

    An anti-symmetrized formal sum of multi-indices (tuples of integers)

    EXAMPLES::

        sage: from sage.modules.tensor_operations import antisymmetrized_coordinate_sums
        sage: antisymmetrized_coordinate_sums(3, 2)
        ((0, 1) - (1, 0), (0, 2) - (2, 0), (1, 2) - (2, 1))
    """
    from sage.structure.formal_sum import FormalSum
    table = []
    from sage.groups.perm_gps.permgroup_named import SymmetricGroup
    S_d = SymmetricGroup(n)
    from sage.combinat.combination import Combinations
    for i in Combinations(range(dim), n):
        i = tuple(i)
        x = []
        for g in S_d:
            x.append([g.sign(), g(i)])
        x = FormalSum(x)
        table.append(x)
    return tuple(table)
Example #8
0
    def automorphism_group(self):
        """
        Returns the subgroup of the automorphism group of the incidence
        graph which respects the P B partition. This is (isomorphic to) the
        automorphism group of the block design, although the degrees
        differ.

        EXAMPLES::

            sage: from sage.combinat.designs.block_design import BlockDesign
            sage: BD = BlockDesign(7,[[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]])
            sage: G = BD.automorphism_group(); G
            Permutation Group with generators [(4,5)(6,7), (4,6)(5,7), (2,3)(6,7), (2,4)(3,5), (1,2)(5,6)]
            sage: BD = BlockDesign(4,[[0],[0,1],[1,2],[3,3]],test=False)
            sage: G = BD.automorphism_group(); G
            Permutation Group with generators [()]
            sage: BD = BlockDesign(7,[[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]])
            sage: G = BD.automorphism_group(); G
            Permutation Group with generators [(4,5)(6,7), (4,6)(5,7), (2,3)(6,7), (2,4)(3,5), (1,2)(5,6)]
        """
        from sage.groups.perm_gps.partn_ref.refinement_matrices import MatrixStruct
        from sage.groups.perm_gps.permgroup import PermutationGroup
        from sage.groups.perm_gps.permgroup_named import SymmetricGroup
        M1 = self.incidence_matrix()
        M2 =  MatrixStruct(M1)
        M2.run()
        gens = M2.automorphism_group()[0]
        v = len(self.points())
        G = SymmetricGroup(v)
        gns = []
        for g in gens:
            L = [j+1 for j in g]
            gns.append(G(L))
        return PermutationGroup(gns)
def SymmetricPresentation(n):
    r"""
    Build the Symmetric group of order `n!` as a finitely presented group.

    INPUT:

    - ``n`` -- The size of the underlying set of arbitrary symbols being acted
      on by the Symmetric group of order `n!`.

    OUTPUT:

    Symmetric group as a finite presentation, implementation uses GAP to find an
    isomorphism from a permutation representation to a finitely presented group
    representation. Due to this fact, the exact output presentation may not be
    the same for every method call on a constant ``n``.

    EXAMPLES::

        sage: S4 = groups.presentation.Symmetric(4)
        sage: S4.as_permutation_group().is_isomorphic(SymmetricGroup(4))
        True

    TESTS::

        sage: S = [groups.presentation.Symmetric(i) for i in range(1,4)]; S[0].order()
        1
        sage: S[1].order(), S[2].as_permutation_group().is_isomorphic(DihedralGroup(3))
        (2, True)
        sage: S5 = groups.presentation.Symmetric(5)
        sage: perm_S5 = S5.as_permutation_group(); perm_S5.is_isomorphic(SymmetricGroup(5))
        True
        sage: groups.presentation.Symmetric(8).order()
        40320
    """
    from sage.groups.perm_gps.permgroup_named import SymmetricGroup
    from sage.groups.free_group import _lexi_gen

    n = Integer(n)
    perm_rep = SymmetricGroup(n)
    GAP_fp_rep = libgap.Image(libgap.IsomorphismFpGroupByGenerators(perm_rep, perm_rep.gens()))
    image_gens = GAP_fp_rep.FreeGeneratorsOfFpGroup()
    name_itr = _lexi_gen()  # Python generator object for variable names
    F = FreeGroup([next(name_itr) for x in perm_rep.gens()])
    ret_rls = tuple(
        [F(rel_word.TietzeWordAbstractWord(image_gens).sage()) for rel_word in GAP_fp_rep.RelatorsOfFpGroup()]
    )
    return FinitelyPresentedGroup(F, ret_rls)
Example #10
0
    def _get_random_ribbon_graph(self):
        r"""
        Return a random ribbon graph with right parameters.
        """
        n = random.randint(self.min_num_seps, self.max_num_seps)
        S = SymmetricGroup(2 * n)

        e = S([(2 * i + 1, 2 * i + 2) for i in range(n)])
        f = S.random_element()
        P = PermutationGroup([e, f])

        while not P.is_transitive():
            f = S.random_element()
            P = PermutationGroup([e, f])

        return RibbonGraph(edges=[e(i + 1) - 1 for i in range(2 * n)],
                           faces=[f(i + 1) - 1 for i in range(2 * n)])
Example #11
0
    def _get_random_ribbon_graph(self):
        r"""
        Return a random ribbon graph with right parameters.
        """
        n = random.randint(self.min_num_seps,self.max_num_seps)
        S = SymmetricGroup(2*n)

        e = S([(2*i+1,2*i+2) for i in xrange(n)])
        f = S.random_element()
        P = PermutationGroup([e,f])

        while not P.is_transitive():
            f = S.random_element()
            P = PermutationGroup([e,f])

        return RibbonGraph(
                 edges=[e(i+1)-1 for i in xrange(2*n)],
                 faces=[f(i+1)-1 for i in xrange(2*n)])
Example #12
0
    def group(self):
        """
        Returns the underlying group

        EXAMPLES ::

            sage: SymmetricGroupAlgebra(QQ,4).group()
            Symmetric group of order 4! as a permutation group
        """
        return SymmetricGroup(self.n)
Example #13
0
def test2():
    from sage.groups.perm_gps.permgroup_named import SymmetricGroup
    S = SymmetricGroup(3)
    r = S('(1,2)')
    u = S('(1,3)')
    o = translation_surfaces.origami(r, u)
    o.edit()
    se, sb = o.get_bundle()
    sb.set_transform(200, 300, 300)
    sb.redraw_all()
Example #14
0
    def to_character(self):
        r"""
        Return the character of the representation.

        EXAMPLES:

        The trivial character::

            sage: rho = SymmetricGroupRepresentation([3])
            sage: chi = rho.to_character(); chi
            Character of Symmetric group of order 3! as a permutation group
            sage: chi.values()
            [1, 1, 1]
            sage: all(chi(g) == 1 for g in SymmetricGroup(3))
            True

        The sign character::

            sage: rho = SymmetricGroupRepresentation([1,1,1])
            sage: chi = rho.to_character(); chi
            Character of Symmetric group of order 3! as a permutation group
            sage: chi.values()
            [1, -1, 1]
            sage: all(chi(g) == g.sign() for g in SymmetricGroup(3))
            True

        The defining representation::

            sage: triv = SymmetricGroupRepresentation([4])
            sage: hook = SymmetricGroupRepresentation([3,1])
            sage: def_rep = lambda p : triv(p).block_sum(hook(p)).trace()
            sage: map(def_rep, Permutations(4))
            [4, 2, 2, 1, 1, 2, 2, 0, 1, 0, 0, 1, 1, 0, 2, 1, 0, 0, 0, 1, 1, 2, 0, 0]
            sage: [p.to_matrix().trace() for p in Permutations(4)]
            [4, 2, 2, 1, 1, 2, 2, 0, 1, 0, 0, 1, 1, 0, 2, 1, 0, 0, 0, 1, 1, 2, 0, 0]

        """
        from sage.groups.perm_gps.permgroup_named import SymmetricGroup
        Sym = SymmetricGroup(sum(self._partition))
        values = [
            self(g).trace() for g in Sym.conjugacy_classes_representatives()
        ]
        return Sym.character(values)
    def to_character(self):
        r"""
        Return the character of the representation.

        EXAMPLES:

        The trivial character::

            sage: rho = SymmetricGroupRepresentation([3])
            sage: chi = rho.to_character(); chi
            Character of Symmetric group of order 3! as a permutation group
            sage: chi.values()
            [1, 1, 1]
            sage: all(chi(g) == 1 for g in SymmetricGroup(3))
            True

        The sign character::

            sage: rho = SymmetricGroupRepresentation([1,1,1])
            sage: chi = rho.to_character(); chi
            Character of Symmetric group of order 3! as a permutation group
            sage: chi.values()
            [1, -1, 1]
            sage: all(chi(g) == g.sign() for g in SymmetricGroup(3))
            True

        The defining representation::

            sage: triv = SymmetricGroupRepresentation([4])
            sage: hook = SymmetricGroupRepresentation([3,1])
            sage: def_rep = lambda p : triv(p).block_sum(hook(p)).trace()
            sage: map(def_rep, Permutations(4))
            [4, 2, 2, 1, 1, 2, 2, 0, 1, 0, 0, 1, 1, 0, 2, 1, 0, 0, 0, 1, 1, 2, 0, 0]
            sage: [p.to_matrix().trace() for p in Permutations(4)]
            [4, 2, 2, 1, 1, 2, 2, 0, 1, 0, 0, 1, 1, 0, 2, 1, 0, 0, 0, 1, 1, 2, 0, 0]

        """
        from sage.groups.perm_gps.permgroup_named import SymmetricGroup

        Sym = SymmetricGroup(sum(self._partition))
        values = [self(g).trace() for g in Sym.conjugacy_classes_representatives()]
        return Sym.character(values)
Example #16
0
    def an_instance(cls):
        """
        Returns an instance of this class.

        EXAMPLES::

            sage: Groupoid.an_instance() # indirect doctest
            Groupoid with underlying set Symmetric group of order 8! as a permutation group
        """
        from sage.groups.perm_gps.permgroup_named import SymmetricGroup
        G = SymmetricGroup(8)
        return cls(G)
Example #17
0
def _check_containment(t, parent):
    """
    Check if ``t`` is an element of ``parent``.

    EXAMPLES::

        sage: S = SymmetricGroup(3+1)
        sage: w = S.from_reduced_word([1, 3, 2])
        sage: B = crystals.FullyCommutativeStableGrothendieck(w, 3, 2)

        sage: from sage.combinat.crystals.fully_commutative_stable_grothendieck import DecreasingHeckeFactorization, _check_containment
        sage: h1 = DecreasingHeckeFactorization([[3, 1], [3], [3, 2]], 4)
        sage: _check_containment(h1, B)

        sage: h2 = DecreasingHeckeFactorization([[3, 1], [3], [], [3, 2]])
        sage: _check_containment(h2, B)
        Traceback (most recent call last):
        ...
        ValueError: number of factors do not match

        sage: h3 = [[3, 1], [2], [3, 2]]
        sage: _check_containment(h3, B)
        Traceback (most recent call last):
        ...
        ValueError: self and parent must be specified based on equivalent words

        sage: h4 = DecreasingHeckeFactorization([[3, 1], [3, 1], [3, 2]], 3)
        sage: _check_containment(h4, B)
        Traceback (most recent call last):
        ...
        ValueError: number of excess letters do not match
    """
    if isinstance(t, DecreasingHeckeFactorization):
        factors = t.factors
        w = t.w
        excess = t.excess
    else:
        factors = len(t)
        max_value = parent.max_value
        from sage.monoids.hecke_monoid import HeckeMonoid
        H = HeckeMonoid(SymmetricGroup(max_value + 1))
        w = tuple(
            H.from_reduced_word(x for factor in t
                                for x in factor).reduced_word())
        excess = sum(len(l) for l in t) - len(w)

    if factors != parent.factors:
        raise ValueError("number of factors do not match")
    if w != parent.w:
        raise ValueError(
            "self and parent must be specified based on equivalent words")
    if excess != parent.excess:
        raise ValueError("number of excess letters do not match")
Example #18
0
    def _get_random_cylinder_diagram(self):
        r"""
        Return a random cylinder diagram with right parameters
        """
        test = False
        while test:
            n = random.randint(self.min_num_seps, self.max_num_seps)
            S = SymmetricGroup(2 * n)

            bot = S.random_element()
            b = [[i - 1 for i in c] for c in bot.cycle_tuples(singletons=True)]

            p = Partitions(2 * n, length=len(b)).random_element()
            top = S([i + 1 for i in canonical_perm(p)])
            t = [[i - 1 for i in c] for c in top.cycle_tuples(singletons=True)]
            prandom.shuffle(t)

            c = CylinderDiagram(zip(b, t))
            test = c.is_connected()

        return c
Example #19
0
    def _get_random_cylinder_diagram(self):
        r"""
        Return a random cylinder diagram with right parameters
        """
        test = False
        while test:
            n = random.randint(self.min_num_seps,self.max_num_seps)
            S = SymmetricGroup(2*n)

            bot = S.random_element()
            b = [[i-1 for i in c] for c in bot.cycle_tuples(singletons=True)]

            p = Partitions(2*n,length=len(b)).random_element()
            top = S([i+1 for i in canonical_perm(p)])
            t = [[i-1 for i in c] for c in top.cycle_tuples(singletons=True)]
            prandom.shuffle(t)

            c = CylinderDiagram(zip(b,t))
            test = c.is_connected()

        return c
Example #20
0
    def an_instance(cls):
        """
        Returns an instance of this class.

        EXAMPLES::

            sage: GSets.an_instance() # indirect doctest
            Category of G-sets for Symmetric group of order 8! as a permutation group
        """
        from sage.groups.perm_gps.permgroup_named import SymmetricGroup
        G = SymmetricGroup(8)
        return cls(G)
Example #21
0
    def __init__(self, G=None):
        """
        TESTS::

            sage: S8 = SymmetricGroup(8)
            sage: C = Groupoid(S8)
            sage: TestSuite(C).run()
        """
        CategoryWithParameters.__init__(self)  #, "Groupoid")
        if G is None:
            from sage.groups.perm_gps.permgroup_named import SymmetricGroup
            G = SymmetricGroup(8)
        self.__G = G
Example #22
0
    def _latex_(self):
        r"""
        Method for describing ``self`` in LaTeX.

        EXAMPLES::

            sage: F.<a> = GF(4)
            sage: latex(SemimonomialTransformationGroup(F, 3)) # indirect doctest
            \left(\Bold{F}_{2^{2}}^3\wr\langle (1,2,3), (1,2) \rangle \right) \rtimes \operatorname{Aut}(\Bold{F}_{2^{2}})
        """
        from sage.groups.perm_gps.permgroup_named import SymmetricGroup
        ring_latex = self.base_ring()._latex_()
        return ('\\left(' + ring_latex + '^' + str(self.degree()) + '\\wr' +
                SymmetricGroup(self.degree())._latex_() +
                ' \\right) \\rtimes \operatorname{Aut}(' + ring_latex + ')')
Example #23
0
    def profile(self):
        r"""
        Return the profile of the surface.

        Return the list of angles of singularities in the surface divided by pi.

        EXAMPLES::

            sage: from surface_dynamics.all import *
            sage: p = iet.Permutation('a b', 'b a')
            sage: p.cover(['(1,2)', '(1,3)']).profile()
            [6]
            sage: p.cover(['(1,2,3)','(1,4)']).profile()
            [6, 2]
            sage: p.cover(['(1,2,3)(4,5,6)','(1,4,7)(2,5)(3,6)']).profile()
            [6, 2, 2, 2, 2]

            sage: p = iet.GeneralizedPermutation('a a b', 'b c c')
            sage: p.cover(['(1,2)', '()', '(1,2)']).profile()
            [2, 2, 2, 2]
        """
        from sage.combinat.partition import Partition
        from sage.groups.perm_gps.permgroup_named import SymmetricGroup

        s = []

        base_diagram = self._base.interval_diagram(sign=True, glue_ends=True)
        p_id = SymmetricGroup(self._degree_cover).identity()
        for orbit in base_diagram:
            flat_orbit = []
            for x in orbit:
                if isinstance(x[0], tuple):
                    flat_orbit.extend(x)
                else:
                    flat_orbit.append(x)
            p = p_id
            for lab,sign in flat_orbit:
                q = self.covering_data(lab)
                if sign: q = q.inverse()
                p = p*q
            for c in p.cycle_type():
               s.append(len(orbit)*c)

        return Partition(sorted(s,reverse=True))
Example #24
0
    def random_permutation(self):
        r"""
        Return a random permutation of ``self``.
        """
        from sage.misc.prandom import randint
        from sage.groups.perm_gps.permgroup_named import SymmetricGroup

        A = self.alphabet()
        P = A.positive_letters()
        s = SymmetricGroup(P).random_element()
        f = {}
        for a in P:
            if randint(0,1):
                f[a] = self([s(a)])
            else:
                f[a] = self([A.inverse_letter(s(a))])

        from free_group_automorphism import FreeGroupAutomorphism #this has to be here and not in the preamble to prevent loop on import statements
        return FreeGroupAutomorphism(f, group=self)
Example #25
0
    def __classcall_private__(cls, w, factors, excess, shape=False):
        """
        Classcall to mend the input.

        EXAMPLES::

            sage: A = crystals.FullyCommutativeStableGrothendieck([[3, 3], [2, 1]], 4, 1, shape=True); A
            Fully commutative stable Grothendieck crystal of type A_3 associated to [3, 2, 4] with excess 1
            sage: B = crystals.FullyCommutativeStableGrothendieck(SkewPartition([[3, 3], [2, 1]]), 4, 1, shape=True)
            sage: A is B
            True

            sage: C = crystals.FullyCommutativeStableGrothendieck((2, 1), 3, 2, shape=True); C
            Fully commutative stable Grothendieck crystal of type A_2 associated to [1, 3, 2] with excess 2
            sage: D = crystals.FullyCommutativeStableGrothendieck(Partition([2, 1]), 3, 2, shape=True)
            sage: C is D
            True
        """
        from sage.monoids.hecke_monoid import HeckeMonoid
        if shape:
            from sage.combinat.partition import _Partitions
            from sage.combinat.skew_partition import SkewPartition
            cond1 = isinstance(w, (tuple, list)) and len(
                w) == 2 and w[0] in _Partitions and w[1] in _Partitions
            cond2 = isinstance(w, SkewPartition)
            if cond1 or cond2:
                sh = SkewPartition([w[0], w[1]])
            elif w in _Partitions:
                sh = SkewPartition([w, []])
            else:
                raise ValueError("w needs to be a (skew) partition")
            word = _to_reduced_word(sh)
            max_value = max(word) if word else 1
            H = HeckeMonoid(SymmetricGroup(max_value + 1))
            w = H.from_reduced_word(word)
        else:
            if isinstance(w.parent(), SymmetricGroup):
                H = HeckeMonoid(w.parent())
                w = H.from_reduced_word(w.reduced_word())
        if (not w.reduced_word()) and excess != 0:
            raise ValueError("excess must be 0 for the empty word")
        return super(FullyCommutativeStableGrothendieckCrystal,
                     cls).__classcall__(cls, w, factors, excess)
Example #26
0
    def automorphism_group(self):
        r"""
        Return the Deck group of the cover.

        EXAMPLES::

            sage: from surface_dynamics.all import *
            sage: p = iet.GeneralizedPermutation('a a b', 'b c c')
            sage: p.cover(['(1,2,3)', '(1,3,2)', '']).automorphism_group()
            Permutation Group with generators [(1,2,3), (1,3,2)]
            sage: p.cover(['(1,2)', '(1,3)', '']).automorphism_group()
            Permutation Group with generators [()]
        """
        from sage.groups.perm_gps.permgroup_named import SymmetricGroup
        from sage.groups.perm_gps.permgroup import PermutationGroup

        Sd = SymmetricGroup(self._degree_cover)
        G = libgap.Subgroup(Sd, [self.covering_data(a) for a in self._base.letters()])
        C = libgap.Centralizer(Sd, G)

        return PermutationGroup(libgap.GeneratorsOfGroup(C).sage())
Example #27
0
    def SymmetricGroupAbsoluteOrderPoset(n, labels="permutations"):
        r"""
        Return the poset of permutations with respect to absolute order.

        INPUT:

        - ``n`` --  a positive integer

        - ``label`` -- (default: ``'permutations'``) a label for the elements
          of the poset returned by the function; the options are

          * ``'permutations'`` - labels the elements are given by their
            one-line notation
          * ``'reduced_words'`` - labels the elements by the
            lexicographically minimal reduced word
          * ``'cycles'`` - labels the elements by their expression
            as a product of cycles

        EXAMPLES::

            sage: Posets.SymmetricGroupAbsoluteOrderPoset(4)
            Finite poset containing 24 elements
            sage: Posets.SymmetricGroupAbsoluteOrderPoset(3, labels="cycles")
            Finite poset containing 6 elements
            sage: Posets.SymmetricGroupAbsoluteOrderPoset(3, labels="reduced_words")
            Finite poset containing 6 elements
        """
        from sage.groups.perm_gps.permgroup_named import SymmetricGroup
        W = SymmetricGroup(n)
        if labels == "permutations":
            element_labels = {s: s.tuple() for s in W}
        if labels == "reduced_words":
            element_labels = {s: tuple(s.reduced_word()) for s in W}
        if labels == "cycles":
            element_labels = {
                s: "".join(x for x in s.cycle_string() if x != ',')
                for s in W
            }

        return Poset({s: s.absolute_covers() for s in W}, element_labels)
Example #28
0
    def covering_data(self, label):
        r"""
        Returns the permutation associated to the given ``label``.

        EXAMPLES::

            sage: from surface_dynamics.all import *

            sage: p = QuadraticStratum([1,1,-1,-1]).components()[0].permutation_representative()
            sage: pc = p.orientation_cover()
            sage: pc
            Covering of degree 2 of the permutation:
            0 1 2 3 3
            2 1 4 4 0

            sage: pc.covering_data(1)
            ()
            sage: pc.covering_data(3)
            (1,2)
        """
        from sage.groups.perm_gps.permgroup_named import SymmetricGroup
        S = SymmetricGroup(self._degree_cover)
        return S([i+1 for i in self.covering_data_tuple(label)])
def galois_action_on_embeddings(G_K):
    K = G_K.number_field()
    Kgal = G_K.splitting_field()
    embeddings = K.embeddings(Kgal)
    # first a shortcut in the case where G_K is normal in S_d since then it doesn't
    # matter for our application since we only care about the image
    # of the galois group in S_d
    d = K.absolute_degree()
    G_K_roots = TransitiveGroup(d, G_K.transitive_number())
    if G_K_roots.is_normal(SymmetricGroup(d)):
        id_G_K = G_K.Hom(G_K).identity()
        return G_K, id_G_K, id_G_K, Kgal, embeddings

    # now for the actual computation
    permutations = []
    for g in G_K.gens():
        phi = g.as_hom()
        g_perm = Permutation(
            [embeddings.index(phi * emb) + 1 for emb in embeddings]).inverse()
        permutations.append(g_perm)
    G_K_emb = PermutationGroup(permutations, canonicalize=False)
    to_emb = G_K.hom(G_K_emb.gens())
    from_emb = G_K_emb.hom(G_K.gens())
    return G_K_emb, to_emb, from_emb, Kgal, embeddings
Example #30
0
 def _symmetric_group(self):
     from sage.groups.perm_gps.permgroup_named import SymmetricGroup
     return SymmetricGroup([i for i,j in enumerate(self._active_darts) if j])
Example #31
0
    def reorder(self, order):
        """
        Return a new isogeny class with the curves reordered.

        INPUT:

        - ``order`` -- None, a string or an iterable over all curves
          in this class.  See
          :meth:`sage.schemes.elliptic_curves.ell_rational_field.EllipticCurve_rational_field.isogeny_class`
          for more details.

        OUTPUT:

        - Another :class:`IsogenyClass_EC` with the curves reordered
          (and matrices and maps changed as appropriate)

        EXAMPLES::

            sage: isocls = EllipticCurve('15a1').isogeny_class(use_tuple=False)
            sage: print "\n".join([repr(C) for C in isocls.curves])
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 10*x - 10 over Rational Field
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 5*x + 2 over Rational Field
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + 35*x - 28 over Rational Field
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 135*x - 660 over Rational Field
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 80*x + 242 over Rational Field
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 over Rational Field
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 110*x - 880 over Rational Field
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 2160*x - 39540 over Rational Field
            sage: isocls2 = isocls.reorder('lmfdb')
            sage: print "\n".join([repr(C) for C in isocls2.curves])
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 2160*x - 39540 over Rational Field
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 135*x - 660 over Rational Field
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 110*x - 880 over Rational Field
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 80*x + 242 over Rational Field
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 10*x - 10 over Rational Field
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 5*x + 2 over Rational Field
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 over Rational Field
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + 35*x - 28 over Rational Field
        """
        if order is None or isinstance(order, basestring) and order == self._algorithm:
            return self
        if isinstance(order, basestring):
            if order == "lmfdb":
                reordered_curves = sorted(self.curves, key = lambda E: E.a_invariants())
            else:
                reordered_curves = list(self.E.isogeny_class(algorithm=order, use_tuple=False))
        elif isinstance(order, (list, tuple, IsogenyClass_EC)):
            reordered_curves = list(order)
            if len(reordered_curves) != len(self.curves):
                raise ValueError("Incorrect length")
        else:
            raise TypeError("order parameter should be a string, list of curves or isogeny class")
        need_perm = self._mat is not None
        cpy = self.copy()
        curves = []
        perm = []
        for E in reordered_curves:
            try:
                j = self.curves.index(E)
            except ValueError:
                try:
                    j = self.curves.index(E.minimal_model())
                except ValueError:
                    raise ValueError("order does not yield a permutation of curves")
            curves.append(self.curves[j])
            if need_perm: perm.append(j+1)
        cpy.curves = tuple(curves)
        if need_perm:
            from sage.groups.perm_gps.permgroup_named import SymmetricGroup
            perm = SymmetricGroup(len(self.curves))(perm)
            cpy._mat = perm.matrix() * self._mat * (~perm).matrix()
            if self._maps is not None:
                n = len(self._maps)
                cpy._maps = [self._maps[perm(i+1)-1] for i in range(n)]
                for i in range(n):
                    cpy._maps[i] = [cpy._maps[i][perm(j+1)-1] for j in range(n)]
        else:
            cpy._mat = None
            cpy._maps = None
        return cpy
Example #32
0
def CyclicCodeFromGeneratingPolynomial(n,g,ignore=True):
    r"""
    If g is a polynomial over GF(q) which divides `x^n-1` then
    this constructs the code "generated by g" (ie, the code associated
    with the principle ideal `gR` in the ring
    `R = GF(q)[x]/(x^n-1)` in the usual way).

    The option "ignore" says to ignore the condition that (a) the
    characteristic of the base field does not divide the length (the
    usual assumption in the theory of cyclic codes), and (b) `g`
    must divide `x^n-1`. If ignore=True, instead of returning
    an error, a code generated by `gcd(x^n-1,g)` is created.

    EXAMPLES::

        sage: P.<x> = PolynomialRing(GF(3),"x")
        sage: g = x-1
        sage: C = codes.CyclicCodeFromGeneratingPolynomial(4,g); C
        Linear code of length 4, dimension 3 over Finite Field of size 3
        sage: P.<x> = PolynomialRing(GF(4,"a"),"x")
        sage: g = x^3+1
        sage: C = codes.CyclicCodeFromGeneratingPolynomial(9,g); C
        Linear code of length 9, dimension 6 over Finite Field in a of size 2^2
        sage: P.<x> = PolynomialRing(GF(2),"x")
        sage: g = x^3+x+1
        sage: C = codes.CyclicCodeFromGeneratingPolynomial(7,g); C
        Linear code of length 7, dimension 4 over Finite Field of size 2
        sage: C.gen_mat()
        [1 1 0 1 0 0 0]
        [0 1 1 0 1 0 0]
        [0 0 1 1 0 1 0]
        [0 0 0 1 1 0 1]
        sage: g = x+1
        sage: C = codes.CyclicCodeFromGeneratingPolynomial(4,g); C
        Linear code of length 4, dimension 3 over Finite Field of size 2
        sage: C.gen_mat()
        [1 1 0 0]
        [0 1 1 0]
        [0 0 1 1]

    On the other hand, CyclicCodeFromPolynomial(4,x) will produce a
    ValueError including a traceback error message: "`x` must
    divide `x^4 - 1`". You will also get a ValueError if you
    type

    ::

        sage: P.<x> = PolynomialRing(GF(4,"a"),"x")
        sage: g = x^2+1

    followed by CyclicCodeFromGeneratingPolynomial(6,g). You will also
    get a ValueError if you type

    ::

        sage: P.<x> = PolynomialRing(GF(3),"x")
        sage: g = x^2-1
        sage: C = codes.CyclicCodeFromGeneratingPolynomial(5,g); C
        Linear code of length 5, dimension 4 over Finite Field of size 3

    followed by C = CyclicCodeFromGeneratingPolynomial(5,g,False), with
    a traceback message including "`x^2 + 2` must divide
    `x^5 - 1`".
    """
    P = g.parent()
    x = P.gen()
    F = g.base_ring()
    p = F.characteristic()
    if not(ignore) and p.divides(n):
        raise ValueError, 'The characteristic %s must not divide %s'%(p,n)
    if not(ignore) and not(g.divides(x**n-1)):
        raise ValueError, '%s must divide x^%s - 1'%(g,n)
    gn = GCD([g,x**n-1])
    d = gn.degree()
    coeffs = Sequence(gn.list())
    r1 = Sequence(coeffs+[0]*(n - d - 1))
    Sn = SymmetricGroup(n)
    s = Sn.gens()[0] # assumes 1st gen of S_n is (1,2,...,n)
    rows = [permutation_action(s**(-i),r1) for i in range(n-d)]
    MS = MatrixSpace(F,n-d,n)
    return LinearCode(MS(rows))
Example #33
0
def PermutationGroupElement(g, parent=None, check=True):
    r"""
    Builds a permutation from ``g``.

    INPUT:

    - ``g`` -- either

      - a list of images

      - a tuple describing a single cycle

      - a list of tuples describing the cycle decomposition

      - a string describing the cycle decomposition

    - ``parent`` -- (optional) an ambient permutation group for the result;
      it is mandatory if you want a permutation on a domain different
      from `\{1, \ldots, n\}`

    - ``check`` -- (default: ``True``) whether additional check are performed;
      setting it to ``False`` is likely to result in faster code

    EXAMPLES:

    Initialization as a list of images::

        sage: p = PermutationGroupElement([1,4,2,3])
        sage: p
        (2,4,3)
        sage: p.parent()
        Symmetric group of order 4! as a permutation group

    Initialization as a list of cycles::

        sage: p = PermutationGroupElement([(3,5),(4,6,9)])
        sage: p
        (3,5)(4,6,9)
        sage: p.parent()
        Symmetric group of order 9! as a permutation group

    Initialization as a string representing a cycle decomposition::

        sage: p = PermutationGroupElement('(2,4)(3,5)')
        sage: p
        (2,4)(3,5)
        sage: p.parent()
        Symmetric group of order 5! as a permutation group

    By default the constructor assumes that the domain is `\{1, \dots, n\}`
    but it can be set to anything via its second ``parent`` argument::

        sage: S = SymmetricGroup(['a', 'b', 'c', 'd', 'e'])
        sage: PermutationGroupElement(['e', 'c', 'b', 'a', 'd'], S)
        ('a','e','d')('b','c')
        sage: PermutationGroupElement(('a', 'b', 'c'), S)
        ('a','b','c')
        sage: PermutationGroupElement([('a', 'c'), ('b', 'e')], S)
        ('a','c')('b','e')
        sage: PermutationGroupElement("('a','b','e')('c','d')", S)
        ('a','b','e')('c','d')

    But in this situation, you might want to use the more direct::

        sage: S(['e', 'c', 'b', 'a', 'd'])
        ('a','e','d')('b','c')
        sage: S(('a', 'b', 'c'))
        ('a','b','c')
        sage: S([('a', 'c'), ('b', 'e')])
        ('a','c')('b','e')
        sage: S("('a','b','e')('c','d')")
        ('a','b','e')('c','d')
    """
    if isinstance(g, permgroup_element.PermutationGroupElement):
        if parent is None or g.parent() is parent:
            return g

    if parent is None:
        from sage.groups.perm_gps.permgroup_named import SymmetricGroup

        try:
            v = standardize_generator(g, None)
        except KeyError:
            raise ValueError("invalid permutation vector: %s" % g)
        parent = SymmetricGroup(len(v))
        # We have constructed the parent from the element and already checked
        #   that it is a valid permutation
        check = False

    return parent.element_class(g, parent, check)
def CyclicCodeFromGeneratingPolynomial(n,g,ignore=True):
    r"""
    If g is a polynomial over GF(q) which divides `x^n-1` then
    this constructs the code "generated by g" (ie, the code associated
    with the principle ideal `gR` in the ring
    `R = GF(q)[x]/(x^n-1)` in the usual way).

    The option "ignore" says to ignore the condition that (a) the
    characteristic of the base field does not divide the length (the
    usual assumption in the theory of cyclic codes), and (b) `g`
    must divide `x^n-1`. If ignore=True, instead of returning
    an error, a code generated by `gcd(x^n-1,g)` is created.

    EXAMPLES::

        sage: P.<x> = PolynomialRing(GF(3),"x")
        sage: g = x-1
        sage: C = codes.CyclicCodeFromGeneratingPolynomial(4,g); C
        Linear code of length 4, dimension 3 over Finite Field of size 3
        sage: P.<x> = PolynomialRing(GF(4,"a"),"x")
        sage: g = x^3+1
        sage: C = codes.CyclicCodeFromGeneratingPolynomial(9,g); C
        Linear code of length 9, dimension 6 over Finite Field in a of size 2^2
        sage: P.<x> = PolynomialRing(GF(2),"x")
        sage: g = x^3+x+1
        sage: C = codes.CyclicCodeFromGeneratingPolynomial(7,g); C
        Linear code of length 7, dimension 4 over Finite Field of size 2
        sage: C.generator_matrix()
        [1 1 0 1 0 0 0]
        [0 1 1 0 1 0 0]
        [0 0 1 1 0 1 0]
        [0 0 0 1 1 0 1]
        sage: g = x+1
        sage: C = codes.CyclicCodeFromGeneratingPolynomial(4,g); C
        Linear code of length 4, dimension 3 over Finite Field of size 2
        sage: C.generator_matrix()
        [1 1 0 0]
        [0 1 1 0]
        [0 0 1 1]

    On the other hand, CyclicCodeFromPolynomial(4,x) will produce a
    ValueError including a traceback error message: "`x` must
    divide `x^4 - 1`". You will also get a ValueError if you
    type

    ::

        sage: P.<x> = PolynomialRing(GF(4,"a"),"x")
        sage: g = x^2+1

    followed by CyclicCodeFromGeneratingPolynomial(6,g). You will also
    get a ValueError if you type

    ::

        sage: P.<x> = PolynomialRing(GF(3),"x")
        sage: g = x^2-1
        sage: C = codes.CyclicCodeFromGeneratingPolynomial(5,g); C
        Linear code of length 5, dimension 4 over Finite Field of size 3

    followed by C = CyclicCodeFromGeneratingPolynomial(5,g,False), with
    a traceback message including "`x^2 + 2` must divide
    `x^5 - 1`".
    """
    P = g.parent()
    x = P.gen()
    F = g.base_ring()
    p = F.characteristic()
    if not(ignore) and p.divides(n):
        raise ValueError('The characteristic %s must not divide %s'%(p,n))
    if not(ignore) and not(g.divides(x**n-1)):
        raise ValueError('%s must divide x^%s - 1'%(g,n))
    gn = GCD([g,x**n-1])
    d = gn.degree()
    coeffs = Sequence(gn.list())
    r1 = Sequence(coeffs+[0]*(n - d - 1))
    Sn = SymmetricGroup(n)
    s = Sn.gens()[0] # assumes 1st gen of S_n is (1,2,...,n)
    rows = [permutation_action(s**(-i),r1) for i in range(n-d)]
    MS = MatrixSpace(F,n-d,n)
    return LinearCode(MS(rows))
Example #35
0
def _lowest_weights(w, factors, ex, parent=None):
    """
    Generate all decreasing factorizations in the 0-Hecke monoid that correspond
    to some valid semistandard Young tableaux.

    The semistandard Young tableaux should have at most ``factors`` columns and their
    column reading words should be equivalent to ``w`` in a 0-Hecke monoid.

    INPUT:

    - ``w`` -- a fully commutative reduced word, expressed as an iterable

    - ``factors`` -- number of factors for each decreasing factorization

    - ``ex`` -- number of extra letters in each decreasing factorizations

    - ``parent`` -- (default: None) parent of the decreasing factorizations, automatically assigned if it is None

    EXAMPLES::

        sage: from sage.combinat.crystals.fully_commutative_stable_grothendieck import _lowest_weights
        sage: _lowest_weights([1, 2, 1], 3, 1)
        Traceback (most recent call last):
        ...
        ValueError: the word w should be fully commutative

        sage: _lowest_weights([2, 1, 3, 2], 4, 3)
        [(2, 1)(3, 1)(3, 1)(2), (2, 1)(3, 1)(3, 2)(2)]

        sage: _lowest_weights([2, 1, 3, 2], 5, 3)
        [(2, 1)(3, 1)(3, 1)(2)(),
         (2, 1)(3, 1)(3, 2)(2)(),
         (2, 1)(3, 1)(1)(1)(2),
         (2, 1)(3, 1)(1)(2)(2),
         (2, 1)(3, 1)(2)(2)(2),
         (2, 1)(3, 2)(2)(2)(2)]

        sage: _lowest_weights([1, 3], 3, 1)
        [(3, 1)(1)(), (3, 1)(3)(), (1)(1)(3), (1)(3)(3)]

        sage: _lowest_weights([3, 2, 1], 5, 2)
        [(3, 2, 1)(1)(1)()()]
    """
    p = permutation.from_reduced_word(w)
    if p.has_pattern([3, 2, 1]):
        raise ValueError("the word w should be fully commutative")
    if parent is None:
        k = max(w)
        S = SymmetricGroup(k + 1)
        word = S.from_reduced_word(w)
        parent = FullyCommutativeStableGrothendieckCrystal(word, factors, ex)

    _canonical_word = lambda w, ex: [list(w)[0]] * ex + list(w)
    L = _list_equivalent_words(_canonical_word(w, ex))

    M = []
    for v in L:
        if _is_valid_column_word(v, factors):
            J = [0] + _jumps(v) + [len(v)]
            t = [v[J[i]:J[i + 1]] for i in range(len(J) - 1)]
            if len(J) < factors + 1:
                t += [()] * (factors + 1 - len(J))
            M.append(parent.element_class(parent, t))
    return sorted(M)
Example #36
0
def braid_from_piecewise(strands):
    r"""
    Compute the braid corresponding to the piecewise linear curves strands.

    INPUT:

    - ``strands`` -- a list of lists of tuples ``(t, c)``, where ``t``
      is a number bewteen 0 and 1, and ``c`` is a complex number

    OUTPUT:

    The braid formed by the piecewise linear strands.

    EXAMPLES::

        sage: from sage.schemes.curves.zariski_vankampen import braid_from_piecewise # optional - sirocco
        sage: paths = [[(0, I), (0.2, -1 - 0.5*I), (0.8, -1), (1, -I)],
        ....:          [(0, -1), (0.5, -I), (1, 1)],
        ....:          [(0, 1), (0.5, 1 + I), (1, I)]]
        sage: braid_from_piecewise(paths) # optional - sirocco
        s0*s1
    """
    L = strands
    i = min(val[1][0] for val in L)
    totalpoints = [[[a[0][1].real(), a[0][1].imag()]] for a in L]
    indices = [1 for a in range(len(L))]
    while i < 1:
        for j, val in enumerate(L):
            if val[indices[j]][0] > i:
                xaux = val[indices[j] - 1][1]
                yaux = val[indices[j]][1]
                aaux = val[indices[j] - 1][0]
                baux = val[indices[j]][0]
                interpola = xaux + (yaux - xaux)*(i - aaux)/(baux - aaux)
                totalpoints[j].append([interpola.real(), interpola.imag()])
            else:
                totalpoints[j].append([val[indices[j]][1].real(), val[indices[j]][1].imag()])
                indices[j] = indices[j] + 1
        i = min(val[indices[k]][0] for k,val in enumerate(L))

    for j, val in enumerate(L):
         totalpoints[j].append([val[-1][1].real(), val[-1][1].imag()])

    braid = []
    G = SymmetricGroup(len(totalpoints))
    def sgn(x, y): # Opposite sign of cmp
        if x < y:
            return 1
        if x > y:
            return -1
        return 0
    for i in range(len(totalpoints[0]) - 1):
        l1 = [totalpoints[j][i] for j in range(len(L))]
        l2 = [totalpoints[j][i+1] for j in range(len(L))]
        M = [[l1[s], l2[s]] for s in range(len(l1))]
        M.sort()
        l1 = [a[0] for a in M]
        l2 = [a[1] for a in M]
        cruces = []
        for j in range(len(l2)):
            for k in range(j):
                if l2[j] < l2[k]:
                    t = (l1[j][0] - l1[k][0])/(l2[k][0] - l1[k][0] + l1[j][0] - l2[j][0])
                    s = sgn(l1[k][1]*(1 - t) + t*l2[k][1], l1[j][1]*(1 - t) + t*l2[j][1])
                    cruces.append([t, k, j, s])
        if cruces:
            cruces.sort()
            P = G(Permutation([]))
            while cruces:
                # we select the crosses in the same t
                crucesl = [c for c in cruces if c[0]==cruces[0][0]]
                crossesl = [(P(c[2]+1) - P(c[1]+1),c[1],c[2],c[3]) for c in crucesl]
                cruces = cruces[len(crucesl):]
                while crossesl:
                    crossesl.sort()
                    c = crossesl.pop(0)
                    braid.append(c[3]*min(map(P, [c[1] + 1, c[2] + 1])))
                    P = G(Permutation([(c[1] + 1, c[2] + 1)]))*P
                    crossesl = [(P(c[2]+1) - P(c[1]+1),c[1],c[2],c[3]) for c in crossesl]

    B = BraidGroup(len(L))
    return B(braid)
Example #37
0
    def reorder(self, order):
        """
        Return a new isogeny class with the curves reordered.

        INPUT:

        - ``order`` -- None, a string or an iterable over all curves
          in this class.  See
          :meth:`sage.schemes.elliptic_curves.ell_rational_field.EllipticCurve_rational_field.isogeny_class`
          for more details.

        OUTPUT:

        - Another :class:`IsogenyClass_EC` with the curves reordered
          (and matrices and maps changed as appropriate)

        EXAMPLES::

            sage: isocls = EllipticCurve('15a1').isogeny_class(use_tuple=False)
            sage: print "\n".join([repr(C) for C in isocls.curves])
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 10*x - 10 over Rational Field
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 5*x + 2 over Rational Field
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + 35*x - 28 over Rational Field
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 135*x - 660 over Rational Field
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 80*x + 242 over Rational Field
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 over Rational Field
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 110*x - 880 over Rational Field
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 2160*x - 39540 over Rational Field
            sage: isocls2 = isocls.reorder('lmfdb')
            sage: print "\n".join([repr(C) for C in isocls2.curves])
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 2160*x - 39540 over Rational Field
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 135*x - 660 over Rational Field
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 110*x - 880 over Rational Field
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 80*x + 242 over Rational Field
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 10*x - 10 over Rational Field
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 5*x + 2 over Rational Field
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 over Rational Field
            Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + 35*x - 28 over Rational Field
        """
        if order is None or isinstance(
                order, basestring) and order == self._algorithm:
            return self
        if isinstance(order, basestring):
            if order == "lmfdb":
                reordered_curves = sorted(self.curves,
                                          key=lambda E: E.a_invariants())
            else:
                reordered_curves = list(
                    self.E.isogeny_class(algorithm=order, use_tuple=False))
        elif isinstance(order, (list, tuple, IsogenyClass_EC)):
            reordered_curves = list(order)
            if len(reordered_curves) != len(self.curves):
                raise ValueError("Incorrect length")
        else:
            raise TypeError(
                "order parameter should be a string, list of curves or isogeny class"
            )
        need_perm = self._mat is not None
        cpy = self.copy()
        curves = []
        perm = []
        for E in reordered_curves:
            try:
                j = self.curves.index(E)
            except ValueError:
                try:
                    j = self.curves.index(E.minimal_model())
                except ValueError:
                    raise ValueError(
                        "order does not yield a permutation of curves")
            curves.append(self.curves[j])
            if need_perm: perm.append(j + 1)
        cpy.curves = tuple(curves)
        if need_perm:
            from sage.groups.perm_gps.permgroup_named import SymmetricGroup
            perm = SymmetricGroup(len(self.curves))(perm)
            cpy._mat = perm.matrix() * self._mat * (~perm).matrix()
            if self._maps is not None:
                n = len(self._maps)
                cpy._maps = [self._maps[perm(i + 1) - 1] for i in range(n)]
                for i in range(n):
                    cpy._maps[i] = [
                        cpy._maps[i][perm(j + 1) - 1] for j in range(n)
                    ]
        else:
            cpy._mat = None
            cpy._maps = None
        return cpy