示例#1
0
文件: ask.py 项目: fchapoton/Zeta
    def root(self):
        if self.mode == 'K':
            ell = self.ell
            self.RS = RationalSet([PositiveOrthant(ell)], ambient_dim=ell)

            actual_ring = self.ring
            F = FractionField(actual_ring)
            r = matrix(F, self.R).rank()
            self.r = r
            if not self.d:
                return

            F = [
                LaurentIdeal(
                    gens=[LaurentPolynomial(f) for f in self.R.minors(j)],
                    RS=self.RS,
                    normalise=True) for j in range(r + 1)
            ]
        elif self.mode == 'O':
            self.RS = RationalSet([PositiveOrthant(self.d)],
                                  ambient_dim=self.d)
            actual_ring = PolynomialRing(QQ, 'x', self.d)
            xx = vector(actual_ring, actual_ring.gens())
            self.C = matrix(actual_ring,
                            [xx * matrix(actual_ring, A) for A in self.basis])
            r = matrix(FractionField(actual_ring), self.C).rank()
            self.r = r
            if not self.d:
                return
            F = [
                LaurentIdeal(
                    gens=[LaurentPolynomial(f) for f in self.C.minors(j)],
                    RS=self.RS,
                    normalise=True) for j in range(r + 1)
            ]
        else:
            raise ValueError('invalid mode')

        oo = r + 1

        # On pairs:
        # The first component is used as is, the second is multiplied by the extra
        # variable. Note that index 0 corresponds to {1} and index oo to {0}.
        self.pairs = ([(oo, 0)] + [(i, oo) for i in range(1, r)] +
                      [(i, i - 1) for i in range(1, r + 1)])
        # Total number of pairs: 2 * r
        self.integrand = ((1, ) + (2 * r - 1) * (0, ),
                          (self.d - r + 1, ) + (r - 1) * (-1, ) + r * (+1, ))
        self.datum = IgusaDatum(F + [
            LaurentIdeal(gens=[], RS=self.RS, ring=FractionField(actual_ring))
        ]).simplify()
        return self.datum
示例#2
0
    def __init__(self, *polynomials):
        if not polynomials:
            raise ValueError('need at least one polynomial')

        polynomials = [f if isinstance(f, LaurentPolynomial) else LaurentPolynomial(FractionField(f.parent())(f)) for f in polynomials]
        self.nvars = polynomials[0].nvars
        self.ideal = LaurentIdeal(gens=polynomials, RS=RationalSet(PositiveOrthant(self.nvars)), normalise=True)
示例#3
0
def split_off_torus(F):
    # Given a list F of polynomials, return G,d,T where len(F) == len(G)
    # and G consists of polynomials in d variables; T = change of basis.
    # There exists A in GL(n,ZZ) s.t. F[i]^A == G[i] * (Laurent term).
    # In particular, F is non-degenerate relative to {0} iff this the case
    # for G; cf Remark 4.3(ii) and Lemma 6.1(ii) in arXiv:1405.5711.
    #
    # The number of variables in G is the dimension of Newton(prod(F)).
    #

    if not F:
        return [], 0, None

    R = F[0].parent()
    v = {f: vector(ZZ, f.exponents()[0]) for f in F}
    submodule = (ZZ**R.ngens()).submodule(
        chain.from_iterable(
            (vector(ZZ, e) - v[f] for e in f.exponents()) for f in F))
    _, _, T = matrix(ZZ, submodule.basis_matrix()).smith_form()
    d = submodule.rank()
    Rd = PolynomialRing(QQ, d, R.gens()[:d])
    K = FractionField(R)
    return [
        Rd(
            normalise_laurent_polynomial(
                K(f([monomial_exp(K, e) for e in T.rows()])))) for f in F
    ], d, T
示例#4
0
    def _purge_multiples(self):
        if self.is_empty():
            return self

        D = conify_polyhedron(self.polyhedron)
        F = FractionField(self.ring)

        def lte(i, j):
            if i == j:
                return True
            rat = F(self.rhs[j] * self.lhs[i] / self.rhs[i] / self.lhs[j])
            try:
                alpha = monomial_log(rat.numerator()) - monomial_log(
                    rat.denominator())
            except ValueError:
                return False
            return is_contained_in_dual(Cone([alpha]), D)

        mins = minimal_elements(range(len(self.rhs)), lte)
        if len(mins) == len(self.rhs):
            return self
        return ToricDatum(self.ring,
                          self.integrand,
                          [(self.lhs[i], self.rhs[i]) for i in mins],
                          [self.initials[i] for i in mins],
                          self.polyhedron,
                          depth=self._depth)
示例#5
0
def normalise_laurent_polynomial(f):
    """
    Rescale a Laurent polynomial by Laurent monomials. Details TBA.
    """

    # Since Sage's Laurent polynomials are useless, we just use rational
    # functions instead.
    # First make sure, 'f' really is one.

    R = f.parent()
    K = FractionField(R)
    f = K(f)
    if K.ngens() == 0:
        return R(0) if not f else R(1)

    f = f.numerator()
    return R(f / gcd(f.monomials()))
示例#6
0
def common_overring(R, S):
    if R.has_coerce_map_from(S):
        return R
    elif S.has_coerce_map_from(R):
        return S
    else:
        combined_vars = list(
            set(R.base_ring().gens()) | set(S.base_ring().gens()))
        K = FractionField(PolynomialRing(QQ, len(combined_vars),
                                         combined_vars))
        return PolynomialRing(K, R.gens())
示例#7
0
def make_map_latex(map_str):
    # FIXME: Get rid of nu when map is defined over QQ
    if "nu" not in map_str:
        R0 = QQ
    else:
        R0 = PolynomialRing(QQ, 'nu')
    R = PolynomialRing(R0, 2, 'x,y')
    F = FractionField(R)
    phi = F(map_str)
    num = phi.numerator()
    den = phi.denominator()
    c_num = num.denominator()
    c_den = den.denominator()
    lc = c_den / c_num
    # rescale coeffs to make them integral. then try to factor out gcds
    # numerator
    num_new = c_num * num
    num_cs = num_new.coefficients()
    if R0 == QQ:
        num_cs_ZZ = num_cs
    else:
        num_cs_ZZ = []
        for el in num_cs:
            num_cs_ZZ = num_cs_ZZ + el.coefficients()
    num_gcd = gcd(num_cs_ZZ)
    # denominator
    den_new = c_den * den
    den_cs = den_new.coefficients()
    if R0 == QQ:
        den_cs_ZZ = den_cs
    else:
        den_cs_ZZ = []
        for el in den_cs:
            den_cs_ZZ = den_cs_ZZ + el.coefficients()
    den_gcd = gcd(den_cs_ZZ)
    lc = lc * (num_gcd / den_gcd)
    num_new = num_new / num_gcd
    den_new = den_new / den_gcd
    # make strings for lc, num, and den
    num_str = latex(num_new)
    den_str = latex(den_new)
    if lc == 1:
        lc_str = ""
    else:
        lc_str = latex(lc)
    if den_new == 1:
        if lc == 1:
            phi_str = num_str
        else:
            phi_str = lc_str + "(" + num_str + ")"
    else:
        phi_str = lc_str + "\\frac{" + num_str + "}" + "{" + den_str + "}"
    return phi_str
示例#8
0
def make_curve_latex(crv_str):
    # FIXME: Get rid of nu when map is defined over QQ
    if "nu" not in crv_str:
        R0 = QQ
    else:
        R0 = PolynomialRing(QQ, 'nu')
    R = PolynomialRing(R0, 2, 'x,y')
    F = FractionField(R)
    sides = crv_str.split("=")
    lhs = latex(F(sides[0])).replace('(', '\\left(').replace(')', '\\right)')
    rhs = latex(F(sides[1])).replace('(', '\\left(').replace(')', '\\right)')
    eqn_str = lhs + '=' + rhs
    return eqn_str
示例#9
0
def make_curve_latex(crv_str):
    # FIXME: Get rid of nu when map is defined over QQ
    if "nu" not in crv_str:
        R0 = QQ
    else:
        R0 = PolynomialRing(QQ, "nu")
    R = PolynomialRing(R0, 2, "x,y")
    F = FractionField(R)
    sides = crv_str.split("=")
    lhs = latex(F(sides[0]))
    rhs = latex(F(sides[1]))
    eqn_str = lhs + "=" + rhs
    return eqn_str
示例#10
0
    def root(self):
        d = self.ring.ngens()
        self.d = d

        polyhedra = []
        for i in range(d):
            eqns = [
                (i+1) * [0] + [1] + (d-i-1) * [0]
            ]
            ieqs = [
                [-1] + j * [0] + [1] + (d-j-1) * [0]
                for j in range(i)
            ]
            ieqs += [
                (j+1) * [0] + [1] + (d-j-1) * [0]
                for j in range(i+1,d)
            ]
            polyhedra.append(Polyhedron(eqns=eqns, ieqs=ieqs))
        self.RS = RationalSet(polyhedra, ambient_dim=d)

        # NOTE:
        # A bug in Sage prevents rank computations over (fields of fractions of)
        # polynomial rings in zero variables over fields.
        if d > 0:
            F = FractionField(self.ring)
        else:
            F = FractionField(self.ring.base_ring())

        two_u = matrix(F, self.R).rank() # self.R.rank()
        if two_u % 2:
            raise RuntimeError('this is odd')
        self.u = two_u // 2
        self.v = matrix(F, self.S).rank() # self.S.rank()

        if not d:
            return

        F = [
            LaurentIdeal(
                gens = [LaurentPolynomial(_sqrt(f)) for f in principal_minors(self.R, 2*j)],
                RS = self.RS,
                normalise = True)
            for j in range(0, self.u+1)
        ]

        G = [LaurentIdeal(gens=[LaurentPolynomial(g) for g in self.S.minors(j)],
                          RS=self.RS,
                          normalise=True)
             for j in range(self.v + 1)]

        oo = self.u + self.v + 2

        # On pairs:
        # The first component is used as is, the second is multiplied by the extra
        # variable. Note that index 0 corresponds to {1} and index oo to {0}.
        # We skip the |F_1|/|F_0 cap xF_1| factor which is generically trivial.
        self.pairs = (
            [(oo, 0)] +
            [(i, oo) for i in range(2, self.u)] + [(i + 1, i) for i in range(1, self.u)] +
            [(i, oo) for i in range(self.u + 2, self.u + self.v + 1)] +
            [(i + 1, i) for i in range(self.u + 1, self.u + self.v + 1)])
        # Note: q^b t^a really corresponds to a*s - b, in contrast to subobjects, where
        # the (-1)-shift coming from Jacobians is included.
        # This also means we don't have to manually add (-1)s for extra variables.
        self.integrand = (
            (self.u,) + (self.u - 2) * (1,) + (self.u - 1) * (-1,) + (2 * self.v - 1) * (0,),
            (self.d + 1 - self.v,) + (2 * self.u - 3) * (0,) + (self.v - 1) * (-1,) + self.v * (1,))

        self.datum = IgusaDatum(F + G + [LaurentIdeal(gens=[], RS=self.RS, ring=FractionField(self.ring))])
        self.datum = self.datum.simplify()

        return self.datum
示例#11
0
def make_map_latex(map_str, nu=None):
    if "nu" not in map_str:
        R0 = QQ
    else:
        R0 = PolynomialRing(QQ, "nu")
    R = PolynomialRing(R0, 2, "x,y")
    F = FractionField(R)
    phi = F(map_str)
    num = phi.numerator()
    den = phi.denominator()
    c_num = num.denominator()
    c_den = den.denominator()
    lc = c_den / c_num
    # rescale coeffs to make them integral. then try to factor out gcds
    # numerator
    num_new = c_num * num
    num_cs = num_new.coefficients()
    if R0 == QQ:
        num_cs_ZZ = num_cs
    else:
        num_cs_ZZ = []
        for el in num_cs:
            num_cs_ZZ = num_cs_ZZ + el.coefficients()
    num_gcd = gcd(num_cs_ZZ)
    # denominator
    den_new = c_den * den
    den_cs = den_new.coefficients()
    if R0 == QQ:
        den_cs_ZZ = den_cs
    else:
        den_cs_ZZ = []
        for el in den_cs:
            den_cs_ZZ = den_cs_ZZ + el.coefficients()
    den_gcd = gcd(den_cs_ZZ)
    lc = lc * (num_gcd / den_gcd)
    num_new = num_new / num_gcd
    den_new = den_new / den_gcd
    # evaluate at nu, if given
    if nu and ("nu" in map_str):
        S = PolynomialRing(CC, 2, 'x,y')
        lc = lc.subs(nu=nu)
        num_dict = dict()
        den_dict = dict()
        for m, c in num_new.dict().items():
            num_dict[m] = c.subs(nu=nu)
        for m, c in den_new.dict().items():
            den_dict[m] = c.subs(nu=nu)
        num_new = S(num_dict)
        den_new = S(den_dict)
    # make strings for lc, num, and den
    num_str = latex(num_new)
    den_str = latex(den_new)

    if lc == 1:
        lc_str = ""
    else:
        lc_str = latex(lc)
    if den_new == 1:
        if lc == 1:
            phi_str = num_str
        else:
            phi_str = lc_str + "(" + num_str + ")"
    else:
        phi_str = lc_str + "\\frac{%s}{%s}" % (num_str, den_str)
    return phi_str
示例#12
0
文件: smurf.py 项目: fchapoton/Zeta
    def from_polyhedron(cls, P, ring, base_list=None):
        """
        Use LattE to compute the generating function of a rational polyhedron
        as a sum of small rational functions.
        """

        if P.is_empty():
            if ring.ngens() != P.ambient_dim():
                raise TypeError('Dimension mismatch')
            return cls(ring, base_list=base_list)
        elif P.is_zero():
            return cls([CyclotomicRationalFunction(ring.one())],
                       base_list=base_list)
        elif len(P.vertices()) == 1 and (not P.rays()) and (not P.lines()):
            # For some reason, LattE doesn't produce .rat files for points.
            return cls([
                CyclotomicRationalFunction(
                    ring.one(), exponents=[vector(ZZ,
                                                  P.vertices()[0])])
            ])

        hrep = 'polyhedron.hrep'
        ratfun = hrep + '.rat'

        with TemporaryDirectory() as tmpdir, cd(tmpdir):
            with open(hrep, 'w') as f:
                f.write(latteify_polyhedron(P))

            with open('/dev/null', 'w') as DEVNULL:
                retcode = subprocess.call([
                    common.count, '--compute-vertex-cones=4ti2',
                    '--triangulation=cddlib',
                    '--multivariate-generating-function', hrep
                ],
                                          stdout=DEVNULL,
                                          stderr=DEVNULL,
                                          env=augmented_env(common.count))
            if retcode != 0:
                raise RuntimeError(
                    'LattE failed. Make sure it has been patched in order to be compatible with Zeta.'
                )

            K = FractionField(ring)
            variables = [K.coerce(x) for x in ring.gens()]

            def exp(a):
                return K.prod(x**e for x, e in zip(variables, a))

            def vectorise_string(s):
                return vector(ZZ, s.strip().split())

            with TemporaryList() as summands, open(ratfun, 'r') as f:
                while True:
                    line = f.readline()
                    if not line:
                        break

                    line = line.strip()
                    if not line:
                        continue  # ignore empty lines

                    # The modified version of 'count' produces files in the following format:
                    # {
                    # scalar
                    # nterms
                    # a[1] ... a[n]  \
                    # ...            | nterms many
                    # c[1] ... c[n]  /
                    # nrays
                    # u[1] ... u[n] \
                    # ...           | nrays many
                    # w[1] ... w[n] /
                    # }
                    # ...
                    # This corresponds to scalar * sum(X^a + ... + X^c) / (1 - X^u) / ... / (1-X^w).

                    if line != "{":
                        raise RuntimeError(
                            'Invalid LattE output (BEGIN) [line=%s]' % line)

                    scalar = ring(f.readline())
                    nterms = int(f.readline())
                    numerator = K(scalar) * K.sum(
                        exp(vectorise_string(f.readline()))
                        for _ in range(nterms))

                    nrays = int(f.readline())
                    exponents = [vector(ZZ, len(variables))] + [
                        vectorise_string(f.readline()) for _ in range(nrays)
                    ]
                    line = f.readline().strip()

                    if line != '}':
                        raise RuntimeError('Invalid Latte output (END)')

                    summands.append(
                        CyclotomicRationalFunction.from_laurent_polynomial(
                            numerator, ring, exponents))

                return cls(summands, base_list=base_list)