line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# Copyright (c) 2019-2021 by Martin Becker. This package is free software, |
2
|
|
|
|
|
|
|
# licensed under The Artistic License 2.0 (GPL compatible). |
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
package Math::Polynomial::Cyclotomic; |
5
|
|
|
|
|
|
|
|
6
|
3
|
|
|
3
|
|
19744
|
use 5.006; |
|
3
|
|
|
|
|
22
|
|
7
|
3
|
|
|
3
|
|
14
|
use strict; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
51
|
|
8
|
3
|
|
|
3
|
|
11
|
use warnings; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
146
|
|
9
|
3
|
|
|
3
|
|
17
|
use Carp qw(croak); |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
191
|
|
10
|
3
|
|
|
3
|
|
3352
|
use Math::BigInt try => 'GMP'; |
|
3
|
|
|
|
|
83367
|
|
|
3
|
|
|
|
|
20
|
|
11
|
3
|
|
|
3
|
|
71274
|
use Math::Polynomial 1.019; |
|
3
|
|
|
|
|
6577
|
|
|
3
|
|
|
|
|
102
|
|
12
|
3
|
|
|
|
|
19
|
use Math::Prime::Util qw( |
13
|
|
|
|
|
|
|
divisors factor factor_exp euler_phi gcd is_square_free is_power |
14
|
|
|
|
|
|
|
moebius kronecker vecprod |
15
|
3
|
|
|
3
|
|
3487
|
); |
|
3
|
|
|
|
|
29623
|
|
16
|
|
|
|
|
|
|
require Exporter; |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
our @ISA = qw(Exporter); |
19
|
|
|
|
|
|
|
our @EXPORT_OK = qw( |
20
|
|
|
|
|
|
|
cyclo_poly cyclo_factors cyclo_plusfactors cyclo_poly_iterate |
21
|
|
|
|
|
|
|
cyclo_lucas_cd cyclo_schinzel_cd cyclo_int_factors cyclo_int_plusfactors |
22
|
|
|
|
|
|
|
); |
23
|
|
|
|
|
|
|
our %EXPORT_TAGS = (all => \@EXPORT_OK); |
24
|
|
|
|
|
|
|
our $VERSION = '0.004'; |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
# some polynomial with coefficient type Math::BigInt |
27
|
|
|
|
|
|
|
my $default = Math::Polynomial->new(Math::BigInt->new('1')); |
28
|
|
|
|
|
|
|
$default->string_config({fold_sign => 1, times => '*'}); |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
# ----- private subroutines ----- |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
sub _cyclo_poly { |
33
|
118
|
|
|
118
|
|
252
|
my ($poly, $table, $n, $divisors) = @_; |
34
|
118
|
100
|
|
|
|
402
|
return $table->{$n} if exists $table->{$n}; |
35
|
62
|
|
|
|
|
302
|
my $m = vecprod(map { $_->[0] } factor_exp($n)); # $m = radix($n) |
|
81
|
|
|
|
|
247
|
|
36
|
62
|
|
|
|
|
148
|
my $o = $m & 1; |
37
|
62
|
100
|
|
|
|
136
|
$m >>= 1 if !$o; |
38
|
62
|
|
|
|
|
87
|
my $p; |
39
|
62
|
100
|
|
|
|
152
|
if (exists $table->{$m}) { |
40
|
26
|
|
|
|
|
54
|
$p = $table->{$m}; |
41
|
|
|
|
|
|
|
} |
42
|
|
|
|
|
|
|
else { |
43
|
36
|
|
|
|
|
98
|
my $one = $poly->coeff_one; |
44
|
36
|
100
|
|
|
|
259
|
my @d = $divisors? (grep { not $m % $_ } @{$divisors}): divisors($m); |
|
116
|
|
|
|
|
213
|
|
|
23
|
|
|
|
|
44
|
|
45
|
36
|
|
|
|
|
108
|
$p = $poly->monomial(pop @d)->sub_const($one); |
46
|
36
|
100
|
|
|
|
8847
|
if (@d) { |
47
|
26
|
|
|
|
|
48
|
my $b = $d[-1]; |
48
|
26
|
|
|
|
|
63
|
$p /= $poly->monomial($b)->sub_const($one); |
49
|
26
|
|
|
|
|
276966
|
for (my $i = 1; $i < $#d; ++$i) { |
50
|
11
|
|
|
|
|
63333
|
my $r = $d[$i]; |
51
|
11
|
100
|
|
|
|
38
|
if ($b % $r) { |
52
|
9
|
|
66
|
|
|
49
|
$p /= $table->{$r} || _cyclo_poly($poly, $table, $r, \@d); |
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
} |
55
|
|
|
|
|
|
|
} |
56
|
36
|
|
|
|
|
77479
|
$table->{$m} = $p; |
57
|
|
|
|
|
|
|
} |
58
|
62
|
100
|
|
|
|
155
|
if (!$o) { |
59
|
29
|
100
|
|
|
|
95
|
$p = -$p if $m == 1; |
60
|
29
|
|
|
|
|
1191
|
$m <<= 1; |
61
|
29
|
|
|
|
|
91
|
$p = $p->mirror; |
62
|
29
|
|
|
|
|
2570
|
$table->{$m} = $p; |
63
|
|
|
|
|
|
|
} |
64
|
62
|
100
|
|
|
|
149
|
if ($m != $n) { |
65
|
21
|
|
|
|
|
92
|
$p = $p->inflate($n/$m); |
66
|
21
|
|
|
|
|
1531
|
$table->{$n} = $p; |
67
|
|
|
|
|
|
|
} |
68
|
62
|
|
|
|
|
230
|
return $p; |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
# for a positive integer n, return r,s so that r is square-free and n=rs^2 |
72
|
|
|
|
|
|
|
sub _square_free_square { |
73
|
16
|
|
|
16
|
|
40
|
my ($n) = @_; |
74
|
16
|
|
|
|
|
43
|
my ($r, $s) = (1, 1); |
75
|
16
|
|
|
|
|
117
|
foreach my $be (factor_exp($n)) { |
76
|
27
|
|
|
|
|
44
|
my ($b, $e) = @{$be}; |
|
27
|
|
|
|
|
56
|
|
77
|
27
|
100
|
|
|
|
69
|
$r *= $b if $e & 1; |
78
|
27
|
|
|
|
|
40
|
$e >>= 1; |
79
|
27
|
|
|
|
|
71
|
while ($e) { |
80
|
7
|
100
|
|
|
|
26
|
$s *= $b if $e & 1; |
81
|
7
|
100
|
|
|
|
23
|
$e >>= 1 and $b *= $b; |
82
|
|
|
|
|
|
|
} |
83
|
|
|
|
|
|
|
} |
84
|
16
|
|
|
|
|
42
|
return ($r, $s); |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
# generate polynomials C, D, satisfying the identity of Aurifeuille, |
88
|
|
|
|
|
|
|
# Le Lasseur and Lucas: for n > 1, square-free, |
89
|
|
|
|
|
|
|
# n === 1 (mod 4): Phi_n(x) = C^2 - n*x*D^2 |
90
|
|
|
|
|
|
|
# else: Phi_2n(x) = C^2 - n*x*D^2 |
91
|
|
|
|
|
|
|
sub _lucas_cd { |
92
|
10
|
|
|
10
|
|
29
|
my ($poly, $table, $n) = @_; |
93
|
10
|
|
|
|
|
31
|
my $c1 = 1 == ($n & 3); |
94
|
10
|
100
|
|
|
|
31
|
my $n1 = $c1? $n: $n + $n; |
95
|
10
|
100
|
|
|
|
40
|
if (exists $table->{"$n1 $n"}) { |
96
|
3
|
|
|
|
|
6
|
return (@{$table->{"$n1 $n"}}) |
|
3
|
|
|
|
|
14
|
|
97
|
|
|
|
|
|
|
} |
98
|
7
|
|
|
|
|
24
|
my $c2 = !($n & 1); |
99
|
7
|
|
|
|
|
28
|
my $ee = euler_phi($n1); |
100
|
7
|
|
|
|
|
17
|
my $e = $ee >> 1; |
101
|
7
|
|
|
|
|
32
|
my $one = $poly->coeff_one; |
102
|
7
|
|
|
|
|
74
|
my $nul = $poly->coeff_zero; |
103
|
|
|
|
|
|
|
|
104
|
7
|
|
|
|
|
30
|
my $E = $e | 1; |
105
|
7
|
|
|
|
|
20
|
my @q = ($one); |
106
|
7
|
|
|
|
|
12
|
my $cos = $one; |
107
|
7
|
|
|
|
|
15
|
my %MP = (); |
108
|
7
|
|
|
|
|
27
|
for (my $k = 2; $k <= $E; ++$k) { |
109
|
30
|
100
|
|
|
|
2118
|
if ($k & 1) { |
110
|
15
|
|
|
|
|
94
|
push @q, $nul + kronecker($n, $k); |
111
|
15
|
|
|
|
|
2604
|
next; |
112
|
|
|
|
|
|
|
} |
113
|
15
|
100
|
100
|
|
|
45
|
if ($c2 && $k & 2) { |
114
|
2
|
|
|
|
|
3
|
push @q, $nul; |
115
|
2
|
|
|
|
|
5
|
next; |
116
|
|
|
|
|
|
|
} |
117
|
13
|
100
|
|
|
|
39
|
$cos = -$cos if !$c1; # $cos is cos((n-1)*k*pi/4) |
118
|
13
|
|
|
|
|
295
|
my $gk = gcd($n1, $k); |
119
|
13
|
|
66
|
|
|
114
|
my $mp = $MP{$gk} ||= moebius($n1 / $gk) * euler_phi($gk); |
120
|
13
|
|
|
|
|
85
|
push @q, $cos * $mp; |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
|
123
|
7
|
|
|
|
|
18
|
my @cs = ($one); |
124
|
7
|
|
|
|
|
16
|
my @ds = ($one); |
125
|
7
|
|
|
|
|
20
|
$cs[$e] = $ds[$e-1] = $one; |
126
|
7
|
|
|
|
|
22
|
for(my $k = 1, my $kk = $e - 1; $k <= $kk; ++$k, --$kk) { |
127
|
15
|
|
|
|
|
2659
|
my ($c, $d) = ($nul, $nul); |
128
|
15
|
|
|
|
|
40
|
for (my $i = 0, my $j = $k-1; $j >= 0; $i += 2, --$j) { |
129
|
37
|
|
|
|
|
5422
|
my $cc = $cs[$j]; |
130
|
37
|
|
|
|
|
57
|
my $dd = $ds[$j]; |
131
|
37
|
|
|
|
|
78
|
my ($q1, $q2) = @q[$i, $i+1]; |
132
|
37
|
|
|
|
|
72
|
$c += $q1 * $n * $dd - $q2 * $cc; |
133
|
37
|
|
|
|
|
14293
|
$d += $q[$i+2] * $cc - $q2 * $dd; |
134
|
|
|
|
|
|
|
} |
135
|
15
|
|
|
|
|
3603
|
$c /= ($k + $k); |
136
|
15
|
|
|
|
|
3337
|
$cs[$k] = $cs[$kk] = $c; |
137
|
15
|
100
|
|
|
|
64
|
$ds[$k] = $ds[$kk-1] = ($d + $c) / ($k + $k + 1) if $k < $kk; |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
7
|
|
|
|
|
42
|
my $cp = $poly->new(@cs); |
141
|
7
|
|
|
|
|
391
|
my $dp = $poly->new(@ds); |
142
|
7
|
|
|
|
|
249
|
$table->{"$n1 $n"} = [$cp, $dp]; |
143
|
7
|
|
|
|
|
70
|
return ($cp, $dp); |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
# generate polynomials C, D, satisfying the identity of Beeger and Schinzel: |
147
|
|
|
|
|
|
|
# for k > 1, square-free, k1 = k (if k === 1 (mod 4)), k1 = 2*k (else), |
148
|
|
|
|
|
|
|
# n = odd multiple of k1: Phi_n(x) = C^2 - k*x*D^2 |
149
|
|
|
|
|
|
|
sub _schinzel_cd { |
150
|
25
|
|
|
25
|
|
82
|
my ($poly, $table, $n, $k) = @_; |
151
|
25
|
100
|
|
|
|
124
|
my $K = ($k & 3) == 1? $k: $k << 1; |
152
|
25
|
|
|
|
|
69
|
my $f = $n / $K; |
153
|
25
|
100
|
|
|
|
71
|
return () if not $f & 1; |
154
|
23
|
|
|
|
|
144
|
my $r = vecprod(map { $_->[0] } factor_exp($f)); |
|
10
|
|
|
|
|
47
|
|
155
|
23
|
|
|
|
|
112
|
my $m = $f / $r * gcd($f, $k); |
156
|
23
|
100
|
|
|
|
62
|
if ($m > 1) { |
157
|
3
|
|
|
|
|
6
|
$n /= $m; |
158
|
3
|
|
|
|
|
5
|
$f /= $m; |
159
|
|
|
|
|
|
|
} |
160
|
23
|
|
|
|
|
63
|
my ($C, $D) = (); |
161
|
23
|
100
|
|
|
|
123
|
if (exists $table->{"$n $k"}) { |
162
|
17
|
|
|
|
|
35
|
($C, $D) = @{$table->{"$n $k"}}; |
|
17
|
|
|
|
|
77
|
|
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
else { |
165
|
6
|
|
|
|
|
25
|
($C, $D) = _lucas_cd($poly, $table, $k); |
166
|
6
|
|
|
|
|
16
|
my ($L, $M, $Q) = (); |
167
|
6
|
|
|
|
|
28
|
foreach my $p (factor($f)) { |
168
|
6
|
|
|
|
|
8632
|
my $p2 = $p >> 1; |
169
|
6
|
|
|
|
|
28
|
my $kp2 = Math::BigInt->new($k)->bpow($p2); |
170
|
6
|
100
|
|
|
|
1947
|
if (!defined $M) { |
171
|
5
|
|
|
|
|
24
|
$Q = $poly->monomial(2, $k); |
172
|
5
|
|
|
|
|
733
|
my $CC = $C->nest($Q); |
173
|
5
|
|
|
|
|
17113
|
my $DD = $D->nest($Q)->shift_up(1)->mul_const($k); |
174
|
5
|
|
|
|
|
13709
|
$L = $CC - $DD; |
175
|
5
|
|
|
|
|
2262
|
$M = $CC + $DD; |
176
|
|
|
|
|
|
|
} |
177
|
6
|
100
|
|
|
|
2008
|
if (kronecker($k, $p) < 0) { |
178
|
5
|
|
|
|
|
22
|
($L, $M) = ( |
179
|
|
|
|
|
|
|
$L->nest($poly->monomial($p, $kp2)) / $M, |
180
|
|
|
|
|
|
|
$M->nest($poly->monomial($p, $kp2)) / $L, |
181
|
|
|
|
|
|
|
); |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
else { |
184
|
1
|
|
|
|
|
7
|
($L, $M) = ( |
185
|
|
|
|
|
|
|
$M->nest($poly->monomial($p, $kp2)) / $M, |
186
|
|
|
|
|
|
|
$L->nest($poly->monomial($p, $kp2)) / $L, |
187
|
|
|
|
|
|
|
); |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
} |
190
|
6
|
100
|
|
|
|
379886
|
if (defined $M) { |
191
|
5
|
|
|
|
|
27
|
$C = ($M + $L)->div_const(2)->unnest($Q); |
192
|
5
|
|
|
|
|
126731
|
$D = (($M - $L) / $poly->monomial(1, $k << 1))->unnest($Q); |
193
|
5
|
|
|
|
|
110447
|
$table->{"$n $k"} = [$C, $D]; |
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
} |
196
|
23
|
100
|
|
|
|
80
|
if ($m > 1) { |
197
|
3
|
|
|
|
|
15
|
$C = $C->inflate($m); |
198
|
3
|
|
|
|
|
242
|
$D = $D->inflate($m)->shift_up($m >> 1); |
199
|
|
|
|
|
|
|
} |
200
|
23
|
|
|
|
|
353
|
return ($C, $D); |
201
|
|
|
|
|
|
|
} |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
# for r > 1, integer, square-free, s > 0, integer, x = r*s^2, |
204
|
|
|
|
|
|
|
# r1 = r (if r === 1 (mod 4)), r1 = 2*r (else), n = odd multiple of r1, |
205
|
|
|
|
|
|
|
# generate integer factors l < m such that l * m = Phi_n(x). |
206
|
|
|
|
|
|
|
# if l = 1, return (m) else (l, m). |
207
|
|
|
|
|
|
|
sub _schinzel_lm { |
208
|
16
|
|
|
16
|
|
89
|
my ($poly, $table, $n, $r, $s, $x) = @_; |
209
|
16
|
|
|
|
|
114
|
my ($c, $d) = _schinzel_cd($poly, $table, $n, $r); |
210
|
16
|
|
|
|
|
55
|
my $cx = $c->evaluate($x); |
211
|
16
|
|
|
|
|
16578
|
my $dx = $d->evaluate($x) * $r * $s; |
212
|
16
|
|
|
|
|
15936
|
my ($l, $m) = ($cx - $dx, $cx + $dx); |
213
|
16
|
100
|
|
|
|
3001
|
return $m if $l == $poly->coeff_one; |
214
|
14
|
|
|
|
|
791
|
return ($l, $m); |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
# ----- Math::Polynomial extension ----- |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
sub Math::Polynomial::cyclotomic { |
220
|
12
|
|
|
12
|
0
|
5506
|
my ($this, $n, $table) = @_; |
221
|
12
|
|
100
|
|
|
56
|
return _cyclo_poly($this, $table || {}, $n); |
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
sub Math::Polynomial::cyclo_factors { |
225
|
6
|
|
|
6
|
0
|
5964
|
my ($this, $n, $table) = @_; |
226
|
6
|
|
|
|
|
56
|
my @d = divisors($n); |
227
|
6
|
|
100
|
|
|
29
|
$table ||= {}; |
228
|
6
|
|
|
|
|
16
|
return map { _cyclo_poly($this, $table, $_, \@d) } @d; |
|
28
|
|
|
|
|
58
|
|
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
sub Math::Polynomial::cyclo_int_factors { |
232
|
13
|
|
|
13
|
0
|
43
|
my ($this, $x, $n, $table) = @_; |
233
|
13
|
100
|
100
|
|
|
73
|
return ($this->coeff_zero) if !$n || $x == $this->coeff_one; |
234
|
11
|
100
|
100
|
|
|
1510
|
return ($x - $this->coeff_one) if $n == 1 || !$x; |
235
|
9
|
|
50
|
|
|
34
|
$table ||= {}; |
236
|
9
|
100
|
|
|
|
95
|
if (my $exp = is_power($x, 0, \my $root)) { |
237
|
2
|
|
|
|
|
5
|
$x = $root; |
238
|
2
|
|
|
|
|
5
|
$n *= $exp; |
239
|
|
|
|
|
|
|
} |
240
|
9
|
|
|
|
|
37
|
my ($r, $s) = _square_free_square($x); |
241
|
9
|
100
|
|
|
|
35
|
my $r1 = (1 == ($r & 3))? $r: $r+$r; |
242
|
9
|
|
|
|
|
68
|
my @d = divisors($n); |
243
|
9
|
|
100
|
|
|
43
|
my $i = $x == 2 || 0; |
244
|
|
|
|
|
|
|
return |
245
|
|
|
|
|
|
|
map { |
246
|
9
|
100
|
100
|
|
|
48
|
!($_ % $r1) && ($_ / $r1) & 1? |
|
45
|
|
|
|
|
19091
|
|
247
|
|
|
|
|
|
|
_schinzel_lm($this, $table, $_, $r, $s, $x): |
248
|
|
|
|
|
|
|
(_cyclo_poly($this, $table, $_, \@d))->evaluate($x) |
249
|
|
|
|
|
|
|
} @d[$i .. $#d]; |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
sub Math::Polynomial::cyclo_plusfactors { |
253
|
4
|
|
|
4
|
0
|
549
|
my ($this, $n, $table) = @_; |
254
|
4
|
|
|
|
|
27
|
my @d = divisors($n << 1); |
255
|
4
|
|
|
|
|
10
|
my $m = $n ^ ($n - 1); |
256
|
4
|
|
100
|
|
|
18
|
$table ||= {}; |
257
|
|
|
|
|
|
|
return |
258
|
8
|
|
|
|
|
18
|
map { _cyclo_poly($this, $table, $_, \@d) } |
259
|
4
|
|
|
|
|
10
|
grep { !($_ & $m) } @d; |
|
20
|
|
|
|
|
36
|
|
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
sub Math::Polynomial::cyclo_int_plusfactors { |
263
|
11
|
|
|
11
|
0
|
30
|
my ($this, $x, $n, $table) = @_; |
264
|
11
|
|
|
|
|
58
|
my $u = $this->coeff_one; |
265
|
11
|
100
|
|
|
|
58
|
return ($u + $u) if !$n; |
266
|
10
|
100
|
100
|
|
|
82
|
return ($x + $u) if $n == 1 || !$x || $x == $u; |
|
|
|
100
|
|
|
|
|
267
|
7
|
100
|
|
|
|
938
|
if (my $exp = is_power($x, 0, \my $root)) { |
268
|
2
|
|
|
|
|
7
|
$x = $root; |
269
|
2
|
|
|
|
|
6
|
$n *= $exp; |
270
|
|
|
|
|
|
|
} |
271
|
7
|
|
|
|
|
27
|
my ($r, $s) = _square_free_square($x); |
272
|
7
|
100
|
|
|
|
31
|
my $r1 = (1 == ($r & 3))? $r: $r+$r; |
273
|
7
|
|
|
|
|
55
|
my @d = divisors($n << 1); |
274
|
7
|
|
|
|
|
21
|
my $m = $n ^ ($n - 1); |
275
|
7
|
|
50
|
|
|
24
|
$table ||= {}; |
276
|
|
|
|
|
|
|
return |
277
|
|
|
|
|
|
|
map { |
278
|
23
|
100
|
100
|
|
|
10461
|
!($_ % $r1) && ($_ / $r1) & 1? |
279
|
|
|
|
|
|
|
_schinzel_lm($this, $table, $_, $r, $s, $x): |
280
|
|
|
|
|
|
|
(_cyclo_poly($this, $table, $_, \@d))->evaluate($x) |
281
|
7
|
|
|
|
|
16
|
} grep { !($_ & $m) } @d; |
|
58
|
|
|
|
|
100
|
|
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
sub Math::Polynomial::cyclo_lucas_cd { |
285
|
6
|
|
|
6
|
0
|
18
|
my ($this, $n, $table) = @_; |
286
|
6
|
100
|
100
|
|
|
73
|
if ($n <= 1 || !is_square_free($n)) { |
287
|
2
|
|
|
|
|
280
|
croak "$n: not a square-free integer greater than one"; |
288
|
|
|
|
|
|
|
} |
289
|
4
|
|
50
|
|
|
21
|
return _lucas_cd($this, $table || {}, $n); |
290
|
|
|
|
|
|
|
} |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
sub Math::Polynomial::cyclo_schinzel_cd { |
293
|
11
|
|
|
11
|
0
|
31
|
my ($this, $n, $k, $table) = @_; |
294
|
11
|
100
|
100
|
|
|
96
|
if ($k <= 1 || !is_square_free($k)) { |
295
|
2
|
|
|
|
|
190
|
croak "$k: not a square-free integer greater than one"; |
296
|
|
|
|
|
|
|
} |
297
|
9
|
|
100
|
|
|
46
|
my @cd = _schinzel_cd($this, $table || {}, $n, $k); |
298
|
9
|
100
|
|
|
|
32
|
if (!@cd) { |
299
|
2
|
100
|
|
|
|
6
|
my $k1 = ($k & 3) == 1? 'k': '2*k'; |
300
|
2
|
|
|
|
|
177
|
croak "$n: n is not an odd multiple of $k1"; |
301
|
|
|
|
|
|
|
} |
302
|
7
|
|
|
|
|
37
|
return @cd; |
303
|
|
|
|
|
|
|
} |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
sub Math::Polynomial::cyclo_poly_iterate { |
306
|
4
|
|
|
4
|
0
|
1733
|
my ($this, $n, $table) = @_; |
307
|
4
|
|
100
|
|
|
19
|
$n ||= 1; |
308
|
4
|
|
|
|
|
6
|
--$n; |
309
|
4
|
|
100
|
|
|
17
|
$table ||= {}; |
310
|
|
|
|
|
|
|
return |
311
|
|
|
|
|
|
|
sub { |
312
|
14
|
|
|
14
|
|
7489
|
++$n; |
313
|
14
|
|
|
|
|
34
|
_cyclo_poly($this, $table, $n); |
314
|
4
|
|
|
|
|
45
|
}; |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
# ----- public subroutines ----- |
318
|
|
|
|
|
|
|
|
319
|
9
|
|
|
9
|
1
|
6429
|
sub cyclo_poly { $default->cyclotomic(@_) } |
320
|
2
|
|
|
2
|
1
|
1952
|
sub cyclo_factors { $default->cyclo_factors(@_) } |
321
|
3
|
|
|
3
|
1
|
3129
|
sub cyclo_plusfactors { $default->cyclo_plusfactors(@_) } |
322
|
2
|
|
|
2
|
1
|
1268
|
sub cyclo_poly_iterate { $default->cyclo_poly_iterate(@_) } |
323
|
6
|
|
|
6
|
1
|
8917
|
sub cyclo_lucas_cd { $default->cyclo_lucas_cd(@_) } |
324
|
11
|
|
|
11
|
1
|
11215
|
sub cyclo_schinzel_cd { $default->cyclo_schinzel_cd(@_) } |
325
|
13
|
|
|
13
|
1
|
10032
|
sub cyclo_int_factors { $default->cyclo_int_factors(@_) } |
326
|
11
|
|
|
11
|
1
|
15406
|
sub cyclo_int_plusfactors { $default->cyclo_int_plusfactors(@_) } |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
1; |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
__END__ |