Beispiel #1
0
def desubstitute(self, u):
    r"""
    EXAMPLES:

    Unique preimage::

        sage: from slabbe.word_morphisms import desubstitute
        sage: s = WordMorphism({0:[0,1],1:[1,0]})
        sage: desubstitute(s, Word([0,1,0,1,1,0]))
        [word: 001]

    Non-unique preimage::

        sage: s = WordMorphism({0:[0,1],1:[1,0],2:[1,0]})
        sage: desubstitute(s, Word([0,1,0,1,1,0]))
        [word: 001, word: 002]

    No preimage::

        sage: s = WordMorphism({0:[0,1],1:[1,0]})
        sage: desubstitute(s, Word([0,1,0,1,1,1]))
        []

    Lot of preimages (computation is done in parallel with Florent's Hivert
    parallel map reduce code)::

        sage: s = WordMorphism({0:[0,1],1:[0,1]})
        sage: w = Word([0,1]) ^ 10
        sage: L = desubstitute(s, w)
        sage: len(L)
        1024
    """
    morph = self._morph
    len_u = len(u)

    def successor(node):
        L, i = node
        if i == len_u:
            return []
        else:
            ui = u[i:]
            return [(L + [k], i + len(v)) for k, v in morph.iteritems()
                    if v.is_prefix(ui)]

    roots = [([], 0)]
    post_process = lambda node: node if node[1] == len_u else None
    from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet
    R = RecursivelyEnumeratedSet(roots,
                                 successor,
                                 structure='forest',
                                 post_process=post_process)
    W = self.domain()
    map_function = lambda node: [W(node[0])]
    reduce_function = lambda x, y: x + y
    reduce_init = []
    return R.map_reduce(map_function, reduce_function, reduce_init)
Beispiel #2
0
    def __iter__(self):
        r"""
        Naive algorithm to give the elements of the conjugacy class.

        .. TODO::

            Implement a non-naive algorithm, cf. for instance
            G. Butler: "An Inductive Schema for Computing Conjugacy Classes
            in Permutation Groups", Math. of Comp. Vol. 62, No. 205 (1994)

        EXAMPLES:

        Groups of permutations::

            sage: G = SymmetricGroup(3)
            sage: g = G((1,2))
            sage: C = ConjugacyClass(G,g)
            sage: sorted(C)
            [(2,3), (1,2), (1,3)]

        It works for infinite groups::

            sage: a = matrix(ZZ,2,[1,1,0,1])
            sage: b = matrix(ZZ,2,[1,0,1,1])
            sage: G = MatrixGroup([a,b])        # takes 1s
            sage: a = G(a)
            sage: C = ConjugacyClass(G, a)
            sage: it = iter(C)
            sage: [next(it) for _ in range(5)] # random (nothing guarantees enumeration order)
            [
            [1 1]  [ 2  1]  [ 0  1]  [ 3  1]  [ 3  4]
            [0 1], [-1  0], [-1  2], [-4 -1], [-1 -1]
            ]

        We check that two matrices are in C::

            sage: b = G(b)
            sage: m1 = b * a * ~b
            sage: m2 = ~b * a * b
            sage: any(x == m1 for x in C)
            True
            sage: any(x == m2 for x in C)
            True

        """
        from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet
        g = self._representative
        gens = self._parent.monoid_generators()
        R = RecursivelyEnumeratedSet([g],
                                     lambda y: [c * y * c**-1 for c in gens],
                                     structure=None)
        return R.breadth_first_search_iterator()
    def __iter__(self):
        r"""
        Naive algorithm to give the elements of the conjugacy class.

        .. TODO::

            Implement a non-naive algorithm, cf. for instance
            G. Butler: "An Inductive Schema for Computing Conjugacy Classes
            in Permutation Groups", Math. of Comp. Vol. 62, No. 205 (1994)

        EXAMPLES:

        Groups of permutations::

            sage: G = SymmetricGroup(3)
            sage: g = G((1,2))
            sage: C = ConjugacyClass(G,g)
            sage: sorted(C)
            [(2,3), (1,2), (1,3)]

        It works for infinite groups::

            sage: a = matrix(ZZ,2,[1,1,0,1])
            sage: b = matrix(ZZ,2,[1,0,1,1])
            sage: G = MatrixGroup([a,b])        # takes 1s
            sage: a = G(a)
            sage: C = ConjugacyClass(G, a)
            sage: it = iter(C)
            sage: [next(it) for _ in range(5)]
            [
            [1 1]  [ 2  1]  [ 0  1]  [ 3  1]  [ 3  4]
            [0 1], [-1  0], [-1  2], [-4 -1], [-1 -1]
            ]

        We check that two matrices are in C::

            sage: b = G(b)
            sage: m1 = b * a * ~b
            sage: m2 = ~b * a * b
            sage: any(x == m1 for x in C)
            True
            sage: any(x == m2 for x in C)
            True

        """
        from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet
        g = self._representative
        gens = self._parent.monoid_generators()
        R = RecursivelyEnumeratedSet([g],
                                     lambda y: [c*y*c**-1 for c in gens],
                                     structure=None)
        return R.breadth_first_search_iterator()
Beispiel #4
0
def desubstitute(self, u):
    r"""
    EXAMPLES:

    Unique preimage::

        sage: from slabbe.word_morphisms import desubstitute
        sage: s = WordMorphism({0:[0,1],1:[1,0]})
        sage: desubstitute(s, Word([0,1,0,1,1,0]))
        [word: 001]

    Non-unique preimage::

        sage: s = WordMorphism({0:[0,1],1:[1,0],2:[1,0]})
        sage: desubstitute(s, Word([0,1,0,1,1,0]))
        [word: 001, word: 002]

    No preimage::

        sage: s = WordMorphism({0:[0,1],1:[1,0]})
        sage: desubstitute(s, Word([0,1,0,1,1,1]))
        []

    Lot of preimages (computation is done in parallel with Florent's Hivert
    parallel map reduce code)::

        sage: s = WordMorphism({0:[0,1],1:[0,1]})
        sage: w = Word([0,1]) ^ 10
        sage: L = desubstitute(s, w)
        sage: len(L)
        1024
    """
    morph = self._morph
    len_u = len(u)
    def successor(node):
        L,i = node
        if i == len_u:
            return []
        else:
            ui = u[i:]
            return [(L+[k],i+len(v)) for k,v in morph.iteritems() if v.is_prefix(ui)]
    roots = [([],0)]
    post_process = lambda node:node if node[1]==len_u else None
    from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet
    R = RecursivelyEnumeratedSet(roots, successor, structure='forest',
            post_process=post_process)
    W = self.domain()
    map_function = lambda node:[W(node[0])]
    reduce_function = lambda x,y:x+y
    reduce_init = []
    return R.map_reduce(map_function, reduce_function, reduce_init)
Beispiel #5
0
        def __iter__(self, index_set=None, max_depth=float("inf")):
            """
            Returns the iterator of ``self``.

            INPUT:

            - ``index_set`` -- (Default: ``None``) The index set; if ``None``
              then use the index set of the crystal

            - ``max_depth`` -- (Default: infinity) The maximum depth to build

            EXAMPLES::

                sage: C = crystals.LSPaths(['A',2,1],[0,1,0])
                sage: sorted([p for p in C.__iter__(max_depth=3)], key=str)
                [(-Lambda[0] + 2*Lambda[2] - delta,),
                 (-Lambda[0] + Lambda[1] + 1/2*Lambda[2] - delta, Lambda[0] - 1/2*Lambda[2]),
                 (1/2*Lambda[0] + Lambda[1] - Lambda[2] - 1/2*delta, -1/2*Lambda[0] + Lambda[2] - 1/2*delta),
                 (2*Lambda[0] - Lambda[2],),
                 (Lambda[0] - Lambda[1] + Lambda[2],),
                 (Lambda[1],)]
                sage: [p for p in C.__iter__(index_set=[0, 1], max_depth=3)]
                [(Lambda[1],), (Lambda[0] - Lambda[1] + Lambda[2],), (-Lambda[0] + 2*Lambda[2] - delta,)]
            """
            if index_set is None:
                index_set = self.index_set()
            from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet
            return RecursivelyEnumeratedSet(
                self.module_generators,
                lambda x: [x.f(i) for i in index_set],
                structure='graded',
                max_depth=max_depth).breadth_first_search_iterator()
Beispiel #6
0
    def elements(self):
        r"""
        Returns the elements of ``self``

        Those are constructed as the elements below the maximal
        elements of ``self`` in Bruhat order.

        OUTPUT: a :class:`RecursivelyEnumeratedSet_generic` object

        EXAMPLES::

            sage: PF = WeylGroup(['A',3]).pieri_factors()
            sage: [w.reduced_word() for w in PF.elements()]
            [[3, 2, 1], [2, 1], [1], [], [3, 1], [3], [3, 2], [2]]

        .. SEEALSO:: :meth:`maximal_elements`

        .. TODO::

            Possibly remove this method and instead have this class
            inherit from :class:`RecursivelyEnumeratedSet_generic`.
        """
        return RecursivelyEnumeratedSet(self.maximal_elements(),
                                        attrcall('bruhat_lower_covers'),
                                        structure=None,
                                        enumeration='naive')
Beispiel #7
0
def category_sample():
    r"""
    Return a sample of categories.

    It is constructed by looking for all concrete category classes
    declared in ``sage.categories.all``, calling
    :meth:`Category.an_instance` on those and taking all their super
    categories.

    EXAMPLES::

        sage: from sage.categories.category import category_sample
        sage: sorted(category_sample(), key=str)
        [Category of G-sets for Symmetric group of order 8! as a permutation group,
         Category of Hecke modules over Rational Field,
         Category of additive magmas, ...,
         Category of fields, ...,
         Category of graded hopf algebras with basis over Rational Field, ...,
         Category of modular abelian varieties over Rational Field, ...,
         Category of simplicial complexes, ...,
         Category of vector spaces over Rational Field, ...,
         Category of weyl groups,...
    """
    import sage.categories.all
    abstract_classes_for_categories = [Category]
    seeds = {
        cls.an_instance()
        for cls in sage.categories.all.__dict__.values()
        if isinstance(cls, type) and issubclass(cls, Category)
        and cls not in abstract_classes_for_categories
    }
    return list(RecursivelyEnumeratedSet(seeds, related_categories))
Beispiel #8
0
    def connected_component_iterator(self, roots=None):
        r"""
        Return an iterator over the connected component of the root.

        This method overwrites the methods
        :meth:`slabbe.discrete_subset.DiscreteSubset.connected_component_iterator`,
        because for billiard words, we go only in one direction in each
        axis which allows to use a forest structure for the enumeration.

        INPUT:

        - ``roots`` - list of some elements immutable in self

        EXAMPLES::

            sage: from slabbe import BilliardCube
            sage: p = BilliardCube([1,pi,sqrt(7)])
            sage: root = vector((0,0,0))
            sage: root.set_immutable()
            sage: it = p.connected_component_iterator(roots=[root])
            sage: [next(it) for _ in range(5)]
            [(0, 0, 0), (0, 1, 0), (0, 1, 1), (0, 2, 1), (1, 2, 1)]

        ::

            sage: p = BilliardCube([1,pi,7.45], start=(10.2,20.4,30.8))
            sage: it = p.connected_component_iterator()
            sage: [next(it) for _ in range(5)]
            [(10.2000000000000, 20.4000000000000, 30.8000000000000),
             (10.2000000000000, 20.4000000000000, 31.8000000000000),
             (10.2000000000000, 21.4000000000000, 31.8000000000000),
             (10.2000000000000, 21.4000000000000, 32.8000000000000),
             (10.2000000000000, 21.4000000000000, 33.8000000000000)]
        """
        roots = roots if roots else [self.an_element()]
        if not all(root in self for root in roots):
            raise ValueError("roots (=%s) must all be in self(=%s)" %
                             (roots, self))
        #for root in roots:
        #    root.set_immutable()
        C = RecursivelyEnumeratedSet(seeds=roots,
                                     successors=self.children,
                                     structure='forest')
        return C.breadth_first_search_iterator()
Beispiel #9
0
    def connected_component_iterator(self, roots=None):
        r"""
        Return an iterator over the connected component of the root.

        This method overwrites the methods
        :meth:`slabbe.discrete_subset.DiscreteSubset.connected_component_iterator`,
        because for billiard words, we go only in one direction in each
        axis which allows to use a forest structure for the enumeration.

        INPUT:

        - ``roots`` - list of some elements immutable in self

        EXAMPLES::

            sage: from slabbe import BilliardCube
            sage: p = BilliardCube([1,pi,sqrt(7)])
            sage: root = vector((0,0,0))
            sage: root.set_immutable()
            sage: it = p.connected_component_iterator(roots=[root])
            sage: [next(it) for _ in range(5)]
            [(0, 0, 0), (0, 1, 0), (0, 1, 1), (0, 2, 1), (1, 2, 1)]

        ::

            sage: p = BilliardCube([1,pi,7.45], start=(10.2,20.4,30.8))
            sage: it = p.connected_component_iterator()
            sage: [next(it) for _ in range(5)]
            [(10.2000000000000, 20.4000000000000, 30.8000000000000),
             (10.2000000000000, 20.4000000000000, 31.8000000000000),
             (10.2000000000000, 21.4000000000000, 31.8000000000000),
             (10.2000000000000, 21.4000000000000, 32.8000000000000),
             (10.2000000000000, 21.4000000000000, 33.8000000000000)]
        """
        roots = roots if roots else [self.an_element()]
        if not all(root in self for root in roots):
            raise ValueError("roots (=%s) must all be in self(=%s)" % (roots, self))
        #for root in roots:
        #    root.set_immutable()
        C = RecursivelyEnumeratedSet(seeds=roots, successors=self.children, structure='forest')
        return C.breadth_first_search_iterator()
    def __iter__(self):
        """
        Returns the iterator of ``self``.

        EXAMPLES::

            sage: KRT = crystals.TensorProductOfKirillovReshetikhinTableaux(['A', 3, 1], [[2,1], [1,1]])
            sage: g = KRT.__iter__()
            sage: next(g)
            [[2], [3]] (X) [[1]]
            sage: next(g)
            [[2], [4]] (X) [[1]]
        """
        index_set = self._cartan_type.classical().index_set()
        from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet
        return RecursivelyEnumeratedSet(self.module_generators,
                    lambda x: [x.f(i) for i in index_set],
                    structure=None).naive_search_iterator()
    def dominant_maximal_weights(self):
        r"""
        Return the dominant maximal weights of ``self``.

        A weight `\mu` is *maximal* if it has nonzero multiplicity but
        `\mu + \delta`` has multiplicity zero. There are a finite number
        of dominant maximal weights. Indeed, [Kac]_ Proposition 12.6
        shows that the dominant maximal weights are in bijection with
        the classical weights in `k \cdot F` where `F` is the fundamental
        alcove and `k` is the level. The construction used in this
        method is based on that Proposition.

        EXAMPLES::

            sage: Lambda = RootSystem(['C',3,1]).weight_lattice(extended=true).fundamental_weights()
            sage: IntegrableRepresentation(2*Lambda[0]).dominant_maximal_weights()
            (2*Lambda[0],
             Lambda[0] + Lambda[2] - delta,
             2*Lambda[1] - delta,
             Lambda[1] + Lambda[3] - 2*delta,
             2*Lambda[2] - 2*delta,
             2*Lambda[3] - 3*delta)
        """
        k = self.level()
        Lambda = self._P.fundamental_weights()

        def next_level(wt):
            return [
                wt + Lambda[i] for i in self._index_set_classical
                if (wt + Lambda[i]).level() <= k
            ]

        R = RecursivelyEnumeratedSet([self._P.zero()], next_level)
        candidates = [x + (k - x.level()) * Lambda[0] for x in list(R)]
        ret = []
        delta = self._Q.null_root()
        for x in candidates:
            if self._from_weight_helper(self._Lam - x, check=True):
                t = 0
                while self.m(self.from_weight(x - t * delta)) == 0:
                    t += 1
                ret.append(x - t * delta)
        return tuple(ret)
        def ideal(self, gens, side="twosided"):
            r"""
            Return the ``side``-sided ideal generated by ``gens``.

            This brute force implementation recursively multiplies the
            elements of ``gens`` by the distinguished generators of
            this semigroup.

            .. SEEALSO:: :meth:`semigroup_generators`

            INPUT:

            - ``gens`` -- a list (or iterable) of elements of ``self``
            - ``side`` -- [default: "twosided"] "left", "right" or "twosided"

            EXAMPLES::

                sage: S = FiniteSemigroups().example()
                sage: sorted(S.ideal([S('cab')], side="left"))
                ['abc', 'abcd', 'abdc', 'acb', 'acbd', 'acdb', 'adbc',
                 'adcb', 'bac', 'bacd', 'badc', 'bca', 'bcad', 'bcda',
                 'bdac', 'bdca', 'cab', 'cabd', 'cadb', 'cba', 'cbad',
                 'cbda', 'cdab', 'cdba', 'dabc', 'dacb', 'dbac', 'dbca',
                 'dcab', 'dcba']
                sage: list(S.ideal([S('cab')], side="right"))
                ['cab', 'cabd']
                sage: sorted(S.ideal([S('cab')], side="twosided"))
                ['abc', 'abcd', 'abdc', 'acb', 'acbd', 'acdb', 'adbc',
                 'adcb', 'bac', 'bacd', 'badc', 'bca', 'bcad', 'bcda',
                 'bdac', 'bdca', 'cab', 'cabd', 'cadb', 'cba', 'cbad',
                 'cbda', 'cdab', 'cdba', 'dabc', 'dacb', 'dbac', 'dbca',
                 'dcab', 'dcba']
                sage: sorted(S.ideal([S('cab')]))
                ['abc', 'abcd', 'abdc', 'acb', 'acbd', 'acdb', 'adbc',
                 'adcb', 'bac', 'bacd', 'badc', 'bca', 'bcad', 'bcda',
                 'bdac', 'bdca', 'cab', 'cabd', 'cadb', 'cba', 'cbad',
                 'cbda', 'cdab', 'cdba', 'dabc', 'dacb', 'dbac', 'dbca',
                 'dcab', 'dcba']
            """
            from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet
            return RecursivelyEnumeratedSet(gens,
                                            self.succ_generators(side=side))
        def __iter__(self):
            r"""
            Return an iterator over the elements of ``self``.

            This brute force implementation recursively multiplies
            together the distinguished semigroup generators.

            .. SEEALSO:: :meth:`semigroup_generators`

            EXAMPLES::

                sage: S = FiniteSemigroups().example(alphabet=('x','y'))
                sage: it = S.__iter__()
                sage: list(it)
                ['x', 'y', 'yx', 'xy']
            """
            from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet
            return iter(RecursivelyEnumeratedSet(self.semigroup_generators(),
                                                 self.succ_generators(side="right"),
                                                 enumeration='breadth'))
    def branch(self, i=None, weyl_character_ring=None, sequence=None, depth=5):
        r"""
        Return the branching rule on ``self``.

        Removing any node from the extended Dynkin diagram of the affine
        Lie algebra results in the Dynkin diagram of a classical Lie
        algebra, which is therefore a Lie subalgebra. For example
        removing the `0` node from the Dynkin diagram of type ``[X, r, 1]``
        produces the classical Dynkin diagram of ``[X, r]``.

        Thus for each `i` in the index set, we may restrict ``self`` to
        the corresponding classical subalgebra. Of course ``self`` is
        an infinite dimensional representation, but each weight `\mu`
        is assigned a grading by the number of times the simple root
        `\alpha_i` appears in `\Lambda-\mu`. Thus the branched
        representation is graded and we get sequence of finite-dimensional
        representations which this method is able to compute.

        OPTIONAL:

        - ``i`` -- (default: 0) an element of the index set
        - ``weyl_character_ring`` -- a WeylCharacterRing
        - ``sequence`` -- a dictionary
        - ``depth`` -- (default: 5) an upper bound for `k` determining
          how many terms to give

        In the default case where `i = 0`, you do not need to specify
        anything else, though you may want to increase the depth if
        you need more terms.

        EXAMPLES::

            sage: Lambda = RootSystem(['A',2,1]).weight_lattice(extended=true).fundamental_weights()
            sage: V = IntegrableRepresentation(2*Lambda[0])
            sage: b = V.branch(); b
            [A2(0,0),
             A2(1,1),
             A2(0,0) + 2*A2(1,1) + A2(2,2),
             2*A2(0,0) + 2*A2(0,3) + 4*A2(1,1) + 2*A2(3,0) + 2*A2(2,2),
             4*A2(0,0) + 3*A2(0,3) + 10*A2(1,1) + 3*A2(3,0) + A2(1,4) + 6*A2(2,2) + A2(4,1),
             6*A2(0,0) + 9*A2(0,3) + 20*A2(1,1) + 9*A2(3,0) + 3*A2(1,4) + 12*A2(2,2) + 3*A2(4,1) + A2(3,3)]

        If the parameter ``weyl_character_ring`` is omitted, the ring may be recovered
        as the parent of one of the branched coefficients::

            sage: A2 = b[0].parent(); A2
            The Weyl Character Ring of Type A2 with Integer Ring coefficients

        If `i` is not zero then you should specify the :class:`WeylCharacterRing` that you
        are branching to. This is determined by the Dynkin diagram::

            sage: Lambda = RootSystem(['B',3,1]).weight_lattice(extended=true).fundamental_weights()
            sage: V = IntegrableRepresentation(Lambda[0])
            sage: V.cartan_type().dynkin_diagram()
                O 0
                |
                |
            O---O=>=O
            1   2   3   
            B3~

        In this example, we observe that removing the `i=2` node from the
        Dynkin diagram produces a reducible diagram of type ``A1xA1xA1``.
        Thus we have a branching to
        `\mathfrak{sl}(2) \times \mathfrak{sl}(2) \times \mathfrak{sl}(2)`::

            sage: A1xA1xA1 = WeylCharacterRing("A1xA1xA1",style="coroots")
            sage: V.branch(i=2,weyl_character_ring=A1xA1xA1)
            [A1xA1xA1(1,0,0),
             A1xA1xA1(0,1,2),
             A1xA1xA1(1,0,0) + A1xA1xA1(1,2,0) + A1xA1xA1(1,0,2),
             A1xA1xA1(2,1,2) + A1xA1xA1(0,1,0) + 2*A1xA1xA1(0,1,2),
             3*A1xA1xA1(1,0,0) + 2*A1xA1xA1(1,2,0) + A1xA1xA1(1,2,2) + 2*A1xA1xA1(1,0,2) + A1xA1xA1(1,0,4) + A1xA1xA1(3,0,0),
             A1xA1xA1(2,1,0) + 3*A1xA1xA1(2,1,2) + 2*A1xA1xA1(0,1,0) + 5*A1xA1xA1(0,1,2) + A1xA1xA1(0,1,4) + A1xA1xA1(0,3,2)]

        If the nodes of the two Dynkin diagrams are not in the same order, you
        must specify an additional parameter, ``sequence`` which gives a dictionary
        to the affine Dynkin diagram to the classical one.

        EXAMPLES::

            sage: Lambda = RootSystem(['F',4,1]).weight_lattice(extended=true).fundamental_weights()
            sage: V = IntegrableRepresentation(Lambda[0])
            sage: V.cartan_type().dynkin_diagram()
            O---O---O=>=O---O
            0   1   2   3   4   
            F4~
            sage: A1xC3=WeylCharacterRing("A1xC3",style="coroots")
            sage: A1xC3.dynkin_diagram()
            O
            1   
            O---O=<=O
            2   3   4   
            A1xC3

        Observe that removing the `i=1` node from the ``F4~`` Dynkin diagram
        gives the ``A1xC3`` diagram, but the roots are in a different order.
        The nodes `0, 2, 3, 4` of ``F4~`` correspond to ``1, 4, 3, 2``
        of ``A1xC3`` and so we encode this in a dictionary::

            sage: V.branch(i=1,weyl_character_ring=A1xC3,sequence={0:1,2:4,3:3,4:2}) # long time
            [A1xC3(1,0,0,0),
             A1xC3(0,0,0,1),
             A1xC3(1,0,0,0) + A1xC3(1,2,0,0),
             A1xC3(2,0,0,1) + A1xC3(0,0,0,1) + A1xC3(0,1,1,0),
             2*A1xC3(1,0,0,0) + A1xC3(1,0,1,0) + 2*A1xC3(1,2,0,0) + A1xC3(1,0,2,0) + A1xC3(3,0,0,0),
             2*A1xC3(2,0,0,1) + A1xC3(2,1,1,0) + A1xC3(0,1,0,0) + 3*A1xC3(0,0,0,1) + 2*A1xC3(0,1,1,0) + A1xC3(0,2,0,1)]

        The branch method gives a way of computing the graded dimension of the integrable representation::

            sage: Lambda = RootSystem("A1~").weight_lattice(extended=true).fundamental_weights()
            sage: V=IntegrableRepresentation(Lambda[0])
            sage: r = [x.degree() for x in V.branch(depth=15)]; r
            [1, 3, 4, 7, 13, 19, 29, 43, 62, 90, 126, 174, 239, 325, 435, 580]
            sage: oeis(r)                                                        # optional -- internet
            0: A029552: Expansion of phi(x) / f(-x) in powers of x where phi(), f() are Ramanujan theta functions.

        """
        if i is None:
            i = self._cartan_type.special_node()
        if i == self._cartan_type.special_node() or self._cartan_type.type(
        ) == 'A':
            if weyl_character_ring is None:
                weyl_character_ring = WeylCharacterRing(
                    self._cartan_type.classical(), style="coroots")
            if weyl_character_ring.cartan_type(
            ) != self._cartan_type.classical():
                raise ValueError(
                    "Cartan type of WeylCharacterRing must be %s" %
                    self.cartan_type().classical())
        elif weyl_character_ring is None:
            raise ValueError(
                "the argument weyl_character_ring cannot be omitted if i != 0")
        if sequence is None:
            sequence = {}
            for j in self._index_set:
                if j < i:
                    sequence[j] = j + 1
                elif j > i:
                    sequence[j] = j

        def next_level(x):
            ret = []
            for j in self._index_set:
                t = list(x[0])
                t[j] += 1
                t = tuple(t)
                m = self.m(t)
                if m > 0 and t[i] <= depth:
                    ret.append((t, m))
            return ret

        hwv = (tuple([0 for j in self._index_set]), 1)
        terms = RecursivelyEnumeratedSet([hwv], next_level)
        fw = weyl_character_ring.fundamental_weights()
        P = self.weight_lattice()
        ret = []
        for l in range(depth + 1):
            lterms = [x for x in terms if x[0][i] == l]
            ldict = {}
            for x in lterms:
                mc = P(self.to_weight(x[0])).monomial_coefficients()
                contr = sum(fw[sequence[j]] * mc.get(j, 0)
                            for j in self._index_set if j != i).coerce_to_sl()
                if contr in ldict:
                    ldict[contr] += x[1]
                else:
                    ldict[contr] = x[1]
            ret.append(weyl_character_ring.char_from_weights(ldict))
        return ret