Ejemplo n.º 1
0
def find_combination(f, d, factors, q):
    """
    find_combination(f, d, factors, q) -> g, list

    Find a combination of d factors which divides f (or its
    complement).  The returned values are: the product g of the
    combination and a list consisting of the combination itself.
    If there is no combination, return (0,[]).
    """
    lf = f.leading_coefficient()
    ZqZX = poly_ring.PolynomialRing(
        intresidue.IntegerResidueClassRing.getInstance(q))

    if d == 1:
        for g in factors:
            product = minimum_absolute_injection(ZqZX.createElement(lf*g))
            if divisibility_test(lf*f, product):
                return (product.primitive_part(), [g])
    else:
        for idx in combinatorial.combinationIndexGenerator(len(factors), d):
            picked = [factors[i] for i in idx]
            product = lf * arith1.product(picked)
            product = minimum_absolute_injection(ZqZX.createElement(product))
            if divisibility_test(lf*f, product):
                return (product.primitive_part(), picked)
    return 0, [] # nothing found
Ejemplo n.º 2
0
def padic_lift_list(f, factors, p, q):
    """
    padicLift(f, factors, p, q) -> lifted_factors

    Find a lifted integer coefficient polynomials such that:
      f = G1*G2*...*Gm (mod q*p),
      Gi = gi (mod q),
    from f and gi's of integer coefficient polynomials such that:
      f = g1*g2*...*gm (mod q),
      gi's are pairwise coprime
    with positive integers p dividing q.
    """
    ZpZx = poly_ring.PolynomialRing(
        intresidue.IntegerResidueClassRing.getInstance(p))
    gg = arith1.product(factors)
    h = ZpZx.createElement([(d, c // q) for (d, c) in (f - gg).iterterms()])
    lifted = []
    for g in factors:
        gg = gg.pseudo_floordiv(g)
        g_mod = ZpZx.createElement(g)
        if gg.degree() == 0:
            break
        u, v, w = extgcdp(g, gg, p)
        if w.degree() > 0:
            raise ValueError("factors must be pairwise coprime.")
        v_mod = ZpZx.createElement(v)
        t = v_mod * h // g_mod
        lifted.append(g +
                      minimum_absolute_injection(v_mod * h - g_mod * t) * q)
        u_mod = ZpZx.createElement(u)
        gg_mod = ZpZx.createElement(gg)
        h = u_mod * h + gg_mod * t
    lifted.append(g + minimum_absolute_injection(h) * q)
    return lifted
Ejemplo n.º 3
0
def padic_lift_list(f, factors, p, q):
    """
    padicLift(f, factors, p, q) -> lifted_factors

    Find a lifted integer coefficient polynomials such that:
      f = G1*G2*...*Gm (mod q*p),
      Gi = gi (mod q),
    from f and gi's of integer coefficient polynomials such that:
      f = g1*g2*...*gm (mod q),
      gi's are pairwise coprime
    with positive integers p dividing q.
    """
    ZpZx = poly_ring.PolynomialRing(
        intresidue.IntegerResidueClassRing.getInstance(p))
    gg = arith1.product(factors)
    h = ZpZx.createElement([(d, c // q) for (d, c) in (f - gg).iterterms()])
    lifted = []
    for g in factors:
        gg = gg.pseudo_floordiv(g)
        g_mod = ZpZx.createElement(g)
        if gg.degree() == 0:
            break
        u, v, w = extgcdp(g, gg, p)
        if w.degree() > 0:
            raise ValueError("factors must be pairwise coprime.")
        v_mod = ZpZx.createElement(v)
        t = v_mod * h // g_mod
        lifted.append(g + minimum_absolute_injection(v_mod * h - g_mod * t)*q)
        u_mod = ZpZx.createElement(u)
        gg_mod = ZpZx.createElement(gg)
        h = u_mod * h + gg_mod * t
        lifted.append(g + minimum_absolute_injection(h)*q)
    return lifted
Ejemplo n.º 4
0
def find_combination(f, d, factors, q):
    """
    find_combination(f, d, factors, q) -> g, list

    Find a combination of d factors which divides f (or its
    complement).  The returned values are: the product g of the
    combination and a list consisting of the combination itself.
    If there is no combination, return (0,[]).
    """
    lf = f.leading_coefficient()
    ZqZX = poly_ring.PolynomialRing(
        intresidue.IntegerResidueClassRing.getInstance(q))

    if d == 1:
        for g in factors:
            product = minimum_absolute_injection(ZqZX.createElement(lf * g))
            if divisibility_test(lf * f, product):
                return (product.primitive_part(), [g])
    else:
        for idx in combinatorial.combinationIndexGenerator(len(factors), d):
            picked = [factors[i] for i in idx]
            product = lf * arith1.product(picked)
            product = minimum_absolute_injection(ZqZX.createElement(product))
            if divisibility_test(lf * f, product):
                return (product.primitive_part(), picked)
    return 0, []  # nothing found
Ejemplo n.º 5
0
    def test_simultaneous(self):
        # f = (X**2 + 17)(X**4 + 2*(1-c)*X**2 + (1+c)**2)
        # c = 2**32*3
        f = hensel.the_ring.createElement({
            0: 2822351843715648061457,
            2: 166020696251069104163,
            4: -25769803757,
            6: 1
        })
        f1 = hensel.the_ring.createElement({0: 5, 1: 1})
        f2 = hensel.the_ring.createElement({0: 2, 1: 1})
        f3 = hensel.the_ring.createElement({0: 2, 2: 1})
        f4 = hensel.the_ring.createElement({0: 4, 2: 1})
        factors = [f1, f2, f3, f4]
        p = 7  # q is also 7

        # PRECONDITIONS
        # target = g1*g2*...*gm (mod q)
        self.assertEqualModulo(f, f1 * f2 * f3 * f4, p)

        # EXECUTION
        lifted, q = hensel.lift_upto(target=f,
                                     factors=[f1, f2, f3, f4],
                                     p=p,
                                     bound=7**128)

        # POSTCONDITIONS:
        self.assertEqual(4, len(lifted))
        self.assertEqual(7**128, q)
        # target = G1*G2*...*Gm (mod q*p),
        self.assertEqualModulo(f, arith1.product(lifted), q, str(lifted))
        # Gi = gi (mod q)
        for gi, Gi in zip(factors, lifted):
            self.assertEqualModulo(gi, Gi, 7)
Ejemplo n.º 6
0
    def first_lift(self):
        """
        Start lifting.
            f == l1*l2*...*lr (mod p**2)
        Initialize di's, ui's, yi's and zi's.
        Update ai's, bi's.
        Then, update q with p**2.
        """
        assert self.p == self.q  # q has not been raised yet
        self._assertEqualModulo(self.f, arith1.product(self.gis), self.q)
        for i in range(self.r - 1):
            self._assertEqualModulo(
                self.f,
                arith1.product(self.gis[:i + 1]) * self.his[i], self.q)
        assert self.gis[-1] == self.his[self.r - 2]

        self._init_dis()
        if len(self.dis) > 1:
            mini_target = self.dis[0] + self.dis[1].scalar_mul(self.p)
            self._assertEqualModulo(self.f, mini_target, self.p**2)
        else:
            mini_target = self.dis[0]
        aj, bj = [], []
        self.uis, self.yis, self.zis = [], {}, {}
        for i in range(self.r - 1):
            dividend = mini_target - self.gis[i] * self.his[i]
            self.uis.append(dividend.scalar_exact_division(self.p))
            self.yis[i], self.zis[i] = self._solve_yz(i)
            aj.append(self.gis[i] + self.zis[i].scalar_mul(self.q))
            bj.append(self.his[i] + self.yis[i].scalar_mul(self.q))
            self._assertEqualModulo(mini_target, aj[i] * bj[i],
                                    self.q * self.p)
            mini_target = bj[i]
        self._assertEqualModulo(self.gis[-1], mini_target, self.q)
        aj.append(bj[-1])
        self.q *= self.p

        for i in range(self.r - 1):
            self._assertEqualModulo(self.f,
                                    arith1.product(aj[:i + 1]) * bj[i], self.q,
                                    "f != l%d * m%d" % (i, i))
            self._assertEqualModulo(self.gis[i], aj[i], self.p)
        self._assertEqualModulo(self.f, arith1.product(aj), self.q)

        self.ais[-1], self.ais[0] = self.gis, tuple(aj)
        self.bis[-1], self.bis[0] = self.his, tuple(bj)
Ejemplo n.º 7
0
    def general_lift(self):
        """
        Continue lifting.
            f == a1*a2*...*ar (mod p*q)
        Update ai's, bi's, ui's, yi's and zi's.
        Then, update q with p*q.
        """
        j = arith1.vp(self.q, self.p)[0]
        if len(self.dis) > j:
            mini_target = self.dis[j]
        else:
            mini_target = the_zero

        self.ais[-2], self.ais[-1] = self.ais[-1], self.ais[0]
        self.bis[-2], self.bis[-1] = self.bis[-1], self.bis[0]
        aj, bj = [], []
        for i in range(self.r - 1):
            yi, zi = self.yis[i], self.zis[i]
            dividend = self.ais[-2][i] * yi + self.bis[-2][i] * zi - self.uis[i]
            v_j = dividend.scalar_exact_division(self.p)
            if j == 2:
                self.uis[i] = mini_target - v_j - yi * zi
            else:
                self.uis[i] = mini_target - v_j - (yi * zi).scalar_mul(
                    self.p**(j - 2))
            self.yis[i], self.zis[i] = self._solve_yz(i)
            aj.append(self.ais[-1][i] + self.zis[i].scalar_mul(self.q))
            bj.append(self.bis[-1][i] + self.yis[i].scalar_mul(self.q))
            self._assertEqualModulo(self.f,
                                    arith1.product(aj) * bj[i],
                                    self.q * self.p, (i, j))
            mini_target = self.yis[i]
        aj.append(bj[-1])
        self.q *= self.p

        for i in range(self.r - 1):
            self._assertEqualModulo(self.f,
                                    arith1.product(aj[:i + 1]) * bj[i], self.q,
                                    "f != a%d * b%d" % (i, i))
            self._assertEqualModulo(self.gis[i], aj[i], self.p)
        self._assertEqualModulo(self.f, arith1.product(aj), self.q)

        self.ais[0] = tuple(aj)
        self.bis[0] = tuple(bj)
Ejemplo n.º 8
0
    def first_lift(self):
        """
        Start lifting.
            f == l1*l2*...*lr (mod p**2)
        Initialize di's, ui's, yi's and zi's.
        Update ai's, bi's.
        Then, update q with p**2.
        """
        assert self.p == self.q # q has not been raised yet
        self._assertEqualModulo(self.f, arith1.product(self.gis), self.q)
        for i in range(self.r - 1):
            self._assertEqualModulo(self.f, arith1.product(self.gis[:i+1])*self.his[i], self.q)
        assert self.gis[-1] == self.his[self.r - 2]

        self._init_dis()
        if len(self.dis) > 1:
            mini_target = self.dis[0] + self.dis[1].scalar_mul(self.p)
            self._assertEqualModulo(self.f, mini_target, self.p**2)
        else:
            mini_target = self.dis[0]
        aj, bj = [], []
        self.uis, self.yis, self.zis = [], {}, {}
        for i in xrange(self.r - 1):
            dividend = mini_target - self.gis[i] * self.his[i]
            self.uis.append(dividend.scalar_exact_division(self.p))
            self.yis[i], self.zis[i] = self._solve_yz(i)
            aj.append(self.gis[i] + self.zis[i].scalar_mul(self.q))
            bj.append(self.his[i] + self.yis[i].scalar_mul(self.q))
            self._assertEqualModulo(mini_target, aj[i]*bj[i], self.q*self.p)
            mini_target = bj[i]
        self._assertEqualModulo(self.gis[-1], mini_target, self.q)
        aj.append(bj[-1])
        self.q *= self.p

        for i in range(self.r - 1):
            self._assertEqualModulo(self.f, arith1.product(aj[:i+1])*bj[i], self.q, "f != l%d * m%d" % (i, i))
            self._assertEqualModulo(self.gis[i], aj[i], self.p)
        self._assertEqualModulo(self.f, arith1.product(aj), self.q)

        self.ais[-1], self.ais[0] = self.gis, tuple(aj)
        self.bis[-1], self.bis[0] = self.his, tuple(bj)
Ejemplo n.º 9
0
    def assert_roots_coefficients(self, solutions, coefficients):
        """
        assert that the given 'solutions' and 'coefficients' satisfies
        the relations between roots and coefficients.

        limitation: only norm and trace are tested, now.
        """
        # norm
        degree = len(coefficients) - 1
        self.assertAlmostEqual(
            0, abs((-1)**degree * coefficients[0] - product(solutions)))
        # trace
        self.assertAlmostEqual(0, abs(-coefficients[-2] - sum(solutions)))
Ejemplo n.º 10
0
    def general_lift(self):
        """
        Continue lifting.
            f == a1*a2*...*ar (mod p*q)
        Update ai's, bi's, ui's, yi's and zi's.
        Then, update q with p*q.
        """
        j = arith1.vp(self.q, self.p)[0]
        if len(self.dis) > j:
            mini_target = self.dis[j]
        else:
            mini_target = the_zero

        self.ais[-2], self.ais[-1] = self.ais[-1], self.ais[0]
        self.bis[-2], self.bis[-1] = self.bis[-1], self.bis[0]
        aj, bj = [], []
        for i in xrange(self.r - 1):
            yi, zi = self.yis[i], self.zis[i]
            dividend = self.ais[-2][i]*yi + self.bis[-2][i]*zi - self.uis[i]
            v_j = dividend.scalar_exact_division(self.p)
            if j == 2:
                self.uis[i] = mini_target - v_j - yi*zi
            else:
                self.uis[i] = mini_target - v_j - (yi*zi).scalar_mul(self.p**(j - 2))
            self.yis[i], self.zis[i] = self._solve_yz(i)
            aj.append(self.ais[-1][i] + self.zis[i].scalar_mul(self.q))
            bj.append(self.bis[-1][i] + self.yis[i].scalar_mul(self.q))
            self._assertEqualModulo(self.f, arith1.product(aj)*bj[i], self.q*self.p, (i, j))
            mini_target = self.yis[i]
        aj.append(bj[-1])
        self.q *= self.p

        for i in range(self.r - 1):
            self._assertEqualModulo(self.f, arith1.product(aj[:i+1])*bj[i], self.q, "f != a%d * b%d" % (i, i))
            self._assertEqualModulo(self.gis[i], aj[i], self.p)
        self._assertEqualModulo(self.f, arith1.product(aj), self.q)

        self.ais[0] = tuple(aj)
        self.bis[0] = tuple(bj)
Ejemplo n.º 11
0
def _factor_minpoly_modp(minpoly_coeff, p):
    """
    Factor theminpoly modulo p, and return two values in a tuple.
    We call gcd(square factors mod p, difference of minpoly and its modp) Z.
    1) degree of Z
    2) (minpoly mod p) / Z
    """
    Fp = finitefield.FinitePrimeField.getInstance(p)
    theminpoly_p = uniutil.polynomial([(d, Fp.createElement(c)) for (d, c) in enumerate(minpoly_coeff)], Fp)
    modpfactors = theminpoly_p.factor()
    mini_p = arith1.product([t for (t, e) in modpfactors])
    quot_p = theminpoly_p.exact_division(mini_p)
    mini = _min_abs_poly(mini_p)
    quot = _min_abs_poly(quot_p)
    minpoly = uniutil.polynomial(enumerate(minpoly_coeff), Z)
    f_p = _mod_p((mini * quot - minpoly).scalar_exact_division(p), p)
    gcd = f_p.getRing().gcd
    common_p = gcd(gcd(mini_p, quot_p), f_p) # called Z
    uniq_p = theminpoly_p // common_p
    uniq = _min_abs_poly(uniq_p)

    return common_p.degree(), uniq
Ejemplo n.º 12
0
def _factor_minpoly_modp(minpoly_coeff, p):
    """
    Factor theminpoly modulo p, and return two values in a tuple.
    We call gcd(square factors mod p, difference of minpoly and its modp) Z.
    1) degree of Z
    2) (minpoly mod p) / Z
    """
    Fp = finitefield.FinitePrimeField.getInstance(p)
    theminpoly_p = uniutil.polynomial([(d, Fp.createElement(c)) for (d, c) in enumerate(minpoly_coeff)], Fp)
    modpfactors = theminpoly_p.factor()
    mini_p = arith1.product([t for (t, e) in modpfactors])
    quot_p = theminpoly_p.exact_division(mini_p)
    mini = _min_abs_poly(mini_p)
    quot = _min_abs_poly(quot_p)
    minpoly = uniutil.polynomial(enumerate(minpoly_coeff), Z)
    f_p = _mod_p((mini * quot - minpoly).scalar_exact_division(p), p)
    gcd = f_p.getRing().gcd
    common_p = gcd(gcd(mini_p, quot_p), f_p) # called Z
    uniq_p = theminpoly_p // common_p
    uniq = _min_abs_poly(uniq_p)

    return common_p.degree(), uniq
Ejemplo n.º 13
0
    def test_lift_multi(self):
        f1 = hensel.the_ring.createElement({0: 5, 1: 1})
        f2 = hensel.the_ring.createElement({0: 1, 1: 1})
        f3 = hensel.the_ring.createElement({0: 1, 2: 1})
        factors = [f1, f2, f3]
        f = hensel.the_ring.createElement(enumerate([-9900, -1, -9899, -1, 1]))
        p = 7  # q is also 7

        # PRECONDITIONS
        # target = g1*g2*...*gm (mod q)
        self.assertEqualModulo(f, f1 * f2 * f3, p)

        # EXECUTION
        lifted, q = hensel.lift_upto(target=f, factors=factors, p=p, bound=100)

        # POSTCONDITIONS:
        self.assertEqual(3, len(lifted))
        self.assertEqual(7**4, q)
        # target = G1*G2*...*Gm (mod q*p),
        self.assertEqualModulo(f, arith1.product(lifted), q, str(lifted))
        # Gi = gi (mod q)
        for gi, Gi in zip(factors, lifted):
            self.assertEqualModulo(gi, Gi, 7)
Ejemplo n.º 14
0
def primonial(p):
    """
    Return 2*3*...*p for given prime p.
    """
    return arith1.product(generator_eratosthenes(p))
Ejemplo n.º 15
0
 def testProduct(self):
     self.assertEqual(1, arith1.product([]))
     self.assertEqual(120, arith1.product(range(1, 6)))
     self.assertEqual(14400, arith1.product(i**2 for i in range(1, 6)))
Ejemplo n.º 16
0
def primonial(p):
    """
    Return 2*3*...*p for given prime p.
    """
    return arith1.product(generator_eratosthenes(p))
Ejemplo n.º 17
0
 def determinant(self):
     """
     Return determinant of the basis (basis ought to be of full
     rank and in Hermite normal form).
     """
     return arith1.product([rational.Rational(self.basis[i][i], self.denominator) for i in range(self.rank)])
Ejemplo n.º 18
0
 def determinant(self):
     """
     Return determinant of the basis (basis ought to be of full
     rank and in Hermite normal form).
     """
     return arith1.product([rational.Rational(self.basis[i][i], self.denominator) for i in range(self.rank)])
Ejemplo n.º 19
0
def embedding(f_q1, f_q2):
    """
    Return embedding homomorphism function from f_q1 to f_q2,
    where q1 = p ** k1, q2 = p ** k2 and k1 divides k2.
    """
    if card(f_q1) == card(f_q2):
        return fqiso(f_q1, f_q2)
    # search multiplicative generators of both fields and relate them.
    # 0. initialize basic variables
    p = f_q2.getCharacteristic()
    q1, q2 = card(f_q1), card(f_q2)
    q1_mult_order, q2_mult_order = q1 - 1, q2 - 1

    # 1. find a multiplicative generator of f_q2
    for i in bigrange.range(p, q2):
        f_q2_gen = f_q2.createElement(i)
        if f_q2.order(f_q2_gen) == q2_mult_order:
            break
    f_q2_subgen = f_q2_gen**((q2 - 1) // (q1 - 1))

    # 2.1 minimal polynomial of g = f_q2_gen ** ((q2 - 1) // (q1 - 1))
    #   minpoly = (X - g)(X - g**p)...(X - g**(p**(k1 - 1)))
    q, gpow = 1, f_q2_subgen
    linear_factors = []
    while q < q2:
        linear_factors.append(univar.BasicPolynomial({0: gpow, 1: f_q2.one}))
        # finally, raise power (Frobenius map).
        q *= p
        gpow **= p
    minpoly = arith1.product(linear_factors)
    # 2.2 minpoly has f_q2 coefficints but they are indeed f_p elements
    minpoly = univar.BasicPolynomial([(d, c.rep[0]) for (d, c) in minpoly])

    # 3. find a multiplicative generator of f_q1
    for i in bigrange.range(p, q1):
        f_q1_gen = f_q1.createElement(i)
        if f_q1.order(f_q1_gen) == q1_mult_order:
            break

    # 4. find f_q1_gen ** c of a root of minpoly and let it f_q1_gen
    for c in bigrange.range(1, q1):
        if gcd.coprime(c, q1_mult_order):
            if not minpoly(f_q1_gen**c):
                break
    f_q1_gen = f_q1_gen**c

    # 5. solve DLP:
    #   x_1 = f_q1_gen ** t
    #   (Here uses "brute force" method)
    x_1 = f_q1.createElement(p)
    gpow = f_q1_gen
    for i in bigrange.range(1, q):
        if gpow == x_1:
            image_of_x_1 = f_q2_subgen**i
            break
        gpow *= f_q1_gen

    # finally, define a function
    def f_q1_to_f_q2_homo(f_q1_elem):
        """
        Return the image of the isomorphism of the given element.
        """
        if not f_q1_elem:
            return f_q2.zero
        if f_q1_elem.rep.degree() == 0:
            # F_p elements
            return f_q2.createElement(f_q1_elem.rep)
        return f_q1_elem.rep(image_of_x_1)

    return f_q1_to_f_q2_homo
Ejemplo n.º 20
0
import logging
import warnings
import nzmath.arith1 as arith1
import nzmath.gcd as gcd
import nzmath.bigrandom as bigrandom
import nzmath.bigrange as bigrange
import nzmath.poly.array as array_poly
from nzmath.config import GRH
from nzmath.plugins import MATHMODULE as math

_log = logging.getLogger('nzmath.prime')
_log.setLevel(logging.DEBUG)

PRIMES_LE_31 = (2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31)
PRIMONIAL_31 = arith1.product(PRIMES_LE_31)


def trialDivision(n, bound=0):
    """
    Trial division primality test for an odd natural number.
    Optional second argument is a search bound of primes.
    If the bound is given and less than the sqaure root of n
    and True is returned, it only means there is no prime factor
    less than the bound.
    """

    if bound:
        m = min(bound, arith1.floorsqrt(n))
    else:
        m = arith1.floorsqrt(n)