示例#1
0
def matId(n):
    Id = []
    n2 = n.quo_rem(2)[0]
    for j in range(n2):
        MSn = MatrixSpace(F, n2-j, n2-j)
        Id.append(MSn.identity_matrix())
    return Id
示例#2
0
def matA(n):
    A = []
    n2 = n.quo_rem(2)[0]
    for j in range(n2+2):
        MS0 = MatrixSpace(F, j, j)
        I = MS0.identity_matrix()
        O = MS0(j*j*[1])
        A.append(I+O)
    return A
def RandomLinearCode(n,k,F):
    r"""
    The method used is to first construct a `k \times n`
    matrix using Sage's random_element method for the MatrixSpace
    class. The construction is probabilistic but should only fail
    extremely rarely.

    INPUT: Integers n,k, with `n>k`, and a finite field F

    OUTPUT: Returns a "random" linear code with length n, dimension k
    over field F.

    EXAMPLES::

        sage: C = codes.RandomLinearCode(30,15,GF(2))
        sage: C
        Linear code of length 30, dimension 15 over Finite Field of size 2
        sage: C = codes.RandomLinearCode(10,5,GF(4,'a'))
        sage: C
        Linear code of length 10, dimension 5 over Finite Field in a of size 2^2

    AUTHORS:

    - David Joyner (2007-05)
    """
    MS = MatrixSpace(F,k,n)
    for i in range(50):
        G = MS.random_element()
        if G.rank() == k:
            V = span(G.rows(), F)
            return LinearCodeFromVectorSpace(V)  # may not be in standard form
    MS1 = MatrixSpace(F,k,k)
    MS2 = MatrixSpace(F,k,n-k)
    Ik = MS1.identity_matrix()
    A = MS2.random_element()
    G = Ik.augment(A)
    return LinearCode(G)                          # in standard form
示例#4
0
def RandomLinearCode(n,k,F):
    r"""
    The method used is to first construct a `k \times n`
    matrix using Sage's random_element method for the MatrixSpace
    class. The construction is probabilistic but should only fail
    extremely rarely.

    INPUT: Integers n,k, with `n>k`, and a finite field F

    OUTPUT: Returns a "random" linear code with length n, dimension k
    over field F.

    EXAMPLES::

        sage: C = codes.RandomLinearCode(30,15,GF(2))
        sage: C
        Linear code of length 30, dimension 15 over Finite Field of size 2
        sage: C = codes.RandomLinearCode(10,5,GF(4,'a'))
        sage: C
        Linear code of length 10, dimension 5 over Finite Field in a of size 2^2

    AUTHORS:

    - David Joyner (2007-05)
    """
    MS = MatrixSpace(F,k,n)
    for i in range(50):
        G = MS.random_element()
        if G.rank() == k:
            V = span(G.rows(), F)
            return LinearCodeFromVectorSpace(V)  # may not be in standard form
    MS1 = MatrixSpace(F,k,k)
    MS2 = MatrixSpace(F,k,n-k)
    Ik = MS1.identity_matrix()
    A = MS2.random_element()
    G = Ik.augment(A)
    return LinearCode(G)                          # in standard form
示例#5
0
    def __call__(self, A, name=''):
        r"""
        Create an element of the homspace ``self`` from `A`.

        INPUT:

        - ``A`` -- one of the following:

          - an element of a Hecke algebra

          - a Hecke module morphism

          - a matrix

          - a list of elements of the codomain specifying the images
            of the basis elements of the domain.

        EXAMPLES::

            sage: M = ModularForms(Gamma0(7), 4)
            sage: H = M.Hom(M)
            sage: H(M.hecke_operator(7))
            Hecke module morphism T_7 defined by the matrix
            [ -7   0   0]
            [  0   1 240]
            [  0   0 343]
            Domain: Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(7) ...
            Codomain: Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(7) ...
            sage: H(H(M.hecke_operator(7)))
            Hecke module morphism T_7 defined by the matrix
            [ -7   0   0]
            [  0   1 240]
            [  0   0 343]
            Domain: Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(7) ...
            Codomain: Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(7) ...
            sage: H(matrix(QQ, 3, srange(9)))
            Hecke module morphism defined by the matrix
            [0 1 2]
            [3 4 5]
            [6 7 8]
            Domain: Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(7) ...
            Codomain: Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(7) ...

        TESTS:

        Make sure that the element is created correctly when the codomain is
        not the full module (related to :trac:`21497`)::

            sage: M = ModularSymbols(Gamma0(3),weight=22,sign=1)
            sage: S = M.cuspidal_subspace()
            sage: H = S.Hom(S)
            sage: H(S.gens())
            Hecke module morphism defined by the matrix
            [1 0 0 0 0 0]
            [0 1 0 0 0 0]
            [0 0 1 0 0 0]
            [0 0 0 1 0 0]
            [0 0 0 0 1 0]
            [0 0 0 0 0 1]
            Domain: Modular Symbols subspace of dimension 6 of Modular Symbols space ...
            Codomain: Modular Symbols subspace of dimension 6 of Modular Symbols space ...

            sage: H.zero() in H
            True
            sage: H.one() in H
            True
        """
        try:
            if A.parent() == self:
                A._set_parent(self)
                return A
            A = A.hecke_module_morphism()
            if A.parent() == self:
                A._set_parent(self)
                return A
            else:
                raise TypeError("unable to coerce A to self")
        except AttributeError:
            pass
        if A in self.base_ring():
            dim_dom = self.domain().rank()
            dim_codom = self.codomain().rank()
            MS = MatrixSpace(self.base_ring(), dim_dom, dim_codom)
            if self.domain() == self.codomain():
                A = A * MS.identity_matrix()
            elif A == 0:
                A = MS.zero()
            else:
                raise ValueError('scalars do not coerce to this homspace')
        elif isinstance(A, (list, tuple)):
            A = matrix([self.codomain().coordinate_vector(f) for f in A])
        return HeckeModuleMorphism_matrix(self, A, name)
示例#6
0
class AlternatingSignMatrices(Parent, UniqueRepresentation):
    r"""
    Class of all `n \times n` alternating sign matrices.

    An alternating sign matrix of size `n` is an `n \times n` matrix of `0`s,
    `1`s and `-1`s such that the sum of each row and column is `1` and the
    non-zero entries in each row and column alternate in sign.

    Alternating sign matrices of size `n` are in bijection with
    :class:`monotone triangles <MonotoneTriangles>` with `n` rows.

    INPUT:

    - `n` -- an integer, the size of the matrices.

    - ``use_monotone_triangle`` -- (Default: ``True``) If ``True``, the
      generation of the matrices uses monotone triangles, else it will use the
      earlier and now obsolete contre-tableaux implementation;
      must be ``True`` to generate a lattice (with the ``lattice`` method)

    EXAMPLES:

    This will create an instance to manipulate the alternating sign
    matrices of size 3::

        sage: A = AlternatingSignMatrices(3)
        sage: A
        Alternating sign matrices of size 3
        sage: A.cardinality()
        7

    Notably, this implementation allows to make a lattice of it::

        sage: L = A.lattice()
        sage: L
        Finite lattice containing 7 elements
        sage: L.category()
        Category of facade finite lattice posets
    """
    def __init__(self, n, use_monotone_triangles=True):
        r"""
        Initialize ``self``.

        TESTS::

            sage: A = AlternatingSignMatrices(4)
            sage: TestSuite(A).run()
            sage: A == AlternatingSignMatrices(4, use_monotone_triangles=False)
            False
        """
        self._n = n
        self._matrix_space = MatrixSpace(ZZ, n)
        self._umt = use_monotone_triangles
        Parent.__init__(self, category=FiniteEnumeratedSets())

    def _repr_(self):
        r"""
        Return a string representation of ``self``.

        TESTS::

            sage: A = AlternatingSignMatrices(4); A
            Alternating sign matrices of size 4
        """
        return "Alternating sign matrices of size %s" % self._n

    def _repr_option(self, key):
        """
        Metadata about the :meth:`_repr_` output.

        See :meth:`sage.structure.parent._repr_option` for details.

        EXAMPLES::

            sage: A = AlternatingSignMatrices(3)
            sage: A._repr_option('element_ascii_art')
            True
        """
        return self._matrix_space._repr_option(key)

    def __contains__(self, asm):
        """
        Check if ``asm`` is in ``self``.

        TESTS::

            sage: A = AlternatingSignMatrices(3)
            sage: [[0,1,0],[1,0,0],[0,0,1]] in A
            True
            sage: [[0,1,0],[1,-1,1],[0,1,0]] in A
            True
            sage: [[0, 1],[1,0]] in A
            False
            sage: [[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]] in A
            False
            sage: [[-1, 1, 1],[1,-1,1],[1,1,-1]] in A
            False
        """
        if isinstance(asm, AlternatingSignMatrix):
            return asm._matrix.nrows() == self._n
        try:
            asm = self._matrix_space(asm)
        except (TypeError, ValueError):
            return False
        for row in asm:
            pos = False
            for val in row:
                if val > 0:
                    if pos:
                        return False
                    else:
                        pos = True
                elif val < 0:
                    if pos:
                        pos = False
                    else:
                        return False
            if not pos:
                return False
        if any(sum(row) != 1 for row in asm.columns()):
            return False
        return True

    def _element_constructor_(self, asm):
        """
        Construct an element of ``self``.

        EXAMPLES::

            sage: A = AlternatingSignMatrices(3)
            sage: elt = A([[1, 0, 0],[0, 1, 0],[0, 0, 1]]); elt
            [1 0 0]
            [0 1 0]
            [0 0 1]
            sage: elt.parent() is A
            True
            sage: A([[3, 2, 1], [2, 1], [1]])
            [1 0 0]
            [0 1 0]
            [0 0 1]
        """
        if isinstance(asm, AlternatingSignMatrix):
            if asm.parent() is self:
                return asm
            raise ValueError("Cannot convert between alternating sign matrices of different sizes")
        if asm in MonotoneTriangles(self._n):
            return self.from_monotone_triangle(asm)
        return self.element_class(self, self._matrix_space(asm))

    Element = AlternatingSignMatrix

    def _an_element_(self):
        """
        Return an element of ``self``.
        """
        return self.element_class(self, self._matrix_space.identity_matrix())

    def from_monotone_triangle(self, triangle):
        r"""
        Return an alternating sign matrix from a monotone triangle.

        EXAMPLES::

            sage: A = AlternatingSignMatrices(3)
            sage: A.from_monotone_triangle([[3, 2, 1], [2, 1], [1]])
            [1 0 0]
            [0 1 0]
            [0 0 1]
            sage: A.from_monotone_triangle([[3, 2, 1], [3, 2], [3]])
            [0 0 1]
            [0 1 0]
            [1 0 0]
        """
        n = len(triangle)
        if n != self._n:
            raise ValueError("Incorrect size")
        asm = []

        prev = [0]*n
        for line in reversed(triangle):
            v = [1 if j+1 in reversed(line) else 0 for j in range(n)]
            row = [a-b for (a, b) in zip(v, prev)]
            asm.append(row)
            prev = v

        return self.element_class(self, self._matrix_space(asm))

    def size(self):
        r"""
        Return the size of the matrices in ``self``.

        TESTS::

            sage: A = AlternatingSignMatrices(4)
            sage: A.size()
            4
        """
        return self._n

    def cardinality(self):
        r"""
        Return the cardinality of ``self``.

        The number of `n \times n` alternating sign matrices is equal to

        .. MATH::

            \prod_{k=0}^{n-1} \frac{(3k+1)!}{(n+k)!} = \frac{1! 4! 7! 10!
            \cdots (3n-2)!}{n! (n+1)! (n+2)! (n+3)! \cdots (2n-1)!}

        EXAMPLES::

            sage: [AlternatingSignMatrices(n).cardinality() for n in range(0, 11)]
            [1, 1, 2, 7, 42, 429, 7436, 218348, 10850216, 911835460, 129534272700]
        """
        return Integer(prod( [ factorial(3*k+1)/factorial(self._n+k)
                       for k in range(self._n)] ))

    def matrix_space(self):
        """
        Return the underlying matrix space.

        EXAMPLES::

            sage: A = AlternatingSignMatrices(3)
            sage: A.matrix_space()
            Full MatrixSpace of 3 by 3 dense matrices over Integer Ring
        """
        return self._matrix_space

    def __iter__(self):
        r"""
        Iterator on the alternating sign matrices of size `n`.

        If defined using ``use_monotone_triangles``, this iterator
        will use the iteration on the monotone triangles. Else, it
        will use the iteration on contre-tableaux.

        TESTS::

            sage: A = AlternatingSignMatrices(4)
            sage: len(list(A))
            42
        """
        if self._umt:
            for t in MonotoneTriangles(self._n):
                yield self.from_monotone_triangle(t)
        else:
            for c in ContreTableaux(self._n):
                yield from_contre_tableau(c)

    def _lattice_initializer(self):
        r"""
        Return a 2-tuple to use in argument of ``LatticePoset``.

        For more details about the cover relations, see
        ``MonotoneTriangles``. Notice that the returned matrices are
        made immutable to ensure their hashability required by
        ``LatticePoset``.

        EXAMPLES:

        Proof of the lattice property for alternating sign matrices of
        size 3::

            sage: A = AlternatingSignMatrices(3)
            sage: P = Poset(A._lattice_initializer())
            sage: P.is_lattice()
            True
        """
        assert(self._umt)
        (mts, rels) = MonotoneTriangles(self._n)._lattice_initializer()
        bij = dict((t, self.from_monotone_triangle(t)) for t in mts)
        asms, rels = bij.itervalues(), [(bij[a], bij[b]) for (a,b) in rels]
        return (asms, rels)

    def cover_relations(self):
        r"""
        Iterate on the cover relations between the alternating sign
        matrices.

        EXAMPLES::

            sage: A = AlternatingSignMatrices(3)
            sage: for (a,b) in A.cover_relations():
            ...     eval('a, b')
            ...
            (
            [1 0 0]  [0 1 0]
            [0 1 0]  [1 0 0]
            [0 0 1], [0 0 1]
            )
            (
            [1 0 0]  [1 0 0]
            [0 1 0]  [0 0 1]
            [0 0 1], [0 1 0]
            )
            (
            [0 1 0]  [ 0  1  0]
            [1 0 0]  [ 1 -1  1]
            [0 0 1], [ 0  1  0]
            )
            (
            [1 0 0]  [ 0  1  0]
            [0 0 1]  [ 1 -1  1]
            [0 1 0], [ 0  1  0]
            )
            (
            [ 0  1  0]  [0 0 1]
            [ 1 -1  1]  [1 0 0]
            [ 0  1  0], [0 1 0]
            )
            (
            [ 0  1  0]  [0 1 0]
            [ 1 -1  1]  [0 0 1]
            [ 0  1  0], [1 0 0]
            )
            (
            [0 0 1]  [0 0 1]
            [1 0 0]  [0 1 0]
            [0 1 0], [1 0 0]
            )
            (
            [0 1 0]  [0 0 1]
            [0 0 1]  [0 1 0]
            [1 0 0], [1 0 0]
            )

        """
        (_, rels) = self._lattice_initializer()
        return (_ for _ in rels)

    def lattice(self):
        r"""
        Return the lattice of the alternating sign matrices of size
        `n`, created by ``LatticePoset``.

        EXAMPLES::

            sage: A = AlternatingSignMatrices(3)
            sage: L = A.lattice()
            sage: L
            Finite lattice containing 7 elements

        """
        return LatticePoset(self._lattice_initializer(), cover_relations=True)
示例#7
0
class MatrixRec(object):
    r"""
    A matrix recurrence simultaneously generating the coefficients and partial
    sums of solutions of an ODE, and possibly derivatives of this solution.

    Note: Mathematically, the recurrence matrix has the structure of a
    StepMatrix (depending on parameters). However, this class does not
    derive from StepMatrix as the data structure is different.
    """
    def __init__(self, diffop, dz, derivatives, nterms_est):

        deq_Scalars = diffop.base_ring().base_ring()
        E = dz.parent()
        if deq_Scalars.characteristic() != 0:
            raise ValueError("only makes sense for scalar rings of "
                             "characteristic 0")
        assert deq_Scalars is dz.parent() or deq_Scalars != dz.parent()

        #### Recurrence operator

        # Reduce to the case of a number field generated by an algebraic
        # integer. This is mainly intended to avoid computing gcds (due to
        # denominators in the representation of number field elements) in the
        # product tree, but could also be useful to extend the field using Pari
        # in the future.
        NF_rec, AlgInts_rec = _number_field_with_integer_gen(deq_Scalars)
        # ore_algebra currently does not support orders as scalar rings
        Pols = PolynomialRing(NF_rec, 'n')
        Rops, Sn = ore_algebra.OreAlgebra(Pols, 'Sn').objgen()
        # Using the primitive part here would break the computation of
        # residuals! (Cf. local_solutions.)
        # recop = diffop.to_S(Rops).primitive_part().numerator()
        recop = diffop.to_S(Rops)
        recop = lcm([p.denominator() for p in recop.coefficients()]) * recop
        # Ensure that ordrec >= orddeq. When the homomorphic image of diffop in
        # Rops is divisible by Sn, it can happen that the recop (e.g., after
        # normalization to Sn-valuation 0) has order < orddeq, and our strategy
        # of using vectors of coefficients of the form [u(n-s'), ..., u(n+r-1)]
        # with s'=s-r does not work in this case.
        orddelta = recop.order() - diffop.order()
        if orddelta < 0:
            recop = Sn**(-orddelta) * recop

        #### Choose computation domains

        if ((isinstance(E, (RealBallField, ComplexBallField)) or E is QQ
             or utilities.is_QQi(E) or E is RLF or E is CLF)
                and (deq_Scalars is QQ or utilities.is_QQi(deq_Scalars))):
            # Special-case QQ and QQ[i] to use arb matrices
            # (overwrites AlgInts_rec)
            self.StepMatrix_class = StepMatrix_arb
            self.binsplit_threshold = 8
            # Working precision. We typically want operations on exact balls to
            # be exact, so that overshooting shouldn't be a problem.
            # XXX Less clear in the case dz ∈ XBF!
            # XXX The rough estimate below ignores the height of rec and dz.
            # prec = nterms_est*(recop.degree()*nterms_est.nbits()
            #                    + recop.order().nbits() + 1)
            prec = 8 + nterms_est * (1 + ZZ(ZZ(recop.order()).nbits()).nbits())
            if (E is QQ or isinstance(E, RealBallField)) and deq_Scalars is QQ:
                AlgInts_rec = AlgInts_pow = RealBallField(prec)
            else:
                AlgInts_rec = AlgInts_pow = ComplexBallField(prec)
            if is_NumberField(E):
                pow_den = AlgInts_pow(dz.denominator())
            else:
                pow_den = AlgInts_pow.one()
        else:
            self.StepMatrix_class = StepMatrix_generic
            self.binsplit_threshold = 64
            if is_NumberField(E):
                # In fact we should probably do something similar for dz in any
                # finite-dimensional Q-algebra. (But how?)
                NF_pow, AlgInts_pow = _number_field_with_integer_gen(E)
                pow_den = NF_pow(dz).denominator()
            else:
                # This includes the case E = ZZ, but dz could live in pretty
                # much any algebra over deq_Scalars (including matrices,
                # intervals...). Then the computation of sums_row may take time,
                # but we still hope to gain something on the computation of the
                # coefficients and/or limit interval blow-up thanks to the use
                # of binary splitting.
                AlgInts_pow = E
                pow_den = ZZ.one()
            assert pow_den.parent() is ZZ
        assert AlgInts_pow is AlgInts_rec or AlgInts_pow != AlgInts_rec

        #### Recurrence matrix

        self.recop = recop

        self.orddeq = diffop.order()
        self.ordrec = recop.order()
        self.orddelta = self.ordrec - self.orddeq

        Pols_rec, n = PolynomialRing(AlgInts_rec, 'n').objgen()
        self.rec_coeffs = [
            -Pols_rec(recop[i])(n - self.orddelta) for i in xrange(self.ordrec)
        ]
        self.rec_den = Pols_rec(recop.leading_coefficient())(n - self.orddelta)
        # Guard against various problems related to number field embeddings and
        # uniqueness
        assert Pols_rec.base_ring() is AlgInts_rec
        assert self.rec_den.base_ring() is AlgInts_rec
        assert self.rec_den(
            self.rec_den.base_ring().zero()).parent() is AlgInts_rec

        # Also store a version of the recurrence operator of the form
        # b[0](n) + b[1](n) S^(-1) + ··· + b[s](n) S^(-s).
        # This is convenient to share code with other implementations, or at
        # least make the implementations easier to compare.
        # XXX: understand what to do about variable names!
        self.bwrec = [
            recop[self.ordrec - k](Rops.base_ring().gen() - self.ordrec)
            for k in xrange(self.ordrec + 1)
        ]

        #### Power of dz. Note that this part does not depend on n.

        # If we extend the removal of denominators above to algebras other than
        # number fields, it would probably make more sense to move this into
        # the caller. --> support dz in non-com ring (mat)? power series work
        # only over com rings
        Series_pow = PolynomialRing(AlgInts_pow, 'delta')
        self.pow_num = Series_pow([pow_den * dz, pow_den])
        self.pow_den = pow_den
        self.derivatives = derivatives

        #### Partial sums

        # We need a parent containing both the coefficients of the operator and
        # the evaluation point.
        # XXX: Is this the correct way to get one? Should we use
        # canonical_coercion()? Something else?
        # XXX: This is not powerful enough to find a number field containing
        # two given number fields (both given with embeddings into CC)

        # Work around #14982 (fixed) + weaknesses of the coercion framework for orders
        #Series_sums = sage.categories.pushout.pushout(AlgInts_rec, Series_pow)
        try:
            AlgInts_sums = sage.categories.pushout.pushout(
                AlgInts_rec, AlgInts_pow)
        except sage.structure.coerce_exceptions.CoercionException:
            AlgInts_sums = sage.categories.pushout.pushout(NF_rec, AlgInts_pow)
        assert AlgInts_sums is AlgInts_rec or AlgInts_sums != AlgInts_rec
        assert AlgInts_sums is AlgInts_pow or AlgInts_sums != AlgInts_pow

        Series_sums = PolynomialRing(AlgInts_sums, 'delta')
        assert Series_sums.base_ring() is AlgInts_sums
        # for speed
        self.Series_sums = Series_sums
        self.series_class_sums = type(Series_sums.gen())

        self.Mat_rec = MatrixSpace(AlgInts_rec, self.ordrec, self.ordrec)
        self.Mat_sums_row = MatrixSpace(Series_sums, 1, self.ordrec)
        self.Mat_series_sums = self.Mat_rec.change_ring(Series_sums)

    def __call__(self, n):
        stepmat = self.StepMatrix_class()
        stepmat.idx_start = n
        stepmat.idx_end = n + 1
        stepmat.rec_den = self.rec_den(n)
        stepmat.rec_mat = self.Mat_rec.matrix()
        for i in xrange(self.ordrec - 1):
            stepmat.rec_mat[i, i + 1] = stepmat.rec_den
        for i in xrange(self.ordrec):
            stepmat.rec_mat[self.ordrec - 1, i] = self.rec_coeffs[i](n)
        stepmat.pow_num = self.pow_num
        stepmat.pow_den = self.pow_den
        # TODO: fix redundancy--the rec_den*pow_den probabably doesn't belong
        # here
        # XXX: should we give a truncation order?
        den = stepmat.rec_den * stepmat.pow_den
        den = self.series_class_sums(self.Series_sums, [den])
        stepmat.sums_row = self.Mat_sums_row.matrix()
        stepmat.sums_row[0, self.orddelta] = den
        stepmat.ord = self.derivatives

        stepmat.BigScalars = self.Series_sums  # XXX unused in arb case
        stepmat.Mat_big_scalars = self.Mat_series_sums

        return stepmat

    def one(self, n):
        stepmat = self.StepMatrix_class()
        stepmat.idx_start = stepmat.idx_end = n
        stepmat.rec_mat = self.Mat_rec.identity_matrix()
        stepmat.rec_den = self.rec_den.base_ring().one()
        stepmat.pow_num = self.pow_num.parent().one()
        stepmat.pow_den = self.pow_den.parent().one()
        stepmat.sums_row = self.Mat_sums_row.matrix()
        stepmat.ord = self.derivatives

        stepmat.BigScalars = self.Series_sums  # XXX unused in arb case
        stepmat.Mat_big_scalars = self.Mat_series_sums

        return stepmat

    def binsplit(self, low, high):
        if high - low <= self.binsplit_threshold:
            mat = self.one(low)
            for n in xrange(low, high):
                mat.imulleft(self(n))
        else:
            mid = (low + high) // 2
            mat = self.binsplit(low, mid)
            mat.imulleft(self.binsplit(mid, high))
        return mat

    def __repr__(self):
        return pprint.pformat(self.__dict__)

    # XXX: needs testing, especially when rop.valuation() > 0
    def normalized_residual(self, maj, prod, n, j):
        r"""
        Compute the normalized residual associated with the fundamental
        solution of index j.

        TESTS::

            sage: from ore_algebra import *
            sage: DOP, t, D = DifferentialOperators()
            sage: ode = D + 1/4/(t - 1/2)
            sage: ode.numerical_transition_matrix([0,1+I,1], 1e-100, algorithm='binsplit')
            [[0.707...2078...] + [0.707...]*I]
        """
        r, s = self.orddeq, self.ordrec
        IC = bounds.IC
        # Compute the "missing" coefficients u(n-s), ..., u(n-s'-1) s'=s-r):
        # indeed, it is convenient to compute the residuals starting from
        # u(n-s), ..., u(n-1), while our recurrence matrices produce the partial
        # sum of index n along with the vector [u(n-s'), ..., u(n+r-1)].
        last = [IC.zero()] * r  # u(n-s), ..., u(n-s'-1)
        last.extend([
            IC(c) / IC(prod.rec_den)  # u(n-s'), ..., u(n+r-1)
            for c in prod.rec_mat.column(s - r + j)
        ])  # XXX: check column index
        rop = self.recop
        v = rop.valuation()
        for i in xrange(r - 1, -1, -1):  # compute u(n-s+i)
            last[i] = ~(rop[v](n - s + i)) * sum(
                rop[k](n - s + i) * last[i + k]  # u(n-s+i)
                for k in xrange(v + 1, s + 1))
        # Now compute the residual. WARNING: this residual must correspond to
        # the operator stored in maj.dop, which typically isn't self.diffop (but
        # an operator in θx equal to x^k·self.diffop for some k).
        # XXX: do not recompute this every time!
        bwrnp = [[[pol(n + i)] for pol in self.bwrec] for i in range(s)]
        altlast = [[c] for c in reversed(last[:s])]
        return maj.normalized_residual(n, altlast, bwrnp)

    def normalized_residuals(self, maj, prod, n):
        return [
            self.normalized_residual(maj, prod, n, j)
            for j in xrange(self.orddeq)
        ]

    def term(self, prod, parent, j):
        r"""
        Given a prodrix representing a product B(n-1)···B(0) where B is the
        recurrence matrix associated to some differential operator P, return the
        term of index n of the fundamental solution of P of the form
        y[j](z) = z^j + O(z^r), 0 <= j < r = order(P).
        """
        orddelta = self.orddelta
        num = parent(prod.rec_mat[orddelta + j, orddelta]) * parent(
            prod.pow_num[0])
        den = parent(prod.rec_den) * parent(prod.pow_den)
        return num / den

    def partial_sums(self, prod, ring, rows):
        r"""
        Return a matrix of partial sums of the series and its derivatives.
        """
        numer = matrix(ring, rows, self.orddeq,
                       lambda i, j: prod.sums_row[0, self.orddelta + j][i])
        denom = ring(prod.rec_den) * ring(prod.pow_den)
        return numer / denom

    def error_estimate(self, prod):
        orddelta = self.orddelta
        num1 = sum(
            abs(prod.rec_mat[orddelta + j, orddelta])
            for j in range(self.orddeq))
        num2 = sum(abs(a) for a in prod.pow_num)
        den = abs(prod.rec_den) * abs(prod.pow_den)
        return num1 * num2 / den
class AlternatingSignMatrices(Parent, UniqueRepresentation):
    r"""
    Class of all `n \times n` alternating sign matrices.

    An alternating sign matrix of size `n` is an `n \times n` matrix of `0`'s,
    `1`'s and `-1`'s such that the sum of each row and column is `1` and the
    non-zero entries in each row and column alternate in sign.

    Alternating sign matrices of size `n` are in bijection with
    :class:`monotone triangles <MonotoneTriangles>` with `n` rows.

    INPUT:

    - `n` -- an integer, the size of the matrices.

    - ``use_monotone_triangle`` -- (Default: ``True``) If ``True``, the
      generation of the matrices uses monotone triangles, else it will use the
      earlier and now obsolete contre-tableaux implementation;
      must be ``True`` to generate a lattice (with the ``lattice`` method)

    EXAMPLES:

    This will create an instance to manipulate the alternating sign
    matrices of size 3::

        sage: A = AlternatingSignMatrices(3)
        sage: A
        Alternating sign matrices of size 3
        sage: A.cardinality()
        7

    Notably, this implementation allows to make a lattice of it::

        sage: L = A.lattice()
        sage: L
        Finite lattice containing 7 elements
        sage: L.category()
        Category of facade finite lattice posets
    """
    def __init__(self, n, use_monotone_triangles=True):
        r"""
        Initialize ``self``.

        TESTS::

            sage: A = AlternatingSignMatrices(4)
            sage: TestSuite(A).run()
            sage: A == AlternatingSignMatrices(4, use_monotone_triangles=False)
            False
        """
        self._n = n
        self._matrix_space = MatrixSpace(ZZ, n)
        self._umt = use_monotone_triangles
        Parent.__init__(self, category=FiniteEnumeratedSets())

    def _repr_(self):
        r"""
        Return a string representation of ``self``.

        TESTS::

            sage: A = AlternatingSignMatrices(4); A
            Alternating sign matrices of size 4
        """
        return "Alternating sign matrices of size %s" % self._n

    def _repr_option(self, key):
        """
        Metadata about the :meth:`_repr_` output.

        See :meth:`sage.structure.parent._repr_option` for details.

        EXAMPLES::

            sage: A = AlternatingSignMatrices(3)
            sage: A._repr_option('element_ascii_art')
            True
        """
        return self._matrix_space._repr_option(key)

    def __contains__(self, asm):
        """
        Check if ``asm`` is in ``self``.

        TESTS::

            sage: A = AlternatingSignMatrices(3)
            sage: [[0,1,0],[1,0,0],[0,0,1]] in A
            True
            sage: [[0,1,0],[1,-1,1],[0,1,0]] in A
            True
            sage: [[0, 1],[1,0]] in A
            False
            sage: [[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]] in A
            False
            sage: [[-1, 1, 1],[1,-1,1],[1,1,-1]] in A
            False
        """
        if isinstance(asm, AlternatingSignMatrix):
            return asm._matrix.nrows() == self._n
        try:
            asm = self._matrix_space(asm)
        except (TypeError, ValueError):
            return False
        for row in asm:
            pos = False
            for val in row:
                if val > 0:
                    if pos:
                        return False
                    else:
                        pos = True
                elif val < 0:
                    if pos:
                        pos = False
                    else:
                        return False
            if not pos:
                return False
        if any(sum(row) != 1 for row in asm.columns()):
            return False
        return True

    def _element_constructor_(self, asm):
        """
        Construct an element of ``self``.

        EXAMPLES::

            sage: A = AlternatingSignMatrices(3)
            sage: elt = A([[1, 0, 0],[0, 1, 0],[0, 0, 1]]); elt
            [1 0 0]
            [0 1 0]
            [0 0 1]
            sage: elt.parent() is A
            True
            sage: A([[3, 2, 1], [2, 1], [1]])
            [1 0 0]
            [0 1 0]
            [0 0 1]
        """
        if isinstance(asm, AlternatingSignMatrix):
            if asm.parent() is self:
                return asm
            raise ValueError("Cannot convert between alternating sign matrices of different sizes")
        if asm in MonotoneTriangles(self._n):
            return self.from_monotone_triangle(asm)
        return self.element_class(self, self._matrix_space(asm))

    Element = AlternatingSignMatrix

    def _an_element_(self):
        """
        Return an element of ``self``.
        """
        return self.element_class(self, self._matrix_space.identity_matrix())

    def from_monotone_triangle(self, triangle):
        r"""
        Return an alternating sign matrix from a monotone triangle.

        EXAMPLES::

            sage: A = AlternatingSignMatrices(3)
            sage: A.from_monotone_triangle([[3, 2, 1], [2, 1], [1]])
            [1 0 0]
            [0 1 0]
            [0 0 1]
            sage: A.from_monotone_triangle([[3, 2, 1], [3, 2], [3]])
            [0 0 1]
            [0 1 0]
            [1 0 0]
        """
        n = len(triangle)
        if n != self._n:
            raise ValueError("Incorrect size")
        asm = []

        prev = [0]*n
        for line in reversed(triangle):
            v = [1 if j+1 in reversed(line) else 0 for j in range(n)]
            row = [a-b for (a, b) in zip(v, prev)]
            asm.append(row)
            prev = v

        return self.element_class(self, self._matrix_space(asm))

    def size(self):
        r"""
        Return the size of the matrices in ``self``.

        TESTS::

            sage: A = AlternatingSignMatrices(4)
            sage: A.size()
            4
        """
        return self._n

    def cardinality(self):
        r"""
        Return the cardinality of ``self``.

        The number of `n \times n` alternating sign matrices is equal to

        .. MATH::

            \prod_{k=0}^{n-1} \frac{(3k+1)!}{(n+k)!} = \frac{1! 4! 7! 10!
            \cdots (3n-2)!}{n! (n+1)! (n+2)! (n+3)! \cdots (2n-1)!}

        EXAMPLES::

            sage: [AlternatingSignMatrices(n).cardinality() for n in range(0, 11)]
            [1, 1, 2, 7, 42, 429, 7436, 218348, 10850216, 911835460, 129534272700]
        """
        return Integer(prod( [ factorial(3*k+1)/factorial(self._n+k)
                       for k in range(self._n)] ))

    def matrix_space(self):
        """
        Return the underlying matrix space.

        EXAMPLES::

            sage: A = AlternatingSignMatrices(3)
            sage: A.matrix_space()
            Full MatrixSpace of 3 by 3 dense matrices over Integer Ring
        """
        return self._matrix_space

    def __iter__(self):
        r"""
        Iterator on the alternating sign matrices of size `n`.

        If defined using ``use_monotone_triangles``, this iterator
        will use the iteration on the monotone triangles. Else, it
        will use the iteration on contre-tableaux.

        TESTS::

            sage: A = AlternatingSignMatrices(4)
            sage: len(list(A))
            42
        """
        if self._umt:
            for t in MonotoneTriangles(self._n):
                yield self.from_monotone_triangle(t)
        else:
            for c in ContreTableaux(self._n):
                yield from_contre_tableau(c)

    def _lattice_initializer(self):
        r"""
        Return a 2-tuple to use in argument of ``LatticePoset``.

        For more details about the cover relations, see
        ``MonotoneTriangles``. Notice that the returned matrices are
        made immutable to ensure their hashability required by
        ``LatticePoset``.

        EXAMPLES:

        Proof of the lattice property for alternating sign matrices of
        size 3::

            sage: A = AlternatingSignMatrices(3)
            sage: P = Poset(A._lattice_initializer())
            sage: P.is_lattice()
            True
        """
        assert(self._umt)
        (mts, rels) = MonotoneTriangles(self._n)._lattice_initializer()
        bij = dict((t, self.from_monotone_triangle(t)) for t in mts)
        asms, rels = bij.itervalues(), [(bij[a], bij[b]) for (a,b) in rels]
        return (asms, rels)

    def cover_relations(self):
        r"""
        Iterate on the cover relations between the alternating sign
        matrices.

        EXAMPLES::

            sage: A = AlternatingSignMatrices(3)
            sage: for (a,b) in A.cover_relations():
            ...     eval('a, b')
            ...
            (
            [1 0 0]  [0 1 0]
            [0 1 0]  [1 0 0]
            [0 0 1], [0 0 1]
            )
            (
            [1 0 0]  [1 0 0]
            [0 1 0]  [0 0 1]
            [0 0 1], [0 1 0]
            )
            (
            [0 1 0]  [ 0  1  0]
            [1 0 0]  [ 1 -1  1]
            [0 0 1], [ 0  1  0]
            )
            (
            [1 0 0]  [ 0  1  0]
            [0 0 1]  [ 1 -1  1]
            [0 1 0], [ 0  1  0]
            )
            (
            [ 0  1  0]  [0 0 1]
            [ 1 -1  1]  [1 0 0]
            [ 0  1  0], [0 1 0]
            )
            (
            [ 0  1  0]  [0 1 0]
            [ 1 -1  1]  [0 0 1]
            [ 0  1  0], [1 0 0]
            )
            (
            [0 0 1]  [0 0 1]
            [1 0 0]  [0 1 0]
            [0 1 0], [1 0 0]
            )
            (
            [0 1 0]  [0 0 1]
            [0 0 1]  [0 1 0]
            [1 0 0], [1 0 0]
            )

        """
        (_, rels) = self._lattice_initializer()
        return (_ for _ in rels)

    def lattice(self):
        r"""
        Return the lattice of the alternating sign matrices of size
        `n`, created by ``LatticePoset``.

        EXAMPLES::

            sage: A = AlternatingSignMatrices(3)
            sage: L = A.lattice()
            sage: L
            Finite lattice containing 7 elements

        """
        return LatticePoset(self._lattice_initializer(), cover_relations=True)