File Coverage

blib/lib/Math/Polynomial/Cyclotomic.pm
Criterion Covered Total %
statement 57 57 100.0
branch 12 12 100.0
condition 14 16 87.5
subroutine 17 17 100.0
pod 4 8 50.0
total 104 110 94.5


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::Cyclotomic;
5              
6 2     2   21425 use 5.006;
  2         13  
7 2     2   11 use strict;
  2         4  
  2         40  
8 2     2   9 use warnings;
  2         11  
  2         55  
9 2     2   11 use Math::Polynomial;
  2         3  
  2         52  
10 2     2   2463 use Math::Prime::Util qw(divisors);
  2         24621  
  2         8  
11             require Exporter;
12              
13             our @ISA = qw(Exporter);
14             our @EXPORT_OK = qw(
15             cyclo_poly cyclo_factors cyclo_poly_iterate cyclo_factors_iterate
16             );
17             our %EXPORT_TAGS = (all => \@EXPORT_OK);
18             our $VERSION = '0.002';
19              
20             # some polynomial with default coefficient type
21             my $poly = Math::Polynomial->new;
22             $poly->string_config({fold_sign => 1, times => '*'});
23              
24             # ----- private subroutine -----
25              
26             sub _cyclo_poly {
27 42     42   98 my ($u, $table, $n, $divisors) = @_;
28 42 100       170 my @d = $divisors? (grep { not $n % $_ } @{$divisors}): divisors($n);
  99         212  
  23         44  
29 42         120 my $p = $u->monomial(pop @d)->sub_($u);
30 42 100       5119 if (@d) {
31 35         63 my $m = $d[-1];
32 35         80 $p /= $u->monomial($m)->sub_($u);
33 35         8407 for (my $i = 1; $i < $#d; ++$i) {
34 20         500 my $r = $d[$i];
35 20 100       58 if ($m % $r) {
36 11   66     51 $p /= $table->{$r} || _cyclo_poly($u, $table, $r, \@d);
37             }
38             }
39             }
40 42         1076 $table->{$n} = $p;
41 42         142 return $p;
42             }
43              
44             sub _cyclo_factors {
45 10     10   28 my ($u, $table, $n) = @_;
46 10         56 my @d = divisors($n);
47 10 100       24 return map { $table->{$_} || _cyclo_poly($u, $table, $_, \@d) } @d;
  34         352  
48             }
49              
50             # ----- Math::Polynomial extension -----
51              
52             sub Math::Polynomial::cyclotomic {
53 11     11 0 1158 my ($this, $n, $table) = @_;
54 11         42 my $u = $this->monomial(0);
55 11 100       541 return _cyclo_poly($u, {}, $n) if !$table;
56 6   66     26 return $table->{$n} || _cyclo_poly($u, $table, $n);
57             }
58              
59             sub Math::Polynomial::cyclo_factors {
60 4     4 0 967 my ($this, $n, $table) = @_;
61 4         14 my $u = $this->monomial(0);
62 4   100     164 return _cyclo_factors($u, $table || {}, $n);
63             }
64              
65             sub Math::Polynomial::cyclo_poly_iterate {
66 4     4 0 1151 my ($this, $n, $table) = @_;
67 4         14 my $u = $this->monomial(0);
68 4   100     160 $n ||= 1;
69 4         6 --$n;
70 4   100     18 $table ||= {};
71             return
72             sub {
73 14     14   6488 ++$n;
74 14 100       68 $table->{$n} || _cyclo_poly($u, $table, $n);
75 4         28 };
76             }
77              
78             sub Math::Polynomial::cyclo_factors_iterate {
79 4     4 0 1110 my ($this, $n, $table) = @_;
80 4         15 my $u = $this->monomial(0);
81 4   100     161 $n ||= 1;
82 4   100     17 $table ||= {};
83 4     6   38 return sub { _cyclo_factors($u, $table, $n++) };
  6         720  
84             }
85              
86             # ----- public subroutines -----
87              
88 8     8 1 4631 sub cyclo_poly { $poly->cyclotomic(@_) }
89 2     2 1 1536 sub cyclo_factors { $poly->cyclo_factors(@_) }
90 2     2 1 910 sub cyclo_poly_iterate { $poly->cyclo_poly_iterate(@_) }
91 2     2 1 1296 sub cyclo_factors_iterate { $poly->cyclo_factors_iterate(@_) }
92              
93             1;
94              
95             __END__