Exemple #1
0
 def _check_generic(self, cones1, cones2, v):
     """ 
     Returns pairs of cones which intersect with respect to `v`.
     
     For every pair of cones `c1`, `c2` from respective lists, check whether 
     they intersect generically with respect to `v`.
     Return list of ordered pairs of cones which intersect with respect to `v`.
     This means the intersection of `c1` and `c2+v` is non-empty.
     
     EXAMPLES::
         
         sage: A = MW(toric_varieties.P2().fan())
         sage: cones = A._fan(1)
         sage: v = (.1,.3)
         sage: A._check_generic(cones,cones,v)
         [(1-d cone of Rational polyhedral fan in 2-d lattice N, 1-d cone of Rational polyhedral fan in 2-d lattice N)]
     
     """
     good_pairs = []
     for c1 in cones1:
         for c2 in cones2:
             # check whether v is in c1 - c2 (i.e. mink sum of c1 and -c2)
             C = Cone(rays=[r for r in c1.rays()] +
                      [-1 * r for r in c2.rays()])
             if C.contains(v):
                 good_pairs.append((c1, c2))
     return good_pairs
Exemple #2
0
def cone_in_homology(tri, angle):
    rays = taut_rays(tri, angle)
    if len(rays) == 0:
        return []
    else:
        A = projection_to_homology(tri,angle)
        projectedRays = [A*v for v in rays]
        C = Cone(projectedRays)
        return [ray for ray in C.rays()]
Exemple #3
0
def experiment():
    rank = 5
    level = 4
    num_points = 11

    client = cbc.CBClient()
    liealg = cbd.TypeALieAlgebra(rank, store_fusion=True, exact=True)
    rays = []
    wts = []
    ranks = []
    for wt in liealg.get_weights(level):
        if wt == tuple([0 for x in range(0, rank)]):
            continue
        cbb = cbd.SymmetricConformalBlocksBundle(client, liealg, wt,
                                                 num_points, level)
        if cbb.get_rank() == 0:
            continue
        divisor = cbb.get_symmetrized_divisor()
        if divisor == [
                sage.Rational(0) for x in range(0, num_points // 2 - 1)
        ]:
            continue
        rays = rays + [divisor]
        wts = wts + [wt]
        ranks = ranks + [cbb.get_rank()]
        #print(wt, cbb.get_rank(), divisor)

    p = Polyhedron(rays=rays, base_ring=RationalField(), backend="cdd")
    extremal_rays = [list(v.vector()) for v in p.Vrepresentation()]
    c = Cone(p)
    print("Extremal rays:")
    for i in range(0, len(rays)):
        ray = rays[i]
        wt = wts[i]
        rk = ranks[i]
        if ray in extremal_rays:
            print(rk, wt, ray)
def fan_isomorphism_generator(fan1, fan2):
    """
    Iterate over the isomorphisms from ``fan1`` to ``fan2``.

    ALGORITHM:

    The :meth:`sage.geometry.fan.Fan.vertex_graph` of the two fans is
    compared. For each graph isomorphism, we attempt to lift it to an
    actual isomorphism of fans.

    INPUT:

    - ``fan1``, ``fan2`` -- two fans.

    OUTPUT:

    Yields the fan isomorphisms as matrices acting from the right on
    rays.

    EXAMPLES::

        sage: fan = toric_varieties.P2().fan()
        sage: from sage.geometry.fan_isomorphism import fan_isomorphism_generator
        sage: tuple( fan_isomorphism_generator(fan, fan) )
        (
        [1 0]  [0 1]  [ 1  0]  [ 0  1]  [-1 -1]  [-1 -1]
        [0 1], [1 0], [-1 -1], [-1 -1], [ 1  0], [ 0  1]
        )

        sage: m1 = matrix([(1, 0), (0, -5), (-3, 4)])
        sage: m2 = matrix([(3, 0), (1, 0), (-2, 1)])
        sage: m1.elementary_divisors() == m2.elementary_divisors() == [1,1,0]
        True
        sage: fan1 = Fan([Cone([m1*vector([23, 14]), m1*vector([   3,100])]),
        ...               Cone([m1*vector([-1,-14]), m1*vector([-100, -5])])])
        sage: fan2 = Fan([Cone([m2*vector([23, 14]), m2*vector([   3,100])]),
        ...               Cone([m2*vector([-1,-14]), m2*vector([-100, -5])])])
        sage: next(fan_isomorphism_generator(fan1, fan2))
        [18  1 -5]
        [ 4  0 -1]
        [ 5  0 -1]

        sage: m0 = identity_matrix(ZZ, 2)
        sage: m1 = matrix([(1, 0), (0, -5), (-3, 4)])
        sage: m2 = matrix([(3, 0), (1, 0), (-2, 1)])
        sage: m1.elementary_divisors() == m2.elementary_divisors() == [1,1,0]
        True
        sage: fan0 = Fan([Cone([m0*vector([1,0]), m0*vector([1,1])]),
        ...               Cone([m0*vector([1,1]), m0*vector([0,1])])])
        sage: fan1 = Fan([Cone([m1*vector([1,0]), m1*vector([1,1])]),
        ...               Cone([m1*vector([1,1]), m1*vector([0,1])])])
        sage: fan2 = Fan([Cone([m2*vector([1,0]), m2*vector([1,1])]),
        ...               Cone([m2*vector([1,1]), m2*vector([0,1])])])
        sage: tuple(fan_isomorphism_generator(fan0, fan0))
        (
        [1 0]  [0 1]
        [0 1], [1 0]
        )
        sage: tuple(fan_isomorphism_generator(fan1, fan1))
        (
        [1 0 0]  [ -3 -20  28]
        [0 1 0]  [ -1  -4   7]
        [0 0 1], [ -1  -5   8]
        )
        sage: tuple(fan_isomorphism_generator(fan1, fan2))
        (
        [18  1 -5]  [ 6 -3  7]
        [ 4  0 -1]  [ 1 -1  2]
        [ 5  0 -1], [ 2 -1  2]
        )
        sage: tuple(fan_isomorphism_generator(fan2, fan1))
        (
        [ 0 -1  1]  [ 0 -1  1]
        [ 1 -7  2]  [ 2 -2 -5]
        [ 0 -5  4], [ 1  0 -3]
        )
    """
    if not fan_isomorphic_necessary_conditions(fan1, fan2):
        return

    graph1 = fan1.vertex_graph()
    graph2 = fan2.vertex_graph()
    graph_iso = graph1.is_isomorphic(graph2, edge_labels=True, certify=True)
    if not graph_iso[0]:
        return
    graph_iso = graph_iso[1]

    # Pick a basis of rays in fan1
    max_cone = fan1(fan1.dim())[0]
    fan1_pivot_rays = max_cone.rays()
    fan1_basis = fan1_pivot_rays + fan1.virtual_rays()  # A QQ-basis for N_1
    fan1_pivot_cones = [fan1.embed(Cone([r])) for r in fan1_pivot_rays]

    # The fan2 cones as set(set(ray indices))
    fan2_cones = frozenset(
        frozenset(cone.ambient_ray_indices())
        for cone in fan2.generating_cones())

    # iterate over all graph isomorphisms graph1 -> graph2
    for perm in graph2.automorphism_group(edge_labels=True):
        # find a candidate m that maps fan1_basis to the image rays under the graph isomorphism
        fan2_pivot_cones = [perm(graph_iso[c]) for c in fan1_pivot_cones]
        fan2_pivot_rays = fan2.rays(
            [c.ambient_ray_indices()[0] for c in fan2_pivot_cones])
        fan2_basis = fan2_pivot_rays + fan2.virtual_rays()
        try:
            m = matrix(ZZ, fan1_basis).solve_right(matrix(ZZ, fan2_basis))
            m = m.change_ring(ZZ)
        except (ValueError, TypeError):
            continue  # no solution

        # check that the candidate m lifts the vertex graph homomorphism
        graph_image_ray_indices = [
            perm(graph_iso[c]).ambient_ray_indices()[0] for c in fan1(1)
        ]
        try:
            matrix_image_ray_indices = [
                fan2.rays().index(r * m) for r in fan1.rays()
            ]
        except ValueError:
            continue
        if graph_image_ray_indices != matrix_image_ray_indices:
            continue

        # check that the candidate m maps generating cone to generating cone
        image_cones = frozenset(  # The image(fan1) cones as set(set(integers)
            frozenset(graph_image_ray_indices[i]
                      for i in cone.ambient_ray_indices())
            for cone in fan1.generating_cones())
        if image_cones == fan2_cones:
            m.set_immutable()
            yield m
Exemple #5
0
    def borcherds_input_Qbasis(self, pole_order, prec, verbose=False):
        r"""
        Compute a Q-basis of input functions into the Borcherds lift with pole order in infinity up to pole_order.

        This method computes a list of Borcherds lift inputs F_0, ..., F_d which is a Q-basis in the following sense: it is minimal with the property that every modular form with pole order at most pole_order whose Borcherds lift is holomorphic can be expressed in the form (k_0 F_0 + ... + k_d F_d) where k_i are nonnegative rational numbers.

        INPUT:
        - ``pole_order`` -- positive number (does not need to be an integer)
        - ``prec`` -- precision of the output

        OUTPUT: WeilRepModularFormsBasis
        """
        S = self.gram_matrix()
        w = self.weilrep()
        K = w.base_field()
        d = K.discriminant()
        wt = self.input_wt()
        M, p, X = self._borcherds_product_polyhedron(pole_order,
                                                     prec,
                                                     verbose=verbose)
        try:
            b = Matrix(Cone(p).rays())
            if verbose:
                print('I will now try to find Borcherds product inputs.')
            try:
                u = M.solve_left(b)
                Y = [v * X for v in u.rows()]
                Y = WeilRepModularFormsBasis(wt, Y, w)
            except ValueError:
                Y = WeilRepModularFormsBasis(wt, [], w)
        except IndexError:
            Y = WeilRepModularFormsBasis(wt, [], w)
        if wt >= 0:
            X = deepcopy(
                w.basis_vanishing_to_order(wt, max(0, -pole_order), prec))
            if X:
                X.extend(Y)
                Y = X
        X = Y._WeilRepModularFormsBasis__basis
        if d >= -4:
            if d == -4:
                f = w.multiplication_by_i()
                n = 2
            else:
                f = w.multiplication_by_zeta()
                f2 = f * f
                n = 3
            for i, x in enumerate(X):
                try:
                    j = X.index(f(x))
                    if j == i:
                        X[i] = x / n
                    else:
                        del X[j]
                except ValueError:
                    pass
                if n == 3:
                    try:
                        j2 = X.index(f2(x))
                        del X[j2]
                    except ValueError:
                        pass
        X.sort(key=lambda x: x.fourier_expansion()[0][2][0])
        return WeilRepModularFormsBasis(wt, X, w)
Exemple #6
0
def trivial(ambient_dim=None, lattice=None):
    r"""
    The trivial cone with no nonzero generators in ``ambient_dim``
    dimensions, or living in ``lattice``.

    INPUT:

    - ``ambient_dim`` -- a nonnegative integer (default: ``None``); the
      dimension of the ambient space

    - ``lattice`` -- a toric lattice (default: ``None``); the lattice in
      which the cone will live

    If ``ambient_dim`` is omitted, then it will be inferred from the
    rank of ``lattice``. If the ``lattice`` is omitted, then the
    default lattice of rank ``ambient_dim`` will be used.

    A ``ValueError`` is raised if neither ``ambient_dim`` nor
    ``lattice`` are specified. It is also a ``ValueError`` to specify
    both ``ambient_dim`` and ``lattice`` unless the rank of
    ``lattice`` is equal to ``ambient_dim``.

    OUTPUT:

    A :class:`.ConvexRationalPolyhedralCone` representing the
    trivial cone with no nonzero generators living in ``lattice``,
    with ambient dimension ``ambient_dim``.

    A ``ValueError`` can be raised if the inputs are incompatible or
    insufficient. See the INPUT documentation for details.

    EXAMPLES:

    Construct the trivial cone, containing only the origin, in three
    dimensions::

        sage: cones.trivial(3)
        0-d cone in 3-d lattice N

    If a ``lattice`` is given, the trivial cone will live in that
    lattice::

        sage: L = ToricLattice(3, 'M')
        sage: cones.trivial(3, lattice=L)
        0-d cone in 3-d lattice M

    TESTS:

    We can construct the trivial cone in a trivial ambient space::

        sage: cones.trivial(0)
        0-d cone in 0-d lattice N

    An error is raised if the rank of the lattice disagrees with
    ``ambient_dim``::

        sage: L = ToricLattice(1, 'M')
        sage: cones.trivial(3, lattice=L)
        Traceback (most recent call last):
        ...
        ValueError: lattice rank=1 and ambient_dim=3 are incompatible

    We also get an error if no arguments are given::

        sage: cones.trivial()
        Traceback (most recent call last):
        ...
        ValueError: either the ambient dimension or the lattice must
        be specified
    """
    from sage.geometry.cone import Cone

    (ambient_dim, lattice) = _preprocess_args(ambient_dim, lattice)

    return Cone([], lattice)
Exemple #7
0
def schur(ambient_dim=None, lattice=None):
    r"""
    The Schur cone in ``ambient_dim`` dimensions, or living
    in ``lattice``.

    The Schur cone in `n` dimensions induces the majorization ordering
    on the ambient space. If `\left\{e_{1}, e_{2}, \ldots,
    e_{n}\right\}` is the standard basis for the space, then its
    generators are `\left\{e_{i} - e_{i+1}\ |\ 1 \le i \le
    n-1\right\}`. Its dual is the downward monotonic cone.

    INPUT:

    - ``ambient_dim`` -- a nonnegative integer (default: ``None``); the
      dimension of the ambient space

    - ``lattice`` -- a toric lattice (default: ``None``); the lattice in
      which the cone will live

    If ``ambient_dim`` is omitted, then it will be inferred from the
    rank of ``lattice``. If the ``lattice`` is omitted, then the
    default lattice of rank ``ambient_dim`` will be used.

    A ``ValueError`` is raised if neither ``ambient_dim`` nor
    ``lattice`` are specified. It is also a ``ValueError`` to specify
    both ``ambient_dim`` and ``lattice`` unless the rank of
    ``lattice`` is equal to ``ambient_dim``.

    OUTPUT:

    A :class:`.ConvexRationalPolyhedralCone` representing the Schur
    cone living in ``lattice``, with ambient dimension ``ambient_dim``.
    Each generating ray has the integer ring as its base ring.

    A ``ValueError`` can be raised if the inputs are incompatible or
    insufficient. See the INPUT documentation for details.

    REFERENCES:

    - [GS2010]_, Section 3.1

    - [IS2005]_, Example 7.3

    - [SS2016]_, Example 7.4

    EXAMPLES:

    Verify the claim [SS2016]_ that the maximal angle between any two
    generators of the Schur cone and the nonnegative orthant in
    dimension five is `\left(3/4\right)\pi`::

        sage: P = cones.schur(5)
        sage: Q = cones.nonnegative_orthant(5)
        sage: G = ( g.change_ring(QQbar).normalized() for g in P )
        sage: H = ( h.change_ring(QQbar).normalized() for h in Q )
        sage: actual = max(arccos(u.inner_product(v)) for u in G for v in H)
        sage: expected = 3*pi/4
        sage: abs(actual - expected).n() < 1e-12
        True

    The dual of the Schur cone is the "downward monotonic cone"
    [GS2010]_, whose elements' entries are in non-increasing order::

        sage: set_random_seed()
        sage: ambient_dim = ZZ.random_element(10)
        sage: K = cones.schur(ambient_dim).dual()
        sage: x = K.random_element()
        sage: all( x[i] >= x[i+1] for i in range(ambient_dim-1) )
        True

    TESTS:

    We get the trivial cone when ``ambient_dim`` is zero::

        sage: cones.schur(0).is_trivial()
        True

    The Schur cone induces the majorization ordering, as in Iusem
    and Seeger's [IS2005]_ Example 7.3::

        sage: set_random_seed()
        sage: def majorized_by(x,y):
        ....:     return (all(sum(x[0:i]) <= sum(y[0:i])
        ....:                 for i in range(x.degree()-1))
        ....:             and sum(x) == sum(y))
        sage: ambient_dim = ZZ.random_element(10)
        sage: V = VectorSpace(QQ, ambient_dim)
        sage: S = cones.schur(ambient_dim)
        sage: majorized_by(V.zero(), S.random_element())
        True
        sage: x = V.random_element()
        sage: y = V.random_element()
        sage: majorized_by(x,y) == ( (y-x) in S )
        True

    If a ``lattice`` was given, it is actually used::

        sage: L = ToricLattice(3, 'M')
        sage: cones.schur(3, lattice=L)
        2-d cone in 3-d lattice M

    Unless the rank of the lattice disagrees with ``ambient_dim``::

        sage: L = ToricLattice(1, 'M')
        sage: cones.schur(3, lattice=L)
        Traceback (most recent call last):
        ...
        ValueError: lattice rank=1 and ambient_dim=3 are incompatible

    We also get an error if no arguments are given::

        sage: cones.schur()
        Traceback (most recent call last):
        ...
        ValueError: either the ambient dimension or the lattice must
        be specified
    """
    from sage.geometry.cone import Cone
    from sage.matrix.constructor import matrix
    from sage.rings.integer_ring import ZZ

    (ambient_dim, lattice) = _preprocess_args(ambient_dim, lattice)

    def _f(i, j):
        if i == j:
            return 1
        elif j - i == 1:
            return -1
        else:
            return 0

    # The "max" below catches the trivial case where ambient_dim == 0.
    S = matrix(ZZ, max(0, ambient_dim - 1), ambient_dim, _f)

    return Cone(S.rows(), lattice)
Exemple #8
0
def rearrangement(p, ambient_dim=None, lattice=None):
    r"""
    The rearrangement cone of order ``p`` in ``ambient_dim``
    dimensions, or living in ``lattice``.

    The rearrangement cone of order ``p`` in ``ambient_dim``
    dimensions consists of all vectors of length ``ambient_dim``
    whose smallest ``p`` components sum to a nonnegative number.

    For example, the rearrangement cone of order one has its single
    smallest component nonnegative. This implies that all components
    are nonnegative, and that therefore the rearrangement cone of
    order one is the nonnegative orthant in its ambient space.

    When ``p`` and ``ambient_dim`` are equal, all components of the
    cone's elements must sum to a nonnegative number. In other
    words, the rearrangement cone of order ``ambient_dim`` is a
    half-space.

    INPUT:

    - ``p`` -- a nonnegative integer; the number of components to
      "rearrange", between ``1`` and ``ambient_dim`` inclusive

    - ``ambient_dim`` -- a nonnegative integer (default: ``None``); the
      dimension of the ambient space

    - ``lattice`` -- a toric lattice (default: ``None``); the lattice in
      which the cone will live

    If ``ambient_dim`` is omitted, then it will be inferred from the
    rank of ``lattice``. If the ``lattice`` is omitted, then the
    default lattice of rank ``ambient_dim`` will be used.

    A ``ValueError`` is raised if neither ``ambient_dim`` nor
    ``lattice`` are specified. It is also a ``ValueError`` to specify
    both ``ambient_dim`` and ``lattice`` unless the rank of
    ``lattice`` is equal to ``ambient_dim``.

    It is also a ``ValueError`` to specify a non-integer ``p``.

    OUTPUT:

    A :class:`.ConvexRationalPolyhedralCone` representing the
    rearrangement cone of order ``p`` living in ``lattice``, with
    ambient dimension ``ambient_dim``. Each generating ray has the
    integer ring as its base ring.

    A ``ValueError`` can be raised if the inputs are incompatible or
    insufficient. See the INPUT documentation for details.

    ALGORITHM:

    Suppose that the ambient space is of dimension `n`. The extreme
    directions of the rearrangement cone for `1 \le p \le n-1` are
    given by [Jeong2017]_ Theorem 5.2.3. When `2 \le p \le n-2` (that
    is, if we ignore `p = 1` and `p = n-1`), they consist of

    - the standard basis `\left\{e_{1},e_{2},\ldots,e_{n}\right\}` for
      the ambient space, and

    - the `n` vectors `\left(1,1,\ldots,1\right)^{T} - pe_{i}` for
      `i = 1,2,\ldots,n`.

    Special cases are then given for `p = 1` and `p = n-1` in the
    theorem. However in SageMath we don't need conically-independent
    extreme directions. We only need a generating set, because the
    :func:`Cone` function will eliminate any redundant generators. And
    one can easily verify that the special-case extreme directions for
    `p = 1` and `p = n-1` are contained in the conic hull of the `2n`
    generators just described. The half space resulting from `p = n`
    is also covered by this set of generators, so for all valid `p` we
    simply take the conic hull of those `2n` vectors.

    REFERENCES:

    - [GJ2016]_, Section 4

    - [HS2010]_, Example 2.21

    - [Jeong2017]_, Section 5.2

    EXAMPLES:

    The rearrangement cones of order one are nonnegative orthants::

        sage: orthant = cones.nonnegative_orthant(6)
        sage: cones.rearrangement(1,6).is_equivalent(orthant)
        True

    When ``p`` and ``ambient_dim`` are equal, the rearrangement cone
    is a half-space, so we expect its lineality to be one less than
    ``ambient_dim`` because it will contain a hyperplane but is not
    the entire space::

        sage: cones.rearrangement(5,5).lineality()
        4

    Jeong's Proposition 5.2.1 [Jeong2017]_ states that all rearrangement
    cones are proper when ``p`` is less than ``ambient_dim``::

        sage: all( cones.rearrangement(p, ambient_dim).is_proper()
        ....:              for ambient_dim in range(10)
        ....:              for p in range(1, ambient_dim) )
        True

    Jeong's Corollary 5.2.4 [Jeong2017]_ states that if `p = n-1` in
    an `n`-dimensional ambient space, then the Lyapunov rank of the
    rearrangement cone is `n`, and that for all other `p > 1` its
    Lyapunov rank is one::

        sage: all( cones.rearrangement(p, ambient_dim).lyapunov_rank()
        ....:      ==
        ....:      ambient_dim
        ....:              for ambient_dim in range(2, 10)
        ....:              for p in [ ambient_dim-1 ] )
        True
        sage: all( cones.rearrangement(p, ambient_dim).lyapunov_rank() == 1
        ....:              for ambient_dim in range(3, 10)
        ....:              for p in range(2, ambient_dim-1) )
        True

    TESTS:

    Jeong's Proposition 5.2.1 [Jeong2017]_ states that rearrangement
    cones are permutation-invariant::

        sage: ambient_dim = ZZ.random_element(2,10).abs()
        sage: p = ZZ.random_element(1, ambient_dim)
        sage: K = cones.rearrangement(p, ambient_dim)
        sage: P = SymmetricGroup(ambient_dim).random_element().matrix()
        sage: all( K.contains(P*r) for r in K )
        True

    The smallest ``p`` components of every element of the rearrangement
    cone should sum to a nonnegative number. In other words, the
    generators really are what we think they are::

        sage: set_random_seed()
        sage: def _has_rearrangement_property(v,p):
        ....:     return sum( sorted(v)[0:p] ) >= 0
        sage: all(
        ....:   _has_rearrangement_property(
        ....:     cones.rearrangement(p, ambient_dim).random_element(),
        ....:     p
        ....:   )
        ....:   for ambient_dim in range(2, 10)
        ....:   for p in range(1, ambient_dim+1)
        ....: )
        True

    The rearrangement cone of order ``p`` is, almost by definition,
    contained in the rearrangement cone of order ``p + 1``::

        sage: set_random_seed()
        sage: ambient_dim = ZZ.random_element(2,10)
        sage: p = ZZ.random_element(1, ambient_dim)
        sage: K1 = cones.rearrangement(p, ambient_dim)
        sage: K2 = cones.rearrangement(p+1, ambient_dim)
        sage: all( x in K2 for x in K1 )
        True

    Jeong's Proposition 5.2.1 [Jeong2017]_ states that the rearrangement
    cone of order ``p`` is linearly isomorphic to the rearrangement
    cone of order ``ambient_dim - p`` when ``p`` is less than
    ``ambient_dim``::

        sage: set_random_seed()
        sage: ambient_dim = ZZ.random_element(2,10)
        sage: p = ZZ.random_element(1, ambient_dim)
        sage: K1 = cones.rearrangement(p, ambient_dim)
        sage: K2 = cones.rearrangement(ambient_dim-p, ambient_dim)
        sage: Mp = ((1/p)*matrix.ones(QQ, ambient_dim)
        ....:    - matrix.identity(QQ, ambient_dim))
        sage: Cone( (Mp*K2.rays()).columns() ).is_equivalent(K1)
        True

    The order ``p`` should be an integer between ``1`` and
    ``ambient_dim``, inclusive::

        sage: cones.rearrangement(0,3)
        Traceback (most recent call last):
        ...
        ValueError: order p=0 should be an integer between 1 and
        ambient_dim=3, inclusive
        sage: cones.rearrangement(5,3)
        Traceback (most recent call last):
        ...
        ValueError: order p=5 should be an integer between 1 and
        ambient_dim=3, inclusive
        sage: cones.rearrangement(3/2, 3)
        Traceback (most recent call last):
        ...
        ValueError: order p=3/2 should be an integer between 1 and
        ambient_dim=3, inclusive

    If a ``lattice`` was given, it is actually used::

        sage: L = ToricLattice(3, 'M')
        sage: cones.rearrangement(2, 3, lattice=L)
        3-d cone in 3-d lattice M

    Unless the rank of the lattice disagrees with ``ambient_dim``::

        sage: L = ToricLattice(1, 'M')
        sage: cones.rearrangement(2, 3, lattice=L)
        Traceback (most recent call last):
        ...
        ValueError: lattice rank=1 and ambient_dim=3 are incompatible

    We also get an error if neither the ambient dimension nor lattice
    are specified::

        sage: cones.rearrangement(3)
        Traceback (most recent call last):
        ...
        ValueError: either the ambient dimension or the lattice must
        be specified
    """
    from sage.geometry.cone import Cone
    from sage.matrix.constructor import matrix
    from sage.rings.integer_ring import ZZ

    (ambient_dim, lattice) = _preprocess_args(ambient_dim, lattice)

    if p < 1 or p > ambient_dim or p not in ZZ:
        raise ValueError("order p=%s should be an integer between 1 "
                         "and ambient_dim=%d, inclusive" % (p, ambient_dim))

    I = matrix.identity(ZZ, ambient_dim)
    M = matrix.ones(ZZ, ambient_dim) - p * I
    G = matrix.identity(ZZ, ambient_dim).rows() + M.rows()
    return Cone(G, lattice=lattice)
Exemple #9
0
def nonnegative_orthant(ambient_dim=None, lattice=None):
    r"""
    The nonnegative orthant in ``ambient_dim`` dimensions, or living
    in ``lattice``.

    The nonnegative orthant consists of all componentwise-nonnegative
    vectors. It is the convex-conic hull of the standard basis.

    INPUT:

    - ``ambient_dim`` -- a nonnegative integer (default: ``None``); the
      dimension of the ambient space

    - ``lattice`` -- a toric lattice (default: ``None``); the lattice in
      which the cone will live

    If ``ambient_dim`` is omitted, then it will be inferred from the
    rank of ``lattice``. If the ``lattice`` is omitted, then the
    default lattice of rank ``ambient_dim`` will be used.

    A ``ValueError`` is raised if neither ``ambient_dim`` nor
    ``lattice`` are specified. It is also a ``ValueError`` to specify
    both ``ambient_dim`` and ``lattice`` unless the rank of
    ``lattice`` is equal to ``ambient_dim``.

    OUTPUT:

    A :class:`.ConvexRationalPolyhedralCone` living in ``lattice``
    and having ``ambient_dim`` standard basis vectors as its
    generators. Each generating ray has the integer ring as its
    base ring.

    A ``ValueError`` can be raised if the inputs are incompatible or
    insufficient. See the INPUT documentation for details.

    REFERENCES:

    - Chapter 2 in [BV2009]_ (Examples 2.4, 2.14, and 2.23 in particular)

    EXAMPLES::

        sage: cones.nonnegative_orthant(3).rays()
        N(1, 0, 0),
        N(0, 1, 0),
        N(0, 0, 1)
        in 3-d lattice N

    TESTS:

    We can construct the trivial cone as the nonnegative orthant in a
    trivial vector space::

        sage: cones.nonnegative_orthant(0)
        0-d cone in 0-d lattice N

    The nonnegative orthant is a proper cone::

        sage: set_random_seed()
        sage: ambient_dim = ZZ.random_element(10)
        sage: K = cones.nonnegative_orthant(ambient_dim)
        sage: K.is_proper()
        True

    If a ``lattice`` was given, it is actually used::

        sage: L = ToricLattice(3, 'M')
        sage: cones.nonnegative_orthant(lattice=L)
        3-d cone in 3-d lattice M

    Unless the rank of the lattice disagrees with ``ambient_dim``::

        sage: L = ToricLattice(1, 'M')
        sage: cones.nonnegative_orthant(3, lattice=L)
        Traceback (most recent call last):
        ...
        ValueError: lattice rank=1 and ambient_dim=3 are incompatible

    We also get an error if no arguments are given::

        sage: cones.nonnegative_orthant()
        Traceback (most recent call last):
        ...
        ValueError: either the ambient dimension or the lattice must
        be specified
    """
    from sage.geometry.cone import Cone
    from sage.matrix.constructor import matrix
    from sage.rings.integer_ring import ZZ

    (ambient_dim, lattice) = _preprocess_args(ambient_dim, lattice)

    I = matrix.identity(ZZ, ambient_dim)
    return Cone(I.rows(), lattice)
Exemple #10
0
    def borcherds_input_Qbasis(self, pole_order, prec, verbose=False):
        r"""
        Compute a Q-basis of input functions into the Borcherds lift with pole order in infinity up to pole_order.

        This method computes a list of Borcherds lift inputs F_0, ..., F_d which is a Q-basis in the following sense: it is minimal with the property that every modular form with pole order at most pole_order whose Borcherds lift is holomorphic can be expressed in the form (k_0 F_0 + ... + k_d F_d) where k_i are nonnegative rational numbers.

        INPUT:
        - ``pole_order`` -- positive number (does not need to be an integer)
        - ``prec`` -- precision of the output

        OUTPUT: WeilRepModularFormsBasis

        EXAMPLES::

            sage: from weilrep import *
            sage: m = ParamodularForms(5)
            sage: m.borcherds_input_Qbasis(1/4, 5)
            [(0), 10 + 50*q + 260*q^2 + 1030*q^3 + 3500*q^4 + O(q^5)]
            [(1/10), 6*q^(-1/20) + 16*q^(19/20) + 82*q^(39/20) + 304*q^(59/20) + 1046*q^(79/20) + 3120*q^(99/20) + O(q^(119/20))]
            [(1/5), q^(-1/5) - 24*q^(4/5) - 143*q^(9/5) - 622*q^(14/5) - 2204*q^(19/5) - 6876*q^(24/5) + O(q^(29/5))]
            [(3/10), -16*q^(11/20) - 102*q^(31/20) - 448*q^(51/20) - 1650*q^(71/20) - 5248*q^(91/20) + O(q^(111/20))]
            [(2/5), -q^(1/5) + 14*q^(6/5) + 92*q^(11/5) + 386*q^(16/5) + 1318*q^(21/5) + O(q^(26/5))]
            [(1/2), 20*q^(3/4) + 160*q^(7/4) + 700*q^(11/4) + 2560*q^(15/4) + 8000*q^(19/4) + O(q^(23/4))]
            [(3/5), -q^(1/5) + 14*q^(6/5) + 92*q^(11/5) + 386*q^(16/5) + 1318*q^(21/5) + O(q^(26/5))]
            [(7/10), -16*q^(11/20) - 102*q^(31/20) - 448*q^(51/20) - 1650*q^(71/20) - 5248*q^(91/20) + O(q^(111/20))]
            [(4/5), q^(-1/5) - 24*q^(4/5) - 143*q^(9/5) - 622*q^(14/5) - 2204*q^(19/5) - 6876*q^(24/5) + O(q^(29/5))]
            [(9/10), 6*q^(-1/20) + 16*q^(19/20) + 82*q^(39/20) + 304*q^(59/20) + 1046*q^(79/20) + 3120*q^(99/20) + O(q^(119/20))]
            ------------------------------------------------------------
            [(0), 36 + 586*q + 3708*q^2 + 17694*q^3 + 68852*q^4 + O(q^5)]
            [(1/10), -5*q^(-1/20) - 270*q^(19/20) - 1935*q^(39/20) - 10275*q^(59/20) - 43245*q^(79/20) - 157545*q^(99/20) + O(q^(119/20))]
            [(1/5), 5*q^(-1/5) + 90*q^(4/5) + 1035*q^(9/5) + 6130*q^(14/5) + 28460*q^(19/5) + 109260*q^(24/5) + O(q^(29/5))]
            [(3/10), -185*q^(11/20) - 1595*q^(31/20) - 8505*q^(51/20) - 36145*q^(71/20) - 131485*q^(91/20) + O(q^(111/20))]
            [(2/5), 65*q^(1/5) + 630*q^(6/5) + 4100*q^(11/5) + 18940*q^(16/5) + 74070*q^(21/5) + O(q^(26/5))]
            [(1/2), 7*q^(-1/4) - 54*q^(3/4) - 747*q^(7/4) - 5026*q^(11/4) - 23859*q^(15/4) - 94960*q^(19/4) + O(q^(23/4))]
            [(3/5), 65*q^(1/5) + 630*q^(6/5) + 4100*q^(11/5) + 18940*q^(16/5) + 74070*q^(21/5) + O(q^(26/5))]
            [(7/10), -185*q^(11/20) - 1595*q^(31/20) - 8505*q^(51/20) - 36145*q^(71/20) - 131485*q^(91/20) + O(q^(111/20))]
            [(4/5), 5*q^(-1/5) + 90*q^(4/5) + 1035*q^(9/5) + 6130*q^(14/5) + 28460*q^(19/5) + 109260*q^(24/5) + O(q^(29/5))]
            [(9/10), -5*q^(-1/20) - 270*q^(19/20) - 1935*q^(39/20) - 10275*q^(59/20) - 43245*q^(79/20) - 157545*q^(99/20) + O(q^(119/20))]
        """
        S = self.gram_matrix()
        w = self.weilrep()
        wt = self.input_wt()
        M, p, X = self._borcherds_product_polyhedron(pole_order,
                                                     prec,
                                                     verbose=verbose)
        try:
            b = matrix(Cone(p).rays())
            if verbose:
                print('I will now try to find Borcherds product inputs.')
            try:
                u = M.solve_left(b)
                Y = [v * X for v in u.rows()]
                Y.sort(key=lambda x: x.fourier_expansion()[0][2][0])
                Y = WeilRepModularFormsBasis(wt, Y, w)
            except ValueError:
                Y = WeilRepModularFormsBasis(wt, [], w)
        except IndexError:
            Y = WeilRepModularFormsBasis(wt, [], w)
        if wt >= 0:
            X = X = deepcopy(
                w.basis_vanishing_to_order(wt, max(0, -pole_order), prec))
            if X:
                X.extend(Y)
                return X
        return Y
Exemple #11
0
    def borcherds_input_basis(self, pole_order, prec, verbose=False):
        r"""
        Compute a basis of input functions into the Borcherds lift with pole up to pole_order.

        This method computes a list of Borcherds lift inputs F_0, ..., F_d which is a basis in the following sense: it is minimal with the property that every modular form with pole order at most pole_order whose Borcherds lift is holomorphic can be expressed in the form (k_0 F_0 + ... + k_d F_d) where k_i are nonnegative integers.

        WARNING: this can take a long time, and the output list might be longer than you expect!!

        INPUT:
        - ``pole_order`` -- positive number (does not need to be an integer)
        - ``prec`` -- precision of the output

        OUTPUT: WeilRepModularFormsBasis

        EXAMPLES::

            sage: from weilrep import *
            sage: m = ParamodularForms(5)
            sage: m.borcherds_input_basis(1/4, 5)
            [(0), 8 + 98*q + 604*q^2 + 2822*q^3 + 10836*q^4 + O(q^5)]
            [(1/10), q^(-1/20) - 34*q^(19/20) - 253*q^(39/20) - 1381*q^(59/20) - 5879*q^(79/20) - 21615*q^(99/20) + O(q^(119/20))]
            [(1/5), q^(-1/5) + 6*q^(4/5) + 107*q^(9/5) + 698*q^(14/5) + 3436*q^(19/5) + 13644*q^(24/5) + O(q^(29/5))]
            [(3/10), -31*q^(11/20) - 257*q^(31/20) - 1343*q^(51/20) - 5635*q^(71/20) - 20283*q^(91/20) + O(q^(111/20))]
            [(2/5), 9*q^(1/5) + 94*q^(6/5) + 612*q^(11/5) + 2816*q^(16/5) + 10958*q^(21/5) + O(q^(26/5))]
            [(1/2), q^(-1/4) - 2*q^(3/4) - 61*q^(7/4) - 518*q^(11/4) - 2677*q^(15/4) - 11280*q^(19/4) + O(q^(23/4))]
            [(3/5), 9*q^(1/5) + 94*q^(6/5) + 612*q^(11/5) + 2816*q^(16/5) + 10958*q^(21/5) + O(q^(26/5))]
            [(7/10), -31*q^(11/20) - 257*q^(31/20) - 1343*q^(51/20) - 5635*q^(71/20) - 20283*q^(91/20) + O(q^(111/20))]
            [(4/5), q^(-1/5) + 6*q^(4/5) + 107*q^(9/5) + 698*q^(14/5) + 3436*q^(19/5) + 13644*q^(24/5) + O(q^(29/5))]
            [(9/10), q^(-1/20) - 34*q^(19/20) - 253*q^(39/20) - 1381*q^(59/20) - 5879*q^(79/20) - 21615*q^(99/20) + O(q^(119/20))]
            ------------------------------------------------------------
            [(0), 10 + 50*q + 260*q^2 + 1030*q^3 + 3500*q^4 + O(q^5)]
            [(1/10), 6*q^(-1/20) + 16*q^(19/20) + 82*q^(39/20) + 304*q^(59/20) + 1046*q^(79/20) + 3120*q^(99/20) + O(q^(119/20))]
            [(1/5), q^(-1/5) - 24*q^(4/5) - 143*q^(9/5) - 622*q^(14/5) - 2204*q^(19/5) - 6876*q^(24/5) + O(q^(29/5))]
            [(3/10), -16*q^(11/20) - 102*q^(31/20) - 448*q^(51/20) - 1650*q^(71/20) - 5248*q^(91/20) + O(q^(111/20))]
            [(2/5), -q^(1/5) + 14*q^(6/5) + 92*q^(11/5) + 386*q^(16/5) + 1318*q^(21/5) + O(q^(26/5))]
            [(1/2), 20*q^(3/4) + 160*q^(7/4) + 700*q^(11/4) + 2560*q^(15/4) + 8000*q^(19/4) + O(q^(23/4))]
            [(3/5), -q^(1/5) + 14*q^(6/5) + 92*q^(11/5) + 386*q^(16/5) + 1318*q^(21/5) + O(q^(26/5))]
            [(7/10), -16*q^(11/20) - 102*q^(31/20) - 448*q^(51/20) - 1650*q^(71/20) - 5248*q^(91/20) + O(q^(111/20))]
            [(4/5), q^(-1/5) - 24*q^(4/5) - 143*q^(9/5) - 622*q^(14/5) - 2204*q^(19/5) - 6876*q^(24/5) + O(q^(29/5))]
            [(9/10), 6*q^(-1/20) + 16*q^(19/20) + 82*q^(39/20) + 304*q^(59/20) + 1046*q^(79/20) + 3120*q^(99/20) + O(q^(119/20))]
            ------------------------------------------------------------
            [(0), 22 + 342*q + 2156*q^2 + 10258*q^3 + 39844*q^4 + O(q^5)]
            [(1/10), -2*q^(-1/20) - 152*q^(19/20) - 1094*q^(39/20) - 5828*q^(59/20) - 24562*q^(79/20) - 89580*q^(99/20) + O(q^(119/20))]
            [(1/5), 3*q^(-1/5) + 48*q^(4/5) + 571*q^(9/5) + 3414*q^(14/5) + 15948*q^(19/5) + 61452*q^(24/5) + O(q^(29/5))]
            [(3/10), -108*q^(11/20) - 926*q^(31/20) - 4924*q^(51/20) - 20890*q^(71/20) - 75884*q^(91/20) + O(q^(111/20))]
            [(2/5), 37*q^(1/5) + 362*q^(6/5) + 2356*q^(11/5) + 10878*q^(16/5) + 42514*q^(21/5) + O(q^(26/5))]
            [(1/2), 4*q^(-1/4) - 28*q^(3/4) - 404*q^(7/4) - 2772*q^(11/4) - 13268*q^(15/4) - 53120*q^(19/4) + O(q^(23/4))]
            [(3/5), 37*q^(1/5) + 362*q^(6/5) + 2356*q^(11/5) + 10878*q^(16/5) + 42514*q^(21/5) + O(q^(26/5))]
            [(7/10), -108*q^(11/20) - 926*q^(31/20) - 4924*q^(51/20) - 20890*q^(71/20) - 75884*q^(91/20) + O(q^(111/20))]
            [(4/5), 3*q^(-1/5) + 48*q^(4/5) + 571*q^(9/5) + 3414*q^(14/5) + 15948*q^(19/5) + 61452*q^(24/5) + O(q^(29/5))]
            [(9/10), -2*q^(-1/20) - 152*q^(19/20) - 1094*q^(39/20) - 5828*q^(59/20) - 24562*q^(79/20) - 89580*q^(99/20) + O(q^(119/20))]
            ------------------------------------------------------------
            [(0), 36 + 586*q + 3708*q^2 + 17694*q^3 + 68852*q^4 + O(q^5)]
            [(1/10), -5*q^(-1/20) - 270*q^(19/20) - 1935*q^(39/20) - 10275*q^(59/20) - 43245*q^(79/20) - 157545*q^(99/20) + O(q^(119/20))]
            [(1/5), 5*q^(-1/5) + 90*q^(4/5) + 1035*q^(9/5) + 6130*q^(14/5) + 28460*q^(19/5) + 109260*q^(24/5) + O(q^(29/5))]
            [(3/10), -185*q^(11/20) - 1595*q^(31/20) - 8505*q^(51/20) - 36145*q^(71/20) - 131485*q^(91/20) + O(q^(111/20))]
            [(2/5), 65*q^(1/5) + 630*q^(6/5) + 4100*q^(11/5) + 18940*q^(16/5) + 74070*q^(21/5) + O(q^(26/5))]
            [(1/2), 7*q^(-1/4) - 54*q^(3/4) - 747*q^(7/4) - 5026*q^(11/4) - 23859*q^(15/4) - 94960*q^(19/4) + O(q^(23/4))]
            [(3/5), 65*q^(1/5) + 630*q^(6/5) + 4100*q^(11/5) + 18940*q^(16/5) + 74070*q^(21/5) + O(q^(26/5))]
            [(7/10), -185*q^(11/20) - 1595*q^(31/20) - 8505*q^(51/20) - 36145*q^(71/20) - 131485*q^(91/20) + O(q^(111/20))]
            [(4/5), 5*q^(-1/5) + 90*q^(4/5) + 1035*q^(9/5) + 6130*q^(14/5) + 28460*q^(19/5) + 109260*q^(24/5) + O(q^(29/5))]
            [(9/10), -5*q^(-1/20) - 270*q^(19/20) - 1935*q^(39/20) - 10275*q^(59/20) - 43245*q^(79/20) - 157545*q^(99/20) + O(q^(119/20))]
        """
        S = self.gram_matrix()
        w = self.weilrep()
        wt = self.input_wt()
        M, p, X = self._borcherds_product_polyhedron(pole_order,
                                                     prec,
                                                     verbose=verbose)
        if verbose:
            print('I will now try to find a Hilbert basis.')
        try:
            b = matrix(Cone(p).Hilbert_basis())
            try:
                u = M.solve_left(b)
                Y = [v * X for v in u.rows()]
                Y.sort(key=lambda x: x.fourier_expansion()[0][2][0])
                Y = WeilRepModularFormsBasis(wt, Y, w)
            except ValueError:
                Y = WeilRepModularFormsBasis(wt, [], w)
        except IndexError:
            Y = WeilRepModularFormsBasis(wt, [], w)
        if wt >= 0:
            X = deepcopy(
                w.basis_vanishing_to_order(wt, max(0, -pole_order), prec))
            if X:
                X.extend(Y)
                return X
        return Y
Exemple #12
0
 def cluster_fan(self, depth=infinity):
     from sage.geometry.cone import Cone
     from sage.geometry.fan import Fan
     seeds = self.seeds(depth=depth, mutating_F=False)
     cones = map(lambda s: Cone(s.g_vectors()), seeds)
     return Fan(cones)