Пример #1
0
    def nrootb(self, index, bits):
        """
        Approximately compute the inverse of index-th root and return it.

        b stands for binary search. It should be used for:
          1 <= bits <= ceil(lg(8 * index))
        """
        # lgy - 1 < lg self <= lgy
        lgy = arith1.log(self.abscissa) + self.exponent
        if DyadicRational(lgy, 1) < self:
            lgy += 1
        assert DyadicRational(lgy - 1, 1) < self <= DyadicRational(lgy, 1)
        lgr = -lgy // index
        ebound = 66 * (2 * index + 1)
        bound = arith1.log(ebound)
        if 2**bound < ebound:
            bound += 1
        rbound = DyadicRational(-10, 993)
        one = DyadicRational(0, 1)

        z = DyadicRational(lgr, 1) + DyadicRational(lgr - 1, 1)
        for j in range(1, bits):
            r = (z.power(index, bound) * self.trunc(bound)).trunc(bound)
            if r <= rbound:
                z += DyadicRational(lgr - j - 1, 1)
            if r > one:
                z = z.sub(DyadicRational(lgr - j - 1, 1))

        return z
Пример #2
0
 def __init__(self, n):
     """
     Create a Bounds object from target number n.
     """
     if _arith1.log(n, 10) < 20:
         self.first = 1000
     elif _arith1.log(n, 10) < 25:
         self.first = 10000
     else:
         self.first = 100000
     self.second = self.first * 50
Пример #3
0
 def __init__(self, n):
     """
     Create a Bounds object from target number n.
     """
     if _arith1.log(n, 10) < 20:
         self.first = 1000
     elif _arith1.log(n, 10) < 25:
         self.first = 10000
     else:
         self.first = 100000
     self.second = self.first * 50
Пример #4
0
def zassenhaus(f):
    """
    zassenhaus(f) -> list of factors of f.

    Factor a squarefree monic integer coefficient polynomial f with
    Berlekamp-Zassenhaus method.
    """
    # keep leading coefficient
    lf = f.leading_coefficient()

    # p-adic factorization
    p, fp_factors = padic_factorization(f)
    if len(fp_factors) == 1:
        return [f]

    # purge leading coefficient from factors
    for i, g in enumerate(fp_factors):
        if g.degree() == 0:
            del fp_factors[i]
            break

    # lift to Mignotte bound
    blm = upper_bound_of_coefficient(f)
    bound = p**(arith1.log(2 * blm, p) + 1)

    # Hensel lifting
    lf_inv_modq = intresidue.IntegerResidueClass(lf, bound).inverse()
    fq = f.coefficients_map(lambda c:
                            (lf_inv_modq * c).minimumAbsolute())  # fq is monic
    fq_factors, q = hensel.lift_upto(fq, fp_factors, p, bound)

    return brute_force_search(f, fq_factors, bound)
Пример #5
0
def _squarefree_decomp(p, field, base_multiply):
    """
    decompose (p) as (p)= A_1 (A_2)^2 (A_3)^2 ..., where each A_i is squarefree
    """
    #CCANT Algo 6.2.9 step 2-5
    n = field.degree
    int_basis = field.integer_ring()
    # step 2
    log_n_p = arith1.log(n, p)
    q = p ** log_n_p
    if  q < n:
        q *= p
    base_p = _kernel_of_qpow(int_basis, q, p, field)
    I_p_over_pO = base_p
    # step 3
    K_lst = [I_p_over_pO]
    while K_lst[-1]: # K[-1] is zero matrix in F_p
        K_lst.append(_mul_mod_pO(K_lst[0], K_lst[-1], base_multiply))
    i = len(K_lst)
    # step 4
    J_lst = [K_lst[0]]
    for j in range(1, i):
        J_lst.append(_div_mod_pO(K_lst[j], K_lst[j - 1], base_multiply, p))
    # step 5
    H_lst = []
    for j in range(i - 1):
        H_lst.append(_div_mod_pO(J_lst[j], J_lst[j + 1], base_multiply, p))
    H_lst.append(J_lst[-1])
    return H_lst
Пример #6
0
def _squarefree_decomp(p, field, base_multiply):
    """
    decompose (p) as (p)= A_1 (A_2)^2 (A_3)^2 ..., where each A_i is squarefree
    """
    #CCANT Algo 6.2.9 step 2-5
    n = field.degree
    int_basis = field.integer_ring()
    # step 2
    log_n_p = arith1.log(n, p)
    q = p ** log_n_p
    if  q < n:
        q *= p
    base_p = _kernel_of_qpow(int_basis, q, p, field)
    I_p_over_pO = base_p
    # step 3
    K_lst = [I_p_over_pO]
    while K_lst[-1]: # K[-1] is zero matrix in F_p
        K_lst.append(_mul_mod_pO(K_lst[0], K_lst[-1], base_multiply))
    i = len(K_lst)
    # step 4
    J_lst = [K_lst[0]]
    for j in range(1, i):
        J_lst.append(_div_mod_pO(K_lst[j], K_lst[j - 1], base_multiply, p))
    # step 5
    H_lst = []
    for j in range(i - 1):
        H_lst.append(_div_mod_pO(J_lst[j], J_lst[j + 1], base_multiply, p))
    H_lst.append(J_lst[-1])
    return H_lst
Пример #7
0
def zassenhaus(f):
    """
    zassenhaus(f) -> list of factors of f.

    Factor a squarefree monic integer coefficient polynomial f with
    Berlekamp-Zassenhaus method.
    """
    # keep leading coefficient
    lf = f.leading_coefficient()

    # p-adic factorization
    p, fp_factors = padic_factorization(f)
    if len(fp_factors) == 1:
        return [f]

    # purge leading coefficient from factors
    for i,g in enumerate(fp_factors):
        if g.degree() == 0:
           del fp_factors[i]
           break

    # lift to Mignotte bound
    blm = upper_bound_of_coefficient(f)
    bound = p**(arith1.log(2*blm,p)+1)

    # Hensel lifting
    lf_inv_modq = intresidue.IntegerResidueClass(lf, bound).inverse()
    fq = f.coefficients_map(lambda c: (lf_inv_modq*c).minimumAbsolute()) # fq is monic
    fq_factors, q = hensel.lift_upto(fq, fp_factors, p, bound)

    return brute_force_search(f, fq_factors, bound)
Пример #8
0
def FFT(f, bound):
    """
    Fast Fourier Transform.
    This function returns the result of valuations of f by fast fourier transform
    against number of bound different values.
    """
    count = 1 << (bound >> 1)
    mod = count + 1
    if isinstance(f, ArrayPoly):
        coefficients = f.coefficients[:]
    else:
        coefficients = f[:]
    coefficients.extend([0] * (bound - len(coefficients)))
    shuf_coefficients = perfect_shuffle(coefficients)
    shuf_coefficients = [min_abs_mod(i, mod) for i in shuf_coefficients]
    bound_log = arith1.log(bound, 2)
    for i in range(1, bound_log + 1):
        m = 1 << i
        wm = count
        wm = wm % mod
        w = 1
        m1 = m >> 1
        for j in range(m1):
            for k in range(j, bound, m):
                m2 = k + m1
                plus = shuf_coefficients[k]
                minus = w * shuf_coefficients[m2]
                shuf_coefficients[k] = (plus + minus) % mod
                shuf_coefficients[m2] = (plus - minus) % mod
            w = w * wm
        shuf_coefficietns = [min_abs_mod(i, mod) for i in shuf_coefficients]
        count = arith1.floorsqrt(count)
    return shuf_coefficients
Пример #9
0
    def nroot(self, index, bits):
        lg8k = arith1.log(8 * index)
        if 2**lg8k < 8 * index:
            lg8k += 1

        if bits <= lg8k:
            return self.nrootb(index, bits)
        else:
            return self.nrootn(index, bits)
Пример #10
0
def ceillog(n, base=2):
    """
    Return ceiling of log(n, 2)
    """
    floor = arith1.log(n, base)
    if base**floor == n:
        return floor
    else:
        return floor + 1
Пример #11
0
    def __init__(self, n, sieverange, factorbase):
        self.number = n
        self.sqrt_n = int(math.sqrt(n))
        for i in [2,3,5,7,11,17,19]:
            if n % i == 0:
                raise ValueError("This number is divided by %d" % i)

        self.digit = arith1.log(self.number, 10) + 1
        self.Srange = sieverange
        self.FBN = factorbase

        self.move_range = range(self.sqrt_n-self.Srange, self.sqrt_n+self.Srange+1)

        i = 0
        k = 0
        factor_base = [-1]
        FB_log = [0]
        while True:
            ii = primes_table[i]
            if arith1.legendre(self.number, ii) == 1:
                factor_base.append(ii)
                FB_log.append(primes_log_table[i])
                k += 1
                i += 1
                if k == self.FBN:
                    break
            else:
                i += 1

        self.FB = factor_base
        self.FB_log = FB_log
        self.maxFB = factor_base[-1]
        N_sqrt_list = []
        for i in self.FB:
            if i != 2 and i != -1:
                e = int(math.log(2*self.Srange, i))
                N_sqrt_modp = sqroot_power(self.number, i, e)
                N_sqrt_list.append(N_sqrt_modp)
        self.solution = N_sqrt_list  #This is square roots of N on Z/pZ, p in factor base.

        poly_table = []
        log_poly = []
        minus_val = []
        for j in self.move_range:
            jj = (j**2)-self.number
            if jj < 0:
                jj = -jj
                minus_val.append(j-self.sqrt_n+self.Srange)
            elif jj == 0:
                jj = 1
            lj = int((math.log(jj)*30)*0.97)  # 0.97 is an erroe
            poly_table.append(jj)
            log_poly.append(lj)
        self.poly_table = poly_table  # This is Q(x) value , x in [-M+sqrt_n,M+sqrt_n].
        self.log_poly = log_poly      # This is log(Q(x)) value.
        self.minus_check = minus_val # This is "x" that Q(x) is minus value.
Пример #12
0
 def __init__(self, exponent, abscissa):
     self.exponent = exponent
     self.abscissa = abscissa
     if self.abscissa:
         while not (self.abscissa & 1):
             self.exponent += 1
             self.abscissa >>= 1
     # f - 1 <= lg abscissa < f
     self.log_absc = arith1.log(self.abscissa)
     if 2**self.log_absc <= self.abscissa:
         self.log_absc += 1
Пример #13
0
def perfect_power_detection(n):
    """
    Return (m, k) if n = m**k.

    Note that k is the smallest possible and m still can be a perfect
    power; if n is not a perfect power, it returns (n, 1).
    """
    f = arith1.log(n) + 1
    y = DyadicRational(0, n).nroot(1, 3 + (f - 1) // 2 + 1)
    for p in prime.generator_eratosthenes(f):
        x = _is_kth_power(n, p, y, f)
        if x != 0:
            return (x, p)
    return (n, 1)
Пример #14
0
 def div(self, divisor, bits):
     """
     Divide a dyadic rational by a positive integer divisor within
     precision bits and return the result.
     """
     # lgd - 1 < lg divisor <= lgd
     lgd = arith1.log(divisor)
     if 2**lgd < divisor:
         lgd += 1
     offset = self.log_absc - lgd - bits
     if offset < 0:
         abscissa = (self.abscissa << -offset) // divisor
     else:
         abscissa = self.abscissa // (divisor << offset)
     return DyadicRational(self.exponent + offset, abscissa)
Пример #15
0
def miller(n):
    """
    Miller's primality test.

    This test is valid under GRH.
    """
    s, t = arith1.vp(n - 1, 2)
    # The O-constant 2 by E.Bach
    ## ln(n) = log_2(n)/log_2(e) = ln(2) * log_2(n)
    ## 2 * ln(2) ** 2 <= 0.960906027836404
    bound = min(n - 1, 960906027836404 * (arith1.log(n) + 1)**2 // 10**15 + 1)
    _log.info("bound: %d" % bound)
    for b in range(2, bound):
        if not spsp(n, b, s, t):
            return False
    return True
Пример #16
0
def miller(n):
    """
    Miller's primality test.

    This test is valid under GRH.
    """
    s, t = arith1.vp(n - 1, 2)
    # The O-constant 2 by E.Bach
    ## 2 log(n) = 2 log_2(n)/log_2(e) = 2 log(2) log_2(n)
    ## 2 log(2) <= 1.3862943611198906
    bound = min(n - 2, 13862943611198906 * arith1.log(n) // 10 ** 16) + 1
    _log.info("bound: %d" % bound)
    for b in range(2, bound):
        if not spsp(n, b, s, t):
            return False
    return True
Пример #17
0
def _p_maximal(p, e, minpoly_coeff):
    """
    Return p-maximal basis with some related informations.

    The arguments:
      p: the prime
      e: the exponent
      minpoly_coeff: (intefer) list of coefficients of the minimal
        polynomial of theta
    """
    # Apply the Dedekind criterion
    finished, omega = Dedekind(minpoly_coeff, p, e)
    if finished:
        _log.info("Dedekind(%d)" % p)
        return omega

    # main loop to construct p-maximal order
    minpoly = uniutil.polynomial(enumerate(minpoly_coeff), Z)
    theminpoly = minpoly.to_field_polynomial()
    n = theminpoly.degree()
    q = p ** (arith1.log(n, p) + 1)
    while True:
        # Ip: radical of pO
        # Ip = <alpha>, l = dim Ip/pO (essential part of Ip)
        alpha, l = _p_radical(omega, p, q, minpoly, n)

        # instead of step 9 big matrix,
        # Kida's LN section 2.2
        # Up = {x in Ip | xIp \subset pIp} = <zeta> + p<omega>
        zeta = _p_module(alpha, l, p, theminpoly)
        if zeta.rank == 0:
            # no new basis is found
            break

        # new order
        # 1/p Up = 1/p<zeta> + <omega>
        omega2 = zeta / p + omega
        if all(o1 == o2 for o1, o2 in zip(omega.basis, omega2.basis)):
            break
        omega = omega2

    # now <omega> is p-maximal.
    return omega
Пример #18
0
def _p_maximal(p, e, minpoly_coeff):
    """
    Return p-maximal basis with some related informations.

    The arguments:
      p: the prime
      e: the exponent
      minpoly_coeff: (intefer) list of coefficients of the minimal
        polynomial of theta
    """
    # Apply the Dedekind criterion
    finished, omega = Dedekind(minpoly_coeff, p, e)
    if finished:
        _log.info("Dedekind(%d)" % p)
        return omega

    # main loop to construct p-maximal order
    minpoly = uniutil.polynomial(enumerate(minpoly_coeff), Z)
    theminpoly = minpoly.to_field_polynomial()
    n = theminpoly.degree()
    q = p ** (arith1.log(n, p) + 1)
    while True:
        # Ip: radical of pO
        # Ip = <alpha>, l = dim Ip/pO (essential part of Ip)
        alpha, l = _p_radical(omega, p, q, minpoly, n)

        # instead of step 9 big matrix,
        # Kida's LN section 2.2
        # Up = {x in Ip | xIp \subset pIp} = <zeta> + p<omega>
        zeta = _p_module(alpha, l, p, theminpoly)
        if zeta.rank == 0:
            # no new basis is found
            break

        # new order
        # 1/p Up = 1/p<zeta> + <omega>
        omega2 = zeta / p + omega
        if all(o1 == o2 for o1, o2 in zip(omega.basis, omega2.basis)):
            break
        omega = omega2

    # now <omega> is p-maximal.
    return omega
Пример #19
0
def _power_sign(n, x, k, f):
    """
    Return the sign of n - x**k.  All of n, x, and k are positive
    integers.
    """
    lg8k = arith1.log(k) + 3
    if 2**lg8k < 8 * k:
        lg8k += 1
    bound = 1
    drn = DyadicRational(0, n)

    while True:
        r = DyadicRational(0, x).power(k, bound + lg8k)
        if drn < r:
            return -1
        elif r * (DyadicRational(0, 1) + DyadicRational(-bound, 1)) <= drn:
            return 1
        elif bound >= f:
            return 0
        bound = min(2 * bound, f)
Пример #20
0
def randrange(start, stop=None, step=1):
    """
    Choose a random item from range([start,] stop[, step]).
    (Return long integer.)

    see random.randrange
    """
    if stop is None:
        if abs(start) < sys.maxint:
            return _random.randrange(start)
    elif abs(stop - start) < sys.maxint:
        return _random.randrange(start, stop, step)

    negative_step = False
    if stop is None:
        start, stop = 0, start
    if step < 0:
        start, stop, step = -start, -stop, -step
        negative_step = True

    _validate_for_randrange(start, stop, step)

    if (stop - start) % step != 0:
        v = (stop - start)//step + 1
    else:
        v = (stop - start)//step

    bitlength = arith1.log(v, base=2)
    if v != 2**bitlength:
        bitlength += 1
    randomized = v + 1 # to pass the first test
    while randomized >= v:
        randomized = 0
        for i in range(bitlength):
            if random() < 0.5:
                randomized += 1 << i
    result = randomized * step + start
    if negative_step:
        return -result
    return result
Пример #21
0
def randrange(start, stop=None, step=1):
    """
    Choose a random item from range([start,] stop[, step]).
    (Return long integer.)

    see random.randrange
    """
    if stop is None:
        if abs(start) < sys.maxint:
            return _random.randrange(start)
    elif abs(stop - start) < sys.maxint:
        return _random.randrange(start, stop, step)

    negative_step = False
    if stop is None:
        start, stop = 0, start
    if step < 0:
        start, stop, step = -start, -stop, -step
        negative_step = True

    _validate_for_randrange(start, stop, step)

    if (stop - start) % step != 0:
        v = (stop - start) // step + 1
    else:
        v = (stop - start) // step

    bitlength = arith1.log(v, base=2)
    if v != 2**bitlength:
        bitlength += 1
    randomized = v + 1  # to pass the first test
    while randomized >= v:
        randomized = 0
        for i in range(bitlength):
            if random() < 0.5:
                randomized += 1 << i
    result = randomized * step + start
    if negative_step:
        return -result
    return result
Пример #22
0
    def nrootn(self, index, bits):
        """
        Approximately compute the inverse of index-th root and return it.

        n stands for Newton's method. It should be used for:
          bits > ceil(lg(8 * index))
        """
        lgk = arith1.log(index)
        if 2**lgk < index:
            lgk += 1
        lg2k = lgk + 1
        lg8k = lgk + 3
        smallbits = lg2k + (bits - lg2k - 1) // 2 + 1
        bound = 2 * smallbits + 4 - lgk

        if smallbits <= lg8k:
            z = self.nrootb(index, smallbits)
        else:
            z = self.nrootn(index, smallbits)

        r2 = z.trunc(bound).mul(index + 1)
        r3 = (z.power(index + 1, bound) * self.trunc(bound)).trunc(bound)
        r4 = r2.sub(r3).div(index, bound)
        return r4
Пример #23
0
    def __init__(self, n, sieverange=0, factorbase=0, multiplier=0):
        self.number = n
        _log.info("The number is %d MPQS starting" % n)

        if prime.primeq(self.number):
            raise ValueError("This number is Prime Number")
        for i in [2,3,5,7,11,13]:
            if n % i == 0:
                raise ValueError("This number is divided by %d" % i)

        self.sievingtime = 0
        self.coefficienttime = 0
        self.d_list = []
        self.a_list = []
        self.b_list = []

        #Decide prameters for each digits
        self.digit = arith1.log(self.number, 10) + 1

        if sieverange != 0:
            self.Srange = sieverange
            if factorbase != 0:
                self.FBN = factorbase
            elif self.digit < 9:
                self.FBN = parameters_for_mpqs[0][1]
            else:
                self.FBN = parameters_for_mpqs[self.digit-9][1]
        elif factorbase != 0:
            self.FBN = factorbase
            if self.digit < 9:
                self.Srange = parameters_for_mpqs[0][0]
            else:
                self.Srange = parameters_for_mpqs[self.digit-9][0]
        elif self.digit < 9:
            self.Srange = parameters_for_mpqs[0][0]
            self.FBN = parameters_for_mpqs[0][1]
        elif self.digit > 53:
            self.Srange = parameters_for_mpqs[44][0]
            self.FBN = parameters_for_mpqs[44][1]
        else:
            self.Srange = parameters_for_mpqs[self.digit-9][0]
            self.FBN = parameters_for_mpqs[self.digit-9][1]

        self.move_range = range(-self.Srange, self.Srange+1)

        # Decide k such that k*n = 1 (mod4) and k*n has many factor base
        if multiplier == 0:
            self.sqrt_state = []
            for i in [3,5,7,11,13]:
                s = arith1.legendre(self.number, i)
                self.sqrt_state.append(s)
            index8 = (self.number % 8) // 2
            j = 0
            while self.sqrt_state != prime_8[index8][j][1]:
                j += 1
            k = prime_8[index8][j][0]
        else:
            if n % 4 == 1:
                k = 1
            else:
                if multiplier == 1:
                    raise ValueError("This number is 3 mod 4 ")
                else:
                    k = multiplier
        self.number = k*self.number
        self.multiplier = k

        _log.info("%d - digits Number" % self.digit)
        _log.info("Multiplier is %d" % self.multiplier)

        # Table of (log p) , p in FB
        i = 0
        k = 0
        factor_base = [-1]
        FB_log = [0]
        while k < self.FBN:
            ii = primes_table[i]
            if arith1.legendre(self.number,ii) == 1:
                factor_base.append(ii)
                FB_log.append(primes_log_table[i])
                k += 1
            i += 1

        self.FB = factor_base
        self.FB_log = FB_log
        self.maxFB = factor_base[-1]

        # Solve x^2 = n (mod p^e)
        N_sqrt_list = []
        for i in self.FB:
            if i != 2 and i != -1:
                e = int(math.log(2*self.Srange, i))
                N_sqrt_modp = sqroot_power(self.number, i, e)
                N_sqrt_list.append(N_sqrt_modp)
        self.Nsqrt = N_sqrt_list
Пример #24
0
def affine_multiple_method(lhs, field):
    """
    Find and return a root of the equation lhs = 0 by brute force
    search in the given field.  If there is no root in the field,
    ValueError is raised.

    The first argument lhs is a univariate polynomial with
    coefficients in a finite field.  The second argument field is
    an extension field of the field of coefficients of lhs.

    Affine multiple A(X) is $\sum_{i=0}^{n} a_i X^{q^i} - a$ for some
    a_i's and a in the coefficient field of lhs, which is a multiple
    of the lhs.
    """
    polynomial_ring = lhs.getRing()
    coeff_field = lhs.getCoefficientRing()
    q = card(coeff_field)
    n = lhs.degree()

    # residues = [x, x^q, x^{q^2}, ..., x^{q^{n-1}}]
    residues = [lhs.mod(polynomial_ring.one.term_mul((1, 1)))]  # x
    for i in range(1, n):
        residues.append(pow(residues[-1], q, lhs))  # x^{q^i}

    # find a linear relation among residues and a constant
    coeff_matrix = matrix.createMatrix(n, n, [coeff_field.zero] * (n**2),
                                       coeff_field)
    for j, residue in enumerate(residues):
        for i in range(residue.degree() + 1):
            coeff_matrix[i + 1, j + 1] = residue[i]
    constant_components = [coeff_field.one] + [coeff_field.zero] * (n - 1)
    constant_vector = vector.Vector(constant_components)
    try:
        relation_vector, kernel = coeff_matrix.solve(constant_vector)
        for j in range(n, 0, -1):
            if relation_vector[j]:
                constant = relation_vector[j].inverse()
                relation = [constant * c for c in relation_vector]
                break
    except matrix.NoInverseImage:
        kernel_matrix = coeff_matrix.kernel()
        relation_vector = kernel_matrix[1]
        assert type(relation_vector) is vector.Vector
        for j in range(n, 0, -1):
            if relation_vector[j]:
                normalizer = relation_vector[j].inverse()
                relation = [normalizer * c for c in relation_vector]
                constant = coeff_field.zero
                break

    # define L(X) = A(X) + constant
    coeffs = {}
    for i, relation_i in enumerate(relation):
        coeffs[q**i] = relation_i
    linearized = uniutil.polynomial(coeffs, coeff_field)

    # Fq basis [1, X, ..., X^{s-1}]
    qbasis = [1]
    root = field.createElement(field.char)
    s = arith1.log(card(field), q)
    qbasis += [root**i for i in range(1, s)]
    # represent L as Matrix
    lmat = matrix.createMatrix(s, s, field.basefield)
    for j, base in enumerate(qbasis):
        imagei = linearized(base)
        if imagei.getRing() == field.basefield:
            lmat[1, j + 1] = imagei
        else:
            for i, coeff in imagei.rep.iterterms():
                if coeff:
                    lmat[i + 1, j + 1] = coeff
    # solve L(X) = the constant
    constant_components = [constant] + [coeff_field.zero] * (s - 1)
    constant_vector = vector.Vector(constant_components)
    solution, kernel = lmat.solve(constant_vector)
    assert lmat * solution == constant_vector
    solutions = [solution]
    for v in kernel:
        for i in range(card(field.basefield)):
            solutions.append(solution + i * v)

    # roots of A(X) contains the solutions of lhs = 0
    for t in bigrange.multirange([(card(field.basefield), )] * len(kernel)):
        affine_root_vector = solution
        for i, ti in enumerate(t):
            affine_root_vector += ti * kernel[i]
        affine_root = field.zero
        for i, ai in enumerate(affine_root_vector):
            affine_root += ai * qbasis[i]
        if not lhs(affine_root):
            return affine_root

    raise ValueError("no root found")
Пример #25
0
def affine_multiple_method(lhs, field):
    """
    Find and return a root of the equation lhs = 0 by brute force
    search in the given field.  If there is no root in the field,
    ValueError is raised.

    The first argument lhs is a univariate polynomial with
    coefficients in a finite field.  The second argument field is
    an extension field of the field of coefficients of lhs.

    Affine multiple A(X) is $\sum_{i=0}^{n} a_i X^{q^i} - a$ for some
    a_i's and a in the coefficient field of lhs, which is a multiple
    of the lhs.
    """
    polynomial_ring = lhs.getRing()
    coeff_field = lhs.getCoefficientRing()
    q = card(coeff_field)
    n = lhs.degree()

    # residues = [x, x^q, x^{q^2}, ..., x^{q^{n-1}}]
    residues = [lhs.mod(polynomial_ring.one.term_mul((1, 1)))] # x
    for i in range(1, n):
        residues.append(pow(residues[-1], q, lhs)) # x^{q^i}

    # find a linear relation among residues and a constant
    coeff_matrix = matrix.createMatrix(n, n, [coeff_field.zero] * (n**2), coeff_field)
    for j, residue in enumerate(residues):
        for i in range(residue.degree() + 1):
            coeff_matrix[i + 1, j + 1] = residue[i]
    constant_components = [coeff_field.one] + [coeff_field.zero] * (n - 1)
    constant_vector = vector.Vector(constant_components)
    try:
        relation_vector, kernel = coeff_matrix.solve(constant_vector)
        for j in range(n, 0, -1):
            if relation_vector[j]:
                constant = relation_vector[j].inverse()
                relation = [constant * c for c in relation_vector]
                break
    except matrix.NoInverseImage:
        kernel_matrix = coeff_matrix.kernel()
        relation_vector = kernel_matrix[1]
        assert type(relation_vector) is vector.Vector
        for j in range(n, 0, -1):
            if relation_vector[j]:
                normalizer = relation_vector[j].inverse()
                relation = [normalizer * c for c in relation_vector]
                constant = coeff_field.zero
                break

    # define L(X) = A(X) + constant
    coeffs = {}
    for i, relation_i in enumerate(relation):
        coeffs[q**i] = relation_i
    linearized = uniutil.polynomial(coeffs, coeff_field)

    # Fq basis [1, X, ..., X^{s-1}]
    qbasis = [1]
    root = field.createElement(field.char)
    s = arith1.log(card(field), q)
    qbasis += [root**i for i in range(1, s)]
    # represent L as Matrix
    lmat = matrix.createMatrix(s, s, field.basefield)
    for j, base in enumerate(qbasis):
        imagei = linearized(base)
        if imagei.getRing() == field.basefield:
            lmat[1, j + 1] = imagei
        else:
            for i, coeff in imagei.rep.iterterms():
                if coeff:
                    lmat[i + 1, j + 1] = coeff
    # solve L(X) = the constant
    constant_components = [constant] + [coeff_field.zero] * (s - 1)
    constant_vector = vector.Vector(constant_components)
    solution, kernel = lmat.solve(constant_vector)
    assert lmat * solution == constant_vector
    solutions = [solution]
    for v in kernel:
        for i in range(card(field.basefield)):
            solutions.append(solution + i * v)

    # roots of A(X) contains the solutions of lhs = 0
    for t in bigrange.multirange([(card(field.basefield),)] * len(kernel)):
        affine_root_vector = solution
        for i, ti in enumerate(t):
            affine_root_vector += ti * kernel[i]
        affine_root = field.zero
        for i, ai in enumerate(affine_root_vector):
            affine_root += ai * qbasis[i]
        if not lhs(affine_root):
            return affine_root

    raise ValueError("no root found")
Пример #26
0
 def testLog(self):
     self.assertEqual(3, arith1.log(8, 2))
     self.assertEqual(3, arith1.log(15, 2))
     self.assertEqual(3, arith1.log(1000, 10))
     self.assertEqual(9, arith1.log(1000000001, 10))
     self.assertTrue(10**arith1.log(1000000001, 10) <= 1000000001)