| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | # Copyright (c) 2013-2019 by Martin Becker.  This package is free software, | 
| 2 |  |  |  |  |  |  | # licensed under The Artistic License 2.0 (GPL compatible). | 
| 3 |  |  |  |  |  |  |  | 
| 4 |  |  |  |  |  |  | package Math::Polynomial::ModInt; | 
| 5 |  |  |  |  |  |  |  | 
| 6 | 3 |  |  | 3 |  | 61919 | use 5.006; | 
|  | 3 |  |  |  |  | 20 |  | 
| 7 | 3 |  |  | 3 |  | 14 | use strict; | 
|  | 3 |  |  |  |  | 4 |  | 
|  | 3 |  |  |  |  | 49 |  | 
| 8 | 3 |  |  | 3 |  | 10 | use warnings; | 
|  | 3 |  |  |  |  | 12 |  | 
|  | 3 |  |  |  |  | 89 |  | 
| 9 | 3 |  |  | 3 |  | 1962 | use Math::BigInt try => 'GMP'; | 
|  | 3 |  |  |  |  | 47963 |  | 
|  | 3 |  |  |  |  | 15 |  | 
| 10 | 3 |  |  | 3 |  | 45986 | use Math::ModInt 0.012; | 
|  | 3 |  |  |  |  | 5755 |  | 
|  | 3 |  |  |  |  | 135 |  | 
| 11 | 3 |  |  | 3 |  | 17 | use Math::ModInt::Event qw(UndefinedResult); | 
|  | 3 |  |  |  |  | 6 |  | 
|  | 3 |  |  |  |  | 123 |  | 
| 12 | 3 |  |  | 3 |  | 1806 | use Math::Polynomial 1.015; | 
|  | 3 |  |  |  |  | 18720 |  | 
|  | 3 |  |  |  |  | 83 |  | 
| 13 | 3 |  |  | 3 |  | 19 | use Carp qw(croak); | 
|  | 3 |  |  |  |  | 5 |  | 
|  | 3 |  |  |  |  | 134 |  | 
| 14 |  |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  | # ----- object definition ----- | 
| 16 |  |  |  |  |  |  |  | 
| 17 |  |  |  |  |  |  | # Math::Polynomial::ModInt=ARRAY(...) | 
| 18 |  |  |  |  |  |  |  | 
| 19 |  |  |  |  |  |  | # .............. index ..............   # .......... value .......... | 
| 20 |  |  |  |  |  |  |  | 
| 21 | 3 |  |  | 3 |  | 15 | use constant _OFFSET  => Math::Polynomial::_NFIELDS; | 
|  | 3 |  |  |  |  | 10 |  | 
|  | 3 |  |  |  |  | 148 |  | 
| 22 | 3 |  |  | 3 |  | 17 | use constant _F_INDEX => _OFFSET + 0;    # ordinal number i, 0 <= i | 
|  | 3 |  |  |  |  | 5 |  | 
|  | 3 |  |  |  |  | 132 |  | 
| 23 | 3 |  |  | 3 |  | 16 | use constant _NFIELDS => _OFFSET + 1; | 
|  | 3 |  |  |  |  | 5 |  | 
|  | 3 |  |  |  |  | 286 |  | 
| 24 |  |  |  |  |  |  |  | 
| 25 |  |  |  |  |  |  | # ----- class data ----- | 
| 26 |  |  |  |  |  |  |  | 
| 27 |  |  |  |  |  |  | BEGIN { | 
| 28 | 3 |  |  | 3 |  | 26 | require Exporter; | 
| 29 | 3 |  |  |  |  | 81 | our @ISA       = qw(Math::Polynomial Exporter); | 
| 30 | 3 |  |  |  |  | 8 | our @EXPORT_OK = qw(modpoly); | 
| 31 | 3 |  |  |  |  | 6 | our $VERSION   = '0.004'; | 
| 32 | 3 |  |  |  |  | 4957 | our @CARP_NOT  = qw(Math::ModInt::Event::Trap Math::Polynomial); | 
| 33 |  |  |  |  |  |  | } | 
| 34 |  |  |  |  |  |  |  | 
| 35 |  |  |  |  |  |  | my $default_string_config = { | 
| 36 |  |  |  |  |  |  | convert_coeff => sub { $_[0]->residue }, | 
| 37 |  |  |  |  |  |  | times         => q[*], | 
| 38 |  |  |  |  |  |  | wrap          => \&_wrap, | 
| 39 |  |  |  |  |  |  | }; | 
| 40 |  |  |  |  |  |  |  | 
| 41 |  |  |  |  |  |  | my $lifted_string_config = { | 
| 42 |  |  |  |  |  |  | times         => q[*], | 
| 43 |  |  |  |  |  |  | fold_sign     => 1, | 
| 44 |  |  |  |  |  |  | }; | 
| 45 |  |  |  |  |  |  |  | 
| 46 |  |  |  |  |  |  | my $ipol = Math::Polynomial->new(Math::BigInt->new); | 
| 47 |  |  |  |  |  |  | $ipol->string_config($lifted_string_config); | 
| 48 |  |  |  |  |  |  |  | 
| 49 |  |  |  |  |  |  | # ----- private subroutines ----- | 
| 50 |  |  |  |  |  |  |  | 
| 51 |  |  |  |  |  |  | # event catcher | 
| 52 |  |  |  |  |  |  | sub _bad_modulus { | 
| 53 | 3 |  |  | 3 |  | 506 | croak 'modulus not prime'; | 
| 54 |  |  |  |  |  |  | } | 
| 55 |  |  |  |  |  |  |  | 
| 56 |  |  |  |  |  |  | # event catcher | 
| 57 |  |  |  |  |  |  | sub _no_inverse { | 
| 58 | 1 |  |  | 1 |  | 291 | croak 'undefined inverse'; | 
| 59 |  |  |  |  |  |  | } | 
| 60 |  |  |  |  |  |  |  | 
| 61 |  |  |  |  |  |  | # wrapper for modular inverse to bail out early if not in a field | 
| 62 |  |  |  |  |  |  | sub _inverse { | 
| 63 | 2 |  |  | 2 |  | 3 | my ($element) = @_; | 
| 64 | 2 |  |  |  |  | 14 | my $trap = UndefinedResult->trap(\&_no_inverse); | 
| 65 | 2 |  |  |  |  | 51 | return $element->inverse; | 
| 66 |  |  |  |  |  |  | } | 
| 67 |  |  |  |  |  |  |  | 
| 68 |  |  |  |  |  |  | # Does a set of coefficient vectors have a zero linear combination? | 
| 69 |  |  |  |  |  |  | # We transform and include them one by one into a matrix in echelon form. | 
| 70 |  |  |  |  |  |  | # Argument is an iterator so we can short-cut generating superfluous vectors. | 
| 71 |  |  |  |  |  |  | # Supplied vectors may be modified. | 
| 72 |  |  |  |  |  |  | sub _linearly_dependent { | 
| 73 | 7 |  |  | 7 |  | 11 | my ($it) = @_; | 
| 74 | 7 |  |  |  |  | 25 | my $trap = UndefinedResult->trap(\&_bad_modulus); | 
| 75 | 7 |  |  |  |  | 126 | my @ech = (); | 
| 76 | 7 |  |  |  |  | 12 | while (defined(my $vec = $it->())) { | 
| 77 | 22 |  |  |  |  | 624 | my $ex = 0; | 
| 78 | 22 |  |  |  |  | 38 | for (; $ex < @ech; ++$ex) { | 
| 79 | 25 |  |  |  |  | 77 | my $evec = $ech[$ex]; | 
| 80 | 25 | 100 |  |  |  | 28 | last if @{$evec} < @{$vec}; | 
|  | 25 |  |  |  |  | 26 |  | 
|  | 25 |  |  |  |  | 43 |  | 
| 81 | 20 | 100 |  |  |  | 24 | if (@{$evec} == @{$vec}) { | 
|  | 20 |  |  |  |  | 24 |  | 
|  | 20 |  |  |  |  | 34 |  | 
| 82 | 16 |  |  |  |  | 18 | my $i = $#{$vec}; | 
|  | 16 |  |  |  |  | 20 |  | 
| 83 | 16 | 100 |  |  |  | 30 | return 1 if !$i; | 
| 84 | 15 |  |  |  |  | 18 | my $w = pop(@{$vec}) / $evec->[$i]; | 
|  | 15 |  |  |  |  | 28 |  | 
| 85 | 14 |  |  |  |  | 213 | while ($i-- > 0) { | 
| 86 | 42 |  |  |  |  | 544 | $vec->[$i] -= $evec->[$i] * $w; | 
| 87 |  |  |  |  |  |  | } | 
| 88 | 14 |  | 100 |  |  | 283 | while (@{$vec} && !$vec->[-1]) { | 
|  | 25 |  |  |  |  | 56 |  | 
| 89 | 11 |  |  |  |  | 71 | pop(@{$vec}); | 
|  | 11 |  |  |  |  | 15 |  | 
| 90 |  |  |  |  |  |  | } | 
| 91 |  |  |  |  |  |  | } | 
| 92 |  |  |  |  |  |  | } | 
| 93 | 20 | 100 |  |  |  | 62 | return 1 if !@{$vec}; | 
|  | 20 |  |  |  |  | 40 |  | 
| 94 | 19 |  |  |  |  | 51 | splice @ech, $ex, 0, $vec; | 
| 95 |  |  |  |  |  |  | } | 
| 96 | 4 |  |  |  |  | 16 | return 0; | 
| 97 |  |  |  |  |  |  | } | 
| 98 |  |  |  |  |  |  |  | 
| 99 |  |  |  |  |  |  | # ----- private methods ----- | 
| 100 |  |  |  |  |  |  |  | 
| 101 |  |  |  |  |  |  | # wrapper to decorate stringified polynomial | 
| 102 |  |  |  |  |  |  | sub _wrap { | 
| 103 | 478 |  |  | 478 |  | 12434 | my ($this, $text) = @_; | 
| 104 | 478 |  |  |  |  | 729 | my $modulus = $this->modulus; | 
| 105 | 478 |  |  |  |  | 3492 | return "$text (mod $modulus)"; | 
| 106 |  |  |  |  |  |  | } | 
| 107 |  |  |  |  |  |  |  | 
| 108 |  |  |  |  |  |  | # ----- protected methods ----- | 
| 109 |  |  |  |  |  |  |  | 
| 110 |  |  |  |  |  |  | # constructor with index argument | 
| 111 |  |  |  |  |  |  | sub _xnew { | 
| 112 | 148 |  |  | 148 |  | 215 | my $this  = shift; | 
| 113 | 148 |  |  |  |  | 167 | my $index = shift; | 
| 114 | 148 |  |  |  |  | 230 | my $poly  = $this->new(@_); | 
| 115 | 148 |  |  |  |  | 7991 | $poly->[_F_INDEX] = $index; | 
| 116 | 148 |  |  |  |  | 465 | return $poly; | 
| 117 |  |  |  |  |  |  | } | 
| 118 |  |  |  |  |  |  |  | 
| 119 |  |  |  |  |  |  | # ----- overridden public methods ----- | 
| 120 |  |  |  |  |  |  |  | 
| 121 |  |  |  |  |  |  | sub new { | 
| 122 | 499 |  |  | 499 | 1 | 21803 | my $this = shift; | 
| 123 | 499 | 100 | 100 |  |  | 825 | if (!@_ && !ref $this) { | 
| 124 | 1 |  |  |  |  | 122 | croak 'insufficient arguments'; | 
| 125 |  |  |  |  |  |  | } | 
| 126 | 498 | 100 |  |  |  | 699 | if (grep {$_->is_undefined} @_) { | 
|  | 1638 |  |  |  |  | 5482 |  | 
| 127 | 2 |  |  |  |  | 34 | _bad_modulus(); | 
| 128 |  |  |  |  |  |  | } | 
| 129 | 496 |  |  |  |  | 2520 | return $this->SUPER::new(@_); | 
| 130 |  |  |  |  |  |  | } | 
| 131 |  |  |  |  |  |  |  | 
| 132 |  |  |  |  |  |  | sub string_config { | 
| 133 | 963 |  |  | 963 | 1 | 45473 | my $this = shift; | 
| 134 | 963 | 100 |  |  |  | 2154 | return $this->SUPER::string_config(@_) if ref $this; | 
| 135 | 482 | 100 |  |  |  | 740 | ($default_string_config) = @_          if @_; | 
| 136 | 482 |  |  |  |  | 2835 | return $default_string_config; | 
| 137 |  |  |  |  |  |  | } | 
| 138 |  |  |  |  |  |  |  | 
| 139 |  |  |  |  |  |  | sub is_equal { | 
| 140 | 10 |  |  | 10 | 1 | 831 | my ($this, $that) = @_; | 
| 141 | 10 |  |  |  |  | 21 | my $i = $this->degree; | 
| 142 | 10 |  | 100 |  |  | 46 | my $eq = $this->modulus == $that->modulus && $i == $that->degree; | 
| 143 | 10 |  | 100 |  |  | 106 | while ($eq && 0 <= $i) { | 
| 144 | 22 |  |  |  |  | 37 | $eq = $this->coeff($i)->residue == $that->coeff($i)->residue; | 
| 145 | 22 |  |  |  |  | 316 | --$i; | 
| 146 |  |  |  |  |  |  | } | 
| 147 | 10 |  |  |  |  | 37 | return $eq; | 
| 148 |  |  |  |  |  |  | } | 
| 149 |  |  |  |  |  |  |  | 
| 150 |  |  |  |  |  |  | sub is_unequal { | 
| 151 | 5 |  |  | 5 | 1 | 7 | my ($this, $that) = @_; | 
| 152 | 5 |  |  |  |  | 12 | my $i = $this->degree; | 
| 153 | 5 |  | 100 |  |  | 24 | my $eq = $this->modulus == $that->modulus && $i == $that->degree; | 
| 154 | 5 |  | 100 |  |  | 47 | while ($eq && 0 <= $i) { | 
| 155 | 10 |  |  |  |  | 15 | $eq = $this->coeff($i)->residue == $that->coeff($i)->residue; | 
| 156 | 10 |  |  |  |  | 146 | --$i; | 
| 157 |  |  |  |  |  |  | } | 
| 158 | 5 |  |  |  |  | 17 | return !$eq; | 
| 159 |  |  |  |  |  |  | } | 
| 160 |  |  |  |  |  |  |  | 
| 161 |  |  |  |  |  |  | sub is_monic { | 
| 162 | 55 |  |  | 55 | 1 | 2461 | my ($this) = @_; | 
| 163 | 55 |  |  |  |  | 103 | my $degree = $this->degree; | 
| 164 | 55 |  | 100 |  |  | 274 | return 0 <= $degree && $this->coeff($degree)->residue == 1; | 
| 165 |  |  |  |  |  |  | } | 
| 166 |  |  |  |  |  |  |  | 
| 167 |  |  |  |  |  |  | sub monize { | 
| 168 | 4 |  |  | 4 | 1 | 15 | my ($this) = @_; | 
| 169 | 4 |  |  |  |  | 12 | my $degree = $this->degree; | 
| 170 | 4 | 100 |  |  |  | 21 | return $this if $degree < 0; | 
| 171 | 3 |  |  |  |  | 8 | my $leader = $this->coeff($degree); | 
| 172 | 3 | 100 |  |  |  | 26 | return $this if $leader->residue == 1; | 
| 173 | 2 |  |  |  |  | 10 | return $this->mul_const(_inverse($leader)); | 
| 174 |  |  |  |  |  |  | } | 
| 175 |  |  |  |  |  |  |  | 
| 176 |  |  |  |  |  |  | # ----- public subroutine ----- | 
| 177 |  |  |  |  |  |  |  | 
| 178 | 146 |  |  | 146 | 1 | 7721 | sub modpoly { __PACKAGE__->from_index(@_) } | 
| 179 |  |  |  |  |  |  |  | 
| 180 |  |  |  |  |  |  | # ----- class-specific public methods ----- | 
| 181 |  |  |  |  |  |  |  | 
| 182 |  |  |  |  |  |  | sub from_index { | 
| 183 | 149 |  |  | 149 | 1 | 1970 | my ($this, $index, $modulus) = @_; | 
| 184 | 149 |  |  |  |  | 182 | my $zero; | 
| 185 | 149 | 100 |  |  |  | 248 | if (defined $modulus) { | 
|  |  | 100 |  |  |  |  |  | 
| 186 | 147 |  |  |  |  | 255 | $zero = Math::ModInt::mod(0, $modulus); | 
| 187 |  |  |  |  |  |  | } | 
| 188 |  |  |  |  |  |  | elsif (ref $this) { | 
| 189 | 1 |  |  |  |  | 4 | $zero = $this->coeff_zero; | 
| 190 | 1 |  |  |  |  | 5 | $modulus = $zero->modulus; | 
| 191 |  |  |  |  |  |  | } | 
| 192 |  |  |  |  |  |  | else { | 
| 193 | 1 |  |  |  |  | 222 | croak('usage error: modulus parameter missing'); | 
| 194 |  |  |  |  |  |  | } | 
| 195 | 148 |  |  |  |  | 14698 | my @coeff = (); | 
| 196 | 148 |  |  |  |  | 178 | my $q = $index; | 
| 197 | 148 |  |  |  |  | 275 | while ($q > 0) { | 
| 198 | 353 |  |  |  |  | 618 | ($q, my $r) = $zero->new2($q); | 
| 199 | 353 |  |  |  |  | 5882 | push @coeff, $r; | 
| 200 |  |  |  |  |  |  | } | 
| 201 | 148 | 100 |  |  |  | 349 | return $this->_xnew(@coeff? ($index, @coeff): (0, $zero)); | 
| 202 |  |  |  |  |  |  | } | 
| 203 |  |  |  |  |  |  |  | 
| 204 |  |  |  |  |  |  | sub from_int_poly { | 
| 205 | 3 |  |  | 3 | 1 | 1200 | my ($this, $poly, $modulus) = @_; | 
| 206 | 3 | 100 |  |  |  | 9 | if (!defined $modulus) { | 
| 207 | 2 | 100 |  |  |  | 6 | if (!ref $this) { | 
| 208 | 1 |  |  |  |  | 143 | croak('usage error: modulus parameter missing'); | 
| 209 |  |  |  |  |  |  | } | 
| 210 | 1 |  |  |  |  | 3 | $modulus = $this->modulus; | 
| 211 |  |  |  |  |  |  | } | 
| 212 | 2 |  |  |  |  | 9 | my @coeff = map { Math::ModInt::mod($_, $modulus) } $poly->coefficients; | 
|  | 12 |  |  |  |  | 250 |  | 
| 213 | 2 |  |  |  |  | 42 | return $this->new(@coeff); | 
| 214 |  |  |  |  |  |  | } | 
| 215 |  |  |  |  |  |  |  | 
| 216 |  |  |  |  |  |  | sub modulus { | 
| 217 | 1264 |  |  | 1264 | 1 | 3880 | my ($this) = @_; | 
| 218 | 1264 |  |  |  |  | 1833 | return $this->coeff_zero->modulus; | 
| 219 |  |  |  |  |  |  | } | 
| 220 |  |  |  |  |  |  |  | 
| 221 |  |  |  |  |  |  | sub index { | 
| 222 | 6 |  |  | 6 | 1 | 617 | my ($this) = @_; | 
| 223 | 6 |  |  |  |  | 11 | my $base  = $this->modulus; | 
| 224 | 6 |  |  |  |  | 24 | my $index = $this->[_F_INDEX]; | 
| 225 | 6 | 100 |  |  |  | 16 | if (!defined $index) { | 
| 226 | 2 |  |  |  |  | 12 | $index = Math::BigInt->new; | 
| 227 | 2 |  |  |  |  | 154 | foreach my $c (reverse $this->coeff) { | 
| 228 | 12 |  |  |  |  | 2681 | $index->bmul($base)->badd($c->residue); | 
| 229 |  |  |  |  |  |  | } | 
| 230 | 2 |  |  |  |  | 419 | $this->[_F_INDEX] = $index; | 
| 231 |  |  |  |  |  |  | } | 
| 232 | 6 |  |  |  |  | 17 | return $index; | 
| 233 |  |  |  |  |  |  | } | 
| 234 |  |  |  |  |  |  |  | 
| 235 | 181 |  |  | 181 | 1 | 3452 | sub number_of_terms { scalar grep { $_->is_not_zero } $_[0]->coeff } | 
|  | 642 |  |  |  |  | 3568 |  | 
| 236 |  |  |  |  |  |  |  | 
| 237 | 1 |  |  | 1 | 1 | 425 | sub lift       { $ipol->new(map { $_->residue          } $_[0]->coefficients) } | 
|  | 6 |  |  |  |  | 38 |  | 
| 238 |  |  |  |  |  |  |  | 
| 239 | 2 |  |  | 2 | 1 | 3478 | sub centerlift { $ipol->new(map { $_->centered_residue } $_[0]->coefficients) } | 
|  | 8 |  |  |  |  | 61 |  | 
| 240 |  |  |  |  |  |  |  | 
| 241 |  |  |  |  |  |  | sub lambda_reduce { | 
| 242 | 8 |  |  | 8 | 1 | 1446 | my ($this, $lambda) = @_; | 
| 243 | 8 |  |  |  |  | 17 | my $degree = $this->degree; | 
| 244 | 8 | 100 |  |  |  | 37 | return $this if $degree <= $lambda; | 
| 245 | 7 |  |  |  |  | 14 | my @coeff = map { $this->coeff($_) } 0 .. $lambda; | 
|  | 22 |  |  |  |  | 107 |  | 
| 246 | 7 |  |  |  |  | 54 | for (my $i = 1, my $n = $lambda+1; $n <= $degree; ++$i, ++$n) { | 
| 247 | 16 |  |  |  |  | 27 | $coeff[$i] += $this->coeff($n); | 
| 248 | 16 | 100 |  |  |  | 260 | $i = 0 if $i == $lambda; | 
| 249 |  |  |  |  |  |  | } | 
| 250 | 7 |  |  |  |  | 12 | return $this->new(@coeff); | 
| 251 |  |  |  |  |  |  | } | 
| 252 |  |  |  |  |  |  |  | 
| 253 |  |  |  |  |  |  | sub first_root { | 
| 254 | 16 |  |  | 16 | 1 | 37 | my ($this) = @_; | 
| 255 | 16 |  |  |  |  | 28 | my $zero = $this->coeff_zero; | 
| 256 | 16 |  |  |  |  | 48 | my $lsc  = $this->coeff(0); | 
| 257 | 16 | 100 |  |  |  | 112 | return $zero if $lsc->is_zero; | 
| 258 | 15 | 100 |  |  |  | 99 | if ($this->degree == 1) { | 
| 259 | 5 |  |  |  |  | 23 | my $mscr = $this->coeff(1)->centered_residue; | 
| 260 | 5 | 100 |  |  |  | 87 | return -$lsc if $mscr ==  1; | 
| 261 | 4 | 100 |  |  |  | 13 | return  $lsc if $mscr == -1; | 
| 262 |  |  |  |  |  |  | } | 
| 263 | 12 |  |  |  |  | 51 | foreach my $n (1 .. $zero->modulus - 1) { | 
| 264 | 66 |  |  |  |  | 6647 | my $root = $zero->new($n); | 
| 265 | 66 | 100 |  |  |  | 578 | return $root if $this->evaluate($root)->is_zero; | 
| 266 |  |  |  |  |  |  | } | 
| 267 | 9 |  |  |  |  | 684 | return undef; | 
| 268 |  |  |  |  |  |  | } | 
| 269 |  |  |  |  |  |  |  | 
| 270 |  |  |  |  |  |  | # implementation restriction: defined for prime moduli only | 
| 271 |  |  |  |  |  |  | sub is_irreducible { | 
| 272 | 16 |  |  | 16 | 1 | 549 | my ($this) = @_; | 
| 273 | 16 |  |  |  |  | 33 | my $n = $this->degree; | 
| 274 | 16 | 100 |  |  |  | 78 | return 0 if $n <= 0; | 
| 275 | 15 | 100 |  |  |  | 23 | return 1 if $n == 1; | 
| 276 | 14 | 100 |  |  |  | 28 | return 0 if !$this->coeff(0); | 
| 277 | 13 | 100 |  |  |  | 235 | return 0 if $this->gcd($this->differentiate)->degree > 0; | 
| 278 | 11 |  |  |  |  | 250 | my $p  = $this->modulus; | 
| 279 |  |  |  |  |  |  | # optimization: O(p) zero search only for small p or very large n | 
| 280 | 11 | 100 | 100 |  |  | 70 | if ($p <= 43 || log($p - 20) <= $n * 0.24 + 2.68) { | 
| 281 | 10 | 100 | 100 |  |  | 47 | my $rp = 2 < $p && $p <= $n? $this->lambda_reduce($p-1): $this; | 
| 282 | 10 | 100 |  |  |  | 184 | return 0 if defined $rp->first_root; | 
| 283 | 8 | 100 |  |  |  | 24 | return 1 if $n <= 3; | 
| 284 |  |  |  |  |  |  | } | 
| 285 |  |  |  |  |  |  | # Berlekamp rank < $n - 1? | 
| 286 | 7 |  |  |  |  | 20 | my $xp = $this->exp_mod($p); | 
| 287 | 7 |  |  |  |  | 248 | my $aj = $xp; | 
| 288 | 7 |  |  |  |  | 17 | my $bj = $this->monomial(1); | 
| 289 | 7 |  |  |  |  | 136 | my $j  = 0; | 
| 290 |  |  |  |  |  |  | return 0 if _linearly_dependent( | 
| 291 |  |  |  |  |  |  | sub { | 
| 292 | 26 | 100 |  | 26 |  | 54 | return undef if $j >= $n - 1; | 
| 293 | 22 | 100 |  |  |  | 35 | if ($j++) { | 
| 294 | 15 |  |  |  |  | 27 | $aj = $aj * $xp % $this; | 
| 295 | 15 |  |  |  |  | 417 | $bj <<= 1; | 
| 296 |  |  |  |  |  |  | } | 
| 297 | 22 |  |  |  |  | 315 | return [($aj - $bj)->coeff]; | 
| 298 |  |  |  |  |  |  | } | 
| 299 | 7 | 100 |  |  |  | 34 | ); | 
| 300 | 4 |  |  |  |  | 80 | return 1; | 
| 301 |  |  |  |  |  |  | } | 
| 302 |  |  |  |  |  |  |  | 
| 303 |  |  |  |  |  |  | 1; | 
| 304 |  |  |  |  |  |  |  | 
| 305 |  |  |  |  |  |  | __END__ |