Esempio n. 1
0
    def __contains__(self, x):
        """
        Check if ``x`` is in ``self``.

        EXAMPLES::

            sage: B = crystals.Tableaux(['A',4], shape=[2,1])
            sage: S = B.subcrystal(generators=(B(2,1,1), B(5,2,4)), index_set=[1,2])
            sage: B(5,2,4) in S
            True
            sage: mg = B.module_generators[0]
            sage: mg in S
            True
            sage: mg.f(2).f(3) in S
            False
        """
        if isinstance(x, Subcrystal.Element) and x.parent() == self:
            return True

        if x in self._ambient:
            if not self._containing(x):
                return False
            x = self.element_class(self, x)

        if self in FiniteCrystals():
            return x in self.list()

        # TODO: make this work for infinite crystals
        import warnings
        warnings.warn("Testing containment in an infinite crystal"
                      " defaults to returning True")
        return True
Esempio n. 2
0
    def cardinality(self):
        """
        Return the cardinality of ``self``.

        EXAMPLES::

            sage: B = crystals.Tableaux(['A',4], shape=[2,1])
            sage: S = B.subcrystal(generators=[B(2,1,1)], index_set=[1,2])
            sage: S.cardinality()
            8
            sage: B = crystals.infinity.Tableaux(['A',2])
            sage: S = B.subcrystal(max_depth=4)
            sage: S.cardinality()
            22
        """
        if self._cardinality is not None:
            return self._cardinality

        try:
            card = Integer(len(self._list))
            self._cardinality = card
            return self._cardinality
        except AttributeError:
            if self in FiniteCrystals():
                return Integer(len(self.list()))
            card = super(Subcrystal, self).cardinality()
            if card == infinity:
                self._cardinality = card
                return card
            self._cardinality = Integer(len(self.list()))
            return self._cardinality
Esempio n. 3
0
    def __contains__(self, x):
        """
        Check if ``x`` is in ``self``.

        EXAMPLES::

            sage: B = crystals.Tableaux(['B',3], shape=[1])
            sage: C = crystals.Tableaux(['D',4], shape=[2])
            sage: psi = B.crystal_morphism(C.module_generators)
            sage: V = psi.image()
            sage: mg = C.module_generators[0]
            sage: mg in V
            True
            sage: mg.f(1) in V
            False
            sage: mg.f(1).f(1) in V
            True
        """
        if not Subcrystal.__contains__(self, x):
            return False
        if self in FiniteCrystals():
            if isinstance(x, self._ambient.element_class):
                if x.parent() == self:
                    x = self.element_class(self, self._ambient(x))
                elif x.parent() == self._ambient:
                    x = self.element_class(self, self._ambient(x))
            elif isinstance(x, self.element_class) and x.parent() != self:
                x = self.element_class(self, x.value)
            return x in self.list()
        return True
Esempio n. 4
0
    def __init__(self, cartan_type, classical_crystal, category=None):
        """
        Input is an affine Cartan type 'cartan_type', a classical crystal 'classical_crystal', and automorphism and its
        inverse 'automorphism' and 'inverse_automorphism', and the Dynkin node 'dynkin_node'

        EXAMPLES::

            sage: n = 1
            sage: C = CrystalOfTableaux(['A',n],shape=[1])
            sage: pr = attrcall("promotion")
            sage: pr_inverse = attrcall("promotion_inverse")
            sage: A = AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1) # indirect doctest
            sage: A.list()
            [[[1]], [[2]]]
            sage: A.cartan_type()
            ['A', 1, 1]
            sage: A.index_set()
            [0, 1]

        Note: AffineCrystalFromClassical is an abstract class, so we
        can't test it directly.

        TESTS::

            sage: TestSuite(A).run()
        """
        if category is None:
            category = FiniteCrystals()
        self._cartan_type = cartan_type
        Parent.__init__(self, category=category)
        self.classical_crystal = classical_crystal
        self.module_generators = map(self.retract,
                                     self.classical_crystal.module_generators)
        self.element_class._latex_ = lambda x: x.lift()._latex_()
Esempio n. 5
0
    def __init__(self, cartan_type, r, s):
        r"""
        Initialize the KirillovReshetikhinTableaux class.

        INPUT:

        - ``cartan_type`` -- The Cartan type
        - ``r``           -- The number of rows
        - ``s``           -- The number of columns

        EXAMPLES::

            sage: KRT = KirillovReshetikhinTableaux(['A', 4, 1], 2, 3); KRT
            Kirillov-Reshetikhin tableaux of type ['A', 4, 1] and shape (2, 3)
            sage: TestSuite(KRT).run()  # long time (4s on sage.math, 2013)
            sage: KRT = KirillovReshetikhinTableaux(['D', 4, 1], 2, 3); KRT
            Kirillov-Reshetikhin tableaux of type ['D', 4, 1] and shape (2, 3)
            sage: TestSuite(KRT).run()  # long time (53s on sage.math, 2013)
            sage: KRT = KirillovReshetikhinTableaux(['D', 4, 1], 4, 1); KRT
            Kirillov-Reshetikhin tableaux of type ['D', 4, 1] and shape (4, 1)
            sage: TestSuite(KRT).run()
        """
        self._r = r
        self._s = s
        Parent.__init__(self, category=FiniteCrystals())
        self.rename(
            "Kirillov-Reshetikhin tableaux of type %s and shape (%d, %d)" %
            (cartan_type, r, s))

        self._cartan_type = cartan_type.classical()
        self.letters = CrystalOfLetters(self._cartan_type)

        self.module_generators = self._build_module_generators()
Esempio n. 6
0
    def __init__(self, cartan_type, B, biject_class):
        r"""
        Initialize all common elements for rigged configurations.

        INPUT:

        - ``cartan_type``  -- The Cartan type
        - ``B``            -- A list of dimensions `[r,s]` for rectangles of height `r` and width `s`
        - ``biject_class`` -- The class the bijection creates

        TESTS::

            sage: RC = HighestWeightRiggedConfigurations(['A', 3, 1], [[3, 2], [1, 2], [1, 1]]) # indirect doctest
            sage: RC
            Highest weight rigged configurations of type ['A', 3, 1] and factors ((3, 2), (1, 2), (1, 1))
            sage: RC = RiggedConfigurations(['A', 3, 1], [[3, 2], [1, 2], [1, 1]]) # indirect doctest
            sage: RC
            Rigged configurations of type ['A', 3, 1] and factors ((3, 2), (1, 2), (1, 1))
        """
        assert cartan_type.is_affine()
        self._affine_ct = cartan_type

        # Force to classical since we do not have e_0 and f_0 yet
        self._cartan_type = cartan_type.classical()
        self.dims = B
        self._bijection_class = biject_class
        self.rename("Rigged configurations of type %s and factors %s" %
                    (cartan_type, B))
        Parent.__init__(self, category=FiniteCrystals())
Esempio n. 7
0
    def __classcall_private__(cls,
                              ambient,
                              contained=None,
                              generators=None,
                              virtualization=None,
                              scaling_factors=None,
                              cartan_type=None,
                              index_set=None,
                              category=None):
        """
        Normalize arguments to ensure a (relatively) unique representation.

        EXAMPLES::

            sage: B = crystals.Tableaux(['A',4], shape=[2,1])
            sage: S1 = B.subcrystal(generators=(B(2,1,1), B(5,2,4)), index_set=[1,2])
            sage: S2 = B.subcrystal(generators=[B(2,1,1), B(5,2,4)], cartan_type=['A',4], index_set=(1,2))
            sage: S1 is S2
            True
        """
        if isinstance(contained, (list, tuple, set, frozenset)):
            contained = frozenset(contained)
        #elif contained in Sets():

        if cartan_type is None:
            cartan_type = ambient.cartan_type()
        else:
            cartan_type = CartanType(cartan_type)
        if index_set is None:
            index_set = cartan_type.index_set
        if generators is None:
            generators = ambient.module_generators

        category = Crystals().or_subcategory(category)
        if ambient in FiniteCrystals() or isinstance(contained, frozenset):
            category = category.Finite()

        if virtualization is not None:
            if scaling_factors is None:
                scaling_factors = {i: 1 for i in index_set}
            from sage.combinat.crystals.virtual_crystal import VirtualCrystal
            return VirtualCrystal(ambient, virtualization, scaling_factors,
                                  contained, generators, cartan_type,
                                  index_set, category)
        if scaling_factors is not None:
            # virtualization must be None
            virtualization = {i: (i, ) for i in index_set}
            from sage.combinat.crystals.virtual_crystal import VirtualCrystal
            return VirtualCrystal(ambient, virtualization, scaling_factors,
                                  contained, generators, cartan_type,
                                  index_set, category)

        # We need to give these as optional arguments so it unpickles correctly
        return super(Subcrystal, cls).__classcall__(cls,
                                                    ambient,
                                                    contained,
                                                    tuple(generators),
                                                    cartan_type=cartan_type,
                                                    index_set=tuple(index_set),
                                                    category=category)
    def super_categories(self):
        r"""
        EXAMPLES::

            sage: ClassicalCrystals().super_categories()
            [Category of finite crystals, Category of highest weight crystals]
        """
        return [FiniteCrystals(), HighestWeightCrystals()]
Esempio n. 9
0
    def __init__(self, starting_weight):
        """
        EXAMPLES::

            sage: C = crystals.LSPaths(['A',2,1],[-1,0,1]); C
            The crystal of LS paths of type ['A', 2, 1] and weight -Lambda[0] + Lambda[2]
            sage: C.R
            Root system of type ['A', 2, 1]
            sage: C.weight
            -Lambda[0] + Lambda[2]
            sage: C.weight.parent()
            Extended weight space over the Rational Field of the Root system of type ['A', 2, 1]
            sage: C.module_generators
            [(-Lambda[0] + Lambda[2],)]

        TESTS::

            sage: C = crystals.LSPaths(['A',2,1], [-1,0,1])
            sage: TestSuite(C).run() # long time
            sage: C = crystals.LSPaths(['E',6], [1,0,0,0,0,0])
            sage: TestSuite(C).run()
        """
        cartan_type = starting_weight.parent().cartan_type()
        self.R = RootSystem(cartan_type)
        self.weight = starting_weight
        if not self.weight.parent().base_ring().has_coerce_map_from(QQ):
            raise ValueError(
                "Please use the weight space, rather than weight lattice for your weights"
            )
        self._cartan_type = cartan_type
        self._name = "The crystal of LS paths of type %s and weight %s" % (
            cartan_type, starting_weight)
        if cartan_type.is_affine():
            if all(i >= 0 for i in starting_weight.coefficients()):
                Parent.__init__(self,
                                category=(RegularCrystals(),
                                          HighestWeightCrystals(),
                                          InfiniteEnumeratedSets()))
            elif starting_weight.parent().is_extended():
                Parent.__init__(self,
                                category=(RegularCrystals(),
                                          InfiniteEnumeratedSets()))
            else:
                Parent.__init__(self,
                                category=(RegularCrystals(), FiniteCrystals()))
        else:
            Parent.__init__(self, category=ClassicalCrystals())

        if starting_weight == starting_weight.parent().zero():
            initial_element = self(tuple([]))
        else:
            initial_element = self(tuple([starting_weight]))
        self.module_generators = [initial_element]
Esempio n. 10
0
    def __classcall_private__(cls,
                              ambient,
                              virtualization,
                              scaling_factors,
                              contained=None,
                              generators=None,
                              cartan_type=None,
                              index_set=None,
                              category=None):
        """
        Normalize arguments to ensure a unique representation.

        EXAMPLES::

            sage: B = crystals.Tableaux(['B',3], shape=[1])
            sage: C = crystals.Tableaux(['D',4], shape=[2])
            sage: psi1 = B.crystal_morphism(C.module_generators)
            sage: V1 = psi1.image()
            sage: psi2 = B.crystal_morphism(C.module_generators, index_set=[1,2,3])
            sage: V2 = psi2.image()
            sage: V1 is V2
            True

        TESTS:

        Check that :trac:`19481` is fixed::

            sage: from sage.combinat.crystals.virtual_crystal import VirtualCrystal
            sage: A = crystals.Tableaux(['A',3], shape=[2,1,1])
            sage: V = VirtualCrystal(A, {1:(1,3), 2:(2,)}, {1:1, 2:2}, cartan_type=['C',2])
            sage: V.category()
            Category of finite crystals
        """
        if cartan_type is None:
            cartan_type = ambient.cartan_type()
        else:
            cartan_type = CartanType(cartan_type)
        if index_set is None:
            index_set = cartan_type.index_set()
        if generators is None:
            generators = ambient.module_generators
        virtualization = Family(virtualization)
        scaling_factors = Family(scaling_factors)

        category = Crystals().or_subcategory(category)
        if ambient in FiniteCrystals() or isinstance(contained, frozenset):
            category = category.Finite()

        return super(Subcrystal,
                     cls).__classcall__(cls, ambient, virtualization,
                                        scaling_factors, contained,
                                        tuple(generators), cartan_type,
                                        tuple(index_set), category)
Esempio n. 11
0
    def __init__(self, cartan_type, weight):
        r"""
        Initialize ``self``.

        EXAMPLES::

            sage: la = RootSystem("A2").weight_lattice().fundamental_weights()
            sage: B = crystals.elementary.R("A2",5*la[2])
            sage: TestSuite(B).run()
        """
        Parent.__init__(self, category = (FiniteCrystals(),HighestWeightCrystals()))
        self._weight = weight
        self._cartan_type = cartan_type
        self.module_generators = (self.element_class(self),)
Esempio n. 12
0
    def cardinality(self):
        """
        Return the cardinality of ``self``.

        EXAMPLES::

            sage: B = crystals.Tableaux(['A',4], shape=[2,1])
            sage: S = B.subcrystal(generators=[B(2,1,1)], index_set=[1,2])
            sage: S.cardinality()
            8
            sage: B = crystals.infinity.Tableaux(['A',2])
            sage: S = B.subcrystal(max_depth=4)
            sage: S.cardinality()
            22

        TESTS:

        Check that :trac:`19481` is fixed::

            sage: from sage.combinat.crystals.virtual_crystal import VirtualCrystal
            sage: A = crystals.infinity.Tableaux(['A',3])
            sage: V = VirtualCrystal(A, {1:(1,3), 2:(2,)}, {1:1, 2:2}, cartan_type=['C',2])
            sage: V.cardinality()
            Traceback (most recent call last):
            ...
            NotImplementedError: unknown cardinality
        """
        if self._cardinality is not None:
            return self._cardinality

        try:
            card = Integer(len(self._list))
            self._cardinality = card
            return self._cardinality
        except AttributeError:
            if self in FiniteCrystals():
                return Integer(len(self.list()))
            try:
                card = super(Subcrystal, self).cardinality()
            except AttributeError:
                raise NotImplementedError("unknown cardinality")
            if card == infinity:
                self._cardinality = card
                return card
            self._cardinality = Integer(len(self.list()))
            return self._cardinality
Esempio n. 13
0
    def __init__(self, cartan_type, starting_weight):
        """
        EXAMPLES::

            sage: C = CrystalOfLSPaths(['A',2,1],[-1,0,1]); C
            The crystal of LS paths of type ['A', 2, 1] and weight (-1, 0, 1)
            sage: C.R
            Root system of type ['A', 2, 1]
            sage: C.weight
            -Lambda[0] + Lambda[2]
            sage: C.weight.parent()
            Extended weight space over the Rational Field of the Root system of type ['A', 2, 1]
            sage: C.module_generators
            [(-Lambda[0] + Lambda[2],)]
        """
        self._cartan_type = CartanType(cartan_type)
        self.R = RootSystem(cartan_type)

        self._name = "The crystal of LS paths of type %s and weight %s" % (
            cartan_type, starting_weight)

        if self._cartan_type.is_affine():
            self.extended = True
            if all(i >= 0 for i in starting_weight):
                Parent.__init__(self, category=HighestWeightCrystals())
            else:
                Parent.__init__(self, category=Crystals())
        else:
            self.extended = False
            Parent.__init__(self, category=FiniteCrystals())

        Lambda = self.R.weight_space(extended=self.extended).basis()
        offset = self.R.index_set()[Integer(0)]

        zero_weight = self.R.weight_space(extended=self.extended).zero()
        self.weight = sum([zero_weight] + [
            starting_weight[j - offset] * Lambda[j]
            for j in self.R.index_set()
        ])

        if self.weight == zero_weight:
            initial_element = self(tuple([]))
        else:
            initial_element = self(tuple([self.weight]))
        self.module_generators = [initial_element]
Esempio n. 14
0
    def __init__(self, cartan_type, classical_crystal, category=None):
        """
        Input is an affine Cartan type ``cartan_type``, a classical crystal
        ``classical_crystal``, and automorphism and its inverse
        ``automorphism`` and ``inverse_automorphism``, and the Dynkin node
        ``dynkin_node``.

        EXAMPLES::

            sage: n = 1
            sage: C = crystals.Tableaux(['A',n],shape=[1])
            sage: pr = attrcall("promotion")
            sage: pr_inverse = attrcall("promotion_inverse")
            sage: A = crystals.AffineFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1) # indirect doctest
            sage: A.list()
            [[[1]], [[2]]]
            sage: A.cartan_type()
            ['A', 1, 1]
            sage: A.index_set()
            (0, 1)

        .. NOTE::

            :class:`~sage.combinat.crystals.affine.AffineCrystalFromClassical`
            is an abstract class, so we can't test it directly.

        TESTS::

            sage: TestSuite(A).run()
        """
        if category is None:
            category = (RegularCrystals(), FiniteCrystals())
        self._cartan_type = cartan_type
        Parent.__init__(self, category=category)
        self.classical_crystal = classical_crystal
        self.module_generators = [
            self.retract(_) for _ in self.classical_crystal.module_generators
        ]
        self.element_class._latex_ = lambda x: x.lift()._latex_()
Esempio n. 15
0
        def q_dimension(self, q=None, prec=None, use_product=False):
            r"""
            Return the `q`-dimension of ``self``.

            Let `B(\lambda)` denote a highest weight crystal. Recall that
            the degree of the `\mu`-weight space of `B(\lambda)` (under
            the principal gradation) is equal to
            `\langle \rho^{\vee}, \lambda - \mu \rangle` where
            `\langle \rho^{\vee}, \alpha_i \rangle = 1` for all `i \in I`
            (in particular, take `\rho^{\vee} = \sum_{i \in I} h_i`).

            The `q`-dimension of a highest weight crystal `B(\lambda)` is
            defined as

            .. MATH::

                \dim_q B(\lambda) := \sum_{j \geq 0} \dim(B_j) q^j,

            where `B_j` denotes the degree `j` portion of `B(\lambda)`. This
            can be expressed as the product

            .. MATH::

                \dim_q B(\lambda) = \prod_{\alpha^{\vee} \in \Delta_+^{\vee}}
                \left( \frac{1 - q^{\langle \lambda + \rho, \alpha^{\vee}
                \rangle}}{1 - q^{\langle \rho, \alpha^{\vee} \rangle}}
                \right)^{\mathrm{mult}\, \alpha},

            where `\Delta_+^{\vee}` denotes the set of positive coroots.
            Taking the limit as `q \to 1` gives the dimension of `B(\lambda)`.
            For more information, see [Ka1990]_ Section 10.10.

            INPUT:

            - ``q`` -- the (generic) parameter `q`

            - ``prec`` -- (default: ``None``) The precision of the power
              series ring to use if the crystal is not known to be finite
              (i.e. the number of terms returned).
              If ``None``, then the result is returned as a lazy power series.

            - ``use_product`` -- (default: ``False``) if we have a finite
              crystal and ``True``, use the product formula

            EXAMPLES::

                sage: C = crystals.Tableaux(['A',2], shape=[2,1])
                sage: qdim = C.q_dimension(); qdim
                q^4 + 2*q^3 + 2*q^2 + 2*q + 1
                sage: qdim(1)
                8
                sage: len(C) == qdim(1)
                True
                sage: C.q_dimension(use_product=True) == qdim
                True
                sage: C.q_dimension(prec=20)
                q^4 + 2*q^3 + 2*q^2 + 2*q + 1
                sage: C.q_dimension(prec=2)
                2*q + 1

                sage: R.<t> = QQ[]
                sage: C.q_dimension(q=t^2)
                t^8 + 2*t^6 + 2*t^4 + 2*t^2 + 1

                sage: C = crystals.Tableaux(['A',2], shape=[5,2])
                sage: C.q_dimension()
                q^10 + 2*q^9 + 4*q^8 + 5*q^7 + 6*q^6 + 6*q^5
                 + 6*q^4 + 5*q^3 + 4*q^2 + 2*q + 1

                sage: C = crystals.Tableaux(['B',2], shape=[2,1])
                sage: qdim = C.q_dimension(); qdim
                q^10 + 2*q^9 + 3*q^8 + 4*q^7 + 5*q^6 + 5*q^5
                 + 5*q^4 + 4*q^3 + 3*q^2 + 2*q + 1
                sage: qdim == C.q_dimension(use_product=True)
                True

                sage: C = crystals.Tableaux(['D',4], shape=[2,1])
                sage: C.q_dimension()
                q^16 + 2*q^15 + 4*q^14 + 7*q^13 + 10*q^12 + 13*q^11
                 + 16*q^10 + 18*q^9 + 18*q^8 + 18*q^7 + 16*q^6 + 13*q^5
                 + 10*q^4 + 7*q^3 + 4*q^2 + 2*q + 1

            We check with a finite tensor product::

                sage: TP = crystals.TensorProduct(C, C)
                sage: TP.cardinality()
                25600
                sage: qdim = TP.q_dimension(use_product=True); qdim # long time
                q^32 + 2*q^31 + 8*q^30 + 15*q^29 + 34*q^28 + 63*q^27 + 110*q^26
                 + 175*q^25 + 276*q^24 + 389*q^23 + 550*q^22 + 725*q^21
                 + 930*q^20 + 1131*q^19 + 1362*q^18 + 1548*q^17 + 1736*q^16
                 + 1858*q^15 + 1947*q^14 + 1944*q^13 + 1918*q^12 + 1777*q^11
                 + 1628*q^10 + 1407*q^9 + 1186*q^8 + 928*q^7 + 720*q^6
                 + 498*q^5 + 342*q^4 + 201*q^3 + 117*q^2 + 48*q + 26
                sage: qdim(1) # long time
                25600
                sage: TP.q_dimension() == qdim # long time
                True

            The `q`-dimensions of infinite crystals are returned
            as formal power series::

                sage: C = crystals.LSPaths(['A',2,1], [1,0,0])
                sage: C.q_dimension(prec=5)
                1 + q + 2*q^2 + 2*q^3 + 4*q^4 + O(q^5)
                sage: C.q_dimension(prec=10)
                1 + q + 2*q^2 + 2*q^3 + 4*q^4 + 5*q^5 + 7*q^6
                 + 9*q^7 + 13*q^8 + 16*q^9 + O(q^10)
                sage: qdim = C.q_dimension(); qdim
                1 + q + 2*q^2 + 2*q^3 + 4*q^4 + 5*q^5 + 7*q^6
                 + 9*q^7 + 13*q^8 + 16*q^9 + 22*q^10 + O(x^11)
                sage: qdim.compute_coefficients(15)
                sage: qdim
                1 + q + 2*q^2 + 2*q^3 + 4*q^4 + 5*q^5 + 7*q^6
                 + 9*q^7 + 13*q^8 + 16*q^9 + 22*q^10 + 27*q^11
                 + 36*q^12 + 44*q^13 + 57*q^14 + 70*q^15 + O(x^16)

            """
            from sage.rings.all import ZZ
            WLR = self.weight_lattice_realization()
            I = self.index_set()
            mg = self.highest_weight_vectors()
            max_deg = float('inf') if prec is None else prec - 1

            def iter_by_deg(gens):
                next = set(gens)
                deg = -1
                while next and deg < max_deg:
                    deg += 1
                    yield len(next)
                    todo = next
                    next = set([])
                    while todo:
                        x = todo.pop()
                        for i in I:
                            y = x.f(i)
                            if y is not None:
                                next.add(y)
                # def iter_by_deg

            from sage.categories.finite_crystals import FiniteCrystals
            if self in FiniteCrystals():
                if q is None:
                    from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
                    q = PolynomialRing(ZZ, 'q').gen(0)

                if use_product:
                    # Since we are in the classical case, all roots occur with multiplicity 1
                    pos_coroots = [
                        x.associated_coroot() for x in WLR.positive_roots()
                    ]
                    rho = WLR.rho()
                    P = q.parent()
                    ret = P.zero()
                    for v in self.highest_weight_vectors():
                        hw = v.weight()
                        ret += P.prod((1 - q**(rho + hw).scalar(ac)) /
                                      (1 - q**rho.scalar(ac))
                                      for ac in pos_coroots)
                    # We do a cast since the result would otherwise live in the fraction field
                    return P(ret)

            elif prec is None:
                # If we're here, we may not be a finite crystal.
                # In fact, we're probably infinite.
                from sage.combinat.species.series import LazyPowerSeriesRing
                if q is None:
                    P = LazyPowerSeriesRing(ZZ, names='q')
                else:
                    P = q.parent()
                if not isinstance(P, LazyPowerSeriesRing):
                    raise TypeError(
                        "the parent of q must be a lazy power series ring")
                ret = P(iter_by_deg(mg))
                ret.compute_coefficients(10)
                return ret

            from sage.rings.power_series_ring import PowerSeriesRing, PowerSeriesRing_generic
            if q is None:
                q = PowerSeriesRing(ZZ, 'q', default_prec=prec).gen(0)
            P = q.parent()
            ret = P.sum(c * q**deg for deg, c in enumerate(iter_by_deg(mg)))
            if ret.degree() == max_deg and isinstance(P,
                                                      PowerSeriesRing_generic):
                ret = P(ret, prec)
            return ret