def __classcall_private__(cls, R, n=None, M=None, ambient=None):
        """
        Normalize input to ensure a unique representation.

        EXAMPLES::

            sage: from sage.categories.examples.finite_dimensional_lie_algebras_with_basis import AbelianLieAlgebra
            sage: A1 = AbelianLieAlgebra(QQ, n=3)
            sage: A2 = AbelianLieAlgebra(QQ, M=FreeModule(QQ, 3))
            sage: A3 = AbelianLieAlgebra(QQ, 3, FreeModule(QQ, 3))
            sage: A1 is A2 and A2 is A3
            True

            sage: A1 = AbelianLieAlgebra(QQ, 2)
            sage: A2 = AbelianLieAlgebra(ZZ, 2)
            sage: A1 is A2
            False

            sage: A1 = AbelianLieAlgebra(QQ, 0)
            sage: A2 = AbelianLieAlgebra(QQ, 1)
            sage: A1 is A2
            False
        """
        if M is None:
            M = FreeModule(R, n)
        else:
            M = M.change_ring(R)
            n = M.dimension()
        return super(AbelianLieAlgebra, cls).__classcall__(cls,
                                                           R,
                                                           n=n,
                                                           M=M,
                                                           ambient=ambient)
    def __classcall_private__(cls, R, n=None, M=None, ambient=None):
        """
        Normalize input to ensure a unique representation.

        EXAMPLES::

            sage: from sage.categories.examples.finite_dimensional_lie_algebras_with_basis import AbelianLieAlgebra
            sage: A1 = AbelianLieAlgebra(QQ, n=3)
            sage: A2 = AbelianLieAlgebra(QQ, M=FreeModule(QQ, 3))
            sage: A3 = AbelianLieAlgebra(QQ, 3, FreeModule(QQ, 3))
            sage: A1 is A2 and A2 is A3
            True

            sage: A1 = AbelianLieAlgebra(QQ, 2)
            sage: A2 = AbelianLieAlgebra(ZZ, 2)
            sage: A1 is A2
            False

            sage: A1 = AbelianLieAlgebra(QQ, 0)
            sage: A2 = AbelianLieAlgebra(QQ, 1)
            sage: A1 is A2
            False
        """
        if M is None:
            M = FreeModule(R, n)
        else:
            M = M.change_ring(R)
            n = M.dimension()
        return super(AbelianLieAlgebra, cls).__classcall__(cls, R, n=n, M=M,
                                                           ambient=ambient)
Пример #3
0
    def normal_cone(self):
        r"""
        Return the (closure of the) normal cone of the triangulation.

        Recall that a regular triangulation is one that equals the
        "crease lines" of a convex piecewise-linear function. This
        support function is not unique, for example, you can scale it
        by a positive constant. The set of all piecewise-linear
        functions with fixed creases forms an open cone. This cone can
        be interpreted as the cone of normal vectors at a point of the
        secondary polytope, which is why we call it normal cone. See
        [GKZ]_ Section 7.1 for details.

        OUTPUT:

        The closure of the normal cone. The `i`-th entry equals the
        value of the piecewise-linear function at the `i`-th point of
        the configuration.

        For an irregular triangulation, the normal cone is empty. In
        this case, a single point (the origin) is returned.

        EXAMPLES::

            sage: triangulation = polytopes.n_cube(2).triangulate(engine='internal')
            sage: triangulation
            (<0,1,3>, <0,2,3>)
            sage: N = triangulation.normal_cone();  N
            4-d cone in 4-d lattice
            sage: N.rays()
            (-1,  0,  0,  0),
            ( 1,  0,  1,  0),
            (-1,  0, -1,  0),
            ( 1,  0,  0, -1),
            (-1,  0,  0,  1),
            ( 1,  1,  0,  0),
            (-1, -1,  0,  0)
            in Ambient free module of rank 4
            over the principal ideal domain Integer Ring
            sage: N.dual().rays()
            (-1, 1, 1, -1)
            in Ambient free module of rank 4
            over the principal ideal domain Integer Ring

        TESTS::

            sage: polytopes.n_simplex(2).triangulate().normal_cone()
            3-d cone in 3-d lattice
            sage: _.dual().is_trivial()
            True
        """
        if not self.point_configuration().base_ring().is_subring(QQ):
            raise NotImplementedError("Only base rings ZZ and QQ are supported")
        from sage.libs.ppl import Variable, Constraint, Constraint_System, Linear_Expression, C_Polyhedron
        from sage.matrix.constructor import matrix
        from sage.misc.misc import uniq
        from sage.rings.arith import lcm

        pc = self.point_configuration()
        cs = Constraint_System()
        for facet in self.interior_facets():
            s0, s1 = self._boundary_simplex_dictionary()[facet]
            p = set(s0).difference(facet).pop()
            q = set(s1).difference(facet).pop()
            origin = pc.point(p).reduced_affine_vector()
            base_indices = [i for i in s0 if i != p]
            base = matrix([pc.point(i).reduced_affine_vector() - origin for i in base_indices])
            sol = base.solve_left(pc.point(q).reduced_affine_vector() - origin)
            relation = [0] * pc.n_points()
            relation[p] = sum(sol) - 1
            relation[q] = 1
            for i, base_i in enumerate(base_indices):
                relation[base_i] = -sol[i]
            rel_denom = lcm([QQ(r).denominator() for r in relation])
            relation = [ZZ(r * rel_denom) for r in relation]
            ex = Linear_Expression(relation, 0)
            cs.insert(ex >= 0)
        from sage.modules.free_module import FreeModule

        ambient = FreeModule(ZZ, self.point_configuration().n_points())
        if cs.empty():
            cone = C_Polyhedron(ambient.dimension(), "universe")
        else:
            cone = C_Polyhedron(cs)
        from sage.geometry.cone import _Cone_from_PPL

        return _Cone_from_PPL(cone, lattice=ambient)
Пример #4
0
    def normal_cone(self):
        r"""
        Return the (closure of the) normal cone of the triangulation.

        Recall that a regular triangulation is one that equals the
        "crease lines" of a convex piecewise-linear function. This
        support function is not unique, for example, you can scale it
        by a positive constant. The set of all piecewise-linear
        functions with fixed creases forms an open cone. This cone can
        be interpreted as the cone of normal vectors at a point of the
        secondary polytope, which is why we call it normal cone. See
        [GKZ1994]_ Section 7.1 for details.

        OUTPUT:

        The closure of the normal cone. The `i`-th entry equals the
        value of the piecewise-linear function at the `i`-th point of
        the configuration.

        For an irregular triangulation, the normal cone is empty. In
        this case, a single point (the origin) is returned.

        EXAMPLES::

            sage: triangulation = polytopes.hypercube(2).triangulate(engine='internal')
            sage: triangulation
            (<0,1,3>, <1,2,3>)
            sage: N = triangulation.normal_cone();  N
            4-d cone in 4-d lattice
            sage: N.rays()
            ( 0,  0,  0, -1),
            ( 0,  0,  1,  1),
            ( 0,  0, -1, -1),
            ( 1,  0,  0,  1),
            (-1,  0,  0, -1),
            ( 0,  1,  0, -1),
            ( 0, -1,  0,  1)
            in Ambient free module of rank 4
            over the principal ideal domain Integer Ring
            sage: N.dual().rays()
            (1, -1, 1, -1)
            in Ambient free module of rank 4
            over the principal ideal domain Integer Ring

        TESTS::

            sage: polytopes.simplex(2).triangulate().normal_cone()
            3-d cone in 3-d lattice
            sage: _.dual().is_trivial()
            True
        """
        if not self.point_configuration().base_ring().is_subring(QQ):
            raise NotImplementedError(
                'Only base rings ZZ and QQ are supported')
        from ppl import Constraint_System, Linear_Expression, C_Polyhedron
        from sage.matrix.constructor import matrix
        from sage.arith.all import lcm
        pc = self.point_configuration()
        cs = Constraint_System()
        for facet in self.interior_facets():
            s0, s1 = self._boundary_simplex_dictionary()[facet]
            p = set(s0).difference(facet).pop()
            q = set(s1).difference(facet).pop()
            origin = pc.point(p).reduced_affine_vector()
            base_indices = [i for i in s0 if i != p]
            base = matrix([
                pc.point(i).reduced_affine_vector() - origin
                for i in base_indices
            ])
            sol = base.solve_left(pc.point(q).reduced_affine_vector() - origin)
            relation = [0] * pc.n_points()
            relation[p] = sum(sol) - 1
            relation[q] = 1
            for i, base_i in enumerate(base_indices):
                relation[base_i] = -sol[i]
            rel_denom = lcm([QQ(r).denominator() for r in relation])
            relation = [ZZ(r * rel_denom) for r in relation]
            ex = Linear_Expression(relation, 0)
            cs.insert(ex >= 0)
        from sage.modules.free_module import FreeModule
        ambient = FreeModule(ZZ, self.point_configuration().n_points())
        if cs.empty():
            cone = C_Polyhedron(ambient.dimension(), 'universe')
        else:
            cone = C_Polyhedron(cs)
        from sage.geometry.cone import _Cone_from_PPL
        return _Cone_from_PPL(cone, lattice=ambient)
Пример #5
0
class FreeAlgebraQuotient(UniqueRepresentation, Algebra, object):
    @staticmethod
    def __classcall__(cls, A, mons, mats, names):
        """
        Used to support unique representation.

        EXAMPLES::

            sage: H = sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)[0]  # indirect doctest
            sage: H1 = sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)[0]
            sage: H is H1
            True        
        """
        new_mats = []
        for M in mats:
            M = M.parent()(M)
            M.set_immutable()
            new_mats.append(M)
        return super(FreeAlgebraQuotient,
                     cls).__classcall__(cls, A, tuple(mons), tuple(new_mats),
                                        tuple(names))

    Element = FreeAlgebraQuotientElement

    def __init__(self, A, mons, mats, names):
        """
        Returns a quotient algebra defined via the action of a free algebra
        A on a (finitely generated) free module. The input for the quotient
        algebra is a list of monomials (in the underlying monoid for A)
        which form a free basis for the module of A, and a list of
        matrices, which give the action of the free generators of A on this
        monomial basis.
        
        EXAMPLES:
        
        Quaternion algebra defined in terms of three generators::
        
            sage: n = 3
            sage: A = FreeAlgebra(QQ,n,'i')
            sage: F = A.monoid()
            sage: i, j, k = F.gens()
            sage: mons = [ F(1), i, j, k ]
            sage: M = MatrixSpace(QQ,4)
            sage: mats = [M([0,1,0,0, -1,0,0,0, 0,0,0,-1, 0,0,1,0]),  M([0,0,1,0, 0,0,0,1, -1,0,0,0, 0,-1,0,0]),  M([0,0,0,1, 0,0,-1,0, 0,1,0,0, -1,0,0,0]) ]
            sage: H3.<i,j,k> = FreeAlgebraQuotient(A,mons,mats)
            sage: x = 1 + i + j + k
            sage: x
            1 + i + j + k
            sage: x**128
            -170141183460469231731687303715884105728 + 170141183460469231731687303715884105728*i + 170141183460469231731687303715884105728*j + 170141183460469231731687303715884105728*k
        
        Same algebra defined in terms of two generators, with some penalty
        on already slow arithmetic.
        
        ::
        
            sage: n = 2
            sage: A = FreeAlgebra(QQ,n,'x')
            sage: F = A.monoid()
            sage: i, j = F.gens()
            sage: mons = [ F(1), i, j, i*j ]
            sage: r = len(mons)
            sage: M = MatrixSpace(QQ,r)
            sage: mats = [M([0,1,0,0, -1,0,0,0, 0,0,0,-1, 0,0,1,0]), M([0,0,1,0, 0,0,0,1, -1,0,0,0, 0,-1,0,0]) ]
            sage: H2.<i,j> = A.quotient(mons,mats)
            sage: k = i*j
            sage: x = 1 + i + j + k
            sage: x
            1 + i + j + i*j
            sage: x**128
            -170141183460469231731687303715884105728 + 170141183460469231731687303715884105728*i + 170141183460469231731687303715884105728*j + 170141183460469231731687303715884105728*i*j

        TEST::

            sage: TestSuite(H2).run()

        """
        if not is_FreeAlgebra(A):
            raise TypeError, "Argument A must be an algebra."
        R = A.base_ring()
        #        if not R.is_field():  # TODO: why?
        #            raise TypeError, "Base ring of argument A must be a field."
        n = A.ngens()
        assert n == len(mats)
        self.__free_algebra = A
        self.__ngens = n
        self.__dim = len(mons)
        self.__module = FreeModule(R, self.__dim)
        self.__matrix_action = mats
        self.__monomial_basis = mons  # elements of free monoid
        Algebra.__init__(self, R, names, normalize=True)

    def __eq__(self, right):
        """
        Return True if all defining properties of self and right match up.

        EXAMPLES::

            sage: HQ = sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)[0]
            sage: HZ = sage.algebras.free_algebra_quotient.hamilton_quatalg(ZZ)[0]
            sage: HQ == HQ
            True
            sage: HQ == HZ
            False
            sage: HZ == QQ
            False            
        """
        return type(self) == type(right) and \
               self.ngens() == right.ngens() and \
               self.rank() == right.rank() and \
               self.module() == right.module() and \
               self.matrix_action() == right.matrix_action() and \
               self.monomial_basis() == right.monomial_basis()

    def _element_constructor_(self, x):
        """
        EXAMPLES::

            sage: H, (i,j,k) = sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)
            sage: H._element_constructor_(i) is i
            True
            sage: a = H._element_constructor_(1); a
            1
            sage: a in H
            True
            sage: a = H._element_constructor_([1,2,3,4]); a
            1 + 2*i + 3*j + 4*k        
        """
        if isinstance(x, FreeAlgebraQuotientElement) and x.parent() is self:
            return x
        return self.element_class(self, x)

    def _coerce_map_from_(self, S):
        """
        EXAMPLES::

            sage: H, (i,j,k) = sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)
            sage: H._coerce_map_from_(H)
            True
            sage: H._coerce_map_from_(QQ)
            True
            sage: H._coerce_map_from_(GF(7))
            False
        """
        return S == self or self.__free_algebra.has_coerce_map_from(S)

    def _repr_(self):
        """
        EXAMPLES::

            sage: H, (i,j,k) = sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)
            sage: H._repr_()
            "Free algebra quotient on 3 generators ('i', 'j', 'k') and dimension 4 over Rational Field"
        """
        R = self.base_ring()
        n = self.__ngens
        r = self.__module.dimension()
        x = self.variable_names()
        return "Free algebra quotient on %s generators %s and dimension %s over %s" % (
            n, x, r, R)

    def gen(self, i):
        """
        The i-th generator of the algebra.

        EXAMPLES::

            sage: H, (i,j,k) = sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)
            sage: H.gen(0)
            i
            sage: H.gen(2)
            k

        An IndexError is raised if an invalid generator is requested::
        
            sage: H.gen(3)
            Traceback (most recent call last):
            ...
            IndexError: Argument i (= 3) must be between 0 and 2.

        Negative indexing into the generators is not supported::
        
            sage: H.gen(-1)
            Traceback (most recent call last):
            ...
            IndexError: Argument i (= -1) must be between 0 and 2.        
        """
        n = self.__ngens
        if i < 0 or not i < n:
            raise IndexError, "Argument i (= %s) must be between 0 and %s." % (
                i, n - 1)
        R = self.base_ring()
        F = self.__free_algebra.monoid()
        n = self.__ngens
        return self.element_class(self, {F.gen(i): R(1)})

    def ngens(self):
        """
        The number of generators of the algebra.

        EXAMPLES::
        
            sage: sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)[0].ngens()
            3
        """
        return self.__ngens

    def dimension(self):
        """
        The rank of the algebra (as a free module).

        EXAMPLES::

            sage: sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)[0].dimension()
            4        
        """
        return self.__dim

    def matrix_action(self):
        """
        EXAMPLES::

            sage: sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)[0].matrix_action()
            (
            [ 0  1  0  0]  [ 0  0  1  0]  [ 0  0  0  1]
            [-1  0  0  0]  [ 0  0  0  1]  [ 0  0 -1  0]
            [ 0  0  0 -1]  [-1  0  0  0]  [ 0  1  0  0]
            [ 0  0  1  0], [ 0 -1  0  0], [-1  0  0  0]
            )
        """
        return self.__matrix_action

    def monomial_basis(self):
        """
        EXAMPLES::
        
            sage: sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)[0].monomial_basis()
            (1, i0, i1, i2)        
        """
        return self.__monomial_basis

    def rank(self):
        """
        The rank of the algebra (as a free module).

        EXAMPLES::

            sage: sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)[0].rank()
            4        
        """
        return self.__dim

    def module(self):
        """
        The free module of the algebra.

            sage: H = sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)[0]; H
            Free algebra quotient on 3 generators ('i', 'j', 'k') and dimension 4 over Rational Field
            sage: H.module()
            Vector space of dimension 4 over Rational Field        
        """
        return self.__module

    def monoid(self):
        """
        The free monoid of generators of the algebra.

       EXAMPLES::

            sage: sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)[0].monoid()
            Free monoid on 3 generators (i0, i1, i2)
        """
        return self.__free_algebra.monoid()

    def monomial_basis(self):
        """
        The free monoid of generators of the algebra as elements of a free
        monoid.

       EXAMPLES::

            sage: sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)[0].monomial_basis()
            (1, i0, i1, i2)
        """
        return self.__monomial_basis

    def free_algebra(self):
        """
        The free algebra generating the algebra.

        EXAMPLES::

            sage: sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)[0].free_algebra()
            Free Algebra on 3 generators (i0, i1, i2) over Rational Field        
        """
        return self.__free_algebra
Пример #6
0
def modform_cusp_info(calc, S, l, precLimit):
	"""
	This goes through all the cusps and compares the space given by `(f|R)[S]`
	with the space of Elliptic modular forms expansion at those cusps.
	"""

	assert l == S.det()
	assert list(calc.curlS) == [S]

	D = calc.D
	HermWeight = calc.HermWeight
	reducedCurlFSize = calc.matrixColumnCount
	herm_modform_fe_expannsion = FreeModule(QQ, reducedCurlFSize)

	if not Integer(l).is_squarefree():
		# The calculation of the cusp expansion space takes very long here, thus
		# we skip them for now.
		return None

	for cusp in Gamma0(l).cusps():
		if cusp == Infinity: continue
		M = cusp_matrix(cusp)

		try:
			gamma, R, tM = solveR(M, S, space=CurlO(D))
		except Exception:
			print (M, S)
			raise
		R.set_immutable() # for caching, we need it hashable

		herm_modforms = herm_modform_fe_expannsion.echelonized_basis_matrix().transpose()
		ell_R_denom, ell_R_order, M_R = calcMatrixTrans(calc, R)
		CycloDegree_R = CyclotomicField(ell_R_order).degree()
		print "M_R[0] nrows, ell_R_denom, ell_R_order, Cyclo degree:", \
			M_R[0].nrows(), ell_R_denom, ell_R_order, CycloDegree_R

		# The maximum precision we can use is M_R[0].nrows().
		# However, that can be quite huge (e.g. 600).
		ce_prec = min(precLimit, M_R[0].nrows())

		ce = cuspExpansions(level=l, weight=2*HermWeight, prec=ce_prec)
		ell_M_denom, ell_M = ce.expansion_at(SL2Z(M))
		print "ell_M_denom, ell_M nrows:", ell_M_denom, ell_M.nrows()
		ell_M_order = ell_R_order # not sure here. just try the one from R. toCyclPowerBase would fail if this doesn't work
		# CyclotomicField(l / prod(l.prime_divisors())) should also work.

		# Transform to same denom.
		denom_lcm = int(lcm(ell_R_denom, ell_M_denom))
		ell_M = addRows(ell_M, denom_lcm / ell_M_denom)
		M_R = [addRows(M_R_i, denom_lcm / ell_R_denom) for M_R_i in M_R]
		ell_R_denom = ell_M_denom = denom_lcm
		print "new denom:", denom_lcm
		assert ell_R_denom == ell_M_denom

		# ell_M rows are the elliptic FE. M_R[i] columns are the elliptic FE.
		# We expect that M_R gives a higher precision for the ell FE. I'm not sure
		# if this is always true but we expect it here (maybe not needed, though).
		print "precision of M_R[0], ell_M, wanted:", M_R[0].nrows(), ell_M.ncols(), ce_prec
		assert ell_M.ncols() >= ce_prec
		prec = min(M_R[0].nrows(), ell_M.ncols())
		# cut to have same precision
		M_R = [M_R_i[:prec,:] for M_R_i in M_R]
		ell_M = ell_M[:,:prec]
		assert ell_M.ncols() == M_R[0].nrows() == prec

		print "M_R[0] rank, herm rank, mult rank:", \
			M_R[0].rank(), herm_modforms.rank(), (M_R[0] * herm_modforms).rank()
		ell_R = [M_R_i * herm_modforms for M_R_i in M_R]

		# I'm not sure on this. Seems to be true and it simplifies things in the following.
		assert ell_M_order <= ell_R_order, "{0}".format((ell_M_order, ell_R_order))
		assert ell_R_order % ell_M_order == 0, "{0}".format((ell_M_order, ell_R_order))

		# Transform to same Cyclomotic Field in same power base.
		ell_M2 = toCyclPowerBase(ell_M, ell_M_order)
		ell_R2 = toLowerCyclBase(ell_R, ell_R_order, ell_M_order)
		# We must work with the matrix. maybe we should transform hf_M instead to a
		# higher order field instead, if this ever fails (I'm not sure).
		assert ell_R2 is not None
		assert len(ell_M2) == len(ell_R2) # They should have the same power base & same degree now.
		print "ell_M2[0], ell_R2[0] rank with order %i:" % ell_M_order, ell_M2[0].rank(), ell_R2[0].rank()

		assert len(M_R) == len(ell_M2)
		for i in range(len(ell_M2)):
			ell_M_space = ell_M2[i].row_space()
			ell_R_space = ell_R2[i].column_space()
			merged = ell_M_space.intersection(ell_R_space)

			herm_modform_fe_expannsion_Ci = M_R[i].solve_right( merged.basis_matrix().transpose() )
			herm_modform_fe_expannsion_Ci_module = herm_modform_fe_expannsion_Ci.column_module()
			herm_modform_fe_expannsion_Ci_module += M_R[i].right_kernel()

			extra_check_on_herm_superspace(
				vs=herm_modform_fe_expannsion_Ci_module,
				D=D, B_cF=calc.B_cF, HermWeight=HermWeight
			)

			herm_modform_fe_expannsion = herm_modform_fe_expannsion.intersection( herm_modform_fe_expannsion_Ci_module )
			print "power", i, merged.dimension(), herm_modform_fe_expannsion_Ci_module.dimension(), \
				herm_modform_fe_expannsion.dimension()
			current_dimension = herm_modform_fe_expannsion.dimension()

	return herm_modform_fe_expannsion
Пример #7
0
def herm_modform_space(D, HermWeight, B_cF=10, parallelization=None, reduction_method_flags=-1):
	"""
	This calculates the vectorspace of Fourier expansions to
	Hermitian modular forms of weight `HermWeight` over \Gamma,
	where \Gamma = \Sp_2(\curlO) and \curlO is the maximal order
	of \QQ(\sqrt{D}).

	Each Fourier coefficient vector is indexed up to a precision
	\curlF which is given by `B_cF` such that for every
	[a,b,c] \in \curlF \subset \Lambda, we have 0 \le a,c \le B_cF.

	The function `herm_modform_indexset()` returns reduced matrices
	of that precision index set \curlF.
	"""

	if HermWeight % 3 != 0:
		raise TypeError, "the modulform is trivial/zero if HermWeight is not divisible by 3"

	# Transform these into native Python objects. We don't want to have
	# any Sage objects (e.g. Integer) here so that the cache index stays
	# unique.
	D = int(D)
	HermWeight = int(HermWeight)
	B_cF = int(B_cF)
	reduction_method_flags = int(reduction_method_flags)

	calc = C.Calc()
	calc.init(D = D, HermWeight = HermWeight, B_cF=B_cF)
	calc.calcReducedCurlF()
	reducedCurlFSize = calc.matrixColumnCount

	# Calculate the dimension of Hermitian modular form space.
	dim = herm_modform_space_dim(D=D, HermWeight=HermWeight)

	cacheIdx = (D, HermWeight, B_cF)
	if reduction_method_flags != -1:
		cacheIdx += (reduction_method_flags,)
	try:
		herm_modform_fe_expannsion, calc, curlS_denoms, pending_tasks = hermModformSpaceCache[cacheIdx]
		if not isinstance(calc, C.Calc): raise TypeError
		print "Resuming from %s" % hermModformSpaceCache._filename_for_key(cacheIdx)
	except (TypeError, ValueError, KeyError, EOFError): # old format or not cached or cache incomplete
		herm_modform_fe_expannsion = FreeModule(QQ, reducedCurlFSize)
		curlS_denoms = set() # the denominators of the visited matrices S
		pending_tasks = ()

	current_dimension = herm_modform_fe_expannsion.dimension()

	verbose("current dimension: %i, wanted: %i" % (herm_modform_fe_expannsion.dimension(), dim))
	if dim == 0:
		print "dim == 0 -> exit"
		return

	def task_iter_func():
		# Iterate S \in Mat_2^T(\curlO), S > 0.
		while True:
			# Get the next S.
			# If calc.curlS is not empty, this is because we have recovered from a resume.
			if len(calc.curlS) == 0:
				S = calc.getNextS()
			else:
				assert len(calc.curlS) == 1
				S = calc.curlS[0]

			l = S.det()
			l = toInt(l)
			curlS_denoms.add(l)

			verbose("trying S={0}, det={1}".format(S, l))

			if reduction_method_flags & Method_Elliptic_reduction:
				yield CalcTask(
					func=modform_restriction_info, calc=calc, kwargs={"S":S, "l":l})

			if reduction_method_flags & Method_EllipticCusp_reduction:
				precLimit = calcPrecisionDimension(B_cF=B_cF, S=S)
				yield CalcTask(
					func=modform_cusp_info, calc=calc, kwargs={"S":S, "l":l, "precLimit": precLimit})

			calc.curlS_clearMatrices() # In the C++ internal curlS, clear previous matrices.

	task_iter = task_iter_func()
	if parallelization:
		parallelization.task_iter = task_iter

	if parallelization and pending_tasks:
		for func, name in pending_tasks:
			parallelization.exec_task(func=func, name=name)

	step_counter = 0
	while True:
		if parallelization:
			new_task_count = 0

			spaces = []
			for task, exc, newspace in parallelization.get_all_ready_results():
				if exc: raise exc

				if newspace is None:
					verbose("no data from %r" % task)
					continue
				if newspace.dimension() == reducedCurlFSize:
					verbose("no information gain from %r" % task)
					continue

				spacecomment = task
				assert newspace.dimension() >= dim, "%r, %r" % (task, newspace)
				if newspace.dimension() < herm_modform_fe_expannsion.dimension():
					# Swap newspace with herm_modform_fe_expannsion.
					herm_modform_fe_expannsion, newspace = newspace, herm_modform_fe_expannsion
					current_dimension = herm_modform_fe_expannsion.dimension()
					if current_dimension == dim:
						if not isinstance(task, IntersectSpacesTask):
							verbose("warning: we expected IntersectSpacesTask for final dim but got: %r" % task)
					verbose("new dimension: %i, wanted: %i" % (current_dimension, dim))
					if current_dimension <= 20:
						pprint(herm_modform_fe_expannsion.basis())
					spacecomment = "<old base space>"

				spaces += [(spacecomment, newspace)]

			if spaces:
				parallelization.exec_task(IntersectSpacesTask(herm_modform_fe_expannsion, spaces))
				new_task_count += 1

			new_task_count += parallelization.maybe_queue_tasks()
			time.sleep(0.1)

		else: # no parallelization
			new_task_count = 1
			if pending_tasks: # from some resuming
				task,_ = pending_tasks[0]
				pending_tasks = pending_tasks[1:]
			else:
				task = next(task_iter)
			newspace = task()

			if newspace is None:
				verbose("no data from %r" % task)
			if newspace is not None and newspace.dimension() == reducedCurlFSize:
				verbose("no information gain from %r" % task)
				newspace = None

			if newspace is not None:
				new_task_count += 1
				spacecomment = task
				herm_modform_fe_expannsion_new = IntersectSpacesTask(
					herm_modform_fe_expannsion, [(spacecomment, newspace)])()
				if herm_modform_fe_expannsion_new is not None:
					herm_modform_fe_expannsion = herm_modform_fe_expannsion_new
				current_dimension = herm_modform_fe_expannsion.dimension()
				verbose("new dimension: %i, wanted: %i" % (current_dimension, dim))

		if new_task_count > 0:
			step_counter += 1

			if step_counter % 10 == 0:
				verbose("save state after %i steps to %s" % (step_counter, os.path.basename(hermModformSpaceCache._filename_for_key(cacheIdx))))
				if parallelization:
					pending_tasks = parallelization.get_pending_tasks()
				hermModformSpaceCache[cacheIdx] = (herm_modform_fe_expannsion, calc, curlS_denoms, pending_tasks)

		if current_dimension == dim:
			verbose("finished!")
			break

	# Test for some other S with other not-yet-seen denominator.
	check_herm_modform_space(
		calc, herm_modform_space=herm_modform_fe_expannsion,
		used_curlS_denoms=curlS_denoms
		)

	return herm_modform_fe_expannsion
Пример #8
0
class FreeAlgebraQuotient(UniqueRepresentation, Algebra, object):
    @staticmethod
    def __classcall__(cls, A, mons, mats, names):
        """
        Used to support unique representation.

        EXAMPLES::

            sage: H = sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)[0]  # indirect doctest
            sage: H1 = sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)[0]
            sage: H is H1
            True
        """
        new_mats = []
        for M in mats:
            M = M.parent()(M)
            M.set_immutable()
            new_mats.append(M)
        return super(FreeAlgebraQuotient, cls).__classcall__(cls, A, tuple(mons),
                                                  tuple(new_mats), tuple(names))

    Element = FreeAlgebraQuotientElement
    def __init__(self, A, mons, mats, names):
        """
        Returns a quotient algebra defined via the action of a free algebra
        A on a (finitely generated) free module. The input for the quotient
        algebra is a list of monomials (in the underlying monoid for A)
        which form a free basis for the module of A, and a list of
        matrices, which give the action of the free generators of A on this
        monomial basis.
        
        EXAMPLES:
        
        Quaternion algebra defined in terms of three generators::
        
            sage: n = 3
            sage: A = FreeAlgebra(QQ,n,'i')
            sage: F = A.monoid()
            sage: i, j, k = F.gens()
            sage: mons = [ F(1), i, j, k ]
            sage: M = MatrixSpace(QQ,4)
            sage: mats = [M([0,1,0,0, -1,0,0,0, 0,0,0,-1, 0,0,1,0]),  M([0,0,1,0, 0,0,0,1, -1,0,0,0, 0,-1,0,0]),  M([0,0,0,1, 0,0,-1,0, 0,1,0,0, -1,0,0,0]) ]
            sage: H3.<i,j,k> = FreeAlgebraQuotient(A,mons,mats)
            sage: x = 1 + i + j + k
            sage: x
            1 + i + j + k
            sage: x**128
            -170141183460469231731687303715884105728 + 170141183460469231731687303715884105728*i + 170141183460469231731687303715884105728*j + 170141183460469231731687303715884105728*k
        
        Same algebra defined in terms of two generators, with some penalty
        on already slow arithmetic.
        
        ::
        
            sage: n = 2
            sage: A = FreeAlgebra(QQ,n,'x')
            sage: F = A.monoid()
            sage: i, j = F.gens()
            sage: mons = [ F(1), i, j, i*j ]
            sage: r = len(mons)
            sage: M = MatrixSpace(QQ,r)
            sage: mats = [M([0,1,0,0, -1,0,0,0, 0,0,0,-1, 0,0,1,0]), M([0,0,1,0, 0,0,0,1, -1,0,0,0, 0,-1,0,0]) ]
            sage: H2.<i,j> = A.quotient(mons,mats)
            sage: k = i*j
            sage: x = 1 + i + j + k
            sage: x
            1 + i + j + i*j
            sage: x**128
            -170141183460469231731687303715884105728 + 170141183460469231731687303715884105728*i + 170141183460469231731687303715884105728*j + 170141183460469231731687303715884105728*i*j

        TEST::

            sage: TestSuite(H2).run()

        """
        if not is_FreeAlgebra(A):
            raise TypeError("Argument A must be an algebra.")
        R = A.base_ring()
#        if not R.is_field():  # TODO: why?
#            raise TypeError, "Base ring of argument A must be a field."
        n = A.ngens()
        assert n == len(mats)
        self.__free_algebra = A
        self.__ngens = n
        self.__dim = len(mons)
        self.__module = FreeModule(R,self.__dim)
        self.__matrix_action = mats
        self.__monomial_basis = mons # elements of free monoid
        Algebra.__init__(self, R, names, normalize=True)

    def __eq__(self, right):
        """
        Return True if all defining properties of self and right match up.

        EXAMPLES::

            sage: HQ = sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)[0]
            sage: HZ = sage.algebras.free_algebra_quotient.hamilton_quatalg(ZZ)[0]
            sage: HQ == HQ
            True
            sage: HQ == HZ
            False
            sage: HZ == QQ
            False
        """
        return isinstance(right, FreeAlgebraQuotient) and \
               self.ngens() == right.ngens() and \
               self.rank() == right.rank() and \
               self.module() == right.module() and \
               self.matrix_action() == right.matrix_action() and \
               self.monomial_basis() == right.monomial_basis()
    

    def _element_constructor_(self, x):
        """
        EXAMPLES::

            sage: H, (i,j,k) = sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)
            sage: H._element_constructor_(i) is i
            True
            sage: a = H._element_constructor_(1); a
            1
            sage: a in H
            True
            sage: a = H._element_constructor_([1,2,3,4]); a
            1 + 2*i + 3*j + 4*k
        """
        if isinstance(x, FreeAlgebraQuotientElement) and x.parent() is self:
            return x
        return self.element_class(self,x)

    def _coerce_map_from_(self,S):
        """
        EXAMPLES::

            sage: H, (i,j,k) = sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)
            sage: H._coerce_map_from_(H)
            True
            sage: H._coerce_map_from_(QQ)
            True
            sage: H._coerce_map_from_(GF(7))
            False
        """
        return S==self or self.__free_algebra.has_coerce_map_from(S)

    def _repr_(self):
        """
        EXAMPLES::

            sage: H, (i,j,k) = sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)
            sage: H._repr_()
            "Free algebra quotient on 3 generators ('i', 'j', 'k') and dimension 4 over Rational Field"
        """
        R = self.base_ring()
        n = self.__ngens
        r = self.__module.dimension()
        x = self.variable_names()
        return "Free algebra quotient on %s generators %s and dimension %s over %s"%(n,x,r,R)

    def gen(self, i):
        """
        The i-th generator of the algebra.

        EXAMPLES::

            sage: H, (i,j,k) = sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)
            sage: H.gen(0)
            i
            sage: H.gen(2)
            k

        An IndexError is raised if an invalid generator is requested::
        
            sage: H.gen(3)
            Traceback (most recent call last):
            ...
            IndexError: Argument i (= 3) must be between 0 and 2.

        Negative indexing into the generators is not supported::
        
            sage: H.gen(-1)
            Traceback (most recent call last):
            ...
            IndexError: Argument i (= -1) must be between 0 and 2.
        """
        n = self.__ngens
        if i < 0 or not i < n: 
            raise IndexError("Argument i (= %s) must be between 0 and %s."%(i, n-1))
        R = self.base_ring()
        F = self.__free_algebra.monoid()
        n = self.__ngens
        return self.element_class(self,{F.gen(i):R(1)})

    def ngens(self):
        """
        The number of generators of the algebra.

        EXAMPLES::
        
            sage: sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)[0].ngens()
            3
        """
        return self.__ngens

    def dimension(self):
        """
        The rank of the algebra (as a free module).

        EXAMPLES::

            sage: sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)[0].dimension()
            4
        """
        return self.__dim

    def matrix_action(self):
        """
        EXAMPLES::

            sage: sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)[0].matrix_action()
            (
            [ 0  1  0  0]  [ 0  0  1  0]  [ 0  0  0  1]
            [-1  0  0  0]  [ 0  0  0  1]  [ 0  0 -1  0]
            [ 0  0  0 -1]  [-1  0  0  0]  [ 0  1  0  0]
            [ 0  0  1  0], [ 0 -1  0  0], [-1  0  0  0]
            )
        """
        return self.__matrix_action

    def monomial_basis(self):
        """
        EXAMPLES::
        
            sage: sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)[0].monomial_basis()
            (1, i0, i1, i2)
        """
        return self.__monomial_basis

    def rank(self):
        """
        The rank of the algebra (as a free module).

        EXAMPLES::

            sage: sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)[0].rank()
            4
        """
        return self.__dim

    def module(self):
        """
        The free module of the algebra.

            sage: H = sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)[0]; H
            Free algebra quotient on 3 generators ('i', 'j', 'k') and dimension 4 over Rational Field
            sage: H.module()
            Vector space of dimension 4 over Rational Field
        """
        return self.__module

    def monoid(self):
        """
        The free monoid of generators of the algebra.

       EXAMPLES::

            sage: sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)[0].monoid()
            Free monoid on 3 generators (i0, i1, i2)
        """
        return self.__free_algebra.monoid()

    def monomial_basis(self):
        """
        The free monoid of generators of the algebra as elements of a free
        monoid.

       EXAMPLES::

            sage: sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)[0].monomial_basis()
            (1, i0, i1, i2)
        """
        return self.__monomial_basis

    def free_algebra(self):
        """
        The free algebra generating the algebra.

        EXAMPLES::

            sage: sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ)[0].free_algebra()
            Free Algebra on 3 generators (i0, i1, i2) over Rational Field
        """
        return self.__free_algebra