File Coverage

blib/lib/Math/NumSeq/KlarnerRado.pm
Criterion Covered Total %
statement 48 51 94.1
branch 16 18 88.8
condition 9 12 75.0
subroutine 12 12 100.0
pod 3 3 100.0
total 88 96 91.6


line stmt bran cond sub pod time code
1             # Copyright 2011, 2012, 2013, 2014 Kevin Ryde
2              
3             # This file is part of Math-NumSeq.
4             #
5             # Math-NumSeq is free software; you can redistribute it and/or modify
6             # it under the terms of the GNU General Public License as published by the
7             # Free Software Foundation; either version 3, or (at your option) any later
8             # version.
9             #
10             # Math-NumSeq is distributed in the hope that it will be useful, but
11             # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12             # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13             # for more details.
14             #
15             # You should have received a copy of the GNU General Public License along
16             # with Math-NumSeq. If not, see .
17              
18              
19             # http://infolab.stanford.edu/TR/CS-TR-72-269.html
20             # http://infolab.stanford.edu/TR/CS-TR-72-275.html
21              
22             package Math::NumSeq::KlarnerRado;
23 1     1   882 use 5.004;
  1         3  
24 1     1   3 use strict;
  1         2  
  1         21  
25 1     1   3 use List::Util;
  1         1  
  1         45  
26              
27 1     1   4 use vars '$VERSION', '@ISA';
  1         1  
  1         43  
28             $VERSION = 72;
29              
30 1     1   3 use Math::NumSeq;
  1         1  
  1         16  
31 1     1   3 use Math::NumSeq::Base::IteratePred;
  1         1  
  1         32  
32             @ISA = ('Math::NumSeq::Base::IteratePred', 'Math::NumSeq');
33              
34             # uncomment this to run the ### lines
35             #use Devel::Comments;
36              
37             # use constant name => Math::NumSeq::__('Klarner-Rado');
38 1     1   3 use constant description => Math::NumSeq::__('Klarner-Rado sequence 1,2,4,5,8,9,etc being 1 and then if n in the sequence so are 2n, 3n+2 and 6n+3.');
  1         2  
  1         3  
39 1     1   4 use constant i_start => 1;
  1         1  
  1         72  
40              
41             sub values_min {
42 4     4 1 7 my ($self) = @_;
43 4         7 return $self->{'start'};
44             }
45              
46 1         200 use constant parameter_info_array =>
47             [ { name => 'start',
48             type => 'integer',
49             default => 1,
50             minimum => 1,
51             width => 3,
52             },
53 1     1   4 ];
  1         1  
54              
55             # cf A005659 2n-2, 3n-3, starting 4
56             # A005660 2n+2, 3n+3, starting 3
57             # A005661 2n-2, 3n-3, starting 5
58             # A005662 2n+2, 3n+3
59             # A185661 2n+1, 3n+1, starting 1
60             # A005658 2n+1, 3n+1, 6n+1, starting 1
61             #
62             my @oeis_anum;
63             $oeis_anum[1] = 'A005658';
64             sub oeis_anum {
65 1     1 1 2 my ($self) = @_;
66 1         2 return $oeis_anum[$self->{'start'}];
67             }
68              
69             # sub rewind {
70             # my ($self) = @_;
71             # $self->{'i'} = $self->i_start;
72             #
73             # # $self->{'pending'} = { 1 => undef };
74             # # $self->{'pref_ref'} = \'';
75             # # $self->{'pstart'} = 0;
76             # }
77              
78             # sub next {
79             # my ($self) = @_;
80             # ### KlarnerRado next(): "$self->{'i'}"
81             #
82             # # my $pstart = $self->{'pstart'};
83             # # vec($$pref,
84             # # # my $pending = $self->{'pending'};
85             # # return ($self->{'i'}++, $min);
86             #
87             # my $pending = $self->{'pending'};
88             # my $min = List::Util::min (keys %$pending);
89             # delete $pending->{$min};
90             # @{$pending}{2*$min,3*$min+2,6*$min+3} = ();
91             # return ($self->{'i'}++, $min);
92             # }
93              
94             sub pred {
95 41     41 1 98 my ($self, $value) = @_;
96             ### KlarnerRado pred(): $value
97              
98 41         26 my $start = $self->{'start'};
99 41         38 my @pending = ($value);
100 41         23 for (;;) {
101             ### @pending
102             ### $value
103              
104 102 100 100     250 if ($value <= $start) {
    100          
    100          
    100          
105 24 50       30 if ($value == $start) {
106 24         37 return 1;
107             }
108 0   0     0 $value = pop @pending || return 0;
109              
110             } elsif ($value == 2 || $value == 4) {
111 20         16 $value /= 2; # from 2k
112             } elsif ($value == 5) {
113 4         5 $value = 1; # from 3k+2
114              
115             } elsif ($value >= 6) {
116             # mod6
117             # 2k = 0,2, 4
118             # 3k+2 = 2, 5
119             # 6k+3 = 3
120             #
121 26         39 my $mod = ($value % 6);
122 26 100 66     66 if ($mod == 0 || $mod == 4) {
    100          
    100          
    50          
123             # 6k under 2n -> 3k is 0,3 mod 6
124             # 6k+4 under 2n -> 3k+2 is 2,5 mod 6
125 8         7 $value /= 2;
126              
127             } elsif ($mod == 2) {
128             ### 6k+2 ...
129             # under 2n -> 3k+2 is 2,5 mod 6
130             # under 3n+2 -> 2k is 0,2,4 mod 6
131 6         7 push @pending, ($value-2)/3; # n <- 3n+2
132 6         7 $value /= 2; # n <- 2n
133              
134             } elsif ($mod == 3) {
135             # 6k+3 -> k
136 4         5 $value -= 3;
137 4         4 $value /= 6;
138              
139             } elsif ($mod == 5) {
140             # 6k+5 under 3n+2 -> 2*k+1
141 0         0 $value -= 2;
142 0         0 $value /= 3;
143              
144             } else {
145             # mod == 1
146 8   100     15 $value = pop @pending || return 0;
147             }
148             } else {
149 28   100     46 $value = pop @pending || return 0;
150             }
151             }
152             }
153              
154             1;
155             __END__