File Coverage

blib/lib/Net/OnlineCode/Decoder.pm
Criterion Covered Total %
statement 21 85 24.7
branch 0 18 0.0
condition 0 9 0.0
subroutine 7 12 58.3
pod 0 5 0.0
total 28 129 21.7


line stmt bran cond sub pod time code
1             package Net::OnlineCode::Decoder;
2              
3 1     1   21334 use strict;
  1         2  
  1         50  
4 1     1   8 use warnings;
  1         2  
  1         38  
5              
6 1     1   7 use Carp;
  1         8  
  1         105  
7              
8 1     1   542 use Net::OnlineCode;
  1         3  
  1         47  
9 1     1   592 use Net::OnlineCode::GraphDecoder;
  1         3  
  1         62  
10              
11             require Exporter;
12              
13 1     1   11 use vars qw(@ISA @EXPORT_OK @EXPORT %EXPORT_TAGS $VERSION);
  1         2  
  1         139  
14              
15             # Inherit from base class
16             @ISA = qw(Net::OnlineCode Exporter);
17             @EXPORT_OK = qw();
18              
19             $VERSION = '0.03';
20              
21 1     1   6 use constant DEBUG => 0;
  1         2  
  1         1207  
22              
23             sub new {
24              
25 0     0 0   my $class = shift;
26              
27 0           my %opts = (
28             # decoder-specific arguments:
29             expand_aux => 0, # override parent class's default
30             expand_msg => 1, # expand_* options used by expansion()
31             initial_rng => undef,
32             # user-supplied arguments:
33             @_
34             );
35 0 0         unless (ref($opts{initial_rng})) {
36 0           carp "$class->new requires an initial_rng => \$rng parameter\n";
37 0           return undef;
38             }
39              
40             # Send all arguments to the base class. It does basic parameter
41             # handling/mangling, calculates the number of auxiliary blocks based
42             # on them and generates a probability distribution.
43              
44 0           my $self = $class->SUPER::new(@_);
45              
46             # Our subclass includes extra data/options
47 0           $self->{expand_msg}=$opts{expand_msg};
48 0           my $graph = Net::OnlineCode::GraphDecoder->new
49             (
50             $self->{mblocks},
51             $self->{ablocks},
52             $self->auxiliary_mapping($opts{initial_rng}),
53             );
54 0           $self->{graph} = $graph;
55              
56             # print "Decoder: returning from constructor\n";
57 0           return $self;
58              
59             }
60              
61             sub accept_check_block {
62 0     0 0   my $self = shift;
63 0           my $rng = shift;
64              
65             # print "Decoder: calling checkblock_mapping\n";
66 0           my $composite_blocks = $self->checkblock_mapping($rng);
67              
68 0           print "Decoder check block: " . (join " ", @$composite_blocks) . "\n" if DEBUG;
69              
70             # print "Decoder: Adding check block to graph\n";
71 0           my $check_node = $self->{graph}->add_check_block($composite_blocks);
72              
73 0           ++($self->{chblocks});
74              
75             # Caller will now have to call resolve manually ...
76             # print "Decoder: Resolving graph\n";
77             # ($self->{graph}->resolve($check_node));
78              
79             # caller probably won't use return value, but if they do it makes
80             # sense to return zero-based array index
81            
82 0           return $check_node - $self->get_coblocks;
83              
84             }
85              
86             # pass calls to resolve onto graph decoder object
87             sub resolve {
88 0     0 0   my ($self,@args) = @_;
89              
90 0           $self->{graph}->resolve(@args);
91             }
92              
93             # new routine to replace xor_list; does "lazy" expansion of node lists
94             # from graph object, honouring the expand_aux and (new) expand_msg
95             # flags.
96             sub expansion {
97              
98 0     0 0   my ($self, $node) = @_;
99              
100             # pull out frequently-used variables (using hash slice)
101 0           my ($expand_aux,$expand_msg) = @{$self}{"expand_aux","expand_msg"};
  0            
102 0           my ($mblocks,$coblocks) = @{$self}{"mblocks","coblocks"};
  0            
103              
104             # Stage 1: collect list of nodes in the expansion, honouring flags
105 0           my ($in,$out,$expanded,$done) =
106             ($self->{graph}->{xor_list}->[$node],[],0,0);
107              
108 0           if (DEBUG) {
109             print "Expansion: node ${node}'s input list is " . (join " ", @$in) . "\n";
110             }
111              
112 0           until ($done) {
113             # we may need several loops to expand everything since aux blocks
114             # may appear in the expansion of message blocks and vice-versa.
115             # It's possible to do the expansion with just one loop, but the
116             # code is more messy/complicated.
117              
118 0           for my $i (@$in) {
119 0 0 0       if ($expand_msg and $i < $mblocks) {
    0 0        
      0        
120 0           ++$expanded;
121 0           push @$out, @{$self->{graph}->{xor_list}->[$i]};
  0            
122             } elsif ($expand_aux and $i >= $mblocks and $i < $coblocks) {
123 0           ++$expanded;
124 0           push @$out, @{$self->{graph}->{xor_list}->[$i]};
  0            
125             } else {
126 0           push @$out, $i;
127             }
128             }
129 0 0         $done = 1 unless $expanded;
130             } continue {
131 0           ($in,$out) = ($out,[]);
132 0           $expanded = 0;
133             }
134              
135             # test expansion after stage 1
136 0           if (0) {
137             for my $i (@$in) {
138             if ($expand_aux) {
139             die "raw expanded list had aux blocks after stage 1\n"
140             if $i >= $mblocks and $i < $coblocks;
141             }
142             if ($expand_msg) {
143             die "raw expanded list had msg blocks after stage 1\n"
144             if $i < $mblocks;
145             }
146             }
147             }
148              
149 0           if (DEBUG) {
150             print "Expansion: list after expand_* is " . (join " ", @$in) . "\n";
151             }
152              
153             # Stage 2: sort the list
154 0           my @sorted = sort { $a <=> $b } @$in;
  0            
155              
156             # Stage 3: create output list containing only nodes that appear an
157             # odd number of times
158 0 0         die "expanded list was empty\n" unless @sorted;
159              
160 0           my ($previous, $runlength) = ($sorted[0], 0);
161 0           my @output = ();
162              
163 0           foreach my $i (@sorted) {
164 0 0         if ($i == $previous) {
165 0           ++$runlength;
166             } else {
167 0 0         push @output, $previous if $runlength & 1;
168 0           $previous = $i;
169 0           $runlength = 1;
170             }
171             }
172 0 0         push @output, $previous if $runlength & 1;
173              
174             # test expansion after stage 3
175 0           if (0) {
176             for my $i (@output) {
177             if ($expand_aux) {
178             die "raw expanded list had aux blocks after stage 3\n"
179             if $i >= $mblocks and $i < $coblocks;
180             }
181             if ($expand_msg) {
182             die "raw expanded list had msg blocks after stage 3\n"
183             if $i < $mblocks;
184             }
185             }
186             }
187              
188             # Finish: return list
189 0           return @output;
190              
191             }
192              
193             # expand_aux already handled in graph object (DELETEME)
194             sub xor_list {
195 0     0 0   my $self = shift;
196 0           my $i = shift;
197              
198 0           return ($self->{graph}->xor_list($i));
199              
200             # algorithm will no longer return just composite blocks
201              
202              
203 0           my $coblocks = $self->get_coblocks;
204              
205             # the graph object assigns check blocks indexes after the composite
206             # blocks, but the user would prefer to count them from zero:
207              
208 0           my @list = map { $_ - $coblocks } ($self->{graph}->xor_list($i));
  0            
209              
210 0 0         foreach (@list) { die "xor_list: $_ is negative!\n" if $_ < 0; }
  0            
211              
212 0           return @list;
213             }
214              
215             1;
216              
217             __END__