Você está na página 1de 53

AKS test for primes

From Rosetta Code


The AKS algorithm (http://www.cse.iitk.ac.in/users/manindra/algebra
/primality_v6.pdf) for testing whether a number is prime is a
polynomial-time algorithm based on an elementary theorem about
Pascal triangles.
The theorem on which the test is based can be stated as follows:
a number p is prime if and only if all the coeicients of the
polynomial expansion of

AKS test
for primes
You are
encouraged
to solve this
task according to the
task description, using
any language you may
know.

(x 1)p (xp 1)
are divisible by p.
For example, trying p = 3:
(x 1)3 (x3 1) = (x3 3x2 + 3x 1) (x3 1) = 3x2 + 3x
And all the coeicients are divisible by 3 so 3 is prime.
Note:
This task is not the AKS primality test. It is an ineicient exponential time
algorithm discovered in the late 1600s and used as an introductory lemma
in the AKS derivation.
The task
1. Create a function/subroutine/method that given p generates the coeicients of the expanded
polynomial representation of (x 1)p.
2. Use the function to show here the polynomial expansions of (x 1)p for p in the range 0 to at
least 7, inclusive.
3. Use the previous function in creating another function that when given p returns whether p
is prime using the theorem.
4. Use your test to generate a list of all primes under 35.
5. As a stretch goal, generate all primes under 50 (Needs greater than 31 bit integers).
References
Agrawal-Kayal-Saxena (AKS) primality test (https://en.wikipedia.org/wiki/AKS_primality_test)
(Wikipedia)
Fool-Proof Test for Primes (http://www.youtube.com/watch?v=HvMSRWTE2mI) Numberphile (Video). The accuracy of this video is disputed -- at best it is an
oversimplication.

Contents
1 ALGOL 68
2 AutoHotkey

1 of 53

3 Bracmat
4C
5 C#
6 Clojure
7 CoeeScript
8 Common Lisp
9D
10 EchoLisp
11 Erlang
12 Fortran
13 Go
14 FreeBASIC
15 Haskell
16 J
17 Java
18 JavaScript
19 jq
20 Julia
21 Maple
22 Mathematica / Wolfram Language
23 Oforth
24 PARI/GP
25 Pascal
26 Perl
26.1 Real AKS
27 Perl 6
28 Phix
29 PicoLisp
30 Prolog
30.1 Prolog(ue)
30.2 Pascal Triangle Generator
30.3 Solutions
31 PureBasic
32 Python
32.1 Python: Output formatted for wiki
33 R
34 Racket
35 REXX
35.1 version 1
35.2 version 2
36 Ruby
37 Rust
38 Scala
39 Scilab
40 Seed7
41 Sidef
42 Swift
43 Tcl
44 uBasic/4tH
45 zkl

ALGOL 68

2 of 53

The code below uses Algol 68 Genie which provides arbitrary precision arithmetic for LONG
LONG modes.

BEGIN
COMMENT
Mathematical preliminaries.
First note that the homogeneous polynomial (a+b)^n is symmetrical
(to see this just swap the variables a and b). Therefore its
coefficients need be calculated only to that of (ab)^{n/2} for even
n or (ab)^{(n-1)/2} for odd n.
Second, the coefficients are the binomial coefficients C(n,k) where
the coefficient of a^k b^(n-k) is C(n,k) = n! / k! (k-1)!. This
leads to an immediate and relatively efficient implementation for
which we do not need to compute n! before dividing by k! and (k-1)!
but, rather cancel common factors as we go along. Further, the
well-known symmetry identity C(n,k) = C(n, n-k) allows a
significant reduction in computational effort.
Third, (x-1)^n is the value of (a + b)^n when a=x and b = -1. The
powers of -1 alternate between +1 and -1 so we may as well compute
(x+1)^n and negate every other coefficient when printing.
COMMENT
PR precision=300 PR
MODE LLI = LONG LONG INT;
CO For brevity CO
PROC choose = (INT n, k) LLI :
BEGIN
LLI result := 1;
INT sym k := (k >= n%2 | n-k | k);
CO Use symmetry CO
IF sym k > 0 THEN
FOR i FROM 0 TO sym k-1
DO
result TIMESAB (n-i);
result OVERAB (i+1)
OD
FI;
result
END;
PROC coefficients = (INT n) [] LLI :
BEGIN
[0:n] LLI a;
FOR i FROM 0 TO n%2
DO
a[i] := a[n-i] := choose (n, i)
CO Use symmetry CO
OD;
a
END;
COMMENT
First print the polynomials (x-1)^n, remembering to alternate signs
and to tidy up the constant term, the x^1 term and the x^n term.
This means we must treat (x-1)^0 and (x-1)^1 specially
COMMENT
FOR n FROM 0 TO 7
DO
[0:n] LLI a := coefficients (n);
printf (($"(x-1)^", g(0), " = "$, n));
CASE n+1 IN
printf (($g(0)l$, a[0])),
printf (($"x - ", g(0)l$, a[1]))
OUT
printf (($"x^", g(0)$, n));
FOR i TO n-2
DO
printf (($xax, g(0), "x^", g(0)$, (ODD i | "-" | "+"), a[i], n-i))
OD;
printf (($xax, g(0), "x"$, (ODD (n-1) | "-" | "+"), a[n-1]));
printf (($xaxg(0)l$, (ODD n | "-" | "+"), a[n]))
ESAC
OD;
COMMENT
Finally, for the "AKS" portion of the task, the sign of the
coefficient has no effect on its divisibility by p so, once again,
we may as well use the positive coefficients. Symmetry clearly

3 of 53

reduces the necessary number of tests by a factor of two.


COMMENT
PROC is prime = (INT n) BOOL :
BEGIN
BOOL prime := TRUE;
FOR i FROM 1 TO n%2 WHILE prime DO prime := choose (n, i) MOD n = 0 OD;
prime
END;
print ("Primes < 50 are ");
FOR n FROM 2 TO 50 DO (is prime (n) | printf (($g(0)x$, n)) ) OD;
print (newline);
print ("And just to show off, the primes between 900 and 1000 are ");
FOR n FROM 900 TO 1000 DO IF is prime (n) THEN printf (($g(0)x$, n)) FI OD;
print (newline)
END

Output:
(x-1)^0 = 1
(x-1)^1 = x - 1
(x-1)^2 = x^2 - 2x + 1
(x-1)^3 = x^3 - 3x^2 + 3x - 1
(x-1)^4 = x^4 - 4x^3 + 6x^2 - 4x + 1
(x-1)^5 = x^5 - 5x^4 + 10x^3 - 10x^2 + 5x - 1
(x-1)^6 = x^6 - 6x^5 + 15x^4 - 20x^3 + 15x^2 - 6x + 1
(x-1)^7 = x^7 - 7x^6 + 21x^5 - 35x^4 + 35x^3 - 21x^2 + 7x - 1
Primes < 50 are 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47
And just to show off, the primes between 900 and 1000 are 907 911 919 929 937 941 947 953 967 971 977 983 991 997

AutoHotkey
Works with: AutoHotkey L
; 1. Create a function/subroutine/method that given p generates the coefficients of the expanded polynomial representation of (x-1)^p.
; Function modified from http://rosettacode.org/wiki/Pascal%27s_triangle#AutoHotkey
pascalstriangle(n=8) ; n rows of Pascal's triangle
{
p := Object(), z:=Object()
Loop, % n
Loop, % row := A_Index
col := A_Index
, p[row, col] := row = 1 and col = 1
? 1
: (p[row-1, col-1] = "" ; math operations on blanks return blanks; I want to assume zero
? 0
: p[row-1, col-1])
- (p[row-1, col] = ""
? 0
: p[row-1, col])
Return p
}
; 2. Use the function to show here the polynomial expansions of p for p in the range 0 to at least 7, inclusive.
For k, v in pascalstriangle()
{
s .= "`n(x-1)^" k-1 . "="
For k, w in v
s .= "+" w "x^" k-1
}
s := RegExReplace(s, "\+-", "-")
s := RegExReplace(s, "x\^0", "")
s := RegExReplace(s, "x\^1", "x")
Msgbox % clipboard := s
; 3. Use the previous function in creating another function that when given p returns whether p is prime using the AKS test.
aks(n)
{
isnotprime := False
For k, v in pascalstriangle(n+1)[n+1]
(k != 1 and k != n+1) ? isnotprime |= !(v // n = v / n) ; if any is not divisible, returns true

4 of 53

Return !isnotprime
}
; 4. Use your AKS test to generate a list of all primes under 35.
i := 49
p := pascalstriangle(i+1)
Loop, % i
{
n := A_Index
isnotprime := False
For k, v in p[n+1]
(k != 1 and k != n+1) ? isnotprime |= !(v // n = v / n) ; if any is not divisible, returns true
t .= isnotprime ? "" : A_Index " "
}
Msgbox % t
Return

Output:
(x-1)^0=+1
(x-1)^1=-1+1x
(x-1)^2=+1-2x+1x^2
(x-1)^3=-1+3x-3x^2+1x^3
(x-1)^4=+1-4x+6x^2-4x^3+1x^4
(x-1)^5=-1+5x-10x^2+10x^3-5x^4+1x^5
(x-1)^6=+1-6x+15x^2-20x^3+15x^4-6x^5+1x^6
(x-1)^7=-1+7x-21x^2+35x^3-35x^4+21x^5-7x^6+1x^7
1 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47

Function maxes out at i = 61 as AutoHotkey supports up to 64-bit signed integers.

Bracmat
Bracmat automatically normalizes symbolic expressions with the algebraic binary operators +, *, ^
and \L (logartithm). It can dierentiate such expressions using the \D binary operator. (These
operators were implemented in Bracmat before all other operators!). Some algebraic values can
exist in two evaluated forms. The equivalent x*(a+b) and x*a+x*b are both considered "normal", but
x*(a+b)+-1 is not, and therefore expanded to -1+a*x+b*x. This is used in the forceExpansion function to
convert e.g. x*(a+b) to x*a+x*b.
The primality test uses a pattern that looks for a fractional factor. If such a factor is found, the
test fails. Otherwise it succeeds.
( (forceExpansion=.1+!arg+-1)
& (expandx-1P=.forceExpansion$((x+-1)^!arg))
& ( isPrime
=
.
forceExpansion
$ (!arg^-1*(expandx-1P$!arg+-1*(x^!arg+-1)))
: ?+/*?+?
& ~`
|
)
& out$"Polynomial representations of (x-1)^p for p <= 7 :"
& -1:?n
&
whl
' ( 1+!n:~>7:?n
& out$(str$("n=" !n ":") expandx-1P$!n)
)
& 1:?n
& :?primes
&
whl
' ( 1+!n:~>50:?n
& ( isPrime$!n&!primes !n:?primes
|

5 of 53

)
)
& out$"2 <= Primes <= 50:"
& out$!primes
);

Output:
Polynomial representations of (x-1)^p for p <= 7 :
n=0: 1
n=1: -1+x
n=2: 1+-2*x+x^2
n=3: -1+3*x+-3*x^2+x^3
n=4: 1+-4*x+6*x^2+-4*x^3+x^4
n=5: -1+5*x+-10*x^2+10*x^3+-5*x^4+x^5
n=6: 1+-6*x+15*x^2+-20*x^3+15*x^4+-6*x^5+x^6
n=7:
-1
+ 7*x
+ -21*x^2
+ 35*x^3
+ -35*x^4
+ 21*x^5
+ -7*x^6
+ x^7
2 <= Primes <= 50:
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47

The AKS test kan be written more concisely than the task describes. This prints the primes
between 980 and 1000:
( out$"Primes between 980 and 1000, short version:"
& 980:?n
&
whl
' ( !n+1:<1000:?n
& ( 1+!n^-1*((x+-1)^!n+-1*(x^!n+-1))+-1:?+/*?+?
| out$!n
)
)
);

Output:
Primes between 980 and 1000, short version:
983
991
997

C
#include <stdio.h>
#include <stdlib.h>
long long c[100];
void coef(int n)
{
int i, j;
if (n < 0 || n > 63) abort(); // gracefully deal with range issue
for (c[i=0] = 1; i < n; c[0] = -c[0], i++)
for (c[1 + (j=i)] = 1; j > 0; j--)
c[j] = c[j-1] - c[j];
}

6 of 53

int is_prime(int n)
{
int i;
coef(n);
c[0] += 1, c[i=n] -= 1;
while (i-- && !(c[i] % n));
return i < 0;
}
void show(int n)
{
do printf("%+lldx^%d", c[n], n); while (n--);
}
int main(void)
{
int n;
for (n = 0; n < 10; n++) {
coef(n);
printf("(x-1)^%d = ", n);
show(n);
putchar('\n');
}
printf("\nprimes (never mind the 1):");
for (n = 1; n <= 63; n++)
if (is_prime(n))
printf(" %d", n);
putchar('\n');
return 0;
}

The ugly output:


(x-1)^0
(x-1)^1
(x-1)^2
(x-1)^3
(x-1)^4
(x-1)^5
(x-1)^6
(x-1)^7
(x-1)^8
(x-1)^9

=
=
=
=
=
=
=
=
=
=

+1x^0
+1x^1-1x^0
+1x^2-2x^1+1x^0
+1x^3-3x^2+3x^1-1x^0
+1x^4-4x^3+6x^2-4x^1+1x^0
+1x^5-5x^4+10x^3-10x^2+5x^1-1x^0
+1x^6-6x^5+15x^4-20x^3+15x^2-6x^1+1x^0
+1x^7-7x^6+21x^5-35x^4+35x^3-21x^2+7x^1-1x^0
+1x^8-8x^7+28x^6-56x^5+70x^4-56x^3+28x^2-8x^1+1x^0
+1x^9-9x^8+36x^7-84x^6+126x^5-126x^4+84x^3-36x^2+9x^1-1x^0

primes (never mind the 1): 1 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61

C#
Translation of: C
using System;
public class AksTest
{
static long[] c = new long[100];
static void Main(string[] args)
{
for (int n = 0; n < 10; n++) {
coef(n);
Console.Write("(x-1)^" + n + " = ");
show(n);
Console.WriteLine("");
}
Console.Write("Primes:");

7 of 53

for (int n = 1; n <= 63; n++)


if (is_prime(n))
Console.Write(n + " ");
Console.WriteLine('\n');
Console.ReadLine();
}
static void coef(int n)
{
int i, j;
if (n < 0 || n > 63) System.Environment.Exit(0);// gracefully deal with range issue
for (c[i = 0] = 1L; i < n; c[0] = -c[0], i++)
for (c[1 + (j = i)] = 1L; j > 0; j--)
c[j] = c[j - 1] - c[j];
}
static bool is_prime(int n)
{
int i;
coef(n);
c[0] += 1;
c[i = n] -= 1;
while (i-- != 0 && (c[i] % n) == 0) ;
return i < 0;
}
static void show(int n)
{
do {
Console.Write("+" + c[n] + "x^" + n);
}while (n-- != 0);
}
}

Clojure
The *' function is an arbitrary precision multiplication.
(defn c
"kth coefficient of (x - 1)^n"
[n k]
(/ (apply *' (range n (- n k) -1))
(apply *' (range k 0 -1))
(if (and (even? k) (< k n)) -1 1)))
(defn cs
"coefficient series for (x - 1)^n, k=[0..n]"
[n]
(map #(c n %) (range (inc n))))
(defn aks? [p] (->> (cs p) rest butlast (every? #(-> % (mod p) zero?))))
(println "coefficient series n (k[0] .. k[n])")
(doseq [n (range 10)] (println n (cs n)))
(println)
(println "primes < 50 per AKS:" (filter aks? (range 2 50)))

Output:
coefficient series n (k[0] .. k[n])
0 (1)
1 (-1 1)
2 (-1 2 1)

8 of 53

3
4
5
6
7
8
9

(-1
(-1
(-1
(-1
(-1
(-1
(-1

3
4
5
6
7
8
9

-3 1)
-6 4 1)
-10 10 -5 1)
-15 20 -15 6 1)
-21 35 -35 21 -7 1)
-28 56 -70 56 -28 8 1)
-36 84 -126 126 -84 36 -9 1)

primes < 50 per AKS: (2 3 5 7 11 13 17 19 23 29 31 37 41 43 47)

CoeeScript
pascal = () ->
a = []
return () ->
if a.length is 0 then a = [1]
else
b = (a[i] + a[i+1] for i in [0 ... a.length - 1])
a = [1].concat(b).concat [1]
show = (a) ->
show_x = (e)
switch e
when
when
else

->
0 then ""
1 then "x"
"x^#{e}"

degree = a.length - 1
str = "(x - 1)^#{degree} ="
sgn = 1
for i in [0...a.length]
str += ' ' + (if sgn > 0 then "+" else "-") + ' ' + a[i] + show_x(degree - i)
sgn = -sgn
return str
primerow = (row) ->
degree = row.length - 1
row[1 ... degree].every (x) -> x % degree is 0
p = pascal()
console.log show p() for i in [0..7]
p = pascal()
p(); p() # skip 0 and 1
primes = (i+1 for i in [1..49] when primerow p())
console.log ""
console.log "The primes upto 50 are: #{primes}"

Output:
(x
(x
(x
(x
(x
(x
(x
(x

1)^0
1)^1
1)^2
1)^3
1)^4
1)^5
1)^6
1)^7

=
=
=
=
=
=
=
=

+
+
+
+
+
+
+
+

1
1x 1x^2
1x^3
1x^4
1x^5
1x^6
1x^7

1
-

2x +
3x^2
4x^3
5x^4
6x^5
7x^6

1
+
+
+
+
+

3x - 1
6x^2 - 4x + 1
10x^3 - 10x^2 + 5x - 1
15x^4 - 20x^3 + 15x^2 - 6x + 1
21x^5 - 35x^4 + 35x^3 - 21x^2 + 7x - 1

The primes upto 50 are: 2,3,5,7,11,13,17,19,23,29,31,37,41,43,47

Common Lisp
(defun coefficients (p)

9 of 53

(cond
((= p 0) #(1))
(t (loop for i from 1 upto p
for result = #(1 -1) then (map 'vector
#'(concatenate 'vector result #(0))
(concatenate 'vector #(0) result))
finally (return result)))))
(defun primep (p)
(cond
((< p 2) nil)
(t (let ((c (coefficients p)))
(decf (elt c 0))
(loop for i from 0 upto (/ (length c) 2)
for x across c
never (/= (mod x p) 0))))))
(defun main ()
(format t "# p: (x-1)^p for small p:~%")
(loop for p from 0 upto 7
do (format t "~D: " p)
(loop for i from 0
for x across (reverse (coefficients p))
do (when (>= x 0) (format t "+"))
(format t "~D" x)
(if (> i 0)
(format t "X^~D " i)
(format t " ")))
(format t "~%"))
(loop for i from 0 to 50
do (when (primep i) (format t "~D " i)))
(format t "~%"))

Output:
# p: (x-1)^p for small p:
0: +1
1: -1 +1X^1
2: +1 -2X^1 +1X^2
3: -1 +3X^1 -3X^2 +1X^3
4: +1 -4X^1 +6X^2 -4X^3 +1X^4
5: -1 +5X^1 -10X^2 +10X^3 -5X^4 +1X^5
6: +1 -6X^1 +15X^2 -20X^3 +15X^4 -6X^5 +1X^6
7: -1 +7X^1 -21X^2 +35X^3 -35X^4 +21X^5 -7X^6 +1X^7
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47

D
Translation of: Python
import std.stdio, std.range, std.algorithm, std.string, std.bigint;
BigInt[] expandX1(in uint p) pure /*nothrow*/ {
if (p == 0) return [1.BigInt];
typeof(return) r = [1.BigInt, BigInt(-1)];
foreach (immutable _; 1 .. p)
r = zip(r~0.BigInt, 0.BigInt~r).map!(xy => xy[0]-xy[1]).array;
r.reverse();
return r;
}
bool aksTest(in uint p) pure /*nothrow*/ {
if (p < 2) return false;
auto ex = p.expandX1;
ex[0]++;
return !ex[0 .. $ - 1].any!(mult => mult % p);
}

10 of 53

void main() {
"# p: (x-1)^p for small p:".writeln;
foreach (immutable p; 0 .. 12)
writefln("%3d: %s", p, p.expandX1.zip(iota(p + 1)).retro
.map!q{"%+dx^%d ".format(a[])}.join.replace("x^0", "")
.replace("^1 ", " ").replace("+", "+ ")
.replace("-", "- ").replace(" 1x", " x")[2 .. $]);
"\nSmall primes using the AKS test:".writeln;
101.iota.filter!aksTest.writeln;
}

Output:
# p:
0:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:

(x-1)^p for small p:


1
x - 1
x^2 - 2x + 1
x^3 - 3x^2 + 3x - 1
x^4 - 4x^3 + 6x^2 - 4x + 1
x^5 - 5x^4 + 10x^3 - 10x^2 + 5x - 1
x^6 - 6x^5 + 15x^4 - 20x^3 + 15x^2 - 6x + 1
x^7 - 7x^6 + 21x^5 - 35x^4 + 35x^3 - 21x^2 + 7x - 1
x^8 - 8x^7 + 28x^6 - 56x^5 + 70x^4 - 56x^3 + 28x^2 - 8x + 1
x^9 - 9x^8 + 36x^7 - 84x^6 + 126x^5 - 126x^4 + 84x^3 - 36x^2 + 9x - 1
x^10 - 10x^9 + 45x^8 - 120x^7 + 210x^6 - 252x^5 + 210x^4 - 120x^3 + 45x^2 - 10x + 1
x^11 - 11x^10 + 55x^9 - 165x^8 + 330x^7 - 462x^6 + 462x^5 - 330x^4 + 165x^3 - 55x^2 + 11x - 1

Small primes using the AKS test:


[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]

EchoLisp
We use the math.lib library and the poly functions to compute and display the required
polynomials. A polynomial P(x) = a0 +a1*x + .. an*x^n is a list of coeicients (a0 a1 .... an).

(lib 'math.lib)
;; 1 - x^p : P = (1 0 0 0 ... 0 -1)
(define (mono p) (append (list 1) (make-list (1- p) 0) (list -1)))
;; compute (x-1)^p , p >= 1
(define (aks-poly p)
(poly-pow (list -1 1) p))
;;
(define (show-them n)
(for ((p (in-range 1 n)))
(writeln 'p p (poly->string 'x (aks-poly p)))))
;; aks-test
;; P = (x-1)^p + 1 - x^p
(define (aks-test p)
(let ((P (poly-add (mono p) (aks-poly p)))
(test (lambda(a) (zero? (modulo a p))))) ;; p divides a[i] ?
(apply and (map test P)))) ;; returns #t if true for all a[i]

Output:

(show-them 13)
p
1
x -1
p
2
x^2 -2x +1
p
3
x^3 -3x^2 +3x -1
p
4
x^4 -4x^3 +6x^2 -4x +1
p
5
x^5 -5x^4 +10x^3 -10x^2 +5x -1

11 of 53

p
p
p
p
p
p
p

6
7
8
9
10
11
12

x^6 -6x^5 +15x^4 -20x^3 +15x^2 -6x +1


x^7 -7x^6 +21x^5 -35x^4 +35x^3 -21x^2 +7x -1
x^8 -8x^7 +28x^6 -56x^5 +70x^4 -56x^3 +28x^2 -8x +1
x^9 -9x^8 +36x^7 -84x^6 +126x^5 -126x^4 +84x^3 -36x^2 +9x -1
x^10 -10x^9 +45x^8 -120x^7 +210x^6 -252x^5 +210x^4 -120x^3 +45x^2 -10x +1
x^11 -11x^10 +55x^9 -165x^8 +330x^7 -462x^6 +462x^5 -330x^4 +165x^3 -55x^2 +11x -1
x^12 -12x^11 +66x^10 -220x^9 +495x^8 -792x^7 +924x^6 -792x^5 +495x^4 -220x^3 +66x^2 -12x +1

(lib 'bigint)
Lib: bigint.lib loaded.
(for ((p (in-range 2 100)))
(when (aks-test p) (write p)))

2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97

Erlang
Translation of: CoeeScript
The Erlang io module can print out lists of characters with any level of nesting as a at string.
(e.g. ["Er", ["la", ["n"]], "g"] prints as "Erlang") which is useful when constructing the strings to
print out for the binomial expansions. The program also shows how lazy lists can be implemented
in Erlang.
#! /usr/bin/escript
-import(lists, [all/2, seq/2, zip/2]).
iterate(F, X) -> fun() -> [X | iterate(F, F(X))] end.
take(0, _lazy) -> [];
take(N, Lazy) ->
[Value | Next] = Lazy(),
[Value | take(N-1, Next)].

pascal() -> iterate(fun (Row) -> [1 | sum_adj(Row)] end, [1]).


sum_adj([_] = L) -> L;
sum_adj([A, B | _] = Row) -> [A+B | sum_adj(tl(Row))].

show_binomial(Row) ->
Degree = length(Row) - 1,
["(x - 1)^", integer_to_list(Degree), " =", binomial_rhs(Row, 1, Degree)].
show_x(0) -> "";
show_x(1) -> "x";
show_x(N) -> [$x, $^ | integer_to_list(N)].
binomial_rhs([], _, _) -> [];
binomial_rhs([Coef | Coefs], Sgn, Exp) ->
SignChar = if Sgn > 0 -> $+; true -> $- end,
[$ , SignChar, $ , integer_to_list(Coef), show_x(Exp) | binomial_rhs(Coefs, -Sgn, Exp-1)].

primerow(Row, N) -> all(fun (Coef) -> (Coef =:= 1) or (Coef rem N =:= 0) end, Row).
main(_) ->
[io:format("~s~n", [show_binomial(Row)]) || Row <- take(8, pascal())],
io:format("~nThe primes upto 50: ~p~n",
[[N || {Row, N} <- zip(tl(tl(take(51, pascal()))), seq(2, 50)),
primerow(Row, N)]]).

Output:

12 of 53

(x
(x
(x
(x
(x
(x
(x
(x

1)^0
1)^1
1)^2
1)^3
1)^4
1)^5
1)^6
1)^7

=
=
=
=
=
=
=
=

+
+
+
+
+
+
+
+

1
1x 1x^2
1x^3
1x^4
1x^5
1x^6
1x^7

1
-

2x +
3x^2
4x^3
5x^4
6x^5
7x^6

1
+
+
+
+
+

3x - 1
6x^2 - 4x + 1
10x^3 - 10x^2 + 5x - 1
15x^4 - 20x^3 + 15x^2 - 6x + 1
21x^5 - 35x^4 + 35x^3 - 21x^2 + 7x - 1

The primes upto 50: [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47]

Fortran
program aks
implicit none
! Coefficients of polynomial expansion
integer(kind=16), dimension(:), allocatable :: coeffs
integer(kind=16) :: n
! Character variable for I/O
character(len=40) :: tmp
! Point #2
do n = 0, 7
write(tmp, *) n
call polynomial_expansion(n, coeffs)
write(*, fmt='(A)', advance='no') '(x - 1)^'//trim(adjustl(tmp))//' ='
call print_polynom(coeffs)
end do
! Point #4
do n = 2, 35
if (is_prime(n)) write(*, '(I4)', advance='no') n
end do
write(*, *)
! Point #5
do n = 2, 124
if (is_prime(n)) write(*, '(I4)', advance='no') n
end do
write(*, *)
if (allocated(coeffs)) deallocate(coeffs)
contains
! Calculate coefficients of (x - 1)^n using binomial theorem
subroutine polynomial_expansion(n, coeffs)
integer(kind=16), intent(in) :: n
integer(kind=16), dimension(:), allocatable, intent(out) :: coeffs
integer(kind=16) :: i, j
if (allocated(coeffs)) deallocate(coeffs)
allocate(coeffs(n + 1))
do i = 1, n + 1
coeffs(i) = binomial(n, i - 1)*(-1)**(n - i - 1)
end do
end subroutine
! Calculate binomial coefficient using recurrent relation, as calculation
! using factorial overflows too quickly.
function binomial(n, k) result (res)
integer(kind=16), intent(in) :: n, k
integer(kind=16) :: res
integer(kind=16) :: i
if (k == 0) then
res = 1
return
end if

13 of 53

res = 1
do i = 0, k - 1
res = res*(n - i)/(i + 1)
end do
end function
! Outputs polynomial with given coefficients
subroutine print_polynom(coeffs)
integer(kind=16), dimension(:), allocatable, intent(in) :: coeffs
integer(kind=4) :: i, p
character(len=40) :: cbuf, pbuf
logical(kind=1) :: non_zero
if (.not. allocated(coeffs)) return
non_zero = .false.
do i = 1, size(coeffs)
if (coeffs(i) .eq. 0) cycle
p = i - 1
write(cbuf, '(I40)') abs(coeffs(i))
write(pbuf, '(I40)') p
if (non_zero) then
if (coeffs(i) .gt. 0)
write(*, fmt='(A)',
else
write(*, fmt='(A)',
endif
else
if (coeffs(i) .gt. 0)
write(*, fmt='(A)',
else
write(*, fmt='(A)',
endif
endif

then
advance='no') ' + '
advance='no') ' - '

then
advance='no') '

'

advance='no') ' - '

if (p .eq. 0) then
write(*, fmt='(A)', advance='no') trim(adjustl(cbuf))
elseif (p .eq. 1) then
if (coeffs(i) .eq. 1) then
write(*, fmt='(A)', advance='no') 'x'
else
write(*, fmt='(A)', advance='no') trim(adjustl(cbuf))//'x'
end if
else
if (coeffs(i) .eq. 1) then
write(*, fmt='(A)', advance='no') 'x^'//trim(adjustl(pbuf))
else
write(*, fmt='(A)', advance='no') &
trim(adjustl(cbuf))//'x^'//trim(adjustl(pbuf))
end if
end if
non_zero = .true.
end do
write(*, *)
end subroutine
! Test if n is prime using AKS test. Point #3.
function is_prime(n) result (res)
integer(kind=16), intent (in) :: n
logical(kind=1) :: res
integer(kind=16), dimension(:), allocatable :: coeffs
integer(kind=16) :: i
call polynomial_expansion(n, coeffs)
coeffs(1) = coeffs(1) + 1
coeffs(n + 1) = coeffs(n + 1) - 1
res = .true.
do i = 1, n + 1
res = res .and. (mod(coeffs(i), n) == 0)
end do

14 of 53

if (allocated(coeffs)) deallocate(coeffs)
end function
end program aks

Output:
(x
(x
(x
(x
(x
(x
(x
(x

2
2

1)^0
1)^1
1)^2
1)^3
1)^4
1)^5
1)^6
1)^7
3
3

=
=
=
=
=
=
=
=

1
- 1 +
1 - 1 +
1 - 1 +
1 - 1 +
5
7
5
7

x
2x
3x
4x
5x
6x
7x
11
11

+ x^2
- 3x^2 + x^3
+ 6x^2 - 4x^3 +
- 10x^2 + 10x^3
+ 15x^2 - 20x^3
- 21x^2 + 35x^3
13 17 19 23
13 17 19 23

x^4
- 5x^4 + x^5
+ 15x^4 - 6x^5 + x^6
- 35x^4 + 21x^5 - 7x^6 + x^7
29 31
29 31 37 41 43 47 53 59

Go
package main
import "fmt"
func bc(p int) []int64 {
c := make([]int64, p+1)
r := int64(1)
for i, half := 0, p/2; i <= half; i++ {
c[i] = r
c[p-i] = r
r = r * int64(p-i) / int64(i+1)
}
for i := p - 1; i >= 0; i -= 2 {
c[i] = -c[i]
}
return c
}
func main() {
for p := 0; p <= 7; p++ {
fmt.Printf("%d: %s\n", p, pp(bc(p)))
}
for p := 2; p < 50; p++ {
if aks(p) {
fmt.Print(p, " ")
}
}
fmt.Println()
}
var e = []rune("")
func pp(c []int64) (s string) {
if len(c) == 1 {
return fmt.Sprint(c[0])
}
p := len(c) - 1
if c[p] != 1 {
s = fmt.Sprint(c[p])
}
for i := p; i > 0; i-- {
s += "x"
if i != 1 {
s += string(e[i-2])
}
if d := c[i-1]; d < 0 {
s += fmt.Sprintf(" - %d", -d)
} else {

15 of 53

61

67

71

73

79

83

89

97 101 103 107 109 113

s += fmt.Sprintf(" + %d", d)
}
}
return
}
func aks(p int) bool {
c := bc(p)
c[p]-c[0]++
for _, d := range c {
if d%int64(p) != 0 {
return false
}
}
return true
}

Output:
0:
1:
2:
3:
4:
5:
6:
7:
2 3

1
x - 1
x - 2x + 1
x - 3x + 3x - 1
x - 4x + 6x - 4x + 1
x - 5x + 10x - 10x +
x - 6x + 15x - 20x +
x - 7x + 21x - 35x +
5 7 11 13 17 19 23 29 31

5x - 1
15x - 6x + 1
35x - 21x + 7x - 1
37 41 43 47

FreeBASIC
'METHOD -- Use the Pascal triangle to retrieve the coefficients
'UPPER LIMIT OF FREEBASIC ULONGINT GETS PRIMES UP TO 70
Sub string_split(s_in As String,char As String,result() As String)
Dim As String s=s_in,var1,var2
Dim As Integer n,pst
#macro split(stri,char,var1,var2)
pst=Instr(stri,char)
var1="":var2=""
If pst<>0 Then
var1=Mid(stri,1,pst-1)
var2=Mid(stri,pst+1)
Else
var1=stri
End If
Redim Preserve result(1 To 1+n-((Len(var1)>0)+(Len(var2)>0)))
result(n+1)=var1
#endmacro
Do
split(s,char,var1,var2):n=n+1:s=var2
Loop Until var2=""
Redim Preserve result(1 To Ubound(result)-1)
End Sub
'Get Pascal triangle components
Function pasc(n As Integer,flag As Integer=0) As String
n+=1
Dim As Ulongint V(n):V(1)=1ul
Dim As String s,sign
For r As Integer= 2 To n
s=""
For i As Integer = r To 1 Step -1
V(i) += V(i-1)
If i Mod 2=1 Then sign="" Else sign="-"
s+=sign+Str(V(i))+","
Next i
Next r
If flag Then 'formatted output
Dim As String i,i2,i3,g
Redim As String a(0)

16 of 53

string_split(s,",",a())
For n1 As Integer=1 To Ubound(a)
If Left(a(n1),1)="-" Then sign="" Else sign="+"
If n1=Ubound(a) Then i2="" Else i2=a(n1)
If n1=2 Then i3="x" Else i3="x^"+Str(n1-1)
If n1=1 Then i="":sign=" " Else i=i3
g+=sign+i2+i+" "
Next n1
g="(x-1)^"+Str(n-1)+" = "+g
Return g
End If
Return s
End Function
Function isprime(num As Integer) As Integer
Redim As String a(0)
string_split(pasc(num),",",a())
For n As Integer=Lbound(a)+1 To Ubound(a)-1
If (Valulng(Ltrim(a(n),"-"))) Mod num<>0 Then Return 0
Next n
Return -1
End Function
'====================================
'Formatted output
For n As Integer=1 To 9
Print pasc(n,1)
Next n
Print
'Limit of Freebasic Ulongint sets about 70 max
Print "Primes up to 70:"
For n As Integer=2 To 70
If isprime(n) Then Print n;
Next n
Sleep

Output:
(x-1)^1
(x-1)^2
(x-1)^3
(x-1)^4
(x-1)^5
(x-1)^6
(x-1)^7
(x-1)^8
(x-1)^9

=
=
=
=
=
=
=
=
=

-1 +x
1 -2x +x^2
-1 +3x -3x^2 +x^3
1 -4x +6x^2 -4x^3 +x^4
-1 +5x -10x^2 +10x^3 -5x^4 +x^5
1 -6x +15x^2 -20x^3 +15x^4 -6x^5 +x^6
-1 +7x -21x^2 +35x^3 -35x^4 +21x^5 -7x^6 +x^7
1 -8x +28x^2 -56x^3 +70x^4 -56x^5 +28x^6 -8x^7 +x^8
-1 +9x -36x^2 +84x^3 -126x^4 +126x^5 -84x^6 +36x^7 -9x^8 +x^9

Primes up to 70:
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67

Haskell
expand p = scanl (\z i -> z * (p-i+1) `div` i) 1 [1..p]

test p | p < 2
= False
| otherwise = and [mod n p == 0 | n <- init . tail $ expand p]

printPoly [1] = "1"


printPoly p
= concat [ unwords [pow i, sgn (l-i), show (p!!(i-1))]
| i <- [l-1,l-2..1] ] where
l = length p
sgn i = if even i then "+" else "-"
pow i = take i "x^" ++ if i > 1 then show i else ""

main = do
putStrLn "-- p: (x-1)^p for small p"

17 of 53

putStrLn $ unlines [show i ++ ": " ++ printPoly (expand i) | i <- [0..10]]


putStrLn "-- Primes up to 100:"
print (filter test [1..100])

Output:
-- p: (x-1)^p for small p
0: 1
1: x - 1
2: x^2 - 2x + 1
3: x^3 - 3x^2 + 3x - 1
4: x^4 - 4x^3 + 6x^2 - 4x + 1
5: x^5 - 5x^4 + 10x^3 - 10x^2 + 5x - 1
6: x^6 - 6x^5 + 15x^4 - 20x^3 + 15x^2 - 6x + 1
7: x^7 - 7x^6 + 21x^5 - 35x^4 + 35x^3 - 21x^2 + 7x - 1
8: x^8 - 8x^7 + 28x^6 - 56x^5 + 70x^4 - 56x^3 + 28x^2 - 8x + 1
9: x^9 - 9x^8 + 36x^7 - 84x^6 + 126x^5 - 126x^4 + 84x^3 - 36x^2 + 9x - 1
10: x^10 - 10x^9 + 45x^8 - 120x^7 + 210x^6 - 252x^5 + 210x^4 - 120x^3 + 45x^2 - 10x + 1
-- Primes up to 100:
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97]

J
Solution:
binomialExpansion =:
testAKS
=:

(!~ * _1 ^ 2 | ]) i.&.:<:
0 *./ .= ] | binomialExpansion

NB. 1) Create a function that gives the coefficients of (x-1)^p.


NB. 3) Use that function to create another which determines whether p is prime

Examples:
binomialExpansion&.> i. 8
NB. 2) show the polynomial expansions p in the range 0 to at 7 inclusive.
+-++--+----+-------+-----------+---------------+------------------+
|0||_2|_3 3|_4 6 _4|_5 10 _10 5|_6 15 _20 15 _6|_7 21 _35 35 _21 7|
+-++--+----+-------+-----------+---------------+------------------+
(#~ testAKS&> ) 2+i. 35
NB. 4) Generate a list of all primes under 35.
2 3 5 7 11 13 17 19 23 29 31
(#~ testAKS&> ) 2+i. 50
NB. 5) [stretch] Generate all primes under 50
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47
i.&.:(_1&p:) 50
NB. Double-check our results using built-in prime filter.
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47

Java
Translation of: C
Solution:

public class AksTest


{
static Long[] c = new Long[100];
public static void main(String[] args)
{
for (int n = 0; n < 10; n++) {
coef(n);
System.out.print("(x-1)^" + n + " = ");
show(n);
System.out.println("");
}
System.out.print("Primes:");
for (int n = 1; n <= 63; n++)

18 of 53

if (is_prime(n))
System.out.printf(" %d", n);
System.out.println('\n');
}
static void coef(int n)
{
int i, j;
if (n < 0 || n > 63) System.exit(0); // gracefully deal with range issue
for (c[i=0] = 1l; i < n; c[0] = -c[0], i++)
for (c[1 + (j=i)] = 1l; j > 0; j--)
c[j] = c[j-1] - c[j];
}
static boolean is_prime(int n)
{
int i;
coef(n);
c[0] += 1;
c[i=n] -= 1;
while (i-- != 0 && (c[i] % n) == 0);
return i < 0;
}
static void show(int n)
{
do {
System.out.print("+" + c[n] + "x^"+ n);
}while (n-- != 0);
}
}

Output:
(x-1)^0
(x-1)^1
(x-1)^2
(x-1)^3
(x-1)^4
(x-1)^5
(x-1)^6
(x-1)^7
(x-1)^8
(x-1)^9
Primes:

=
=
=
=
=
=
=
=
=
=
1

+1x^0
+1x^1+-1x^0
+1x^2+-2x^1+1x^0
+1x^3+-3x^2+3x^1+-1x^0
+1x^4+-4x^3+6x^2+-4x^1+1x^0
+1x^5+-5x^4+10x^3+-10x^2+5x^1+-1x^0
+1x^6+-6x^5+15x^4+-20x^3+15x^2+-6x^1+1x^0
+1x^7+-7x^6+21x^5+-35x^4+35x^3+-21x^2+7x^1+-1x^0
+1x^8+-8x^7+28x^6+-56x^5+70x^4+-56x^3+28x^2+-8x^1+1x^0
+1x^9+-9x^8+36x^7+-84x^6+126x^5+-126x^4+84x^3+-36x^2+9x^1+-1x^0
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61

JavaScript
Translation of: CoeeScript
var i, p, pascal, primerow, primes, show, _i;
pascal = function() {
var a;
a = [];
return function() {
var b, i;
if (a.length === 0) {
return a = [1];
} else {
b = (function() {
var _i, _ref, _results;
_results = [];
for (i = _i = 0, _ref = a.length - 1; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {

19 of 53

_results.push(a[i] + a[i + 1]);


}
return _results;
})();
return a = [1].concat(b).concat([1]);
}
};
};
show = function(a) {
var degree, i, sgn, show_x, str, _i, _ref;
show_x = function(e) {
switch (e) {
case 0:
return "";
case 1:
return "x";
default:
return "x^" + e;
}
};
degree = a.length - 1;
str = "(x - 1)^" + degree + " =";
sgn = 1;
for (i = _i = 0, _ref = a.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
str += ' ' + (sgn > 0 ? "+" : "-") + ' ' + a[i] + show_x(degree - i);
sgn = -sgn;
}
return str;
};
primerow = function(row) {
var degree;
degree = row.length - 1;
return row.slice(1, degree).every(function(x) {
return x % degree === 0;
});
};
p = pascal();
for (i = _i = 0; _i <= 7; i = ++_i) {
console.log(show(p()));
}
p = pascal();
p();
p();
primes = (function() {
var _j, _results;
_results = [];
for (i = _j = 1; _j <= 49; i = ++_j) {
if (primerow(p())) {
_results.push(i + 1);
}
}
return _results;
})();
console.log("");
console.log("The primes upto 50 are: " + primes);

Output:
(x
(x
(x
(x
(x
(x
(x

20 of 53

1)^0
1)^1
1)^2
1)^3
1)^4
1)^5
1)^6

=
=
=
=
=
=
=

+
+
+
+
+
+
+

1
1x 1x^2
1x^3
1x^4
1x^5
1x^6

1
-

2x +
3x^2
4x^3
5x^4
6x^5

1
+
+
+
+

3x - 1
6x^2 - 4x + 1
10x^3 - 10x^2 + 5x - 1
15x^4 - 20x^3 + 15x^2 - 6x + 1

(x - 1)^7 = + 1x^7 - 7x^6 + 21x^5 - 35x^4 + 35x^3 - 21x^2 + 7x - 1


The primes upto 50 are: 2,3,5,7,11,13,17,19,23,29,31,37,41,43,47

Reviewed (ES6):
function pascal(n) {
var cs = []; if (n) while (n--) coef(); return coef
function coef() {
if (cs.length === 0) return cs = [1];
for (var t=[1,1], i=cs.length-1; i; i-=1) t.splice( 1, 0, cs[i-1]+cs[i] ); return cs = t
}
}
function show(cs) {
for (var s='', sgn=true, i=0, deg=cs.length-1; i<=deg; sgn=!sgn, i+=1) {
s += ' ' + (sgn ? '+' : '-') + cs[i] + (e => e==0 ? '' : e==1 ? 'x' : 'x<sup>' + e + '</sup>')(deg-i)
}
return '(x-1)<sup>' + deg + '</sup> =' + s;
}
function isPrime(cs) {
var deg=cs.length-1; return cs.slice(1, deg).every( function(c) { return c % deg === 0 } )
}
var coef=pascal(); for (var i=0; i<=7; i+=1) document.write(show(coef()), '<br>')
document.write('<br>Primes: ');
for (var coef=pascal(2), n=2; n<=50; n+=1) if (isPrime(coef())) document.write(' ', n)

Output:
(x-1)0 = +1
(x-1)1 = +1x -1
(x-1)2 = +1x2 -2x +1
(x-1)3 = +1x3 -3x2 +3x -1
(x-1)4 = +1x4 -4x3 +6x2 -4x +1
(x-1)5 = +1x5 -5x4 +10x3 -10x2 +5x -1
(x-1)6 = +1x6 -6x5 +15x4 -20x3 +15x2 -6x +1
(x-1)7 = +1x7 -7x6 +21x5 -35x4 +35x3 -21x2 +7x -1
Primes: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47

Translation of: C
function coef(n) {
for (var c=[1], i=0; i<n; c[0]=-c[0], i+=1) {
c[i+1]=1; for (var j=i; j; j-=1) c[j] = c[j-1]-c[j]
}
return c
}
function show(cs)
{
var s='', n=cs.length-1
do s += (cs[n]>0 ? ' +' : ' ') + cs[n] + (n==0 ? '' : n==1 ? 'x' :'x<sup>'+n+'</sup>'); while (n--)
return s
}
function isPrime(n) {
var cs=coef(n), i=n-1; while (i-- && cs[i]%n == 0);
return i < 1
}
for (var n=0; n<=7; n++) document.write('(x-1)<sup>',n,'</sup> = ', show(coef(n)), '<br>')
document.write('<br>Primes: ');
for (var n=2; n<=50; n++) if (isPrime(n)) document.write(' ', n)

21 of 53

Output:
(x-1)0 = +1
(x-1)1 = +1x -1
(x-1)2 = +1x2 -2x +1
(x-1)3 = +1x3 -3x2 +3x -1
(x-1)4 = +1x4 -4x3 +6x2 -4x +1
(x-1)5 = +1x5 -5x4 +10x3 -10x2 +5x -1
(x-1)6 = +1x6 -6x5 +15x4 -20x3 +15x2 -6x +1
(x-1)7 = +1x7 -7x6 +21x5 -35x4 +35x3 -21x2 +7x -1
Primes: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47

jq
Works with: jq version 1.5rc1
In the #Prolog section of this page, it is shown how the symmetry of rows in a Pascal triangle can
be used to yield a more eicient test of primality than is apparently envisioned by the problem
statement. The key concept is the "OptPascal row", which is just the longest non-decreasing
sequence of the corresponding Pascal row. In this article, the focus will therefore be on OptPascal
rows.
NOTE: jq uses IEEE 754 64-bit numbers and thus if builtin arithmetic is used, is_prime will only
be accurate up to 96 by this method because of loss of precision. The program below, however,
can easily be adapted to use a BigInt library such as the one at https://github.com/joelpurra
/jq-bigint
# add_pairs is a helper function for optpascal/0
# Input: an OptPascal array
# Output: the next OptPascal array (obtained by adding adjacent items,
# but if the last two items are unequal, then their sum is repeated)
def add_pairs:
if length <= 1 then .
elif length == 2 then (.[0] + .[1]) as $S
| if (.[0] == .[1]) then [$S]
else [$S,$S]
end
else [.[0] + .[1]] + (.[1:]|add_pairs)
end;
# Input: an OptPascal row
# Output: the next OptPascalRow
def next_optpascal: [1] + add_pairs;
# generate a stream of OptPascal arrays, beginning with []
def optpascals: [] | recurse(next_optpascal);
# generate a stream of Pascal arrays
def pascals:
# pascalize takes as input an OptPascal array and produces
# the corresponding Pascal array;
# if the input ends in a pair, then peel it off before reversing it.
def pascalize:
. + ((if .[-2] == .[-1] then .[0:-2] else .[0:-1] end) | reverse);
optpascals | pascalize;
# Input: integer n
# Output: the n-th Pascal row
def pascal: nth(.; pascals);
def optpascal: nth(.; optpascals);

22 of 53

Task 1: "A method to generate the coefficients of (x-1)^p"

def coefficients:
def alternate_signs: . as $in
| reduce range(0; length) as $i ([]; . + [$in[$i] * (if $i % 2 == 0 then 1 else -1 end )]);
(.+1) | pascal | alternate_signs;

Task 2: "Show here the polynomial expansions of (x 1)^p for p in the range 0 to at least 7,
inclusive."
range(0;8) | "Coefficient for (x - 1)^\(.): \(coefficients)"

Output:
Coefficients
Coefficients
Coefficients
Coefficients
Coefficients
Coefficients
Coefficients
Coefficients

for
for
for
for
for
for
for
for

(x
(x
(x
(x
(x
(x
(x
(x

1)^0:
1)^1:
1)^2:
1)^3:
1)^4:
1)^5:
1)^6:
1)^7:

[1]
[1,-1]
[1,-2,1]
[1,-3,3,-1]
[1,-4,6,-4,1]
[1,-5,10,-10,5,-1]
[1,-6,15,-20,15,-6,1]
[1,-7,21,-35,35,-21,7,-1]

Task 3: Prime Number Test


For brevity, we show here only the relatively eicient solution based on optpascal/0:
def is_prime:
. as $N
| if . < 2 then false
else (1+.) | optpascal
| all( .[2:][]; . % $N == 0 )
end;

Task 4: "Use your AKS test to generate a list of all primes under 35."
range(0;36) | select(is_prime)

Output:
2
3
5
7
11
13
17
19
23
29
31

Task 5: "As a stretch goal, generate all primes under 50."


[range(0;50) | select(is_prime)]

Output:

23 of 53

[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47]

Julia
Task 1

function polycoefs(n::Int64)
pc = typeof(n)[]
if n < 0
return pc
end
sgn = one(n)
for k in n:-1:0
push!(pc, sgn*binomial(n, k))
sgn = -sgn
end
return pc
end

Perhaps this should be done with a comprehension, but properly accounting for the sign is tricky
in that case.
Task 2

function stringpoly(n::Int64)
if n < 0
return ""
end
st = @sprintf "(x - 1)^{%d} & = & " n
for (i, c) in enumerate(polycoefs(n))
if i == 1
op = ""
ac = c
elseif c < 0
op = "-"
ac = abs(c)
else
op = "+"
ac = abs(c)
end
p = n + 1 - i
if p == 0
st *= @sprintf " %s %d\\\\" op ac
elseif ac == 1
st *= @sprintf " %s x^{%d}" op p
else
st *= @sprintf " %s %dx^{%d}" op ac p
end
end
return st
end

Of course this could be simpler, but this produces a nice payo in typeset equations that do on
include extraneous characters (leading pluses and coeicients of 1).
Task 3

function isaksprime(n::Int64)
if n < 2

24 of 53

return false
end
for c in polycoefs(n)[2:(end-1)]
if c%n != 0
return false
end
end
return true
end

Task 4

println("<math>")
println("\\begin{array}{lcl}")
for i in 0:10
println(stringpoly(i))
end
println("\\end{array}")
println("</math>\n")
L = 50
print("AKS primes less than ", L, ":
sep = ""
for i in 1:L
if isaksprime(i)
print(sep, i)
sep = ", "
end
end
println()

")

Output:

AKS primes less than 50: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47

Maple
Maple handles algebraic manipulation of polynomials natively.
> for xpr in seq( expand( (x-1)^p ), p = 0 .. 7 ) do print( xpr ) end:
1
x - 1
2

25 of 53

- 2 x + 1

3
2
x - 3 x + 3 x - 1
4
3
2
x - 4 x + 6 x - 4 x + 1
5
4
3
2
x - 5 x + 10 x - 10 x + 5 x - 1
6
5
4
3
2
x - 6 x + 15 x - 20 x + 15 x - 6 x + 1
7
6
5
4
3
2
x - 7 x + 21 x - 35 x + 35 x - 21 x + 7 x - 1

To implement the primality test, we write the following procedure that uses the (built-in)
polynomial expansion to generate a list of coeicients of the expanded polynomial.
polc := p -> [coeffs]( expand( (x-1)^p - (x^p-1) ) ):

Use

polc

to implement

prime?

which does the primality test.

prime? := n -> n > 1 and {op}( map( modp, polc( n ), n ) ) = {0}

Of course, rather than calling polc, we can inline it, just for the sake of making the whole thing a
one-liner (while adding argument type-checking for good measure):
prime? := (n::posint) -> n > 1 and {op}( map( modp, [coeffs]( expand( (x-1)^n - (x^n-1) ) ), n ) ) = {0}

This agrees with the built-in primality test

isprime:

> evalb( seq( prime?(i), i = 1 .. 1000 ) = seq( isprime( i ), i = 1 .. 1000 ) );


true

Use

prime?

with the built-in Maple

select

procedure to pick o the primes up to 50:

> select( prime?, [seq](1..50) );


[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]

Mathematica / Wolfram Language


Algebraic manipulation is built into Mathematica, so there's no need to create a function to do
(x-1)^p
Print["powers of (x-1)"]
(x - 1)^( Range[0, 7]) // Expand // TableForm
Print["primes under 50"]
poly[p_] := (x - 1)^p - (x^p - 1) // Expand;
coefflist[p_Integer] := Coefficient[poly[p], x, #] & /@ Range[0, p - 1];
AKSPrimeQ[p_Integer] := (Mod[coefflist[p] , p] // Union) == {0};

26 of 53

Select[Range[1, 50], AKSPrimeQ]

Output:
powers of (x-1)
1
-1+x
1-2 x+x^2
-1+3 x-3 x^2+x^3
1-4 x+6 x^2-4 x^3+x^4
-1+5 x-10 x^2+10 x^3-5 x^4+x^5
1-6 x+15 x^2-20 x^3+15 x^4-6 x^5+x^6
-1+7 x-21 x^2+35 x^3-35 x^4+21 x^5-7 x^6+x^7
primes under 50
{1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47}

Oforth
func: nextCoef(prev)
{
| i |
ListBuffer new dup add(0)
prev size 1 - loop: i [ dup add(prev at(i) prev at(i 1 +) - ) ]
dup add(0)
}
func: coefs(n) { [ 0, 1, 0 ] #nextCoef times(n) extract(2, n 2 + ) }
func: isPrime(n) { coefs(n) extract(2, n) conform(#[n mod 0 == ]) }
func: aks
{
| i |
0 10 for: i [ System.Out "(x-1)^" << i << " = " << coefs(i) << cr ]
50 seq filter(#isPrime) apply(#[ print " " print ]) printcr
}

Output:
(x-1)^0 = [1]
(x-1)^1 = [-1, 1]
(x-1)^2 = [1, -2, 1]
(x-1)^3 = [-1, 3, -3, 1]
(x-1)^4 = [1, -4, 6, -4, 1]
(x-1)^5 = [-1, 5, -10, 10, -5, 1]
(x-1)^6 = [1, -6, 15, -20, 15, -6, 1]
(x-1)^7 = [-1, 7, -21, 35, -35, 21, -7, 1]
(x-1)^8 = [1, -8, 28, -56, 70, -56, 28, -8, 1]
(x-1)^9 = [-1, 9, -36, 84, -126, 126, -84, 36, -9, 1]
(x-1)^10 = [1, -10, 45, -120, 210, -252, 210, -120, 45, -10, 1]
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47

PARI/GP
getPoly(n)=('x-1)^n;
vector(8,n,getPoly(n-1))
AKS_slow(n)=my(P=getPoly(n));for(i=1,n-1,if(polcoeff(P,i)%n,return(0))); 1;
AKS(n)=my(X=('x-1)*Mod(1,n));X^n=='x^n-1;
select(AKS, [1..50])

Output:

[1, x - 1, x^2 - 2*x + 1, x^3 - 3*x^2 + 3*x - 1, x^4 - 4*x^3 + 6*x^2 - 4*x + 1, x^5 - 5*x^4 + 10*x^3 - 10*x^2 + 5*x - 1, x^6 - 6*x^5 + 15

27 of 53

[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]

Pascal
tested wth freepascal

const
pasTriMax = 61;
type
tpasTri =array[0..pasTriMax] of UInt64;
var
pasTri : tpasTri;
procedure pastriangle(n:longInt);
//calculate the n'th line 0.. middle
var
j,k: longWord;
begin
pasTri[0] := 1;
j := 1;
while (j<=n) do
begin
inc(j);
k := j SHR 1;
pasTri[k] :=pasTri[k-1];
For k := k downto 1 do
inc(pasTri[k],pasTri[k-1]);
end;
end;
function CheckPrime(n:longWord):boolean;
var
i : integer;
res: boolean;
Begin
IF n > pasTriMax then
begin
writeln(n,' is out of range ');
EXIT;
end;
pastriangle(n);
res := true;
i := n shr 1;
while res AND (i >1) do
Begin
res := res AND(pasTri[i] mod n = 0);
dec(i);
end;
CheckPrime := res;
end;
procedure ExpandPoly(n:longWord);
const
Vz :array[boolean] of char = ('+','-');
var
j,k: longWord;
bVz: Boolean;
Begin
IF n < 2 then
Begin
IF n = 0 then
writeln('(x-1)^0 = 1')
else
writeln('(x-1)^1 = x-1');
EXIT;
end;
IF n > pasTriMax then
begin

28 of 53

writeln(n,' is out of range ');


EXIT;
end;
pastriangle(n);
write('(x-1)^',n,' = ');
k := 0;
j := n;
bVz := false;
repeat
IF j=n then
write('x^',j)
else
write(Vz[bVz],pasTri[k],'*x^',j);
bVz := Not(bVz);
inc(k);
dec(j);
until k>= j;
k := j;
while k > 0 do
Begin
IF j <> 1 then
write(Vz[bVz],pasTri[k],'*x^',j)
else
write(Vz[bVz],pasTri[k],'*x');
bVz := Not(bVz);
dec(k);
dec(j);
end;
write(Vz[bVz],pasTri[0]);
writeln;
end;
var
n: LongWord;
Begin
For n := 0 to 9 do
ExpandPoly(n);
For n := 2 to pasTriMax do
IF CheckPrime(n) then
write(n:3);
end.

output
(x-1)^0 = 1
(x-1)^1 = x-1
(x-1)^2 = x^2-2*x+1
(x-1)^3 = x^3-3*x^2+3*x-1
(x-1)^4 = x^4-4*x^3+6*x^2-4*x+1
(x-1)^5 = x^5-5*x^4+10*x^3-10*x^2+5*x-1
(x-1)^6 = x^6-6*x^5+15*x^4-20*x^3+15*x^2-6*x+1
(x-1)^7 = x^7-7*x^6+21*x^5-35*x^4+35*x^3-21*x^2+7*x-1
(x-1)^8 = x^8-8*x^7+28*x^6-56*x^5+70*x^4-56*x^3+28*x^2-8*x+1
(x-1)^9 = x^9-9*x^8+36*x^7-84*x^6+126*x^5-126*x^4+84*x^3-36*x^2+9*x-1

7 11 13 17 19 23 29 31 37 41 43 47 53 59 61

Perl
use strict;

29 of 53

use warnings;
# Select one of these lines. Math::BigInt is in core, but quite slow.
use Math::BigInt; sub binomial { Math::BigInt->new(shift)->bnok(shift) }
# use Math::Pari "binomial";
# use ntheory "binomial";
sub binprime {
my $p = shift;
return 0 unless $p >= 2;
# binomial is symmetric, so only test half the terms
for (1 .. ($p>>1)) { return 0 if binomial($p,$_) % $p }
1;
}
sub coef {
# For prettier printing
my($n,$e) = @_;
return $n unless $e;
$n = "" if $n==1;
$e==1 ? "${n}x" : "${n}x^$e";
}
sub binpoly {
my $p = shift;
join(" ", coef(1,$p),
map { join("",("+","-")[($p-$_)&1]," ",coef(binomial($p,$_),$_)) }
reverse 0..$p-1 );
}
print "expansions of (x-1)^p:\n";
print binpoly($_),"\n" for 0..9;
print "Primes to 80: [", join(",", grep { binprime($_) } 2..80), "]\n";

Output:
expansions of (x-1)^p:
1
x - 1
x^2 - 2x + 1
x^3 - 3x^2 + 3x - 1
x^4 - 4x^3 + 6x^2 - 4x + 1
x^5 - 5x^4 + 10x^3 - 10x^2 + 5x - 1
x^6 - 6x^5 + 15x^4 - 20x^3 + 15x^2 - 6x + 1
x^7 - 7x^6 + 21x^5 - 35x^4 + 35x^3 - 21x^2 + 7x - 1
x^8 - 8x^7 + 28x^6 - 56x^5 + 70x^4 - 56x^3 + 28x^2 - 8x + 1
x^9 - 9x^8 + 36x^7 - 84x^6 + 126x^5 - 126x^4 + 84x^3 - 36x^2 + 9x - 1
Primes to 80: [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79]

Real AKS
The ntheory module has implementations of the full AKS algorithm in Perl, C, and C+GMP. This is
vastly faster than the method used in this task and is polynomial time, but like all current AKS
implementations is still much slower than other methods such as BPSW, APR-CL, and ECPP.
Library: ntheory
use ntheory ":all";
# Uncomment next line to see the r and s values used. Set to 2 for more detail.
# prime_set_config(verbose => 1);
say join(" ", grep { is_aks_prime($_) } 1_000_000_000 .. 1_000_000_100);

Output:
1000000007 1000000009 1000000021 1000000033 1000000087 1000000093 1000000097

Perl 6
constant expansions = [1], [1,-1], -> @prior { [@prior,0 Z- 0,@prior] } ... *;

30 of 53

sub polyprime($p where 2..*) { so expansions[$p].[1 ..^ */2].all %% $p }

The expansions are generated similarly to how most FP languages generate sequences that
resemble Pascal's triangle, using a zipwith meta-operator (Z) with subtraction, applied between
two lists that add a 0 on either end to the prior list. Here we dene a constant innite sequence
using the ... sequence operator with a "whatever" endpoint. In fact, the second term [1,-1] could
have been generated from the rst term, but we put it in there for documentation so the reader
can see what direction things are going.
The polyprime function pretty much reads like the original description. Is it "so" that the p'th
expansion's coeicients are all divisible by p? The .[1 ..^ */2] slice is done simply to weed out
divisions by 1 or by factors we've already tested (since the coeicients are symmetrical in terms
of divisibility). If we wanted to write polyprime even more idiomatically, we could have made it
another innite constant list that is just a mapping of the rst list, but we decided that would just
be showing o. :-)
Showing the expansions:
say ' p: (x-1)';
say '-----------';
sub super ($n) {
$n.trans: '0123456789'
=> '';
}
for ^13 -> $d {
say $d.fmt('%2i: '), (
expansions[$d].kv.map: -> $i, $n {
my $p = $d - $i;
[~] gather {
take < + - >[$n < 0] ~ ' ' unless $p == $d;
take $n.abs
unless $p == $d > 0;
take 'x'
if $p > 0;
take super $p - $i
if $p > 1;
}
}
)
}

Output:
p: (x-1)
----------0: 1
1: x - 1
2: x - 2x + 1
3: x - 3x + 3x - 1
4: x - 4x + 6x - 4x + 1
5: x - 5x + 10x - 10x + 5x - 1
6: x - 6x + 15x - 20x + 15x - 6x + 1
7: x - 7x + 21x - 35x + 35x - 21x + 7x - 1
8: x - 8x + 28x - 56x + 70x - 56x + 28x - 8x + 1
9: x - 9x + 36x - 84x + 126x - 126x + 84x - 36x + 9x - 1
10: x - 10x + 45x - 120x + 210x - 252x + 210x - 120x + 45x - 10x + 1
11: x - 11x + 55x - 165x + 330x - 462x + 462x - 330x + 165x - 55x + 11x - 1
12: x - 12x + 66x - 220x + 495x - 792x + 924x - 792x + 495x - 220x + 66x - 12x + 1

And testing the function:


print "\nPrimes up to 100:\n

31 of 53

{ grep &polyprime, 2..100 }\n";

Output:
Primes up to 100:
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97

Phix
-- Does not work for primes above 53, which is actually beyond the original task anyway.
-- Translated from the C version, just about everything is (working) out-by-1, what fun.
sequence c = repeat(0,100)
procedure coef(integer n)
-- out-by-1, ie coef(1)==^0, coef(2)==^1, coef(3)==^2 etc.
c[n] = 1
for i=n-1 to 2 by -1 do
c[i] = c[i]+c[i-1]
end for
end procedure
function is_prime(integer n)
coef(n+1); -- (I said it was out-by-1)
for i=2 to n-1 do
-- (technically "to n" is more correct)
if remainder(c[i],n)!=0 then
return 0
end if
end for
return 1
end function
procedure show(integer n)
-- (As per coef, this is (working) out-by-1)
object ci
for i=n to 1 by -1 do
ci = c[i]
if ci=1 then
if remainder(n-i,2)=0 then
if i=1 then
if n=1 then
ci = "1"
else
ci = "+1"
end if
else
ci = ""
end if
else
ci = "-1"
end if
else
if remainder(n-i,2)=0 then
ci = sprintf("+%d",ci)
else
ci = sprintf("-%d",ci)
end if
end if
if i=1 then -- ie ^0
printf(1,"%s",{ci})
elsif i=2 then -- ie ^1
printf(1,"%sx",{ci})
else
printf(1,"%sx^%d",{ci,i-1})
end if
end for
end procedure
procedure AKS_test_for_primes()
for n=1 to 10 do -- (0 to 9 really)
coef(n);
printf(1,"(x-1)^%d = ", n-1);
show(n);

32 of 53

puts(1,'\n');
end for
puts(1,"\nprimes (<=53):");
coef(2); -- (needed to reset c, if we want to avoid saying 1 is prime...)
c[2] = 1 -- (this manages "", which is all that call did anyway...)
for n = 2 to 53 do
if is_prime(n) then
printf(1," %d", n);
end if
end for
puts(1,'\n');
if getc(0) then end if
end procedure
--

AKS_test_for_primes()

Output:
(x-1)^0
(x-1)^1
(x-1)^2
(x-1)^3
(x-1)^4
(x-1)^5
(x-1)^6
(x-1)^7
(x-1)^8
(x-1)^9

=
=
=
=
=
=
=
=
=
=

1
x-1
x^2-2x+1
x^3-3x^2+3x-1
x^4-4x^3+6x^2-4x+1
x^5-5x^4+10x^3-10x^2+5x-1
x^6-6x^5+15x^4-20x^3+15x^2-6x+1
x^7-7x^6+21x^5-35x^4+35x^3-21x^2+7x-1
x^8-8x^7+28x^6-56x^5+70x^4-56x^3+28x^2-8x+1
x^9-9x^8+36x^7-84x^6+126x^5-126x^4+84x^3-36x^2+9x-1

primes (<=53): 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53

PicoLisp
(de pascal (N)
(let D 1
(make
(for X (inc N)
(link D)
(setq D
(*/ D (- (inc N) X) (- X)) ) ) ) ) )
(for (X 0 (> 10 X) (inc X))
(println X '-> (pascal X) ) )
(println
(filter
'((X)
(fully
'((Y) (=0 (% Y X)))
(cdr (head -1 (pascal X))) ) )
(range 2 50) ) )
(bye)

Output:
0
1
2
3
4
5
6
7
8

33 of 53

->
->
->
->
->
->
->
->
->

(1)
(1 -1)
(1 -2 1)
(1 -3 3 -1)
(1 -4 6 -4 1)
(1 -5 10 -10 5 -1)
(1 -6 15 -20 15 -6 1)
(1 -7 21 -35 35 -21 7 -1)
(1 -8 28 -56 70 -56 28 -8 1)

9 -> (1 -9 36 -84 126 -126 84 -36 9 -1)


(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47)

Prolog
Prolog(ue)
The theorem as stated ties together two elementary concepts in mathematics: prime numbers and
the Pascal triangle. The simplicity of the connection can be expressed directly in Prolog by the
following prime number generator:

prime(P) :pascal([1,P|Xs]),
append(Xs, [1], Rest),
forall( member(X,Xs), 0 is X mod P).

where pascal/1 is a generator of rows of the Pascal triangle, for example as dened below; the
other predicates used above are standard.
This solution to the Rosetta Code problems will accordingly focus on the Pascal triangle, but to
illustrate a number of points, we shall exploit its symmetry by representing each of its rows by
the longest initial non-decreasing segment of that row, as illustrated in the third column of the
following table:
Row
1
2
3
4

Pascal Row
1
1 1
1 2 1
1 3 3 1

optpascal
[1]
[1, 1]
[1, 2]
[1, 3, 3]

We shall refer to this condensed representation of a row as an "optpascal list". Using it, we can
simplify and improve the above prime number generator by dening it as follows:
prime(N) :- optpascal([1,N|Xs]), forall( member(X,Xs), 0 is X mod N).

Using SWI-Prolog without modifying any of the memory management parameters, this prime
number generator was used to generate all primes up to and including 75,659.
Since Pascal triangles are the foundation of our approach to addressing the specic Rosetta Code
problems, we begin by dening the generator pascal/2 that is required by the rst problem, but
we do so by dening it in terms of an eicient generator, optpascal/1.

Pascal Triangle Generator


% To generate the n-th row of a Pascal triangle
% pascal(+N, Row)
pascal(0, [1]).
pascal(N, Row) :N > 0, optpascal( [1, N|Xs] ),
!,
pascalize( [1, N|Xs], Row ).
pascalize( Opt, Row ) :% if Opt ends in a pair, then peel off the pair:

34 of 53

( append(X, [R,R], Opt) -> true ; append(X, [R], Opt) ),


reverse(X, Rs),
append( Opt, Rs, Row ).
% optpascal(-X) generates optpascal lines:
optpascal(X) :optpascal_successor( [], X).
% optpascal_successor(+P, -Q) is true if Q is an optpascal list beneath the optpascal list P:
optpascal_successor(P, Q) :optpascal(P, NextP),
(Q = NextP ; optpascal_successor(NextP, Q)).
% optpascal(+Row, NextRow) is true if Row and NextRow are adjacent rows in the Pascal triangle.
% optpascal(+Row, NextRow) where the optpascal representation is used
optpascal(X, [1|Y]) :add_pairs(X, Y).
% add_pairs(+OptPascal, NextOptPascal) is a helper function for optpascal/2.
% Given one OptPascal list, it generates the next by adding adjacent
% items, but if the last two items are unequal, then their sum is
% repeated. This is intended to be a deterministic predicate, and to
% avoid a probable compiler limitation, we therefore use one cut.
add_pairs([], []).
add_pairs([X], [X]).
add_pairs([X,Y], Ans) :S is X + Y,
(X = Y -> Ans=[S] ; Ans=[S,S]),
!. % To overcome potential limitation of compiler
add_pairs( [X1, X2, X3|Xs], [S|Ys]) :S is X1 + X2,
add_pairs( [X2, X3|Xs], Ys).

Solutions
Solutions with output from SWI-Prolog:

%%% Task 1: "A method to generate the coefficients of (1-X)^p"


coefficients(N, Coefficients) :pascal(N, X),
alternate_signs(X, Coefficients).
alternate_signs( [], [] ).
alternate_signs( [A], [A] ).
alternate_signs( [A,B | X], [A, MB | Y] ) :MB is -B,
alternate_signs(X,Y).
%%% Task 2. "Show here the polynomial expansions of (x 1)p for p in the range 0 to at least 7, inclusive."
coefficients(Coefficients) :optpascal( Opt),
pascalize( Opt, Row ),
alternate_signs(Row, Coefficients).

% As required by the problem statement, but necessarily very inefficient:


:- between(0, 7, N), coefficients(N, Coefficients), writeln(Coefficients), fail ; true.

[1]
[1,-1]
[1,-2,1]
[1,-3,3,-1]
[1,-4,6,-4,1]
[1,-5,10,-10,5,-1]
[1,-6,15,-20,15,-6,1]
[1,-7,21,-35,35,-21,7,-1]

35 of 53

The following would be more eicient because backtracking saves recomputation:


:- coefficients(Coefficients),
writeln(Coefficients),
Coefficients = [_,N|_], N = -7.

%%% Task 3. Use the previous function in creating [sic]


%%% another function that when given p returns whether p is prime
%%% using the AKS test.
% Even for testing whether a given number, N, is prime,
% this approach is inefficient, but here is a Prolog implementation:
prime_test_per_requirements(N) :coefficients(N, [1|Coefficients]),
append(Cs, [_], Coefficients),
forall( member(C, Cs), 0 is C mod N).

The following is more eicient (because it relies on optpascal lists rather than the full array of
coeicients), and more exible (because it can be used to generate primes without requiring
recomputation):

prime(N) :- optpascal([1,N|Xs]), forall( member(X,Xs), 0 is X mod N).

%%% Task 4. Use your AKS test to generate a list of all primes under 35.
:-

prime(N), (N < 35 -> write(N), write(' '), fail ; nl).

% Output: 1 2 3 5 7 11 13 17 19 23 29 31
%%% Task 5. As a stretch goal, generate all primes under 50.
:-

prime(N), (N < 50 -> write(N), write(' '), fail ; nl).

% Output: 1 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47

PureBasic
EnableExplicit
Define vzr.b = -1, vzc.b = ~vzr, nMAX.i = 10, n , k
Procedure coeff(nRow.i, Array pd.i(2))
Define.i n, k
For n=1 To nRow
For k=0 To n
If k=0 Or k=n : pd(n,k)=1 : Continue : EndIf
pd(n,k)=pd(n-1,k-1)+pd(n-1,k)
Next
Next
EndProcedure
Procedure.b isPrime(n.i, Array pd.i(2))
Define.i m
For m=1 To n-1
If Not pd(n,m) % n = 0 : ProcedureReturn #False : EndIf

36 of 53

Next
ProcedureReturn #True
EndProcedure
Dim pd.i(nMAX,nMAX)
pd(0,0)=1 : coeff(nMAX, pd())
OpenConsole()
For n=0 To nMAX
Print(RSet(Str(n),3,Chr(32))+": ")
If vzr : Print("+") : Else : Print("-") : EndIf
For k=0 To n
If k>0 : If vzc : Print("+") : Else : Print("-") : EndIf : vzc = ~vzc : EndIf
Print(RSet(Str(pd(n,k)),3,Chr(32))+Space(3))
Next
PrintN("")
vzr = ~vzr : vzc = ~vzr
Next
PrintN("")
nMAX=50 : Dim pd.i(nMAX,nMAX)
Print("Primes n<=50 : ") : coeff(nMAX, pd())
For n=2 To 50
If isPrime(n,pd()) : Print(Str(n)+Space(2)) : EndIf
Next
Input()

Output:
0:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:

+
+
+
+
+
+

1
1
1
1
1
1
1
1
1
1
1

+ 1
- 2
+ 3
- 4
+ 5
- 6
+ 7
- 8
+ 9
- 10

Primes n<=50 : 2

+
+
+
+
+

1
3
6
10
15
21
28
36
45

+ 1
- 4
+ 10
- 20
+ 35
- 56
+ 84
-120

11

+ 1
- 5
+ 15
- 35
+ 70
-126
+210

13

17

+ 1
- 6
+ 21
- 56
+126
-252

19

23

+ 1
- 7
+ 28
- 84
+210

29

31

+ 1
- 8
+ 36
-120

37

Python
def expand_x_1(n):
# This version uses a generator and thus less computations
c =1
for i in range(n/2+1):
c = c*(n-i)/(i+1)
yield c
def aks(p):
if p==2:
return True
for i in expand_x_1(p):
if i % p:
# we stop without computing all possible solutions
return False
return True

def expand_x_1(p):
ex = [1]
for i in range(p):
ex.append(ex[-1] * -(p-i) / (i+1))
return ex[::-1]

37 of 53

+ 1
- 9
+ 45

41

43

+ 1
- 10

47

def aks_test(p):
if p < 2: return False
ex = expand_x_1(p)
ex[0] += 1
return not any(mult % p for mult in ex[0:-1])

print('# p: (x-1)^p for small p')


for p in range(12):
print('%3i: %s' % (p, ' '.join('%+i%s' % (e, ('x^%i' % n) if n else '')
for n,e in enumerate(expand_x_1(p)))))
print('\n# small primes using the aks test')
print([p for p in range(101) if aks_test(p)])

Output:
# p:
0:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:

(x-1)^p for small p


+1
-1 +1x^1
+1 -2x^1 +1x^2
-1 +3x^1 -3x^2 +1x^3
+1 -4x^1 +6x^2 -4x^3 +1x^4
-1 +5x^1 -10x^2 +10x^3 -5x^4 +1x^5
+1 -6x^1 +15x^2 -20x^3 +15x^4 -6x^5 +1x^6
-1 +7x^1 -21x^2 +35x^3 -35x^4 +21x^5 -7x^6 +1x^7
+1 -8x^1 +28x^2 -56x^3 +70x^4 -56x^5 +28x^6 -8x^7 +1x^8
-1 +9x^1 -36x^2 +84x^3 -126x^4 +126x^5 -84x^6 +36x^7 -9x^8 +1x^9
+1 -10x^1 +45x^2 -120x^3 +210x^4 -252x^5 +210x^6 -120x^7 +45x^8 -10x^9 +1x^10
-1 +11x^1 -55x^2 +165x^3 -330x^4 +462x^5 -462x^6 +330x^7 -165x^8 +55x^9 -11x^10 +1x^11

# small primes using the aks test


[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]

Python: Output formatted for wiki


Using a wikitable and math features with the following additional code produces better formatted
polynomial output:
print('''
{| class="wikitable" style="text-align:left;"
|+ Polynomial Expansions and AKS prime test
|! <math>p</math>
! <math>(x-1)^p</math>
|-''')
for p in range(12):
print('! <math>%i</math>\n| <math>%s</math>\n| %r\n|-'
% (p,
' '.join('%s%s' % (('%+i' % e) if (e != 1 or not p or (p and not n) ) else '+',
(('x^{%i}' % n) if n > 1 else 'x') if n else '')
for n,e in enumerate(expand_x_1(p))),
aks_test(p)))
print('|}')

Output:

38 of 53

Polynomial Expansions and AKS prime test


(x 1)p

p
0 +1

False

1 1+x
2 + 1 2x +

Prime(p)?
False

x2

True

3 1 + 3x 3x2 + x3

True

4 + 1 4x + 6x2 4x3 + x4

False

5 1 + 5x 10x2 + 10x3 5x4 + x5

True

6 + 1 6x + 15x2 20x3 + 15x4 6x5 + x6

False

7 1 + 7x 21x2 + 35x3 35x4 + 21x5 7x6 + x7

True

8 + 1 8x + 28x2 56x3 + 70x4 56x5 + 28x6 8x7 + x8

False

9 1 + 9x 36x2 + 84x3 126x4 + 126x5 84x6 + 36x7 9x8 + x9

False

10

+ 1 10x + 45x2 120x3 + 210x4 252x5 + 210x6 120x7 + 45x8 10x9 +


False
x10

11

1 + 11x 55x2 + 165x3 330x4 + 462x5 462x6 + 330x7 165x8 + 55x9


11x10 + x11

True

R
Borrowing heavily from Python listing. Optimized for the fact that the vector of the coeicients is
a palindrome.
Is.Prime<-function(x){
expand<-function(p){
ex = 1
for (i in 0:(p/2-1)){
ex<-c(ex[1]*(p-i)/(i+1),ex)
}
return(rev(ex)[-1])
}
return(as.logical(min(expand(x)%%x==0)))
}

Racket
With copious use of the math/number-theory library...
#lang racket
(require math/number-theory)
;; 1. coefficients of expanded polynomial (x-1)^p
;;
produces a vector because in-vector can provide a start
;;
and stop (of 1 and p) which allow us to drop the (-1)^p
;;
and the x^p terms, respectively.
;;
;;
(vector-ref (coefficients p) e) is the coefficient for p^e
(define (coefficients p)
(for/vector ((e (in-range 0 (add1 p))))
(define sign (expt -1 (- p e)))
(* sign (binomial p e))))
;; 2. Show the polynomial expansions from p=0 .. 7 (inclusive)

39 of 53

;; (it's possible some of these can be merged...)


(define (format-coefficient c e leftmost?)
(define (format-c.x^e c e)
(define +c (abs c))
(match* (+c e)
[(_ 0) (format "~a" +c)]
[(1 _) (format "x^~a" e)]
[(_ _) (format "~ax^~a" +c e)]))
(define +/- (if (negative? c) "-" "+"))
(define +c.x^e (format-c.x^e c e))
(match* (c e leftmost?)
[(0 _ _) ""]
[((? negative?) _ #t) (format "-~a" +c.x^e)]
[(_ _ #t) +c.x^e]
[(_ _ _) (format " ~a ~a" +/- +c.x^e)]))
(define (format-polynomial cs)
(define cs-length (sequence-length cs))
(apply
string-append
(reverse ; convention is to display highest exponent first
(for/list ((c cs) (e (in-naturals)))
(format-coefficient c e (= e (sub1 cs-length)))))))
(for ((p (in-range 0 (add1 11))))
(printf "p=~a: ~a~%" p (format-polynomial (coefficients p))))
;; 3. AKS primeality test
(define (prime?/AKS p)
(define cs (coefficients p))
(and
(or (= (vector-ref cs 0) -1) ; c_0 = -1 -> c_0 - (-1) = 0
(divides? p 2))
; c_0 = 1 -> c_0 - (-1) = 2 -> divides?
(for/and ((c (in-vector cs 1 p))) (divides? p c))))
;; there is some discussion (see Discussion) about what to do with the perennial "1"
;; case. This is my way of saying that I'm ignoring it
(define lowest-tested-number 2)
;; 4. list of numbers < 35 that are prime (note that 1 is prime
;;
by the definition of the AKS test for primes):
(displayln (for/list ((i (in-range lowest-tested-number 35)) #:when (prime?/AKS i)) i))
;; 5. stretch goal: all prime numbers under 50
(displayln (for/list ((i (in-range lowest-tested-number 50)) #:when (prime?/AKS i)) i))
(displayln (for/list ((i (in-range lowest-tested-number 100)) #:when (prime?/AKS i)) i))

Output:
p=0: 1
p=1: x^1 - 1
p=2: x^2 - 2x^1 + 1
p=3: x^3 - 3x^2 + 3x^1 - 1
p=4: x^4 - 4x^3 + 6x^2 - 4x^1 + 1
p=5: x^5 - 5x^4 + 10x^3 - 10x^2 + 5x^1 - 1
p=6: x^6 - 6x^5 + 15x^4 - 20x^3 + 15x^2 - 6x^1 + 1
p=7: x^7 - 7x^6 + 21x^5 - 35x^4 + 35x^3 - 21x^2 + 7x^1 - 1
p=8: x^8 - 8x^7 + 28x^6 - 56x^5 + 70x^4 - 56x^3 + 28x^2 - 8x^1 + 1
p=9: x^9 - 9x^8 + 36x^7 - 84x^6 + 126x^5 - 126x^4 + 84x^3 - 36x^2 + 9x^1 - 1
p=10: x^10 - 10x^9 + 45x^8 - 120x^7 + 210x^6 - 252x^5 + 210x^4 - 120x^3 + 45x^2 - 10x^1 + 1
p=11: x^11 - 11x^10 + 55x^9 - 165x^8 + 330x^7 - 462x^6 + 462x^5 - 330x^4 + 165x^3 - 55x^2 + 11x^1 - 1
(2 3 5 7 11 13 17 19 23 29 31)
(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47)
(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97)

REXX
version 1
/* REXX ---------------------------------------------------------------

40 of 53

* 09.02.2014 Walter Pachl


* 22.02.2014 WP fix 'accounting' problem (courtesy GS)
*--------------------------------------------------------------------*/
c.=1
Numeric Digits 100
limit=200
pl=''
mmm=0
Do p=3 To limit
pm1=p-1
c.p.1=1
c.p.p=1
Do j=2 To p-1
jm1=j-1
c.p.j=c.pm1.jm1+c.pm1.j
mmm=max(mmm,c.p.j)
End
End
Say '(x-1)**0 = 1'
do i=2 To limit
im1=i-1
sign='+'
ol='(x-1)^'im1 '='
Do j=i to 2 by -1
If j=2 Then
term='x '
Else
term='x^'||(j-1)
If j=i Then
ol=ol term
Else
ol=ol sign c.i.j'*'term
sign=translate(sign,'+-','-+')
End
If i<10 then
Say ol sign 1
Do j=2 To i-1
If c.i.j//(i-1)>0 Then
Leave
End
If j>i-1 Then
pl=pl (i-1)
End
Say ' '
Say 'Primes:' subword(pl,2,27)
Say '
' subword(pl,29)
Say 'Largest coefficient:' mmm
Say 'This has' length(mmm) 'digits'

Output:
(x-1)**0 = 1
(x-1)^1 = x
(x-1)^2 = x^2
(x-1)^3 = x^3
(x-1)^4 = x^4
(x-1)^5 = x^5
(x-1)^6 = x^6
(x-1)^7 = x^7
(x-1)^8 = x^8

1
2*x
3*x^2
4*x^3
5*x^4
6*x^5
7*x^6
8*x^7

+
+
+
+
+
+
+

1
3*x
- 1
6*x^2 - 4*x
+
10*x^3 - 10*x^2
15*x^4 - 20*x^3
21*x^5 - 35*x^4
28*x^6 - 56*x^5

1
+
+
+
+

5*x
- 1
15*x^2 - 6*x
+ 1
35*x^3 - 21*x^2 + 7*x
- 1
70*x^4 - 56*x^3 + 28*x^2 - 8*x

+ 1

Primes: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103


107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199
Largest coefficient: 45274257328051640582702088538742081937252294837706668420660
This has 59 digits

version 2
This REXX version is an optimized version (of version 1) and modied to address each of the
requirements.
The program determines programmatically the required number of digits (precision) for the large

41 of 53

coeicients.
/*REXX pgm calculates primes via the Agrawal-Kayal-Saxena (AKS) primality test*/
parse arg Z .;
if Z=='' then Z=200 /*Z not specified?
Then use default.*/
OZ=Z;
tell=Z<0;
Z=abs(Z)
/*Is Z negative? Then show expression.*/
numeric digits max(9,Z%3)
/*define a dynamic # of decimal digits.*/
$.0='-';
$.1="+";
@.=1
/*$.x: sign char; default coefficients.*/
#=
/*define list of prime numbers (so far)*/
do p=3 for Z;
pm=p-1; pp=p+1 /*PM & PP: used as a coding convenience*/
do m=2 for pp%2-1;
mm=m-1 /*calculate coefficients for a power. */
@.p.m=@.pm.mm + @.pm.m; h=pp-m /*calculate left side of coefficients*/
@.p.h=@.p.m
/*
"
right
"
"
"
*/
end
/*m*/
/* [] The M DO loop creates both
*/
end
/*p*/
/*
sides in the same loop, saving */
/*
a bunch of execution time.
*/
if tell then say '(x-1)^0: 1'
/*possibly display the first expression*/
/* [] test for primality by division.*/
do n=2 for Z;
nh=n%2;
d=n-1 /*create expressions; find the primes.*/
do k=3 to nh while @.n.k//d==0 /*are coefficients divisible by N-1 ? */
end
/*k*/
/* [] skip the 1st & 2nd coefficients*/
/* [] multiple THENIF faster than &s*/
if d\==1 then if d\==4 then if k>nh then #=# d /*add number to prime list.*/
if \tell then iterate
/*Don't tell?
Don't show expressions.*/
y='(x-1)^'d": "
/*define first part of the expression. */
s=1
/*S:
is the sign indicator (-1+1).*/
do j=n to 2 by -1
/*create the higher powers first.
*/
if j==2 then xp='x'
/*if power=1, then don't show the power*/
else xp='x^' || (j-1)
/*
else show power with ^ */
if j==n then y=y xp
/*no sign (+-) for the 1st expression.*/
else y=y $.s @.n.j''xp /*build the expression with sign (+|-).*/
s=\s
/*flip the sign for the next expression*/
end
/*j*/
/* [] the sign (now) is either 0 1,*/
/*
and is displayed either - + */
say y $.s 1
/*just show the first N expressions, */
end
/*n*/
/* [] but only for negative Z. */
say
/* [] Has Z a leading + ? Then show.*/
is="isn't"; if Z==word(. #,words(#)+1) then is='is' /*is or isn't a prime.*/
if left(OZ,1)=='+' then say Z is 'prime.'
/*tell if OZ has a +. */
else say 'primes:' #
/*display prime # list. */
say
/* [] size of big 'un.*/
say 'Found '
words(#)
' primes and the largest coefficient has' ,
length(@.pm.h) "decimal digits." /*stick a fork in it, we're all done. */

output for requirement #2, showing twenty expressions using as input:


(x-1)^0:
(x-1)^1:
(x-1)^2:
(x-1)^3:
(x-1)^4:
(x-1)^5:
(x-1)^6:
(x-1)^7:
(x-1)^8:
(x-1)^9:
(x-1)^10:
(x-1)^11:
(x-1)^12:
(x-1)^13:
(x-1)^14:
(x-1)^15:
(x-1)^16:
(x-1)^17:
(x-1)^18:
(x-1)^19:
(x-1)^20:
primes:
Found

1
x - 1
x^2 x^3 x^4 x^5 x^6 x^7 x^8 x^9 x^10
x^11
x^12
x^13
x^14
x^15
x^16
x^17
x^18
x^19
x^20

-20

2x + 1
3x^2 + 3x - 1
4x^3 + 6x^2 - 4x + 1
5x^4 + 10x^3 - 10x^2 + 5x - 1
6x^5 + 15x^4 - 20x^3 + 15x^2 - 6x + 1
7x^6 + 21x^5 - 35x^4 + 35x^3 - 21x^2 + 7x - 1
8x^7 + 28x^6 - 56x^5 + 70x^4 - 56x^3 + 28x^2 - 8x + 1
9x^8 + 36x^7 - 84x^6 + 126x^5 - 126x^4 + 84x^3 - 36x^2 + 9x - 1
- 10x^9 + 45x^8 - 120x^7 + 210x^6 - 252x^5 + 210x^4 - 120x^3 + 45x^2 - 10x + 1
- 11x^10 + 55x^9 - 165x^8 + 330x^7 - 462x^6 + 462x^5 - 330x^4 + 165x^3 - 55x^2 + 11x - 1
- 12x^11 + 66x^10 - 220x^9 + 495x^8 - 792x^7 + 924x^6 - 792x^5 + 495x^4 - 220x^3 + 66x^2 - 12x + 1
- 13x^12 + 78x^11 - 286x^10 + 715x^9 - 1287x^8 + 1716x^7 - 1716x^6 + 1287x^5 - 715x^4 + 286x^3 - 78x^2 + 13x - 14x^13 + 91x^12 - 364x^11 + 1001x^10 - 2002x^9 + 3003x^8 - 3432x^7 + 3003x^6 - 2002x^5 + 1001x^4 - 364x^3 + 9
- 15x^14 + 105x^13 - 455x^12 + 1365x^11 - 3003x^10 + 5005x^9 - 6435x^8 + 6435x^7 - 5005x^6 + 3003x^5 - 1365x^4
- 16x^15 + 120x^14 - 560x^13 + 1820x^12 - 4368x^11 + 8008x^10 - 11440x^9 + 12870x^8 - 11440x^7 + 8008x^6 - 4368
- 17x^16 + 136x^15 - 680x^14 + 2380x^13 - 6188x^12 + 12376x^11 - 19448x^10 + 24310x^9 - 24310x^8 + 19448x^7 - 12
- 18x^17 + 153x^16 - 816x^15 + 3060x^14 - 8568x^13 + 18564x^12 - 31824x^11 + 43758x^10 - 48620x^9 + 43758x^8 - 3
- 19x^18 + 171x^17 - 969x^16 + 3876x^15 - 11628x^14 + 27132x^13 - 50388x^12 + 75582x^11 - 92378x^10 + 92378x^9 - 20x^19 + 190x^18 - 1140x^17 + 4845x^16 - 15504x^15 + 38760x^14 - 77520x^13 + 125970x^12 - 167960x^11 + 184756x

2 3 5 7 11 13 17 19
8

primes and the largest coefficient has 6 decimal digits.

output for requirement #3, showing if 2221 is prime (or not) using for input:

42 of 53

+2221

(Output note: this number is really pushing at the limits of REXX's use of virtual memory; the
version of
Regina REXX used herein has a limit of around 2 Gbytes.)
2221 is prime.
Found

331

primes and the largest coefficient has 668 decimal digits.

output for requirement #4, showing all primes under 35 using the input:
primes:

35

Found

2 3 5 7 11 13 17 19 23 29 31
11

primes and the largest coefficient has 10 decimal digits.

output for requirement #5 (stretch goal), showing all primes under 50 using the input:
primes:

2 3 5 7 11 13 17 19 23 29 31 37 41 43 47

Found

15

primes and the largest coefficient has 15 decimal digits.

output when using the input:


primes:
Found

500

2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 17
95

primes and the largest coefficient has 150 decimal digits.

Ruby
Using the `polynomial` Rubygem, this can be written directly from the denition in the
description:
require 'polynomial'
def x_minus_1_to_the(p)
return Polynomial.new(-1,1)**p
end
def prime?(p)
return false if p < 2
(x_minus_1_to_the(p) - Polynomial.from_string("x**#{p}-1")).coefs.all?{|n| n%p==0}
end
8.times do |n|
# the default Polynomial#to_s would be OK here; the substitutions just make the
# output match the other version below.
puts "(x-1)^#{n} = #{x_minus_1_to_the(n).to_s.gsub(/\*\*/,'^').gsub(/\*/,'')}"
end
puts "\nPrimes below 50:", 50.times.select {|n| prime? n}.join(',')

Or without the dependency:


def x_minus_1_to_the(p)
p.times.inject([1]) do |ex, _|
([0] + ex).zip(ex + [0]).map { |x,y| x - y }
end
end

43 of 53

50

def prime?(p)
return false if p < 2
coeff = x_minus_1_to_the(p)
coeff[0] += coeff.pop
coeff.all?{|n| n%p==0}
end
8.times do |n|
puts "(x-1)^#{n} = " +
x_minus_1_to_the(n).
each_with_index.
map { |c, p|
if p.zero? then c.to_s
else
(c<0 ? " - " : " + ") + (c.abs==1 ? "x" : "#{c.abs}x") + (p==1 ? "" : "^#{p}")
end
}.join
end
puts "\nPrimes below 50:", 50.times.select {|n| prime? n}.join(',')

Output:
(x-1)^0
(x-1)^1
(x-1)^2
(x-1)^3
(x-1)^4
(x-1)^5
(x-1)^6
(x-1)^7

=
=
=
=
=
=
=
=

1
-1 + x
1 - 2x + x^2
-1 + 3x - 3x^2 + x^3
1 - 4x + 6x^2 - 4x^3 + x^4
-1 + 5x - 10x^2 + 10x^3 - 5x^4 + x^5
1 - 6x + 15x^2 - 20x^3 + 15x^4 - 6x^5 + x^6
-1 + 7x - 21x^2 + 35x^3 - 35x^4 + 21x^5 - 7x^6 + x^7

Primes below 50:


2,3,5,7,11,13,17,19,23,29,31,37,41,43,47

Rust
#![feature(core)]
use std::iter::{range_inclusive, repeat};
fn aks_coefficients(k: usize) -> Vec<i64> {
let mut coefficients = repeat(0i64).take(k + 1).collect::<Vec<_>>();
coefficients[0] = 1;
for i in 1..(k + 1) {
coefficients[i] = -(1..i).fold(coefficients[0], |prev, j|{
let old = coefficients[j];
coefficients[j] = old - prev;
old
});
}
coefficients
}
fn is_prime(p: usize) -> bool {
if p < 2 {
false
} else {
let c = aks_coefficients(p);
range_inclusive(1, (c.len() - 1) / 2).all(|i| (c[i] % (p as i64)) == 0)
}
}
fn main() {
for i in 0..8 {
println!("{}: {:?}", i, aks_coefficients(i));
}
for i in (1..51).filter(|&i| is_prime(i)) {
print!("{} ", i);
}
}

44 of 53

Output:
0: [1]
1: [1, -1]
2: [1, -2,
3: [1, -3,
4: [1, -4,
5: [1, -5,
6: [1, -6,
7: [1, -7,
2 3 5 7 11

1]
3, -1]
6, -4, 1]
10, -10, 5, -1]
15, -20, 15, -6, 1]
21, -35, 35, -21, 7, -1]
13 17 19 23 29 31 37 41 43 47

An alternative version which computes the coeicients in a more functional but less eicient way.

fn aks_coefficients(k: usize) -> Vec<i64> {


if k == 0 {
vec![1i64]
} else {
let zero = Some(0i64);
range(1, k).fold(vec![1i64, -1], |r, _| {
let a = r.iter().chain(zero.iter());
let b = zero.iter().chain(r.iter());
a.zip(b).map(|(x, &y)| x-y).collect()
})
}
}

Scala
def powerMin1(n: BigInt) = if (n % 2 == 0) BigInt(1) else BigInt(-1)
val pascal = (( Vector(Vector(BigInt(1))) /: (1 to 50)) { (rows, i) =>
val v = rows.head
val newVector = ((1 until v.length) map (j =>
powerMin1(j+i) * (v(j-1).abs + v(j).abs))
).toVector
(powerMin1(i) +: newVector :+ powerMin1(i+v.length)) +: rows
}).reverse
def poly2String(poly: Vector[BigInt]) = ((0 until poly.length) map { i =>
(i, poly(i)) match {
case (0, c) => c.toString
case (_, c) =>
(if (c >= 0) "+" else "-") +
(if (c == 1) "x" else c.abs + "x") +
(if (i == 1) "" else "^" + i)
}
}) mkString ""
def isPrime(n: Int) = {
val poly = pascal(n)
poly.slice(1, poly.length - 1).forall(i => i % n == 0)
}
for(i <- 0 to 7) { println( f"(x-1)^$i = ${poly2String( pascal(i) )}" ) }
val primes = (2 to 50).filter(isPrime)
println
println(primes mkString " ")

Output:
(x-1)^0 = 1
(x-1)^1 = -1+x
(x-1)^2 = 1-2x+x^2

45 of 53

(x-1)^3
(x-1)^4
(x-1)^5
(x-1)^6
(x-1)^7

=
=
=
=
=

-1+3x-3x^2+x^3
1-4x+6x^2-4x^3+x^4
-1+5x-10x^2+10x^3-5x^4+x^5
1-6x+15x^2-20x^3+15x^4-6x^5+x^6
-1+7x-21x^2+35x^3-35x^4+21x^5-7x^6+x^7

2 3 5 7 11 13 17 19 23 29 31 37 41 43 47

Scilab
clear
xdel(winsid())
stacksize('max')
sz=stacksize();
n=7; //For the expansion up to power of n
g=50; //For test of primes up to g
function X = pascal(g) //Pascals triangle
X(1,1)=1; //Zeroth power
X(2,1)=1; //First power
X(2,2)=1;
for q=3:1:g+1 //From second power use this loop
X(q,1)=1;
X(q,q)=1;
for p=2:1:q-1
X(q,p)=X(q-1,p-1)+X(q-1,p);
end
end
endfunction
Z=pascal(g); //Generate Pascal's triangle up to g
Q(0+1)="(x-1)^0 = 1"; //For nicer display
Q(1+1)="(x-1)^1 = x^1-1"; //For nicer display
disp(Q(1))
disp(Q(2))
function cf=coef(Z,q,p) //Return coeffiecents for nicer display of expansion without "ones"
if Z(q,p)==1 then
cf="";
else
cf=string(Z(q,p));
end
endfunction
for q=3:n+1 //Generate and display the expansions
Q(q)=strcat(["(x-1)^",string(q-1)," = "]);
sing=""; //Sign of coeff.
for p=1:q-1 //Number of coefficients equals power minus 1
Q(q)=strcat([Q(q),sing,coef(Z,q,p),"x^",string(q-p)]);
if sing=="-" then sing="+"; else sing="-"; end
end
Q(q)=strcat([Q(q),sing,string(1)]);
disp(Q(q))
clear Q
end
function prime=prime(Z,g)
prime="true";
for p=2:g
if abs(floor(Z(g+1,p)/g)-Z(g+1,p)/g)>0 then
prime="false";
break;
end
end
endfunction
R="2"; //For nicer display
for r=3:g

46 of 53

if prime(Z,r)=="true" then
R=strcat([R, ", ",string(r)]);
end
end
disp(R)

Output:
(x-1)^0 = 1
(x-1)^1 = x^1-1
(x-1)^2 = x^2-2x^1+1
(x-1)^3 = x^3-3x^2+3x^1-1
(x-1)^4 = x^4-4x^3+6x^2-4x^1+1
(x-1)^5 = x^5-5x^4+10x^3-10x^2+5x^1-1
(x-1)^6 = x^6-6x^5+15x^4-20x^3+15x^2-6x^1+1
(x-1)^7 = x^7-7x^6+21x^5-35x^4+35x^3-21x^2+7x^1-1
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47

Seed7
$ include "seed7_05.s7i";
const func array integer: expand_x_1 (in integer: p) is func
result
var array integer: ex is [] (1);
local
var integer: i is 0;
begin
for i range 0 to p - 1 do
ex := [] (ex[1] * -(p - i) div (i + 1)) & ex;
end for;
end func;
const func boolean: aks_test (in integer: p) is func
result
var boolean: aks_test is FALSE;
local
var array integer: ex is 0 times 0;
var integer: idx is 0;
begin
if p >= 2 then
ex := expand_x_1(p);
ex[1] +:= 1;
for idx range 1 to pred(length(ex)) until ex[idx] rem p <> 0 do
noop;
end for;
aks_test := idx = length(ex);
end if;
end func;
const proc: main is func
local
var integer: p is 0;
var integer: n is 0;
var integer: e is 0;
begin
writeln("# p: (x-1)^p for small p");
for p range 0 to 11 do
write(p lpad 3 <& ": ");
for n key e range expand_x_1(p) do
write(" ");
if n >= 0 then

47 of 53

write("+");
end if;
write(n);
if e > 1 then
write("x^" <& pred(e));
end if;
end for;
writeln;
end for;
writeln;
writeln("# small primes using the aks test");
for p range 0 to 61 do
if aks_test(p) then
write(p <& " ");
end if;
end for;
writeln;
end func;

Output:
# p: (x-1)^p for small p
0: +1
1: -1 +1x^1
2: +1 -2x^1 +1x^2
3: -1 +3x^1 -3x^2 +1x^3
4: +1 -4x^1 +6x^2 -4x^3 +1x^4
5: -1 +5x^1 -10x^2 +10x^3 -5x^4 +1x^5
6: +1 -6x^1 +15x^2 -20x^3 +15x^4 -6x^5 +1x^6
7: -1 +7x^1 -21x^2 +35x^3 -35x^4 +21x^5 -7x^6 +1x^7
8: +1 -8x^1 +28x^2 -56x^3 +70x^4 -56x^5 +28x^6 -8x^7 +1x^8
9: -1 +9x^1 -36x^2 +84x^3 -126x^4 +126x^5 -84x^6 +36x^7 -9x^8 +1x^9
10: +1 -10x^1 +45x^2 -120x^3 +210x^4 -252x^5 +210x^6 -120x^7 +45x^8 -10x^9 +1x^10
11: -1 +11x^1 -55x^2 +165x^3 -330x^4 +462x^5 -462x^6 +330x^7 -165x^8 +55x^9 -11x^10 +1x^11
# small primes using the aks test
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61

Sidef
Translation of: Perl
func binprime(p) {
p >= 2 || return false;
range(1, p>>1).each { |i|
(binomial(p, i) % p) && return false;
};
return true;
}
func coef(n,
(e == 0)
(n == 1)
(e == 1)
}

e) {
&& return "#{n}";
&& (n = "");
? "#{n}x" : "#{n}x^#{e}";

func binpoly(p) {
join(" ", coef(1, p), range(p-1).reverse.map {|i|
join(" ", %w(+ -)[(p-i)&1], coef(binomial(p, i), i));
}...);
}
say "expansions of (x-1)^p:";
range(9).each { |i| say binpoly(i) };
say "Primes to 80: [#{(2..80).grep { binprime(_) }}]";

Output:
expansions of (x-1)^p:

48 of 53

1
x - 1
x^2 - 2x + 1
x^3 - 3x^2 + 3x - 1
x^4 - 4x^3 + 6x^2 - 4x + 1
x^5 - 5x^4 + 10x^3 - 10x^2 +
x^6 - 6x^5 + 15x^4 - 20x^3 +
x^7 - 7x^6 + 21x^5 - 35x^4 +
x^8 - 8x^7 + 28x^6 - 56x^5 +
x^9 - 9x^8 + 36x^7 - 84x^6 +
Primes to 80: [2 3 5 7 11 13

5x - 1
15x^2 - 6x + 1
35x^3 - 21x^2 + 7x - 1
70x^4 - 56x^3 + 28x^2 - 8x + 1
126x^5 - 126x^4 + 84x^3 - 36x^2 + 9x - 1
17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79]

Swift
func polynomialCoeffs(n: Int) -> [Int] {
var result = [Int](count : n+1, repeatedValue : 0)
result[0]=1
for i in 1 ..< n/2+1 { //Progress up, until reaching the middle value
result[i] = result[i-1] * (n-i+1)/i;
}
for i in n/2+1 ..< n+1 { //Copy the inverse of the first part
result[i] = result[n-i];
}
// Take into account the sign
for i in stride(from: 1, through: n, by: 2) {
result[i] = -result[i]
}
return result
}
func isPrime(n: Int) -> Bool {
var coeffs = polynomialCoeffs(n)
coeffs[0]-coeffs[n]++
for i in 1 ... n {
if coeffs[i]%n != 0 {
return false
}
}
return true
}
for i in 0...10 {
let coeffs = polynomialCoeffs(i)
print("(x-1)^\(i) = ")
if i == 0 {
print("1")
} else {
if i == 1 {
print("x")
} else {
print("x^\(i)")
if i == 2 {
print("\(coeffs[i-1])x")
} else {
for j in 1...(i - 2) {
if j%2 == 0 {
print("+\(coeffs[j])x^\(i-j)")
} else {
print("\(coeffs[j])x^\(i-j)")
}
}
if (i-1)%2 == 0 {
print("+\(coeffs[i-1])x")
} else {

49 of 53

print("\(coeffs[i-1])x")
}
}
}
if i%2 == 0 {
print("+\(coeffs[i])")
} else {
print("\(coeffs[i])")
}
}
println()
}
println()
print("Primes under 50 : ")
for i in 1...50 {
if isPrime(i) {
print("\(i) ")
}
}

Output:
(x-1)^0 = 1
(x-1)^1 = x-1
(x-1)^2 = x^2-2x+1
(x-1)^3 = x^3-3x^2+3x-1
(x-1)^4 = x^4-4x^3+6x^2-4x+1
(x-1)^5 = x^5-5x^4+10x^3-10x^2+5x-1
(x-1)^6 = x^6-6x^5+15x^4-20x^3+15x^2-6x+1
(x-1)^7 = x^7-7x^6+21x^5-35x^4+35x^3-21x^2+7x-1
(x-1)^8 = x^8-8x^7+28x^6-56x^5+70x^4-56x^3+28x^2-8x+1
(x-1)^9 = x^9-9x^8+36x^7-84x^6+126x^5-126x^4+84x^3-36x^2+9x-1
(x-1)^10 = x^10-10x^9+45x^8-120x^7+210x^6-252x^5+210x^4-120x^3+45x^2-10x+1
Primes under 50 : 1 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47

Tcl
A recursive method with memorization would be more eicient, but this is suicient for
small-scale work.
proc coeffs {p {signs 1}} {
set clist 1
for {set i 0} {$i < $p} {incr i} {
set clist [lmap x [list 0 {*}$clist] y [list {*}$clist 0] {
expr {$x + $y}
}]
}
if {$signs} {
set s -1
set clist [lmap c $clist {expr {[set s [expr {-$s}]] * $c}}]
}
return $clist
}
proc aksprime {p} {
if {$p < 2} {
return false
}
foreach c [coeffs $p 0] {
if {$c == 1} continue
if {$c % $p} {
return false
}
}
return true
}

50 of 53

for {set i 0} {$i <= 7} {incr i} {


puts -nonewline "(x-1)^$i ="
set j $i
foreach c [coeffs $i] {
puts -nonewline [format " %+dx^%d" $c $j]
incr j -1
}
puts ""
}
set sub35primes {}
for {set i 1} {$i < 35} {incr i} {
if {[aksprime $i]} {
lappend sub35primes $i
}
}
puts "primes under 35: [join $sub35primes ,]"
set sub50primes {}
for {set i 1} {$i < 50} {incr i} {
if {[aksprime $i]} {
lappend sub50primes $i
}
}
puts "primes under 50: [join $sub50primes ,]"

Output:
(x-1)^0 = +1x^0
(x-1)^1 = +1x^1 -1x^0
(x-1)^2 = +1x^2 -2x^1 +1x^0
(x-1)^3 = +1x^3 -3x^2 +3x^1 -1x^0
(x-1)^4 = +1x^4 -4x^3 +6x^2 -4x^1 +1x^0
(x-1)^5 = +1x^5 -5x^4 +10x^3 -10x^2 +5x^1 -1x^0
(x-1)^6 = +1x^6 -6x^5 +15x^4 -20x^3 +15x^2 -6x^1 +1x^0
(x-1)^7 = +1x^7 -7x^6 +21x^5 -35x^4 +35x^3 -21x^2 +7x^1 -1x^0
primes under 35: 2,3,5,7,11,13,17,19,23,29,31
primes under 50: 2,3,5,7,11,13,17,19,23,29,31,37,41,43,47

uBasic/4tH
For n = 0 To 9
Push n : Gosub _coef : Gosub _drop
Print "(x-1)^";n;" = ";
Push n : Gosub _show
Print
Next
Print
Print "primes (never mind the 1):";
For n = 1 To 34
Push n : Gosub _isprime
If Pop() Then Print " ";n;
Next
Print
End

_show
Do
If @(Tos()) > -1 Then Print "+";
Print @(Tos());"x^";Tos();
While (Tos())
Push Pop() - 1
Loop
Gosub _drop
Return

51 of 53

' show polynomial expansions


' ( n --)

_isprime
Gosub _coef

' test whether number is a prime


' ( n --)

i = Tos()
@(0) = @(0) + 1
@(i) = @(i) - 1

Do While (i) * ((@(i) % Tos()) = 0)


i = i - 1
Loop
Gosub _drop
Push (i = 0)
Return
' generate coefficients
_coef
' ( n -- n)
If (Tos() < 0) + (Tos() > 34) Then End
' gracefully deal with range issue
i = 0
@(i) = 1
Do While i < Tos()
j = i
@(j+1) = 1
Do While j > 0
@(j) = @(j-1) - @(j)
j = j - 1
Loop
@(0) = -@(0)
i = i + 1
Loop
Return

_drop
If Pop() Endif
Return

' drop a value from the stack


' ( n --)

Output:
(x-1)^0
(x-1)^1
(x-1)^2
(x-1)^3
(x-1)^4
(x-1)^5
(x-1)^6
(x-1)^7
(x-1)^8
(x-1)^9

=
=
=
=
=
=
=
=
=
=

+1x^0
+1x^1-1x^0
+1x^2-2x^1+1x^0
+1x^3-3x^2+3x^1-1x^0
+1x^4-4x^3+6x^2-4x^1+1x^0
+1x^5-5x^4+10x^3-10x^2+5x^1-1x^0
+1x^6-6x^5+15x^4-20x^3+15x^2-6x^1+1x^0
+1x^7-7x^6+21x^5-35x^4+35x^3-21x^2+7x^1-1x^0
+1x^8-8x^7+28x^6-56x^5+70x^4-56x^3+28x^2-8x^1+1x^0
+1x^9-9x^8+36x^7-84x^6+126x^5-126x^4+84x^3-36x^2+9x^1-1x^0

primes (never mind the 1): 1 2 3 5 7 11 13 17 19 23 29 31

zkl
Translation of: Python
var BN=Import("zklBigNum");
fcn expand_x_1(p){
ex := L(BN(1));
foreach i in (p){ ex.append(ex[-1] * -(p-i) / (i+1)) }
return(ex.reverse())
}
fcn aks_test(p){
if (p < 2) return(False);
ex := expand_x_1(p);

52 of 53

ex[0] = ex[0] + 1;
return(not ex[0,-1].filter('%.fp1(p)));
}
println("# p: (x-1)^p for small p");
foreach p in (12){
println("%3d: ".fmt(p),expand_x_1(p).enumerate()
.pump(String,fcn([(n,e)]){"%+d%s ".fmt(e,n and "x^%d".fmt(n) or "")}));
}
println("\n# small primes using the aks test");
println([0..110].filter(aks_test).toString(*));

Output:
# p:
0:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:

(x-1)^p for small p


+1
-1 +1x^1
+1 -2x^1 +1x^2
-1 +3x^1 -3x^2 +1x^3
+1 -4x^1 +6x^2 -4x^3 +1x^4
-1 +5x^1 -10x^2 +10x^3 -5x^4 +1x^5
+1 -6x^1 +15x^2 -20x^3 +15x^4 -6x^5 +1x^6
-1 +7x^1 -21x^2 +35x^3 -35x^4 +21x^5 -7x^6 +1x^7
+1 -8x^1 +28x^2 -56x^3 +70x^4 -56x^5 +28x^6 -8x^7 +1x^8
-1 +9x^1 -36x^2 +84x^3 -126x^4 +126x^5 -84x^6 +36x^7 -9x^8 +1x^9
+1 -10x^1 +45x^2 -120x^3 +210x^4 -252x^5 +210x^6 -120x^7 +45x^8 -10x^9 +1x^10
-1 +11x^1 -55x^2 +165x^3 -330x^4 +462x^5 -462x^6 +330x^7 -165x^8 +55x^9 -11x^10 +1x^11

# small primes using the aks test


L(2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109)

Retrieved from "http://rosettacode.org/mw/index.php?title=AKS_test_for_primes&oldid=210996"


Categories: Programming Tasks Prime Numbers ALGOL 68 AutoHotkey Bracmat C
C sharp Clojure CoeeScript Common Lisp D EchoLisp Erlang Fortran Go FreeBASIC
Haskell J Java JavaScript Jq Julia Maple Mathematica Wolfram Language Oforth
PARI/GP Pascal Perl Ntheory Perl 6 Phix PicoLisp Prolog PureBasic Python R Racket
REXX Ruby Rust Scala Scilab Seed7 Sidef Swift Tcl UBasic/4tH Zkl
This page was last modied on 5 September 2015, at 17:36.
Content is available under GNU Free Documentation License 1.2.

53 of 53

Você também pode gostar