File Coverage

blib/lib/Math/PRBS.pm
Criterion Covered Total %
statement 146 146 100.0
branch 86 86 100.0
condition 33 33 100.0
subroutine 25 25 100.0
pod 19 19 100.0
total 309 309 100.0


line stmt bran cond sub pod time code
1             =head1 NAME
2            
3             Math::PRBS - Generate Pseudorandom Binary Sequences using an iterator-based Linear Feedback Shift Register
4            
5             =cut
6             package Math::PRBS;
7 8     8   412684 use warnings;
  8         59  
  8         206  
8 8     8   33 use strict;
  8         13  
  8         207  
9            
10 8     8   2874 use version 0.77; our $VERSION = version->declare('0.004');
  8         11807  
  8         40  
11            
12             =head1 SYNOPSIS
13            
14             use Math::PRBS;
15             my $x3x2 = Math::PRBS->new( taps => [3,2] );
16             my $prbs7 = Math::PRBS->new( prbs => 7 );
17             my ($i, $value) = $x3x2t->next();
18             my @p7 = $prbs7->generate_all();
19             my @ints = $prbs7->generate_all_int();
20            
21             =head1 DESCRIPTION
22            
23             This module will generate various Pseudorandom Binary Sequences (PRBS). This module creates a iterator object, and you can use that object to generate the sequence one value at a time, or I.
24            
25             The generated sequence is a series of 0s and 1s which appears random for a certain length, and then repeats thereafter. (You can also convert the bitstream into a sequence of integers using the C and C methods.)
26            
27             It is implemented using an XOR-based Linear Feedback Shift Register (LFSR), which is described using a feedback polynomial (or reciprocal characteristic polynomial). The terms that appear in the polynomial are called the 'taps', because you tap off of that bit of the shift register for generating the feedback for the next value in the sequence.
28            
29             =head1 FUNCTIONS AND METHODS
30            
31             =head2 Initialization
32            
33             =over
34            
35             =item C<$seq = Math::PRBS->new( I value> )>
36            
37             Creates the sequence iterator C<$seq> using one of the C value> pairs described below.
38            
39             =cut
40            
41             sub new {
42 29     29 1 4692 my $class = shift;
43 29         130 my $self = bless { lfsr => 0, start => 0, i => 0, period => undef, taps => [] }, $class;
44 29         43 my %pairs;
45 29 100       105 %pairs = @_%2 ? () : @_;
46            
47             =over
48            
49             =item C I>
50            
51             C needs an integer I to indicate one of the "standard" PRBS polynomials.
52            
53             # example: PRBS7 = x**7 + x**6 + 1
54             $seq = Math::PRBS->new( prbs => 7 );
55            
56             The "standard" PRBS polynomials implemented are
57            
58             polynomial | prbs | taps | poly (string)
59             ------------------+------------+-----------------+---------------
60             x**7 + x**6 + 1 | prbs => 7 | taps => [7,6] | poly => '1100000'
61             x**15 + x**14 + 1 | prbs => 15 | taps => [15,14] | poly => '110000000000000'
62             x**23 + x**18 + 1 | prbs => 23 | taps => [23,18] | poly => '10000100000000000000000'
63             x**31 + x**28 + 1 | prbs => 31 | taps => [31,28] | poly => '1001000000000000000000000000000'
64            
65             =cut
66            
67 29 100       80 if( exists $pairs{prbs} )
    100          
    100          
68             {
69 5         32 my %prbs = (
70             7 => [7,6] ,
71             15 => [15,14],
72             23 => [23,18],
73             31 => [31,28],
74             );
75 5 100       35 die __PACKAGE__."->new(prbs => '$pairs{prbs}'): standard PRBS include 7, 15, 23, 31" unless exists $prbs{ $pairs{prbs} };
76 4         6 $self->{taps} = [ @{ $prbs{ $pairs{prbs} } } ];
  4         16  
77             }
78            
79             =item C [ I, I, ... ]>
80            
81             C needs an array reference containing the powers in the polynomial that you tap off for creating the feedback. Do I include the C<0> for the C in the polynomial; that's automatically included.
82            
83             # example: x**3 + x**2 + 1
84             # 3 and 2 are taps, 1 is not tapped, 0 is implied feedback
85             $seq = Math::PRBS->new( taps => [3,2] );
86            
87             =cut
88            
89             elsif( exists $pairs{taps} )
90             {
91 12 100       50 die __PACKAGE__."->new(taps => $pairs{taps}): argument should be an array reference" unless 'ARRAY' eq ref($pairs{taps});
92 11         16 $self->{taps} = [ sort {$b <=> $a} @{ $pairs{taps} } ]; # taps in descending order
  14         49  
  11         41  
93 11 100       14 die __PACKAGE__."->new(taps => [@{$pairs{taps}}]): need at least one tap" unless @{ $pairs{taps} };
  1         9  
  11         29  
94             }
95            
96             =item C '...'>
97            
98             C needs a string for the bits C downto C, with a 1 indicating the power is included in the list, and a 0 indicating it is not.
99            
100             # example: x**3 + x**2 + 1
101             # 3 and 2 are taps, 1 is not tapped, 0 is implied feedback
102             $seq = Math::PRBS->new( poly => '110' );
103            
104             =cut
105            
106             elsif( exists $pairs{poly} )
107             {
108 10         13 local $_ = $pairs{poly}; # used for implicit matching in die-unless and while-condition
109 10 100       62 die __PACKAGE__."->new(poly => '$pairs{poly}'): argument should be an binary string" unless /^[01]*$/;
110 8         15 my @taps = ();
111 8         10 my $l = length;
112 8         29 while( m/([01])/g ) {
113 24 100       74 push @taps, $l - pos() + 1 if $1;
114             }
115 8         24 $self->{taps} = [ reverse sort {$a <=> $b} @taps ];
  7         37  
116 8 100       29 die __PACKAGE__."->new(poly => '$pairs{poly}'): need at least one tap" unless @taps;
117             } else {
118 2         24 die __PACKAGE__."->new(".join(',',@_)."): unknown arguments";
119             }
120            
121 21         98 $self->{lfsr} = oct('0b1' . '0'x($self->{taps}[0] - 1));
122 21         33 $self->{start} = $self->{lfsr};
123            
124 21         92 return $self;
125             }
126            
127             =back
128            
129             =item C<$seq-Ereset()>
130            
131             Reinitializes the sequence: resets the sequence back to the starting state. The next call to C will be the initial C<$i,$value> again.
132            
133             =cut
134            
135             sub reset {
136 21     21 1 34 my $self = shift;
137 21         45 $self->{lfsr} = $self->{start};
138 21         34 $self->{i} = 0;
139 21         44 return $self;
140             }
141            
142             =back
143            
144             =head2 Iteration
145            
146             =over
147            
148             =item C<$value = $seq-Enext()>
149            
150             =item C<($i, $value) = $seq-Enext()>
151            
152             Computes the next value in the sequence. (Optionally, in list context, also returns the current value of the i for the sequence.)
153            
154             =cut
155            
156             sub next {
157 1885445     1885445 1 1681116 my $self = shift;
158 1885445         1636628 my $newbit = 0;
159 1885445         2518414 my $mask = oct( '0b' . '1'x($self->{taps}[0]) );
160 1885445         1708429 my $i = $self->{i};
161 1885445         1696823 ++ $self->{i};
162            
163 1885445         1646411 $newbit ^= ( $self->{lfsr} >> ($_-1) ) & 1 for @{ $self->{taps} };
  1885445         3367237  
164            
165 1885445         2151740 $self->{lfsr} = (($self->{lfsr} << 1) | $newbit) & $mask;
166            
167 1885445 100 100     4150583 $self->{period} = $i+1 if $i && !defined($self->{period}) && ($self->{lfsr} eq $self->{start});
      100        
168            
169 1885445 100       3052985 return wantarray ? ( $i , $newbit ) : $newbit;
170             }
171            
172             =item C<$seq-Erewind()>
173            
174             Rewinds the sequence back to the starting state. The subsequent call to C will be the initial C<$i,$value> again.
175             (This is actually an alias for C).
176            
177             =cut
178            
179 8     8   5424 BEGIN { *rewind = \&reset; } # alias
180            
181             =item C<$i = $seq-Etell_i()>
182            
183             Return the current C position. The subsequent call to C will return this C.
184            
185             =cut
186            
187             sub tell_i {
188 27     27 1 3800 return $_[0]->{i};
189             }
190            
191             =item C<$state = $seq-Etell_state()>
192            
193             Return the current internal state of the feedback register. Useful for debug, or plugging into C<-Eseek_to_state($state)> to get back to this state at some future point in the program.
194            
195             =cut
196            
197             sub tell_state {
198 21     21 1 94 return $_[0]->{lfsr};
199             }
200            
201             =item C<$seq-Eseek_to_i( $n )>
202            
203             =item C<$seq-Eith( $n )>
204            
205             Moves forward in the sequence until C reaches C<$n>. If C $n> already, will internally C first. If C<$n E period>, it will stop at the end of the period, instead.
206            
207             =cut
208            
209             sub seek_to_i {
210 10     10 1 1607 my $self = shift;
211 10         359 my $n = shift;
212            
213 10 100       44 $self->rewind() if $self->{i} > $n;
214 10   100     107 $self->next() while(($self->{i} < $n) && !(defined($self->{period}) && ($self->{i} >= $self->{period})));
      100        
215             }
216            
217 8     8   6814 BEGIN { *ith = \&seek_to_i; } # alias
218            
219             =item C<$seq-Eseek_to_state( $lfsr )>
220            
221             Moves forward in the sequence until the internal LFSR state reaches C<$lfsr>. It will wrap around, if necessary, but will stop once the internal state returns to the starting point.
222            
223             =cut
224            
225             sub seek_to_state {
226 3     3 1 6 my $self = shift;
227 3         5 my $lfsr = shift;
228 3         6 my $state = $self->{lfsr};
229            
230             #local $\ = "\n";
231             #local $, = "\t";
232             #print STDERR __LINE__, "seek_to_state($lfsr):", $self->{i}, $self->{lfsr};
233 3 100       11 $self->next() unless $state == $lfsr;
234             #print STDERR __LINE__, "seek_to_state($lfsr):", $self->{i}, $self->{lfsr};
235 3   100     15 $self->next() while ($self->{lfsr} != $lfsr) && ($self->{lfsr} != $state); # Devel::Cover = the coverage hole is because I am testing for a condition that shouldn't be possible: getting back to initial state without ever having
236             #print STDERR __LINE__, "seek_to_state($lfsr):", $self->{i}, $self->{lfsr};
237             }
238            
239             =item C<$seq-Eseek_forward_n( $n )>
240            
241             Moves forward in the sequence C<$n> steps.
242            
243             =cut
244            
245             sub seek_forward_n {
246 4     4 1 9 my $self = shift;
247 4         6 my $n = shift;
248            
249 4         17 $self->next() for 1 .. $n;
250             }
251            
252             =item C<$seq-Eseek_to_end()>
253            
254             =item C<$seq-Eseek_to_end( limit =E $n )>
255            
256             Moves forward until it's reached the end of the the period. (Will start in the first period using C.)
257            
258             If C $n> is used, will not seek beyond C.
259            
260             =cut
261            
262             sub seek_to_end {
263 7     7 1 15 my $self = shift;
264            
265 7 100       35 die __PACKAGE__."::seek_to_end(@_) requires even number of arguments, expecting name=>value pairs" unless 0 == @_ % 2;
266            
267 6         24 my %opts = map lc, @_; # lowercase name,value pairs for canonical
268 6 100       18 my $limit = exists $opts{limit} ? $opts{limit} : 65535;
269 6 100       36 $limit = (2 ** $self->{taps}[0] - 1) if lc($limit) eq 'max';
270 6 100 100     30 $self->{i} %= $self->{period} if defined $self->{period} && $self->{i} > $self->{period};
271 6         18 while( $self->{i} % $limit ) {
272 245837         311311 $self->next();
273 245837 100 100     522974 $limit = $self->{period} if defined $self->{period} && $self->{period} < $limit; # pick PERIOD if PERIOD smaller than LIMIT
274             }
275             }
276            
277             =item C<@all = $seq-Egenerate( I )>
278            
279             Generates the next I values in the sequence, wrapping around if it reaches the end. In list context, returns the values as a list; in scalar context, returns the string concatenating that list.
280            
281             =cut
282            
283             sub generate {
284 65598     65598 1 83262 my ($self, $n) = @_;
285 65598         60885 my @ret = ();
286 65598         78254 foreach( 1 .. $n ) {
287 1114649         1326667 push @ret, scalar $self->next(); # need to force the scalar version to not push (i,value)
288             }
289 65598 100       314834 return wantarray ? @ret : join '', @ret;
290             }
291            
292             =item C<@all = $seq-Egenerate_all( )>
293            
294             =item C<@all = $seq-Egenerate_all( I $max_i> )>
295            
296             Returns the whole sequence, from the beginning, up to the end of the sequence; in list context, returns the list of values; in scalar context, returns the string concatenating that list. If the sequence is longer than the default limit of 65535, or the limit given by C<$max_i> if the optional C $max_i> is provided, then it will stop before the end of the sequence.
297            
298             =item C<@all = $seq-Egenerate_to_end( )>
299            
300             =item C<@all = $seq-Egenerate_to_end( I $max_i> )>
301            
302             Returns the remaining sequence, from whatever state the list is currently at, up to the end of the sequence; in list context, returns the list of values; in scalar context, returns the string concatenating that list. The limits work just as with C.
303            
304             =cut
305            
306             sub generate_to_end {
307 19     19 1 427 my $self = shift;
308            
309 19 100       71 die __PACKAGE__."::generate_to_end(@_) requires even number of arguments, expecting name=>value pairs" unless 0 == @_ % 2;
310            
311 18         71 my %opts = map lc, @_; # lowercase name,value pairs for canonical
312 18 100       55 my $limit = exists $opts{limit} ? $opts{limit} : 65535;
313 18 100       54 $limit = (2 ** $self->{taps}[0] - 1) if lc($limit) eq 'max';
314             # originally, the next block was "$self->rewind() if ($self->{i} && $opts{rewind});", but Devel::Cover complained that not all conditions were tested
315             # so I broke it into the following, which made Devel::Cover happy: note, it doesn't matter whether the i comes before or after rewind
316 18 100       34 if ($self->{i}) {
317 7 100       14 if( $opts{rewind} ) {
318 2         6 $self->rewind();
319             }
320             }
321 18 100 100     62 $self->{i} %= $self->{period} if defined $self->{period} && $self->{i} > $self->{period};
322 18         26 my $ret = '';
323 18         30 while( $self->{i} < $limit ) {
324 278993         317531 $ret .= scalar $self->next(); # need to force the scalar version to not push (i,value)
325 278993 100 100     578475 $limit = $self->{period} if defined $self->{period} && $self->{period} < $limit; # pick PERIOD if PERIOD smaller than LIMIT
326             }
327 18 100       380 return wantarray ? split(//, $ret) : $ret;
328             }
329            
330             sub generate_all {
331 8     8 1 18 my $self = shift;
332            
333 8 100       56 die __PACKAGE__."::generate_all(@_) requires even number of arguments, expecting name=>value pairs" unless 0 == @_ % 2;
334            
335 7         20 my %opts = @_;
336 7         11 $opts{rewind} = 1; # override existing rewind value
337 7         22 return generate_to_end($self, %opts);
338             }
339            
340             =item C<@all = $seq-Egenerate_int( I<$n> )>
341            
342             Generates the next I<$n> integers in the sequence, wrapping around if it reaches the end (it will generate just one if I<$n> is missing). In list context, returns the values as a list; in scalar context, returns the string concatenating that list.
343            
344             =cut
345            
346             sub generate_int {
347 10     10 1 17 my ($self, $n) = @_;
348 10 100       23 $n = 1 unless defined $n;
349 10         17 my $k = $self->k_bits();
350 10         3173 my @arr = map { oct '0b' . $self->generate($k) } 1 .. $n;
  65594         87781  
351 10 100       6665 return wantarray ? @arr : join ',', @arr;
352             }
353            
354             =item C<@all = $seq-Egenerate_all_int( )>
355            
356             =item C<@all = $seq-Egenerate_all_int( I $max_i> )>
357            
358             Returns the whole sequence of C-bit integers, from the beginning, up to the end of the sequence; in list context, returns the list of values; in scalar context, returns the string concatenating that list. If the sequence is longer than the default limit of 65535, or the limit given by C<$max_i> if the optional C $max_i> is provided, then it will stop before the end of the sequence.
359            
360             =cut
361            
362             sub generate_all_int {
363 7     7 1 777 my $self = shift;
364            
365 7 100       28 die __PACKAGE__."::generate_all_int(@_) requires even number of arguments, expecting name=>value pairs" unless 0 == @_ % 2;
366            
367 6         21 my %opts = map lc, @_; # lowercase name,value pairs for canonical
368 6 100       16 my $limit = exists $opts{limit} ? $opts{limit} : 65535;
369 6         17 my $maxlimit = 2 ** $self->k_bits - 1;
370 6         15 my $period = $self->period( force => $maxlimit );
371 6 100 100     31 $limit = $period if lc($limit) eq 'max' or $limit > $period;
372 6         14 $self->rewind();
373 6         13 return $self->generate_int( $limit );
374             }
375            
376             =back
377            
378             =head2 Information
379            
380             =over
381            
382             =item C<$i = $seq-Edescription>
383            
384             Returns a string describing the sequence in terms of the polynomial.
385            
386             $prbs7->description # "PRBS from polynomial x**7 + x**6 + 1"
387            
388             =cut
389            
390             sub description {
391 11     11 1 618 my $self = shift;
392 11         17 my $p = '';
393 11         13 foreach ( reverse sort {$a <=> $b} @{ $self->{taps} } ) {
  12         31  
  11         31  
394 23 100       38 $p .= ' + ' if $p;
395 23         38 $p .= "x**$_";
396             }
397 11         49 return "PRBS from polynomial $p + 1";
398             }
399            
400             =item C<$n = $seq-Epolynomial_degree>
401            
402             =item C<$n = $seq-Ek_bits>
403            
404             Returns the highest power C from the PRBS polynomial. As described in the L section, if you group a maximum length sequence sequence into groups of C bits, you will produce all the C-bit numbers from C<1> to C<2**k - 1>.
405            
406             $seq = Math::PRBS->new( taps => [6,7] );
407             $k = $seq->k_bits(); # 7
408            
409             When using C to generate the next integer in the sequence, it is consuming C bits from the sequence to create the decimal integer.
410            
411             @integers = $seq->generate_int($num_ints); # consumes $seq->k_bits() bits of the sequence per integer generated
412            
413             =cut
414            
415             sub polynomial_degree {
416 24     24 1 30 my $self = shift;
417 24 100       51 $self->{degree} = (sort {$b<=>$a} @{ $self->{taps}})[0] unless exists $self->{degree};
  11         33  
  9         35  
418 24         67 return $self->{degree};
419             }
420            
421 8     8   7767 BEGIN { *k_bits = \&polynomial_degree; } # alias
422            
423             =item C<$i = $seq-Etaps>
424            
425             Returns an array-reference containing the list of tap identifiers, which could then be passed to C<-Enew(taps =E ...)>.
426            
427             my $old_prbs = ...;
428             my $new_prbs = Math::PRBS->new( taps => $old_prbs->taps() );
429            
430             =cut
431            
432             sub taps {
433 12     12 1 22 return [@{ $_[0]->{taps} }];
  12         71  
434             }
435            
436             =item C<$i = $seq-Eperiod( I 'estimate' | $n | 'max'> )>
437            
438             Returns the period of the sequence.
439            
440             Without any arguments, will return undef if the period hasn't been determined yet (ie, haven't travelled far enough in the sequence):
441            
442             $i = $seq->period(); # unknown => undef
443            
444             If I is set to 'estimate', will return C if the period hasn't been determined yet:
445            
446             $i = $seq->period(force => 'estimate'); # unknown => 2**k - 1
447            
448             If I is set to an integer C<$n>, it will try to generate the whole sequence (up to C= $n>), and return the period if found, or undef if not found.
449            
450             $i = $seq->period(force => $n); # look until $n; undef if sequence period still not found
451            
452             If I is set 'max', it will loop thru the entire sequence (up to C), and return the period that was found. It will still return undef if still not found, but all sequences B find the period within C<2**k-1>. If you find a sequence that doesn't, feel free to file a bug report, including the Cnew()> command listing the taps array or poly string; if C is greater than C<32>, please include a code that fixes the bug in the bug report, as development resources may not allow for debug of issues when C 32>.
453            
454             $i = $seq->period(force => 'max'); # look until 2**k - 1; undef if sequence period still not found
455            
456            
457             =cut
458            
459             sub period {
460 25     25 1 1527 my $self = shift;
461 25 100       127 return $self->{period} if defined $self->{period}; # if period's already computed, use it
462            
463 9 100       32 die __PACKAGE__."::period(@_) requires even number of arguments, expecting name=>value pairs" unless 0 == @_ % 2;
464            
465 8         38 my %opts = map lc, @_; # lowercase the arguments and make them into a canonical hash
466 8 100       22 my $force = exists($opts{force}) ? $opts{force} : 'not';
467 8 100       24 return $self->{period} if 'not' eq $force; # if not forced, return the undefined period
468            
469 6         16 my $max = 2**$self->{taps}[0] - 1; # if forced, max is 2**k-1
470 6 100       15 return $max if $force eq 'estimate'; # if estimate, guess that period is maximal
471            
472 5 100       27 $max = $force unless $force =~ /[^\d]/; # don't change max if force is a string (or negative, or floatingpoint)
473            
474             # ... loop thru all, until limit is reached or period is defined
475 5   100     35 $self->next while $self->{i}<$max && !defined $self->{period};
476            
477 5         38 return $self->{period};
478             }
479            
480             =item C<$i = $seq-Eoeis_anum>
481            
482             For known polynomials, return the L "A" number. For example, you can go to L to look at the sequence A011686.
483            
484             Not all maximum-length PRBS sequences (binary m-sequences) are in OEIS. Of the four "standard" PRBS (7, 15, 23, 31) mentioned above, only PRBS7 is there, as L. If you have the A-number for other m-sequences that aren't included below, please let the module maintainer know.
485            
486             Polynomial | Taps | OEIS
487             ----------------------------------------------+-----------------------+---------
488             x**2 + x**1 + 1 | [ 2, 1 ] | A011655
489             x**3 + x**2 + 1 | [ 3, 2 ] | A011656
490             x**3 + x**1 + 1 | [ 3, 1 ] | A011657
491             x**4 + x**3 + x**2 + x**1 + 1 | [ 4, 3, 2, 1 ] | A011658
492             x**4 + x**1 + 1 | [ 4, 1 ] | A011659
493             x**5 + x**4 + x**2 + x**1 + 1 | [ 5, 4, 2, 1 ] | A011660
494             x**5 + x**3 + x**2 + x**1 + 1 | [ 5, 3, 2, 1 ] | A011661
495             x**5 + x**2 + 1 | [ 5, 2 ] | A011662
496             x**5 + x**4 + x**3 + x**1 + 1 | [ 5, 4, 3, 1 ] | A011663
497             x**5 + x**3 + 1 | [ 5, 3 ] | A011664
498             x**5 + x**4 + x**3 + x**2 + 1 | [ 5, 4, 3, 2 ] | A011665
499             x**6 + x**5 + x**4 + x**1 + 1 | [ 6, 5, 4, 1 ] | A011666
500             x**6 + x**5 + x**3 + x**2 + 1 | [ 6, 5, 3, 2 ] | A011667
501             x**6 + x**5 + x**2 + x**1 + 1 | [ 6, 5, 2, 1 ] | A011668
502             x**6 + x**1 + 1 | [ 6, 1 ] | A011669
503             x**6 + x**4 + x**3 + x**1 + 1 | [ 6, 4, 3, 1 ] | A011670
504             x**6 + x**5 + x**4 + x**2 + 1 | [ 6, 5, 4, 2 ] | A011671
505             x**6 + x**3 + 1 | [ 6, 3 ] | A011672
506             x**6 + x**5 + 1 | [ 6, 5 ] | A011673
507             x**7 + x**6 + x**5 + x**4 + x**3 + x**2 + 1 | [ 7, 6, 5, 4, 3, 2 ] | A011674
508             x**7 + x**4 + 1 | [ 7, 4 ] | A011675
509             x**7 + x**6 + x**4 + x**2 + 1 | [ 7, 6, 4, 2 ] | A011676
510             x**7 + x**5 + x**2 + x**1 + 1 | [ 7, 5, 2, 1 ] | A011677
511             x**7 + x**5 + x**3 + x**1 + 1 | [ 7, 5, 3, 1 ] | A011678
512             x**7 + x**6 + x**4 + x**1 + 1 | [ 7, 6, 4, 1 ] | A011679
513             x**7 + x**6 + x**5 + x**4 + x**2 + x**1 + 1 | [ 7, 6, 5, 4, 2, 1 ] | A011680
514             x**7 + x**6 + x**5 + x**3 + x**2 + x**1 + 1 | [ 7, 6, 5, 3, 2, 1 ] | A011681
515             x**7 + x**1 + 1 | [ 7, 1 ] | A011682
516             x**7 + x**5 + x**4 + x**3 + x**2 + x**1 + 1 | [ 7, 5, 4, 3, 2, 1 ] | A011683
517             x**7 + x**4 + x**3 + x**2 + 1 | [ 7, 4, 3, 2 ] | A011684
518             x**7 + x**6 + x**3 + x**1 + 1 | [ 7, 6, 3, 1 ] | A011685
519             x**7 + x**6 + 1 | [ 7, 6 ] | A011686
520             x**7 + x**6 + x**5 + x**4 + 1 | [ 7, 6, 5, 4 ] | A011687
521             x**7 + x**5 + x**4 + x**3 + 1 | [ 7, 5, 4, 3 ] | A011688
522             x**7 + x**3 + x**2 + x**1 + 1 | [ 7, 3, 2, 1 ] | A011689
523             x**7 + x**3 + 1 | [ 7, 3 ] | A011690
524             x**7 + x**6 + x**5 + x**2 + 1 | [ 7, 6, 5, 2 ] | A011691
525             x**8 + x**6 + x**4 + x**3 + x**2 + x**1 + 1 | [ 8, 6, 4, 3, 2, 1 ] | A011692
526             x**8 + x**5 + x**4 + x**3 + 1 | [ 8, 5, 4, 3 ] | A011693
527             x**8 + x**7 + x**5 + x**3 + 1 | [ 8, 7, 5, 3 ] | A011694
528             x**8 + x**7 + x**6 + x**5 + x**4 + x**2 + 1 | [ 8, 7, 6, 5, 4, 2 ] | A011695
529             x**8 + x**7 + x**6 + x**5 + x**4 + x**3 + 1 | [ 8, 7, 6, 5, 4, 3 ] | A011696
530             x**8 + x**4 + x**3 + x**2 + 1 | [ 8, 4, 3, 2 ] | A011697
531             x**8 + x**6 + x**5 + x**4 + x**2 + x**1 + 1 | [ 8, 6, 5, 4, 2, 1 ] | A011698
532             x**8 + x**7 + x**5 + x**1 + 1 | [ 8, 7, 5, 1 ] | A011699
533             x**8 + x**7 + x**3 + x**1 + 1 | [ 8, 7, 3, 1 ] | A011700
534             x**8 + x**5 + x**4 + x**3 + x**2 + x**1 + 1 | [ 8, 5, 4, 3, 2, 1 ] | A011701
535             x**8 + x**7 + x**5 + x**4 + x**3 + x**2 + 1 | [ 8, 7, 5, 4, 3, 2 ] | A011702
536             x**8 + x**7 + x**6 + x**4 + x**3 + x**2 + 1 | [ 8, 7, 6, 4, 3, 2 ] | A011703
537             x**8 + x**6 + x**3 + x**2 + 1 | [ 8, 6, 3, 2 ] | A011704
538             x**8 + x**7 + x**3 + x**2 + 1 | [ 8, 7, 3, 2 ] | A011705
539             x**8 + x**6 + x**5 + x**2 + 1 | [ 8, 6, 5, 2 ] | A011706
540             x**8 + x**7 + x**6 + x**4 + x**2 + x**1 + 1 | [ 8, 7, 6, 4, 2, 1 ] | A011707
541             x**8 + x**7 + x**6 + x**3 + x**2 + x**1 + 1 | [ 8, 7, 6, 3, 2, 1 ] | A011708
542             x**8 + x**7 + x**2 + x**1 + 1 | [ 8, 7, 2, 1 ] | A011709
543             x**8 + x**7 + x**6 + x**1 + 1 | [ 8, 7, 6, 1 ] | A011710
544             x**8 + x**7 + x**6 + x**5 + x**2 + x**1 + 1 | [ 8, 7, 6, 5, 2, 1 ] | A011711
545             x**8 + x**7 + x**5 + x**4 + 1 | [ 8, 7, 5, 4 ] | A011712
546             x**8 + x**6 + x**5 + x**1 + 1 | [ 8, 6, 5, 1 ] | A011713
547             x**8 + x**4 + x**3 + x**1 + 1 | [ 8, 4, 3, 1 ] | A011714
548             x**8 + x**6 + x**5 + x**4 + 1 | [ 8, 6, 5, 4 ] | A011715
549             x**8 + x**7 + x**6 + x**5 + x**4 + x**1 + 1 | [ 8, 7, 6, 5, 4, 1 ] | A011716
550             x**8 + x**5 + x**3 + x**2 + 1 | [ 8, 5, 3, 2 ] | A011717
551             x**8 + x**6 + x**5 + x**4 + x**3 + x**1 + 1 | [ 8, 6, 5, 4, 3, 1 ] | A011718
552             x**8 + x**5 + x**3 + x**1 + 1 | [ 8, 5, 3, 1 ] | A011719
553             x**8 + x**7 + x**4 + x**3 + x**2 + x**1 + 1 | [ 8, 7, 4, 3, 2, 1 ] | A011720
554             x**8 + x**6 + x**5 + x**3 + 1 | [ 8, 6, 5, 3 ] | A011721
555             x**9 + x**4 + 1 | [ 9, 4 ] | A011722
556             x**10 + x**3 + 1 | [ 10, 3 ] | A011723
557             x**11 + x**2 + 1 | [ 11, 2 ] | A011724
558             x**12 + x**7 + x**4 + x**3 + 1 | [ 12, 7, 4, 3 ] | A011725
559             x**13 + x**4 + x**3 + x**1 + 1 | [ 13, 4, 3, 1 ] | A011726
560             x**14 + x**12 + x**11 + x**1 + 1 | [ 14, 12, 11, 1 ] | A011727
561             x**15 + x**1 + 1 | [ 15, 1 ] | A011728
562             x**16 + x**5 + x**3 + x**2 + 1 | [ 16, 5, 3, 2 ] | A011729
563             x**17 + x**3 + 1 | [ 17, 3 ] | A011730
564             x**18 + x**7 + 1 | [ 18, 7 ] | A011731
565             x**19 + x**6 + x**5 + x**1 + 1 | [ 19, 6, 5, 1 ] | A011732
566             x**20 + x**3 + 1 | [ 20, 3 ] | A011733
567             x**21 + x**2 + 1 | [ 21, 2 ] | A011734
568             x**22 + x**1 + 1 | [ 22, 1 ] | A011735
569             x**23 + x**5 + 1 | [ 23, 5 ] | A011736
570             x**24 + x**4 + x**3 + x**1 + 1 | [ 24, 4, 3, 1 ] | A011737
571             x**25 + x**3 + 1 | [ 25, 3 ] | A011738
572             x**26 + x**8 + x**7 + x**1 + 1 | [ 26, 8, 7, 1 ] | A011739
573             x**27 + x**8 + x**7 + x**1 + 1 | [ 27, 8, 7, 1 ] | A011740
574             x**28 + x**3 + 1 | [ 28, 3 ] | A011741
575             x**29 + x**2 + 1 | [ 29, 2 ] | A011742
576             x**30 + x**16 + x**15 + x**1 + 1 | [ 30, 16, 15, 1 ] | A011743
577             x**31 + x**3 + 1 | [ 31, 3 ] | A011744
578             x**32 + x**28 + x**27 + x**1 + 1 | [ 32, 28, 27, 1 ] | A011745
579            
580             =cut
581            
582             my %OEIS = (
583             join(';', @{ [ 2, 1 ] } ) => 'A011655',
584             join(';', @{ [ 3, 2 ] } ) => 'A011656',
585             join(';', @{ [ 3, 1 ] } ) => 'A011657',
586             join(';', @{ [ 4, 3, 2, 1 ] } ) => 'A011658',
587             join(';', @{ [ 4, 1 ] } ) => 'A011659',
588             join(';', @{ [ 5, 4, 2, 1 ] } ) => 'A011660',
589             join(';', @{ [ 5, 3, 2, 1 ] } ) => 'A011661',
590             join(';', @{ [ 5, 2 ] } ) => 'A011662',
591             join(';', @{ [ 5, 4, 3, 1 ] } ) => 'A011663',
592             join(';', @{ [ 5, 3 ] } ) => 'A011664',
593             join(';', @{ [ 5, 4, 3, 2 ] } ) => 'A011665',
594             join(';', @{ [ 6, 5, 4, 1 ] } ) => 'A011666',
595             join(';', @{ [ 6, 5, 3, 2 ] } ) => 'A011667',
596             join(';', @{ [ 6, 5, 2, 1 ] } ) => 'A011668',
597             join(';', @{ [ 6, 1 ] } ) => 'A011669',
598             join(';', @{ [ 6, 4, 3, 1 ] } ) => 'A011670',
599             join(';', @{ [ 6, 5, 4, 2 ] } ) => 'A011671',
600             join(';', @{ [ 6, 3 ] } ) => 'A011672',
601             join(';', @{ [ 6, 5 ] } ) => 'A011673',
602             join(';', @{ [ 7, 6, 5, 4, 3, 2 ] } ) => 'A011674',
603             join(';', @{ [ 7, 4 ] } ) => 'A011675',
604             join(';', @{ [ 7, 6, 4, 2 ] } ) => 'A011676',
605             join(';', @{ [ 7, 5, 2, 1 ] } ) => 'A011677',
606             join(';', @{ [ 7, 5, 3, 1 ] } ) => 'A011678',
607             join(';', @{ [ 7, 6, 4, 1 ] } ) => 'A011679',
608             join(';', @{ [ 7, 6, 5, 4, 2, 1 ] } ) => 'A011680',
609             join(';', @{ [ 7, 6, 5, 3, 2, 1 ] } ) => 'A011681',
610             join(';', @{ [ 7, 1 ] } ) => 'A011682',
611             join(';', @{ [ 7, 5, 4, 3, 2, 1 ] } ) => 'A011683',
612             join(';', @{ [ 7, 4, 3, 2 ] } ) => 'A011684',
613             join(';', @{ [ 7, 6, 3, 1 ] } ) => 'A011685',
614             join(';', @{ [ 7, 6 ] } ) => 'A011686',
615             join(';', @{ [ 7, 6, 5, 4 ] } ) => 'A011687',
616             join(';', @{ [ 7, 5, 4, 3 ] } ) => 'A011688',
617             join(';', @{ [ 7, 3, 2, 1 ] } ) => 'A011689',
618             join(';', @{ [ 7, 3 ] } ) => 'A011690',
619             join(';', @{ [ 7, 6, 5, 2 ] } ) => 'A011691',
620             join(';', @{ [ 8, 6, 4, 3, 2, 1 ] } ) => 'A011692',
621             join(';', @{ [ 8, 5, 4, 3 ] } ) => 'A011693',
622             join(';', @{ [ 8, 7, 5, 3 ] } ) => 'A011694',
623             join(';', @{ [ 8, 7, 6, 5, 4, 2 ] } ) => 'A011695',
624             join(';', @{ [ 8, 7, 6, 5, 4, 3 ] } ) => 'A011696',
625             join(';', @{ [ 8, 4, 3, 2 ] } ) => 'A011697',
626             join(';', @{ [ 8, 6, 5, 4, 2, 1 ] } ) => 'A011698',
627             join(';', @{ [ 8, 7, 5, 1 ] } ) => 'A011699',
628             join(';', @{ [ 8, 7, 3, 1 ] } ) => 'A011700',
629             join(';', @{ [ 8, 5, 4, 3, 2, 1 ] } ) => 'A011701',
630             join(';', @{ [ 8, 7, 5, 4, 3, 2 ] } ) => 'A011702',
631             join(';', @{ [ 8, 7, 6, 4, 3, 2 ] } ) => 'A011703',
632             join(';', @{ [ 8, 6, 3, 2 ] } ) => 'A011704',
633             join(';', @{ [ 8, 7, 3, 2 ] } ) => 'A011705',
634             join(';', @{ [ 8, 6, 5, 2 ] } ) => 'A011706',
635             join(';', @{ [ 8, 7, 6, 4, 2, 1 ] } ) => 'A011707',
636             join(';', @{ [ 8, 7, 6, 3, 2, 1 ] } ) => 'A011708',
637             join(';', @{ [ 8, 7, 2, 1 ] } ) => 'A011709',
638             join(';', @{ [ 8, 7, 6, 1 ] } ) => 'A011710',
639             join(';', @{ [ 8, 7, 6, 5, 2, 1 ] } ) => 'A011711',
640             join(';', @{ [ 8, 7, 5, 4 ] } ) => 'A011712',
641             join(';', @{ [ 8, 6, 5, 1 ] } ) => 'A011713',
642             join(';', @{ [ 8, 4, 3, 1 ] } ) => 'A011714',
643             join(';', @{ [ 8, 6, 5, 4 ] } ) => 'A011715',
644             join(';', @{ [ 8, 7, 6, 5, 4, 1 ] } ) => 'A011716',
645             join(';', @{ [ 8, 5, 3, 2 ] } ) => 'A011717',
646             join(';', @{ [ 8, 6, 5, 4, 3, 1 ] } ) => 'A011718',
647             join(';', @{ [ 8, 5, 3, 1 ] } ) => 'A011719',
648             join(';', @{ [ 8, 7, 4, 3, 2, 1 ] } ) => 'A011720',
649             join(';', @{ [ 8, 6, 5, 3 ] } ) => 'A011721',
650             join(';', @{ [ 9, 4 ] } ) => 'A011722',
651             join(';', @{ [ 10, 3 ] } ) => 'A011723',
652             join(';', @{ [ 11, 2 ] } ) => 'A011724',
653             join(';', @{ [ 12, 7, 4, 3 ] } ) => 'A011725',
654             join(';', @{ [ 13, 4, 3, 1 ] } ) => 'A011726',
655             join(';', @{ [ 14, 12, 11, 1 ] } ) => 'A011727',
656             join(';', @{ [ 15, 1 ] } ) => 'A011728',
657             join(';', @{ [ 16, 5, 3, 2 ] } ) => 'A011729',
658             join(';', @{ [ 17, 3 ] } ) => 'A011730',
659             join(';', @{ [ 18, 7 ] } ) => 'A011731',
660             join(';', @{ [ 19, 6, 5, 1 ] } ) => 'A011732',
661             join(';', @{ [ 20, 3 ] } ) => 'A011733',
662             join(';', @{ [ 21, 2 ] } ) => 'A011734',
663             join(';', @{ [ 22, 1 ] } ) => 'A011735',
664             join(';', @{ [ 23, 5 ] } ) => 'A011736',
665             join(';', @{ [ 24, 4, 3, 1 ] } ) => 'A011737',
666             join(';', @{ [ 25, 3 ] } ) => 'A011738',
667             join(';', @{ [ 26, 8, 7, 1 ] } ) => 'A011739',
668             join(';', @{ [ 27, 8, 7, 1 ] } ) => 'A011740',
669             join(';', @{ [ 28, 3 ] } ) => 'A011741',
670             join(';', @{ [ 29, 2 ] } ) => 'A011742',
671             join(';', @{ [ 30, 16, 15, 1 ] } ) => 'A011743',
672             join(';', @{ [ 31, 3 ] } ) => 'A011744',
673             join(';', @{ [ 32, 28, 27, 1 ] } ) => 'A011745',
674             );
675             sub oeis_anum {
676 9     9 1 14 my $taps = join ';', @{ $_[0]->{taps} };
  9         24  
677 9 100       45 return exists $OEIS{$taps} ? $OEIS{$taps} : undef;
678             }
679            
680            
681             =back
682            
683             =head1 THEORY
684            
685             A pseudorandom binary sequence (PRBS) is the sequence of N unique bits, in this case generated from an LFSR. Once it generates the N bits, it loops around and repeats that seqence. While still within the unique N bits, the sequence of N bits shares some properties with a truly random sequence of the same length. The benefit of this sequence is that, while it shares statistical properites with a random sequence, it is actually deterministic, so is often used to deterministically test hardware or software that requires a data stream that needs pseudorandom properties.
686            
687             In an LFSR, the polynomial description (like C) indicates which bits are "tapped" to create the feedback bit: the taps are the powers of x in the polynomial (3 and 2). The C<1> is really the C term, and isn't a "tap", in the sense that it isn't used for generating the feedback; instead, that is the location where the new feedback bit comes back into the shift register; the C<1> is in all characteristic polynomials, and is implied when creating a new instance of B.
688            
689             If the largest power of the polynomial is C (ie, a polynomial of degree C), there are C bits in the register (one for each of the powers C down to C<1> and one for the C's feedback bit). For any given C, the largest sequence that can be produced is C, and any sequence with that length is called a "maximum length sequence" or m-sequence; there can be more than one m-sequence for a given C.
690            
691             One useful feature of an m-sequence is that if you divide it into every possible partial sequence that's C bits long (wraping from N-1 to 0 to make the last few partial sequences also C bits), you will generate every possible combination of C bits (*), except for C zeroes in a row. (It then includes the binary representation of every k-bit integer from C<1> to C<2**k - 1>.) For example,
692            
693             # x**3 + x**2 + 1 = "1011100"
694             "_101_1100 " -> 101 (5)
695             "1_011_100 " -> 011 (3)
696             "10_111_00 " -> 111 (7)
697             "101_110_0 " -> 110 (6)
698             "1011_100_ " -> 100 (4)
699             "1_0111_00 " -> 001 (1) (requires wrap to get three digits: 00 from the end of the sequence, and 1 from the beginning)
700             "10_1110_0 " -> 010 (2) (requires wrap to get three digits: 0 from the end of the sequence, and 10 from the beginning)
701            
702             The Wikipedia:LFSR article lists some polynomials that create m-sequence for various register sizes, and links to Philip Koopman's complete list up to C (see L for links to both).
703            
704             If you want to create your own polynonial to find a long m-sequence, here are some things to consider: 1) the number of taps for the feedback (remembering not to count the feedback bit as a tap) must be even; 2) the entire set of taps must be relatively prime; 3) those two conditions are necesssary, but not sufficient, so you may have to try multiple polynomials to find an m-sequence; 4) keep in mind that the time to compute the period (and thus determine if it's an m-sequence) doubles every time C increases by 1; as the time increases, it makes more sense to look at the complete list up to C), and pure-perl is probably tpp wrong language for searching C64>.
705            
706             (*) Since a maximum length sequence contains every k-bit combination (except all zeroes), it can be used for verifying that software or hardware behaves properly for every possible sequence of k-bits.
707            
708             =head1 REFERENCES
709            
710             =over
711            
712             =item * Wikipedia:Linear-feedback Shift Register (LFSR) at L
713            
714             =over
715            
716             =item * Article includes a list of some L
717            
718             =item * Article links to Philip Koopman's complete list of maximum length polynomials, up to C at L
719            
720             =back
721            
722             =item * Wikipedia:Pseudorandom Binary Sequence (PRBS) at L
723            
724             =over
725            
726             =item * The underlying algorithm in B is based on the C code in this article's L<"Practical Implementation"|https://en.wikipedia.org/w/index.php?title=Pseudorandom_binary_sequence&oldid=700999060#Practical_implementation>
727            
728             =back
729            
730             =item * Wikipedia:Maximum Length Sequence (m-sequence) at L
731            
732             =over
733            
734             =item * Article describes some of the properties of m-sequences
735            
736             =back
737            
738             =back
739            
740             =head1 INSTALLATION
741            
742             To install this module, use your favorite CPAN client.
743            
744             For a manual install, type the following:
745            
746             perl Makefile.PL
747             make
748             make test
749             make install
750            
751             (On Windows machines, you may need to use "dmake" or "gmake" instead of "make", depending on your setup.)
752            
753             =head1 SEE ALSO
754            
755             =over
756            
757             =item * L - an iterator-based sequence generator, with a variety of numeric sequences that can be generated
758            
759             The primary API for B was based on L, but it was decided to not make B dependent on it, because L does not L.
760            
761             =item * L and L - generate sequences using symbolic forumla
762            
763             =item * L - Implements a (159, 31, 0) LFSR
764            
765             =back
766            
767             =head1 AUTHOR
768            
769             Peter C. Jones Cpetercj AT cpan DOT orgE>
770            
771             Please report any bugs or feature requests thru the web interface at
772             L
773            
774             =begin html
775            
776            
777            
778            
779            
780            
781            
782            
783            
784             =end html
785            
786             =head1 COPYRIGHT
787            
788             Copyright (C) 2016,2018 Peter C. Jones
789            
790             =head1 LICENSE
791            
792             This program is free software; you can redistribute it and/or modify it
793             under the terms of either: the GNU General Public License as published
794             by the Free Software Foundation; or the Artistic License.
795            
796             See L for more information.
797            
798            
799             =cut
800            
801             1;