File Coverage

blib/lib/Math/Polynomial/ModInt.pm
Criterion Covered Total %
statement 98 98 100.0
branch 16 16 100.0
condition 12 12 100.0
subroutine 24 24 100.0
pod 11 11 100.0
total 161 161 100.0


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 2     2   54152 use 5.006;
  2         12  
7 2     2   9 use strict;
  2         3  
  2         34  
8 2     2   17 use warnings;
  2         4  
  2         52  
9 2     2   957 use Math::BigInt;
  2         25100  
  2         11  
10 2     2   27361 use Math::ModInt 0.011;
  2         6793  
  2         82  
11 2     2   1241 use Math::Polynomial 1.015;
  2         13335  
  2         61  
12 2     2   13 use Carp qw(croak);
  2         2  
  2         102  
13              
14             # ----- object definition -----
15              
16             # Math::Polynomial::ModInt=ARRAY(...)
17              
18             # .............. index .............. # .......... value ..........
19              
20 2     2   11 use constant _OFFSET => Math::Polynomial::_NFIELDS;
  2         3  
  2         104  
21 2     2   10 use constant _F_INDEX => _OFFSET + 0; # ordinal number i, 0 <= i
  2         8  
  2         95  
22 2     2   13 use constant _NFIELDS => _OFFSET + 1;
  2         4  
  2         161  
23              
24             # ----- class data -----
25              
26             BEGIN {
27 2     2   12 require Exporter;
28 2         55 our @ISA = qw(Math::Polynomial Exporter);
29 2         13 our @EXPORT_OK = qw(modpoly);
30 2         1661 our $VERSION = '0.002';
31             }
32              
33             my $default_string_config = {
34             convert_coeff => sub { $_[0]->residue },
35             times => q[*],
36             wrap => \&_wrap,
37             };
38              
39             my $lifted_string_config = {
40             times => q[*],
41             fold_sign => 1,
42             };
43              
44             my $ipol = Math::Polynomial->new(Math::BigInt->new);
45             $ipol->string_config($lifted_string_config);
46              
47             # ----- private methods -----
48              
49             # wrapper to decorate stringified polynomial
50             sub _wrap {
51 477     477   13045 my ($this, $text) = @_;
52 477         749 my $modulus = $this->modulus;
53 477         3557 return "$text (mod $modulus)";
54             }
55              
56             # ----- protected methods -----
57              
58             # constructor with index argument
59             sub _xnew {
60 123     123   159 my $this = shift;
61 123         140 my $index = shift;
62 123         288 my $poly = $this->new(@_);
63 123         6895 $poly->[_F_INDEX] = $index;
64 123         410 return $poly;
65             }
66              
67             # ----- overridden public methods -----
68              
69             sub string_config {
70 961     961 1 48294 my $this = shift;
71 961 100       2339 return $this->SUPER::string_config(@_) if ref $this;
72 481 100       941 ($default_string_config) = @_ if @_;
73 481         3106 return $default_string_config;
74             }
75              
76             sub is_equal {
77 6     6 1 789 my ($this, $that) = @_;
78 6         11 my $i = $this->degree;
79 6   100     30 my $eq = $this->modulus == $that->modulus && $i == $that->degree;
80 6   100     62 while ($eq && 0 <= $i) {
81 16         25 $eq = $this->coeff($i)->residue == $that->coeff($i)->residue;
82 16         236 --$i;
83             }
84 6         23 return $eq;
85             }
86              
87             sub is_unequal {
88 5     5 1 12 my ($this, $that) = @_;
89 5         9 my $i = $this->degree;
90 5   100     48 my $eq = $this->modulus == $that->modulus && $i == $that->degree;
91 5   100     50 while ($eq && 0 <= $i) {
92 10         15 $eq = $this->coeff($i)->residue == $that->coeff($i)->residue;
93 10         157 --$i;
94             }
95 5         19 return !$eq;
96             }
97              
98             # ----- public subroutine -----
99              
100 121     121 1 3175 sub modpoly { __PACKAGE__->from_index(@_) }
101              
102             # ----- class-specific public methods -----
103              
104             sub from_index {
105 124     124 1 1997 my ($this, $index, $modulus) = @_;
106 124         141 my $zero;
107 124 100       191 if (defined $modulus) {
    100          
108 122         213 $zero = Math::ModInt::mod(0, $modulus);
109             }
110             elsif (ref $this) {
111 1         4 $zero = $this->coeff_zero;
112 1         5 $modulus = $zero->modulus;
113             }
114             else {
115 1         191 croak('usage error: modulus parameter missing');
116             }
117 123         9726 my @coeff = ();
118 123         146 my $q = $index;
119 123         227 while ($q > 0) {
120 275         467 ($q, my $r) = $zero->new2($q);
121 275         4376 push @coeff, $r;
122             }
123 123 100       277 return $this->_xnew(@coeff? ($index, @coeff): (0, $zero));
124             }
125              
126             sub from_int_poly {
127 3     3 1 1260 my ($this, $poly, $modulus) = @_;
128 3 100       9 if (!defined $modulus) {
129 2 100       5 if (!ref $this) {
130 1         121 croak('usage error: modulus parameter missing');
131             }
132 1         3 $modulus = $this->modulus;
133             }
134 2         10 my @coeff = map { Math::ModInt::mod($_, $modulus) } $poly->coefficients;
  12         275  
135 2         45 return $this->new(@coeff);
136             }
137              
138             sub modulus {
139 1244     1244 1 3677 my ($this) = @_;
140 1244         1936 return $this->coeff_zero->modulus;
141             }
142              
143             sub index {
144 6     6 1 680 my ($this) = @_;
145 6         14 my $base = $this->modulus;
146 6         29 my $index = $this->[_F_INDEX];
147 6 100       16 if (!defined $index) {
148 2         15 $index = Math::BigInt->new;
149 2         172 foreach my $c (reverse $this->coeff) {
150 12         2517 $index->bmul($base)->badd($c->residue);
151             }
152 2         452 $this->[_F_INDEX] = $index;
153             }
154 6         17 return $index;
155             }
156              
157 181     181 1 3472 sub number_of_terms { scalar grep { $_->is_not_zero } $_[0]->coeff }
  642         3487  
158              
159 1     1 1 466 sub lift { $ipol->new(map { $_->residue } $_[0]->coefficients) }
  6         37  
160              
161 1     1 1 3462 sub centerlift { $ipol->new(map { $_->centered_residue } $_[0]->coefficients) }
  6         79  
162              
163             1;
164              
165             __END__