diff options
author | dos-reis <gdr@axiomatics.org> | 2007-08-14 05:14:52 +0000 |
---|---|---|
committer | dos-reis <gdr@axiomatics.org> | 2007-08-14 05:14:52 +0000 |
commit | ab8cc85adde879fb963c94d15675783f2cf4b183 (patch) | |
tree | c202482327f474583b750b2c45dedfc4e4312b1d /src/algebra/intfact.spad.pamphlet | |
download | open-axiom-ab8cc85adde879fb963c94d15675783f2cf4b183.tar.gz |
Initial population.
Diffstat (limited to 'src/algebra/intfact.spad.pamphlet')
-rw-r--r-- | src/algebra/intfact.spad.pamphlet | 534 |
1 files changed, 534 insertions, 0 deletions
diff --git a/src/algebra/intfact.spad.pamphlet b/src/algebra/intfact.spad.pamphlet new file mode 100644 index 00000000..996b9232 --- /dev/null +++ b/src/algebra/intfact.spad.pamphlet @@ -0,0 +1,534 @@ +\documentclass{article} +\usepackage{axiom} +\begin{document} +\title{\$SPAD/src/algebra intfact.spad} +\author{Michael Monagan} +\maketitle +\begin{abstract} +\end{abstract} +\eject +\tableofcontents +\eject +\section{package PRIMES IntegerPrimesPackage} +<<package PRIMES IntegerPrimesPackage>>= +)abbrev package PRIMES IntegerPrimesPackage +++ Author: Michael Monagan +++ Date Created: August 1987 +++ Date Last Updated: 31 May 1993 +++ Updated by: James Davenport +++ Updated Because: of problems with strong pseudo-primes +++ and for some efficiency reasons. +++ Basic Operations: +++ Related Domains: +++ Also See: +++ AMS Classifications: +++ Keywords: integer, prime +++ Examples: +++ References: Davenport's paper in ISSAC 1992 +++ AXIOM Technical Report ATR/6 +++ Description: +++ The \spadtype{IntegerPrimesPackage} implements a modification of +++ Rabin's probabilistic +++ primality test and the utility functions \spadfun{nextPrime}, +++ \spadfun{prevPrime} and \spadfun{primes}. +IntegerPrimesPackage(I:IntegerNumberSystem): with + prime?: I -> Boolean + ++ \spad{prime?(n)} returns true if n is prime and false if not. + ++ The algorithm used is Rabin's probabilistic primality test + ++ (reference: Knuth Volume 2 Semi Numerical Algorithms). + ++ If \spad{prime? n} returns false, n is proven composite. + ++ If \spad{prime? n} returns true, prime? may be in error + ++ however, the probability of error is very low. + ++ and is zero below 25*10**9 (due to a result of Pomerance et al), + ++ below 10**12 and 10**13 due to results of Pinch, + ++ and below 341550071728321 due to a result of Jaeschke. + ++ Specifically, this implementation does at least 10 pseudo prime + ++ tests and so the probability of error is \spad{< 4**(-10)}. + ++ The running time of this method is cubic in the length + ++ of the input n, that is \spad{O( (log n)**3 )}, for n<10**20. + ++ beyond that, the algorithm is quartic, \spad{O( (log n)**4 )}. + ++ Two improvements due to Davenport have been incorporated + ++ which catches some trivial strong pseudo-primes, such as + ++ [Jaeschke, 1991] 1377161253229053 * 413148375987157, which + ++ the original algorithm regards as prime + nextPrime: I -> I + ++ \spad{nextPrime(n)} returns the smallest prime strictly larger than n + prevPrime: I -> I + ++ \spad{prevPrime(n)} returns the largest prime strictly smaller than n + primes: (I,I) -> List I + ++ \spad{primes(a,b)} returns a list of all primes p with + ++ \spad{a <= p <= b} + == add + smallPrimes: List I := [2::I,3::I,5::I,7::I,11::I,13::I,17::I,19::I,_ + 23::I,29::I,31::I,37::I,41::I,43::I,47::I,_ + 53::I,59::I,61::I,67::I,71::I,73::I,79::I,_ + 83::I,89::I,97::I,101::I,103::I,107::I,109::I,_ + 113::I,127::I,131::I,137::I,139::I,149::I,151::I,_ + 157::I,163::I,167::I,173::I,179::I,181::I,191::I,_ + 193::I,197::I,199::I,211::I,223::I,227::I,229::I,_ + 233::I,239::I,241::I,251::I,257::I,263::I,269::I,_ + 271::I,277::I,281::I,283::I,293::I,307::I,311::I,_ + 313::I] + + productSmallPrimes := */smallPrimes + nextSmallPrime := 317::I + nextSmallPrimeSquared := nextSmallPrime**2 + two := 2::I + tenPowerTwenty:=(10::I)**20 + PomeranceList:= [25326001::I, 161304001::I, 960946321::I, 1157839381::I, + -- 3215031751::I, -- has a factor of 151 + 3697278427::I, 5764643587::I, 6770862367::I, + 14386156093::I, 15579919981::I, 18459366157::I, + 19887974881::I, 21276028621::I ]::(List I) + PomeranceLimit:=27716349961::I -- replaces (25*10**9) due to Pinch + PinchList:= [3215031751::I, 118670087467::I, 128282461501::I, 354864744877::I, + 546348519181::I, 602248359169::I, 669094855201::I ] + PinchLimit:= (10**12)::I + PinchList2:= [2152302898747::I, 3474749660383::I] + PinchLimit2:= (10**13)::I + JaeschkeLimit:=341550071728321::I + rootsMinus1:Set I := empty() + -- used to check whether we detect too many roots of -1 + count2Order:Vector NonNegativeInteger := new(1,0) + -- used to check whether we observe an element of maximal two-order + + primes(m, n) == + -- computes primes from m to n inclusive using prime? + l:List(I) := + m <= two => [two] + empty() + n < two or n < m => empty() + if even? m then m := m + 1 + ll:List(I) := [k::I for k in + convert(m)@Integer..convert(n)@Integer by 2 | prime?(k::I)] + reverse_! concat_!(ll, l) + + rabinProvesComposite : (I,I,I,I,NonNegativeInteger) -> Boolean + rabinProvesCompositeSmall : (I,I,I,I,NonNegativeInteger) -> Boolean + + + rabinProvesCompositeSmall(p,n,nm1,q,k) == + -- probability n prime is > 3/4 for each iteration + -- for most n this probability is much greater than 3/4 + t := powmod(p, q, n) + -- neither of these cases tells us anything +-- if not (one? t or t = nm1) then + if not ((t = 1) or t = nm1) then + for j in 1..k-1 repeat + oldt := t + t := mulmod(t, t, n) +-- one? t => return true + (t = 1) => return true + -- we have squared someting not -1 and got 1 + t = nm1 => + leave + not (t = nm1) => return true + false + + rabinProvesComposite(p,n,nm1,q,k) == + -- probability n prime is > 3/4 for each iteration + -- for most n this probability is much greater than 3/4 + t := powmod(p, q, n) + -- neither of these cases tells us anything + if t=nm1 then count2Order(1):=count2Order(1)+1 +-- if not (one? t or t = nm1) then + if not ((t = 1) or t = nm1) then + for j in 1..k-1 repeat + oldt := t + t := mulmod(t, t, n) +-- one? t => return true + (t = 1) => return true + -- we have squared someting not -1 and got 1 + t = nm1 => + rootsMinus1:=union(rootsMinus1,oldt) + count2Order(j+1):=count2Order(j+1)+1 + leave + not (t = nm1) => return true + # rootsMinus1 > 2 => true -- Z/nZ can't be a field + false + + prime? n == + n < two => false + n < nextSmallPrime => member?(n, smallPrimes) +-- not one? gcd(n, productSmallPrimes) => false + not (gcd(n, productSmallPrimes) = 1) => false + n < nextSmallPrimeSquared => true + + nm1 := n-1 + q := (nm1) quo two + for k in 1.. while not odd? q repeat q := q quo two + -- q = (n-1) quo 2**k for largest possible k + + n < JaeschkeLimit => + rabinProvesCompositeSmall(2::I,n,nm1,q,k) => return false + rabinProvesCompositeSmall(3::I,n,nm1,q,k) => return false + + n < PomeranceLimit => + rabinProvesCompositeSmall(5::I,n,nm1,q,k) => return false + member?(n,PomeranceList) => return false + true + + rabinProvesCompositeSmall(7::I,n,nm1,q,k) => return false + n < PinchLimit => + rabinProvesCompositeSmall(10::I,n,nm1,q,k) => return false + member?(n,PinchList) => return false + true + + rabinProvesCompositeSmall(5::I,n,nm1,q,k) => return false + rabinProvesCompositeSmall(11::I,n,nm1,q,k) => return false + n < PinchLimit2 => + member?(n,PinchList2) => return false + true + + rabinProvesCompositeSmall(13::I,n,nm1,q,k) => return false + rabinProvesCompositeSmall(17::I,n,nm1,q,k) => return false + true + + rootsMinus1:= empty() + count2Order := new(k,0) -- vector of k zeroes + + mn := minIndex smallPrimes + for i in mn+1..mn+10 repeat + rabinProvesComposite(smallPrimes i,n,nm1,q,k) => return false + import IntegerRoots(I) + q > 1 and perfectSquare?(3*n+1) => false + ((n9:=n rem (9::I))=1 or n9 = -1) and perfectSquare?(8*n+1) => false + -- Both previous tests from Damgard & Landrock + currPrime:=smallPrimes(mn+10) + probablySafe:=tenPowerTwenty + while count2Order(k) = 0 or n > probablySafe repeat + currPrime := nextPrime currPrime + probablySafe:=probablySafe*(100::I) + rabinProvesComposite(currPrime,n,nm1,q,k) => return false + true + + nextPrime n == + -- computes the first prime after n + n < two => two + if odd? n then n := n + two else n := n + 1 + while not prime? n repeat n := n + two + n + + prevPrime n == + -- computes the first prime before n + n < 3::I => error "no primes less than 2" + n = 3::I => two + if odd? n then n := n - two else n := n - 1 + while not prime? n repeat n := n - two + n + +@ +\section{package IROOT IntegerRoots} +<<package IROOT IntegerRoots>>= +)abbrev package IROOT IntegerRoots +++ Author: Michael Monagan +++ Date Created: November 1987 +++ Date Last Updated: +++ Basic Operations: +++ Related Domains: +++ Also See: +++ AMS Classifications: +++ Keywords: integer roots +++ Examples: +++ References: +++ Description: The \spadtype{IntegerRoots} package computes square roots and +++ nth roots of integers efficiently. +IntegerRoots(I:IntegerNumberSystem): Exports == Implementation where + NNI ==> NonNegativeInteger + + Exports ==> with + perfectNthPower?: (I, NNI) -> Boolean + ++ \spad{perfectNthPower?(n,r)} returns true if n is an \spad{r}th + ++ power and false otherwise + perfectNthRoot: (I,NNI) -> Union(I,"failed") + ++ \spad{perfectNthRoot(n,r)} returns the \spad{r}th root of n if n + ++ is an \spad{r}th power and returns "failed" otherwise + perfectNthRoot: I -> Record(base:I, exponent:NNI) + ++ \spad{perfectNthRoot(n)} returns \spad{[x,r]}, where \spad{n = x\^r} + ++ and r is the largest integer such that n is a perfect \spad{r}th power + approxNthRoot: (I,NNI) -> I + ++ \spad{approxRoot(n,r)} returns an approximation x + ++ to \spad{n**(1/r)} such that \spad{-1 < x - n**(1/r) < 1} + perfectSquare?: I -> Boolean + ++ \spad{perfectSquare?(n)} returns true if n is a perfect square + ++ and false otherwise + perfectSqrt: I -> Union(I,"failed") + ++ \spad{perfectSqrt(n)} returns the square root of n if n is a + ++ perfect square and returns "failed" otherwise + approxSqrt: I -> I + ++ \spad{approxSqrt(n)} returns an approximation x + ++ to \spad{sqrt(n)} such that \spad{-1 < x - sqrt(n) < 1}. + ++ Compute an approximation s to \spad{sqrt(n)} such that + ++ \spad{-1 < s - sqrt(n) < 1} + ++ A variable precision Newton iteration is used. + ++ The running time is \spad{O( log(n)**2 )}. + + Implementation ==> add + import IntegerPrimesPackage(I) + + resMod144: List I := [0::I,1::I,4::I,9::I,16::I,25::I,36::I,49::I,_ + 52::I,64::I,73::I,81::I,97::I,100::I,112::I,121::I] + two := 2::I + + + perfectSquare? a == (perfectSqrt a) case I + perfectNthPower?(b, n) == perfectNthRoot(b, n) case I + + perfectNthRoot n == -- complexity (log log n)**2 (log n)**2 + m:NNI +-- one? n or zero? n or n = -1 => [n, 1] + (n = 1) or zero? n or n = -1 => [n, 1] + e:NNI := 1 + p:NNI := 2 + while p::I <= length(n) + 1 repeat + for m in 0.. while (r := perfectNthRoot(n, p)) case I repeat + n := r::I + e := e * p ** m + p := convert(nextPrime(p::I))@Integer :: NNI + [n, e] + + approxNthRoot(a, n) == -- complexity (log log n) (log n)**2 + zero? n => error "invalid arguments" +-- one? n => a + (n = 1) => a + n=2 => approxSqrt a + negative? a => + odd? n => - approxNthRoot(-a, n) + 0 + zero? a => 0 +-- one? a => 1 + (a = 1) => 1 + -- quick check for case of large n + ((3*n) quo 2)::I >= (l := length a) => two + -- the initial approximation must be >= the root + y := max(two, shift(1, (n::I+l-1) quo (n::I))) + z:I := 1 + n1:= (n-1)::NNI + while z > 0 repeat + x := y + xn:= x**n1 + y := (n1*x*xn+a) quo (n*xn) + z := x-y + x + + perfectNthRoot(b, n) == + (r := approxNthRoot(b, n)) ** n = b => r + "failed" + + perfectSqrt a == + a < 0 or not member?(a rem (144::I), resMod144) => "failed" + (s := approxSqrt a) * s = a => s + "failed" + + approxSqrt a == + a < 1 => 0 + if (n := length a) > (100::I) then + -- variable precision newton iteration + n := n quo (4::I) + s := approxSqrt shift(a, -2 * n) + s := shift(s, n) + return ((1 + s + a quo s) quo two) + -- initial approximation for the root is within a factor of 2 + (new, old) := (shift(1, n quo two), 1) + while new ^= old repeat + (new, old) := ((1 + new + a quo new) quo two, new) + new + +@ +\section{package INTFACT IntegerFactorizationPackage} +<<package INTFACT IntegerFactorizationPackage>>= +)abbrev package INTFACT IntegerFactorizationPackage +++ This Package contains basic methods for integer factorization. +++ The factor operation employs trial division up to 10,000. It +++ then tests to see if n is a perfect power before using Pollards +++ rho method. Because Pollards method may fail, the result +++ of factor may contain composite factors. We should also employ +++ Lenstra's eliptic curve method. + +IntegerFactorizationPackage(I): Exports == Implementation where + I: IntegerNumberSystem + + B ==> Boolean + FF ==> Factored I + NNI ==> NonNegativeInteger + LMI ==> ListMultiDictionary I + FFE ==> Record(flg:Union("nil","sqfr","irred","prime"), + fctr:I, xpnt:Integer) + + Exports ==> with + factor : I -> FF + ++ factor(n) returns the full factorization of integer n + squareFree : I -> FF + ++ squareFree(n) returns the square free factorization of integer n + BasicMethod : I -> FF + ++ BasicMethod(n) returns the factorization + ++ of integer n by trial division + PollardSmallFactor: I -> Union(I,"failed") + ++ PollardSmallFactor(n) returns a factor + ++ of n or "failed" if no one is found + + Implementation ==> add + import IntegerRoots(I) + + BasicSieve: (I, I) -> FF + + squareFree(n:I):FF == + u:I + if n<0 then (m := -n; u := -1) + else (m := n; u := 1) + (m > 1) and ((v := perfectSqrt m) case I) => + for rec in (l := factorList(sv := squareFree(v::I))) repeat + rec.xpnt := 2 * rec.xpnt + makeFR(u * unit sv, l) + -- avoid using basic sieve when the lim is too big + lim := 1 + approxNthRoot(m,3) + lim > (100000::I) => makeFR(u, factorList factor m) + x := BasicSieve(m, lim) + y := +-- one?(m:= unit x) => factorList x + ((m:= unit x) = 1) => factorList x + (v := perfectSqrt m) case I => + concat_!(factorList x, ["sqfr",v,2]$FFE) + concat_!(factorList x, ["sqfr",m,1]$FFE) + makeFR(u, y) + + -- Pfun(y: I,n: I): I == (y**2 + 5) rem n + PollardSmallFactor(n:I):Union(I,"failed") == + -- Use the Brent variation + x0 := random()$I + m := 100::I + y := x0 rem n + r:I := 1 + q:I := 1 + G:I := 1 + until G > 1 repeat + x := y + for i in 1..convert(r)@Integer repeat + y := (y*y+5::I) rem n + q := (q*abs(x-y)) rem n + k:I := 0 + until (k>=r) or (G>1) repeat + ys := y + for i in 1..convert(min(m,r-k))@Integer repeat + y := (y*y+5::I) rem n + q := q*abs(x-y) rem n + G := gcd(q,n) + k := k+m + r := 2*r + if G=n then + until G>1 repeat + ys := (ys*ys+5::I) rem n + G := gcd(abs(x-ys),n) + G=n => "failed" + G + + BasicSieve(r, lim) == + l:List(I) := + [1::I,2::I,2::I,4::I,2::I,4::I,2::I,4::I,6::I,2::I,6::I] + concat_!(l, rest(l, 3)) + d := 2::I + n := r + ls := empty()$List(FFE) + for s in l repeat + d > lim => return makeFR(n, ls) + if n<d*d then + if n>1 then ls := concat_!(ls, ["prime",n,1]$FFE) + return makeFR(1, ls) + for m in 0.. while zero?(n rem d) repeat n := n quo d + if m>0 then ls := concat_!(ls, ["prime",d,convert m]$FFE) + d := d+s + + BasicMethod n == + u:I + if n<0 then (m := -n; u := -1) + else (m := n; u := 1) + x := BasicSieve(m, 1 + approxSqrt m) + makeFR(u, factorList x) + + factor m == + u:I + zero? m => 0 + if negative? m then (n := -m; u := -1) + else (n := m; u := 1) + b := BasicSieve(n, 10000::I) + flb := factorList b +-- one?(n := unit b) => makeFR(u, flb) + ((n := unit b) = 1) => makeFR(u, flb) + a:LMI := dictionary() -- numbers yet to be factored + b:LMI := dictionary() -- prime factors found + f:LMI := dictionary() -- number which could not be factored + insert_!(n, a) + while not empty? a repeat + n := inspect a; c := count(n, a); remove_!(n, a) + prime?(n)$IntegerPrimesPackage(I) => insert_!(n, b, c) + -- test for a perfect power + (s := perfectNthRoot n).exponent > 1 => + insert_!(s.base, a, c * s.exponent) + -- test for a difference of square + x:=approxSqrt n; + if (x**2<n) then x:=x+1 + (y:=perfectSqrt (x**2-n)) case I => + insert_!(x+y,a,c) + insert_!(x-y,a,c) + (d := PollardSmallFactor n) case I => + for m in 0.. while zero?(n rem d) repeat n := n quo d + insert_!(d, a, m * c) + if n > 1 then insert_!(n, a, c) + -- an elliptic curve factorization attempt should be made here + insert_!(n, f, c) + -- insert prime factors found + while not empty? b repeat + n := inspect b; c := count(n, b); remove_!(n, b) + flb := concat_!(flb, ["prime",n,convert c]$FFE) + -- insert non-prime factors found + while not empty? f repeat + n := inspect f; c := count(n, f); remove_!(n, f) + flb := concat_!(flb, ["nil",n,convert c]$FFE) + makeFR(u, flb) + +@ +\section{License} +<<license>>= +--Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd. +--All rights reserved. +-- +--Redistribution and use in source and binary forms, with or without +--modification, are permitted provided that the following conditions are +--met: +-- +-- - Redistributions of source code must retain the above copyright +-- notice, this list of conditions and the following disclaimer. +-- +-- - Redistributions in binary form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in +-- the documentation and/or other materials provided with the +-- distribution. +-- +-- - Neither the name of The Numerical ALgorithms Group Ltd. nor the +-- names of its contributors may be used to endorse or promote products +-- derived from this software without specific prior written permission. +-- +--THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +--IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +--TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +--PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +--OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +--EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +--PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +--PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +--LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +--NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +--SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +@ +<<*>>= +<<license>> + +<<package PRIMES IntegerPrimesPackage>> +<<package IROOT IntegerRoots>> +<<package INTFACT IntegerFactorizationPackage>> +@ +\eject +\begin{thebibliography}{99} +\bibitem{1} nothing +\end{thebibliography} +\end{document} |