Example #1
0
def min_reol_maybe_with3gens(data):
    forms = data.relatively_prime_3forms_maybe()
    d = data.brackets_dict
    if forms is None:
        return None
    F = FreeModule(R, 2)
    f, g, h = forms
    e0, e1 = F.gens()

    a = d[(g, h)]
    b = -d[(f, h)]
    c = d[(f, g)]

    f = e0 * c
    g = e1 * c
    h = -(a * e0 + b * e1)

    if c.degree() > 0:
        n = smodule(f, h)
        idl = sideal(b)
        m = squotient(n, idl)
    else:
        m = smodule(f, g)
    wts = data.weight_of_basis()
    mls = list(takewhile(lambda l: any(x != 0 for x in l), slist(smres(m, 0))))
    mls = [[list(v) for v in list(l)] for l in mls]
    wts_of_mls = []
    wts_of_mls.append([degree_vec(v, wts) for v in mls[0]])
    for i, l in enumerate(mls[1:]):
        wts = wts_of_mls[i]
        wts_of_mls.append([degree_vec(v, wts) for v in l])
    return (mls, wts_of_mls, (forms[0], forms[1], c))
Example #2
0
    def __init__(self, base_ring, coordinate):
        self.coordinate = coordinate

        self.Vector = flatsurf.Vector._unwrapped[self.coordinate]

        self._isomorphic_vector_space = FreeModule(base_ring, 2)
        if isinstance(base_ring, real_embedded_number_field.RealEmbeddedNumberField):
            self._isomorphic_vector_space = FreeModule(base_ring.number_field, 2)

        Parent.__init__(self, base_ring, category=FreeModules(base_ring))

        self.register_coercion(self._isomorphic_vector_space)
        self._isomorphic_vector_space.register_conversion(ConversionVectorSpace(self))
def is_product(n, den_tuple):
    r"""
    INPUT:

    - ``n`` - number of variables

    - ``den_tuple`` - tuple of pairs ``(vector, power)``

    TESTS::

        sage: from surface_dynamics.misc.generalized_multiple_zeta_values import is_product
        sage: is_product(3, [((1,0,0),2), ((0,1,0),5), ((1,1,0),1), ((0,0,1),3)])
        [(2, (((0, 1), 5), ((1, 0), 2), ((1, 1), 1))), (1, (((1), 3),))]
        sage: is_product(3, [((1,0,0),2), ((0,1,0),3), ((1,0,1),1), ((0,0,1),5)])
        [(2, (((0, 1), 5), ((1, 0), 2), ((1, 1), 1))), (1, (((1), 3),))]
        sage: is_product(3, [((1,1,1),3)]) is None
        True
    """
    D = DisjointSet(n)
    assert all(len(v) == n for v, p in den_tuple), (n, den_tuple)

    # 1. product structure
    for v, _ in den_tuple:
        i0 = 0
        while not v[i0]:
            i0 += 1
        i = i0 + 1
        while i < n:
            if v[i]:
                D.union(i0, i)
            i += 1
        if D.number_of_subsets() == 1:
            # no way to split variables
            return

    # split variables
    Rdict = D.root_to_elements_dict()
    keys = sorted(Rdict.keys())
    key_indices = {k: i for i, k in enumerate(keys)}
    values = [Rdict[k] for k in keys]
    values_indices = [{v: i for i, v in enumerate(v)} for v in values]
    n_list = [len(J) for J in values]
    F = [FreeModule(ZZ, nn) for nn in n_list]
    new_terms = [[] for _ in range(len(Rdict))]
    for v, p in den_tuple:
        i0 = 0
        while not v[i0]:
            i0 += 1
        i0 = D.find(i0)
        assert all(D.find(i) == i0 for i in range(n)
                   if v[i]), (i0, [D.find(i) for i in range(n) if v[i]])
        k = key_indices[i0]
        vv = F[k]()
        for i in range(n):
            if v[i]:
                vv[values_indices[k][i]] = v[i]
        vv.set_immutable()
        new_terms[k].append((vv, p))

    return list(zip(n_list, [tuple(sorted(terms)) for terms in new_terms]))
Example #4
0
    def __init__(self, surface):
        if isinstance(surface, TranslationSurface):
            base_ring = surface.base_ring()
            from flatsurf.geometry.pyflatsurf_conversion import to_pyflatsurf
            self._surface = to_pyflatsurf(surface)
        else:
            from flatsurf.geometry.pyflatsurf_conversion import sage_base_ring
            base_ring, _ = sage_base_ring(surface)
            self._surface = surface

        # A model of the vector space R² in libflatsurf, e.g., to represent the
        # vector associated to a saddle connection.
        self.V2 = pyflatsurf.vector.Vectors(base_ring)

        # We construct a spanning set of edges, that is a subset of the
        # edges that form a basis of H_1(S, Sigma; Z)
        # It comes together with a projection matrix
        t, m = self._spanning_tree()
        assert set(t.keys()) == set(f[0] for f in self._faces())
        self.spanning_set = []
        v = set(t.values())
        for e in self._surface.edges():
            if e.positive() not in v and e.negative() not in v:
                self.spanning_set.append(e)
        self.d = len(self.spanning_set)
        assert 3*self.d - 3 == self._surface.size()
        assert m.rank() == self.d
        m = m.transpose()
        # projection matrix from Z^E to H_1(S, Sigma; Z) in the basis
        # of spanning edges
        self.proj = matrix(ZZ, [r for r in m.rows() if not r.is_zero()])

        self.Omega = self._intersection_matrix(t, self.spanning_set)

        self.V = FreeModule(self.V2.base_ring(), self.d)
        self.H = matrix(self.V2.base_ring(), self.d, 2)
        for i in range(self.d):
            s = self._surface.fromHalfEdge(self.spanning_set[i].positive())
            self.H[i] = self.V2._isomorphic_vector_space(self.V2(s))
        self.Hdual = self.Omega * self.H

        # Note that we don't use Sage vector spaces because they are usually
        # way too slow (in particular we avoid calling .echelonize())
        self._U = matrix(self.V2._algebraic_ring(), self.d)
        
        if self._U.base_ring() is not QQ:
            from sage.all import next_prime
            self._good_prime = self._U.base_ring().ideal(next_prime(2**30)).factor()[0][0]
            self._Ubar = matrix(self._good_prime.residue_field(), self.d)

        self._U_rank = 0

        self.update_tangent_space_from_vector(self.H.transpose()[0])
        self.update_tangent_space_from_vector(self.H.transpose()[1])
Example #5
0
def test_skipper_cpa_enc(skipper=Skipper4, kyber=Kyber, t=128, l=None, exhaustive=False):
    if not exhaustive:
        for i in range(t):
            pk, sk = kyber.key_gen(seed=i)
            m0 = random_vector(GF(2), kyber.n)
            c = skipper.enc(kyber, pk, m0, seed=i, l=l)
            m1 = kyber.dec(sk, c)
            assert(m0 == m1)
    else:
        # exhaustive test
        for i in range(16):
            pk, sk = kyber.key_gen(seed=i)
            for m0 in FreeModule(GF(2), kyber.n):
                c = skipper.enc(kyber, pk, m0, seed=i, l=l)
                m1 = kyber.dec(sk, c)
                assert(m0 == m1)
Example #6
0
    def boundaries(self):
        r"""
        Return the list of boundaries (ie sum of edges around a triangular face).

        These are elements of H_1(S, Sigma; Z).

        TESTS::

            sage: from flatsurf import polygons, similarity_surfaces
            sage: from flatsurf import GL2ROrbitClosure  # optional: pyflatsurf

            sage: from itertools import product
            sage: for a in range(1,5):  # optional: pyflatsurf
            ....:     for b in range(a, 5):
            ....:         for c in range(b, 5):
            ....:             if gcd([a, b, c]) != 1 or (a,b,c) == (1,1,2):
            ....:                 continue
            ....:             T = polygons.triangle(a, b, c)
            ....:             S = similarity_surfaces.billiard(T)
            ....:             S = S.minimal_cover(cover_type="translation")
            ....:             O = GL2ROrbitClosure(S)
            ....:             for b in O.boundaries():
            ....:                 assert (O.proj * b).is_zero()
        """
        n = self._surface.size()
        V = FreeModule(ZZ, n)
        B = []
        for (f1,f2,f3) in self._faces():
            i1 = f1.index()
            s1 = -1 if i1%2 else 1
            i2 = f2.index()
            s2 = -1 if i2%2 else 1
            i3 = f3.index()
            s3 = -1 if i3%2 else 1
            i1 = f1.edge().index()
            i2 = f2.edge().index()
            i3 = f3.edge().index()
            v = [0] * n
            v[i1] = 1
            v[i2] = s1 * s2
            v[i3] = s1 * s3
            B.append(V(v))
            B[-1].set_immutable()

        return B
def linear_forms(d):
    r"""
    EXAMPLES::

        sage: from surface_dynamics.misc.generalized_multiple_zeta_values import linear_forms

        sage: list(linear_forms(1))
        [(1)]

        sage: list(linear_forms(2))
         [(1, 0), (0, 1), (1, 1)]

        sage: L1 = list(linear_forms(3))
        sage: L2 = L1[:]
        sage: L2.sort(key = lambda x: x[::-1])
        sage: assert L1 == L2
    """
    F = FreeModule(ZZ, d)
    for n in range(1, 2**d):
        v = F(ZZ(n).digits(2, padto=d))
        v.set_immutable()
        yield v
Example #8
0
class Vectors(UniqueRepresentation, Parent):
    r"""
    The subspace of the vector space `\mathbb{R}^2` modeled by vectors with
    entries in ``base_ring``. Unlike normal SageMath vector spaces, this space
    is backed by flatsur's ``Vector`` class with entries in ``coordinate``.

    EXAMPLES::

        sage: from pyflatsurf.vector import Vectors
        sage: K = NumberField(x**2 - 2, 'a', embedding=sqrt(AA(2)))
        sage: V = Vectors(K)
        sage: v = V((1,K.gen() - 3/2))
        sage: v
        (1, (a-3/2 ~ -0.085786438))
        sage: VectorSpace(K, 2)(v)
        (1, a - 3/2)

        sage: from pyeantic import RealEmbeddedNumberField
        sage: R = RealEmbeddedNumberField(K)
        sage: Vectors(R) is V
        True
        sage: Vectors(R.renf) is V
        True

        sage: from gmpxxyy import mpz, mpq
        sage: Vectors(QQ) is Vectors(mpq)
        True
        sage: Vectors(ZZ) is Vectors(mpz)
        True
    """
    Element = Vector

    @staticmethod
    def __classcall__(cls, base_ring):
        if base_ring in [ZZ, mpz]:
            base_ring = ZZ
            coordinate = mpz
        elif base_ring in [QQ, mpq]:
            base_ring = QQ
            coordinate = mpq
        elif isinstance(base_ring, real_embedded_number_field.RealEmbeddedNumberField):
            coordinate = cppyy.gbl.eantic.renf_elem_class
        elif isinstance(base_ring, eantic.renf_class):
            base_ring = real_embedded_number_field.RealEmbeddedNumberField(base_ring)
            coordinate = cppyy.gbl.eantic.renf_elem_class
        elif isinstance(base_ring, SageNumberField):
            base_ring = real_embedded_number_field.RealEmbeddedNumberField(base_ring)
            coordinate = cppyy.gbl.eantic.renf_elem_class
        elif isinstance(base_ring, ExactReals):
            coordinate = base_ring._element_factory
        else:
            raise NotImplementedError("unsupported base_ring {!r}".format(base_ring))

        return super(Vectors, cls).__classcall__(cls, base_ring, coordinate)

    def __init__(self, base_ring, coordinate):
        self.coordinate = coordinate

        self.Vector = flatsurf.Vector._unwrapped[self.coordinate]

        self._isomorphic_vector_space = FreeModule(base_ring, 2)
        if isinstance(base_ring, real_embedded_number_field.RealEmbeddedNumberField):
            self._isomorphic_vector_space = FreeModule(base_ring.number_field, 2)

        Parent.__init__(self, base_ring, category=FreeModules(base_ring))

        self.register_coercion(self._isomorphic_vector_space)
        self._isomorphic_vector_space.register_conversion(ConversionVectorSpace(self))

    def _algebraic_ring(self):
        r"""
        Return the Sage algebraic ring which underlies our base ring; typically
        this is (an isomorphic ring to) the base ring itself but for
        non-algebraic rings such as ``ExactReals``, this gives the coefficient
        ring.

        EXAMPLES::

            sage: from pyflatsurf.vector import Vectors
            sage: from pyexactreal import ExactReals

            sage: Vectors(QQ)._algebraic_ring()
            Rational Field
            sage: R = ExactReals()
            sage: Vectors(R)._algebraic_ring()
            Rational Field

            sage: K = NumberField(x^3 - 2, 'a', embedding=AA(2)**(1/3))
            sage: Vectors(K)._algebraic_ring()
            Number Field in a with defining polynomial x^3 - 2 with a = 1.259921049894873?
            sage: R = ExactReals(K)
            sage: Vectors(R)._algebraic_ring()
            Number Field in a with defining polynomial x^3 - 2 with a = 1.259921049894873?
        """
        algebraic_ring = self.base_ring()

        if isinstance(algebraic_ring, ExactReals):
            algebraic_ring = algebraic_ring.base_ring()
        if algebraic_ring not in [ZZ, QQ]:
            algebraic_ring = algebraic_ring.number_field

        return algebraic_ring

    def decomposition(self, vector, base=None):
        r"""
        Write ``vector`` as a shortest sum `v = \sum a_i v_i` where the
        `a_i` are coefficients from our ``base_ring()`` and the `v_i` are
        vectors with entries in ``base``.

        EXAMPLES::

            sage: from pyflatsurf.vector import Vectors
            sage: V = Vectors(ZZ)
            sage: V.decomposition([13, 37])
            [(1, (13, 37))]
            sage: V.decomposition([0, 0])
            []

        ::

            sage: from pyexactreal import ExactReals
            sage: R = ExactReals()
            sage: V = Vectors(R)
            sage: V.decomposition([R.random_element(), R.random_element()])
            [(ℝ(0.178808…), (1, 0)), (ℝ(0.478968…), (0, 1))]

        ::

            sage: from pyeantic import RealEmbeddedNumberField
            sage: K = NumberField(x^3 - 2, 'a', embedding=AA(2)**(1/3))
            sage: V = Vectors(K)
            sage: V.decomposition([0, 1])
            [(1, (0, 1))]

        ::

            sage: R = ExactReals(K)
            sage: V = Vectors(R)
            sage: V.decomposition([K.random_element() * R.random_element(), R.random_element(), R.random_element()])
            [(ℝ(0.621222…), (0, 1, 0)),
             (ℝ(0.673083…), (0, 0, 1)),
             (ℝ(0.782515…), (-1/2*a^2 - 4, 0, 0))]

        """
        vector = tuple(self._to_coordinate(x) for x in vector)

        if not any(vector): return []

        if base is None:
            base = self._algebraic_ring()

        if base is self.base_ring():
            return [(self.base_ring().one(), tuple(map(base, vector)))]

        if hasattr(self.base_ring(), "number_field") and self.base_ring().number_field is base:
            return [(self.base_ring().one(), tuple(base(self.base_ring()(x)) for x in vector))]

        if isinstance(self.base_ring(), ExactReals):
           from functools import reduce
           span = type(vector[0].module()).span
           module = reduce(lambda x,y: span(x, y.module()), vector, vector[0].module())

           vector = [entry.promote(module).coefficients() for entry in vector]
           vector = [[base(Vectors(base).base_ring()(c)) for c in coefficients] for coefficients in vector]

           V = base**len(vector)
           return [(self.base_ring()(module.gen(i)), tuple(V(coefficients))) for (i, coefficients) in enumerate(zip(*vector)) if any(coefficients)]

        raise NotImplementedError("cannot decompose vector in %s over %s"%(self, base))

    def _to_coordinate(self, x):
        r"""
        Convert ``x`` to something that the flatsurf backend for this vector type understands.

        EXAMPLES::

            sage: from pyflatsurf.vector import Vectors
            sage: V = Vectors(QQ)
            sage: type(V._to_coordinate(1))
            <class cppyy.gbl.__gmp_expr<__mpz_struct[1],__mpz_struct[1]> at ...>
            sage: type(V._to_coordinate(1/2))
            <class cppyy.gbl.__gmp_expr<__mpq_struct[1],__mpq_struct[1]> at ...>

        """
        if isinstance(x, self.coordinate):
            return x
        if isinstance(x, cppyy.gbl.mpz_class):
            return x
        if isinstance(x, cppyy.gbl.mpq_class):
            return x
        if isinstance(self.base_ring(), real_embedded_number_field.RealEmbeddedNumberField):
            # We create a copy of the coordinate. Otherwise, cppyy (as of
            # 1.9.5) treats this as an r-value and moves x out even if it is
            # referenced elsewhere.
            value = self.base_ring()(x).renf_elem
            return type(value)(value)
        if isinstance(self.base_ring(), ExactReals):
            return self.base_ring()(x)._backend
        if x in ZZ:
            return cppyy.gbl.mpz_class(str(x))
        if x in QQ:
            return cppyy.gbl.mpq_class(str(x))

        raise NotImplementedError("Cannot convert %s to something the flatsurf backend understands yet, i.e., cannot convert a %s into a %s"%(x, type(x), type(self.coordinate)))

    def _repr_(self):
        r"""
        Return a printable representation of this vector space.

        EXAMPLES::

            sage: from pyflatsurf.vector import Vectors
            sage: V = Vectors(QQ)
            sage: V
            Flatsurf Vectors over Rational Field

        """
        return "Flatsurf Vectors over %r"%(self.base_ring(),)

    def an_element(self):
        return self((1,0))

    def zero(self):
        r"""
        Return the zero vector.

        EXAMPLES::

            sage: from pyflatsurf.vector import Vectors
            sage: V = Vectors(QQ)
            sage: V.zero()
            (0, 0)
        """
        return self((0,0))
def is_reducible(n, den_tuple):
    r"""
    If (x1+x2+...+xd) is not present, use a linear relation to create it. Then
    try to kill using other forms. Then try to write as P(x1,x2,...,x_{d-1}) (x1+x2+...+xd) and recurse.

    Should solve all Tonrheim

    EXAMPLES::

        sage: from surface_dynamics.misc.generalized_multiple_zeta_values import linear_forms, is_reducible
        sage: va, vb, vd, vc, ve, vf, vg = linear_forms(3)
        sage: is_reducible(3, ((va,3),(vb,3),(vc,3)))
        [(1, (((0, 0, 1), 3), ((0, 1, 1), 3), ((1, 1, 1), 3))),
         (1, (((0, 1, 0), 3), ((0, 1, 1), 3), ((1, 1, 1), 3))),
         (3, (((0, 0, 1), 2), ((0, 1, 1), 4), ((1, 1, 1), 3))),
         (3, (((0, 1, 0), 2), ((0, 1, 1), 4), ((1, 1, 1), 3))),
        ...
         (90, (((1, 0, 0), 1), ((1, 0, 1), 1), ((1, 1, 1), 7))),
         (90, (((0, 1, 0), 1), ((1, 1, 0), 1), ((1, 1, 1), 7))),
         (90, (((1, 0, 0), 1), ((1, 1, 0), 1), ((1, 1, 1), 7)))]
    """
    F = FreeModule(ZZ, n)
    vmax = F([1] * n)
    vmax.set_immutable()

    if len(den_tuple) == 1:
        return

    # force the max vector (1,1,...,1) to appear
    imax = None
    for i, (v, p) in enumerate(den_tuple):
        if v == vmax:
            imax = i
            break
    if imax is None:
        imax = len(den_tuple)
        den_tuple = den_tuple + ((vmax, 0), )
    if imax != len(den_tuple) - 1:
        den_tuple = list(den_tuple)
        den_tuple.append(den_tuple.pop(imax))
        den_tuple = tuple(den_tuple)
        imax = len(den_tuple) - 1

    assert den_tuple[imax][0] == vmax

    M = matrix(QQ, [v for v, p in den_tuple if v != vmax])
    try:
        relation = M.solve_left(vmax)
    except ValueError:
        if den_tuple[-1][1] == 0:
            return
        den_tuple2 = den_tuple[:-1]
        variables = set().union(*[[i for i in range(n) if v[i]]
                                  for v, p in den_tuple2])
        if len(variables) == n:
            return
        killed = [(1, den_tuple)]
    else:
        killed = kill_relation(n, den_tuple, imax, list(relation) + [0])

    ans = defaultdict(QQ)
    for coeff, den_tuple2 in killed:
        assert den_tuple2[-1][0] == vmax
        pmax = den_tuple2[-1][1]
        assert pmax
        den_tuple2 = den_tuple2[:-1]

        variables = set().union(*[[i for i in range(n) if v[i]]
                                  for v, p in den_tuple2])
        if len(variables) == n:
            # removing the maximal vector (1,1,...,1) is not enough to make a variable disappear
            data = is_reducible(n, den_tuple2)
            if data is None:
                data = [(1, den_tuple2)]
        else:
            # less variables!
            nn = len(variables)
            variables = sorted(variables)
            new_indices = {j: i for i, j in enumerate(variables)}
            G = FreeModule(ZZ, nn)
            new_den_tuple2 = []
            for v, p in den_tuple2:
                vv = G([v[i] for i in variables])
                vv.set_immutable()
                new_den_tuple2.append((vv, p))
            new_den_tuple2 = tuple(new_den_tuple2)
            data = is_reducible(nn, new_den_tuple2)
            if data is None:
                data = [(1, new_den_tuple2)]

            # lift to the n variables version
            new_data = []
            for coeff3, den_tuple3 in data:
                den_tuple3 = [(F([
                    v[new_indices[j]] if j in new_indices else 0
                    for j in range(n)
                ]), p) for v, p in den_tuple3]
                for v, p in den_tuple3:
                    v.set_immutable()
                new_data.append((coeff3, tuple(sorted(den_tuple3))))
            data = new_data

        # update the answer
        for coeff3, den_tuple3 in data:
            imax = None
            for i, (v, p) in enumerate(den_tuple3):
                if v == vmax:
                    imax = i
                    break
            if imax is None:
                den_tuple3 = den_tuple3 + ((vmax, pmax), )
            else:
                den_tuple3 = den_tuple3[:imax] + (
                    (vmax,
                     den_tuple3[imax][1] + pmax), ) + den_tuple3[imax + 1:]
            ans[den_tuple3] += coeff * coeff3

    if len(ans) > 1:
        return [(coeff, den_tuple) for den_tuple, coeff in ans.items()]