File Coverage

blib/lib/Math/Primality/AKS.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package Math::Primality::AKS;
2             {
3             $Math::Primality::AKS::VERSION = '0.08';
4             }
5 1     1   3461 use warnings;
  1         2  
  1         29  
6 1     1   4 use strict;
  1         2  
  1         32  
7              
8 1     1   363 use Math::GMPz qw/:mpz/;
  0            
  0            
9             use Math::Primality::BigPolynomial;
10              
11             use base 'Exporter';
12             use Carp qw/croak/;
13              
14             use constant DEBUG => 0;
15              
16             use constant GMP => 'Math::GMPz';
17              
18             # ABSTRACT: Check for primality using the AKS (Agrawal-Kayal-Saxena) algorithm
19              
20              
21             our @EXPORT_OK = qw/is_aks_prime/;
22              
23             our %EXPORT_TAGS = ( all => \@EXPORT_OK );
24              
25              
26             sub debug {
27             if ( DEBUG or $ENV{DEBUG} ) {
28             warn $_[0];
29             }
30             }
31              
32             sub is_aks_prime($) {
33             # http://ece.gmu.edu/courses/ECE746/project/F06_Project_resources/Salembier_Southerington_AKS.pdf
34             # http://islab.oregonstate.edu/koc/ece575/04Project2/Halim-Chanleudfa/Report.pdf
35             # http://fatphil.org/maths/AKS/
36             my $n = GMP->new($_[0]);
37             # Step 1 - check if $n = m^d for some m, d
38             # if $n is a power then return 0
39             if (Rmpz_perfect_power_p($n)) {
40             debug "fails step 1 of aks - $n is a perfect power";
41             return 0; # composite
42             }
43             my $r = Math::GMPz->new(2);
44             my $logn = Rmpz_sizeinbase($n, 2);
45             my $limit = Math::GMPz->new($logn * $logn);
46             Rmpz_mul_ui($limit, $limit, 4);
47              
48             # Witness search
49              
50             OUTERLOOP: while (Rmpz_cmp($r, $n) == -1) {
51             if(Rmpz_divisible_p($n, $r)) {
52             debug "$n is divisible by $r\n";
53             return 0;
54             }
55              
56             if(Rmpz_probab_prime_p($n, 5)) {
57             my $i = Math::GMPz->new(1);
58             my $res = Math::GMPz->new(0);
59              
60             INNERLOOP: for ( ; Rmpz_cmp($n, $limit) <= 0; Rmpz_add_ui($i, $i, 1)) {
61             Rmpz_powm($res, $n, $i, $r);
62             if (Rmpz_cmp_ui($res, 1) == 0) {
63             last OUTERLOOP;
64             }
65             }
66              
67             }
68             Rmpz_add_ui($r, $r, 1);
69             }
70             if (Rmpz_cmp($r, $n) == 0) {
71             debug "Found $n is prime while checking for r\n";
72             return 1;
73             }
74              
75             # Polynomial check
76             my $a;
77             my $sqrtr = Math::GMPz->new($r);
78              
79             Rmpz_sqrt($sqrtr, $r);
80             my $polylimit = Math::GMPz->new(0);
81             Rmpz_add_ui($polylimit, $sqrtr, 1);
82             Rmpz_mul_ui($polylimit, $polylimit, $logn);
83             Rmpz_mul_ui($polylimit, $polylimit, 2);
84              
85             my $intr = Rmpz_get_ui($r);
86              
87             for($a = 1; Rmpz_cmp_ui($polylimit, $a) >= 0; $a++) {
88             debug "Checking at $a\n";
89             my $final_size = Math::GMPz->new(0);
90             Rmpz_mod($final_size, $n, $r);
91             my $compare = Math::Primality::BigPolynomial->new(Rmpz_get_ui($final_size));
92             $compare->setCoef(Math::GMPz->new(1), $final_size);
93             $compare->setCoef(Math::GMPz->new($a), 0);
94             my $res = Math::Primality::BigPolynomial->new($intr);
95             my $base = Math::Primality::BigPolynomial->new(1);
96             $base->setCoef(Math::GMPz->new(0), $a);
97             $base->setCoef(Math::GMPz->new(1), 1);
98              
99             Math::Primality::BigPolynomial::mpz_poly_mod_power($res, $base, $n, $n, $intr);
100              
101              
102             if($res->isEqual($compare)) {
103             debug "Found not prime at $a\n";
104             return 0;
105             }
106             }
107             return 1;
108             }
109              
110              
111             exp(0); # End of Math::Primality::AKS
112              
113             __END__