File Coverage

blib/lib/AI/NNFlex/Dataset.pm
Criterion Covered Total %
statement 119 125 95.2
branch 16 26 61.5
condition 4 6 66.6
subroutine 8 8 100.0
pod 5 7 71.4
total 152 172 88.3


line stmt bran cond sub pod time code
1             ##########################################################
2             # AI::NNFlex::Dataset
3             ##########################################################
4             # Dataset methods for AI::NNFlex - perform learning etc
5             # on groups of data
6             #
7             ##########################################################
8             # Versions
9             # ========
10             #
11             # 1.0 20050115 CColbourn New module
12             #
13             # 1.1 20050324 CColbourn Added load support
14             #
15             ##########################################################
16             # ToDo
17             # ----
18             #
19             #
20             ###########################################################
21             #
22 5     5   4329 use strict;
  5         12  
  5         9045  
23             package AI::NNFlex::Dataset;
24              
25              
26             ###########################################################
27             # AI::NNFlex::Dataset::new
28             ###########################################################
29             sub new
30             {
31 7     7 1 1884 my $class = shift;
32 7         14 my $params = shift;
33 7         500 my $dataset;
34 7 100       59 if ($class =~ /HASH/)
35             {
36 1         2 $dataset = $class;
37 1         3 $dataset->{'data'} = $params;
38 1         21 return 1;
39             }
40              
41 6         606 my %attributes;
42 6         18 $attributes{'data'} = $params;
43              
44 6         11 $dataset = \%attributes;
45 6         18 bless $dataset,$class;
46 6         20 return $dataset;
47             }
48              
49              
50             ###########################################################
51             # AI::NNFlex::Datasets::run
52             ###########################################################
53             sub run
54             {
55 4     4 0 773 my $self = shift;
56 4         9 my $network = shift;
57 4         8 my @outputs;
58 4         7 my $counter=0;
59              
60 4         16 for (my $itemCounter=0;$itemCounter<(scalar @{$self->{'data'}});$itemCounter +=2)
  17         54  
61             {
62 13         17 $network->run(@{$self->{'data'}}[$itemCounter]);
  13         313  
63 13         40 $outputs[$counter] = $network->output();
64 13         47 $counter++;
65             }
66              
67 4         14 return \@outputs;
68              
69             }
70              
71             ###############################################################
72             # AI::NNFlex::Dataset::learn
73             ###############################################################
74             sub learn
75             {
76 3     3 0 625 my $self = shift;
77 3         5 my $network = shift;
78 3         5 my $error;
79              
80 3         6 for (my $itemCounter=0;$itemCounter<(scalar @{$self->{'data'}});$itemCounter +=2)
  12         41  
81             {
82 9         12 $network->run(@{$self->{'data'}}[$itemCounter]);
  9         70  
83 9         14 $error += $network->learn(@{$self->{'data'}}[$itemCounter+1]);
  9         40  
84             }
85              
86 3         7 $error = $error*$error;
87              
88 3         10 return $error;
89             }
90              
91             #################################################################
92             # AI::NNFlex::Dataset::save
93             #################################################################
94             # save a dataset in an snns .pat file
95             #################################################################
96             sub save
97             {
98 1     1 1 181 my $dataset = shift;
99 1         4 my %config = @_;
100              
101 1 50       124 open (OFILE,">".$config{'filename'}) or return "File error $!";
102              
103 1         2 print OFILE "No. of patterns : ".((scalar @{$dataset->{'data'}})/2)."\n";
  1         17  
104 1         2 print OFILE "No. of input units : ".(scalar @{$dataset->{'data'}->[0]})."\n";
  1         4  
105 1         1 print OFILE "No. of output units : ".(scalar @{$dataset->{'data'}->[1]})."\n\n";
  1         4  
106              
107 1         2 my $counter = 1;
108 1         1 my @values = @{$dataset->{'data'}};
  1         3  
109 1         4 while (@values)
110             {
111 5         10 print OFILE "# Input pattern $counter:\n";
112 5         7 my $input = shift (@values);
113 5         12 my @array = join " ",@$input;
114 5         7 print OFILE @array;
115 5         6 print OFILE "\n";
116              
117 5         7 print OFILE "# Output pattern $counter:\n";
118 5         6 my $output = shift(@values);
119 5         14 @array = join " ",@$output;
120 5         7 print OFILE @array;
121 5         6 print OFILE "\n";
122              
123 5         14 $counter++;
124             }
125              
126 1         50 close OFILE;
127 1         4 return 1;
128             }
129              
130              
131             #############################################################
132             # AI::NNFlex::Dataset::load
133             #############################################################
134             sub load
135             {
136 1     1 1 192 my $dataset = shift;
137 1         4 my %params = @_;
138              
139 1         1 my @data;
140              
141 1         2 my $filename = $params{'filename'};
142 1 50       4 if (!$filename)
143             {
144 0         0 return "No filename specified";
145             }
146              
147 1 50       38 open (IFILE,"$filename") or return "Unable to load $filename - $!";
148              
149 1         1 my %config;
150             # snns pat files have a 3 line header, defining number of patterns &
151             # number of input and output units
152 1         2 my $counter =0;
153 1         3 while ($counter <3)
154             {
155 3         18 my $line = ;
156 3 50 33     24 if ($line =~/^\n/ || $line =~/^#/){next}
  0         0  
157 3         47 my ($tag,$value) = split/:/,$line;
158 3         7 $tag=lc($tag);
159 3         12 $tag =~s/ //g;
160            
161 3         7 $config{lc($tag)} = $value;
162 3         8 $counter++;
163             }
164              
165 1         1 my $filecontent;
166 1         5 while ()
167             {
168 21 100 100     100 if($_ =~ /^#/ || $_ =~ /^\n/){next}
  11         29  
169 10         28 $filecontent .= $_;
170             }
171              
172 1         9 my @individualvals = split /\s+/s,$filecontent;
173              
174 1         6 for (my $offset=0;$offset<(scalar @individualvals);$offset+=($config{'no.ofinputunits'} + $config{'no.ofoutputunits'}))
175             {
176 5         24 my @input=@individualvals[$offset..($offset+$config{'no.ofinputunits'}-1)];
177 5         11 push @data,\@input;
178 5 50       15 if ($config{'no.ofoutputunits'} > 0)
179             {
180 5         20 my @output=@individualvals[($offset+$config{'no.ofinputunits'})..($offset+$config{'no.ofinputunits'}+$config{'no.ofoutputunits'}-1)];
181 5         11774 push @data,\@output;
182             }
183             }
184              
185            
186 1         7 $dataset->new(\@data);
187              
188 1         10 return 1;
189             }
190            
191             ##########################################################
192             # AI::NNFlex::Dataset::add
193             ##########################################################
194             # add an input/output pair to the dataset
195             ##########################################################
196             sub add
197             {
198 3     3 1 207 my $dataset= shift;
199 3         6 my $params = shift;
200              
201 3 50       9 if (!$params){return "Nothing to add"};
  0         0  
202 3 50       17 if ($params !~/ARRAY/){return "Need a reference to an array"}
  0         0  
203              
204             # support adding single patterns (for Hopfield type nets)
205 3 100       11 if ($$params[0] !~ /ARRAY/)
206             {
207 2         2 push @{$dataset->{'data'}},$params;
  2         9  
208             }
209             else
210             {
211 1         2 push @{$dataset->{'data'}},$$params[0];
  1         3  
212 1         1 push @{$dataset->{'data'}},$$params[1];
  1         3  
213             }
214              
215 3         7 return 1;
216             }
217              
218             ##################################################################
219             # AI::NNFlex::Dataset::delete
220             ##################################################################
221             # delete an item from the dataset by index
222             ##################################################################
223             sub delete
224             {
225 1     1 1 532 my $dataset = shift;
226 1         3 my $index = shift;
227 1         2 my @indexarray;
228              
229 1 50       5 if (!$index){return 0}
  0         0  
230              
231 1 50       9 if ($index =~ /ARRAY/)
232             {
233 1         4 @indexarray = @$index;
234             }
235             else
236             {
237 0         0 $indexarray[0] = $index;
238             }
239              
240 1         1 my @newarray;
241 1         3 my $counter=0;
242 1         2 foreach (@indexarray)
243             {
244 2 50       6 unless ($counter == $_)
245             {
246 2         4 push @newarray,${$dataset->{'data'}}[$_];
  2         7  
247             }
248             }
249              
250 1         3 $dataset->{'data'} = \@newarray;
251              
252 1         10 return 1;
253             }
254              
255              
256              
257             1;
258             =pod
259              
260             =head1 NAME
261              
262             AI::NNFlex::Dataset - support for creating/loading/saving datasets for NNFlex nets
263              
264             =head1 SYNOPSIS
265              
266             use AI::NNFlex::Dataset;
267              
268             my $dataset = AI::NNFlex::Dataset->new([[0,1,1,0],[0,0,1,1]]);
269              
270             $dataset->add([[0,1,0,1],[1,1,0,0]]);
271              
272             $dataset->add([0,1,0,0]);
273              
274             $dataset->save(filename=>'test.pat');
275              
276             $dataset->load(filename=>'test.pat');
277              
278             =head1 DESCRIPTION
279              
280             This module allows you to construct, load, save and maintain datasets for use with neural nets implemented using the AI::NNFlex classes. The dataset consists of an array of references to arrays of data. Items may be added in pairs (useful for feedforward nets with an input & target pair of values) or individually (for Hopfield type nets where only an input is specified). The load and save methods use files that are compatible (I think) with SNNS .pat files.
281              
282             =head1 CONSTRUCTOR
283              
284             =head2 AI::NNFlex::Dataset->new([[INPUT],[TARGET]]);
285              
286             Parameters:
287              
288             The constructor takes an (optional) reference to an array of one or more arrays. For convenience you can specify two values at a time (for INPUT and OUTPUT values) or a single value at a time. You can also leave the parameters blank, in which case the constructor creates a Dataset object with no values. Values can then be added with the 'add' method.
289              
290             The return value is an AI::NNFlex::Dataset object.
291              
292             =head1 METHODS
293              
294             This is a short list of the main methods implemented in AI::NNFlex::Dataset
295              
296              
297             =head2 add
298              
299             Syntax:
300              
301             $dataset->add([[INPUT],[OUTPUT]]);
302              
303             or
304              
305             $dataset->add([VALUE]);
306              
307             This method adds new values to the end of the dataset. You can specify the values as pairs or individually.
308              
309             =head2 load
310              
311             Syntax:
312              
313             $dataset->load(filename=>'filename.pat');
314              
315             Loads an SNNS type .pat file into a blank dataset. If called on an existing dataset IT WILL OVERWRITE IT!
316              
317             =head2 save
318              
319             $dataset->save(filename=>'filename.pat');
320              
321             Save the existing dataset as an SNNS .pat file. If the file already exists it will be overwritten.
322              
323             =head2 delete
324              
325             $dataset->delete(INDEX);
326              
327             or
328              
329             $dataset->delete([ARRAY OF INDICES]);
330              
331             Deletes 1 or more items from the dataset by their index (counting from 0). Note that if you are using pairs of values (in a backprop net for example) you MUST delete in pairs - otherwise you will delete only the input/target, and the indices will be shifted leaving your dataset in a messed up state.
332              
333             =head1 EXAMPLES
334              
335             See the code in ./examples.
336              
337              
338             =head1 PREREQs
339              
340             None.
341              
342             =head1 SEE ALSO
343              
344             AI::NNFlex
345              
346              
347             =head1 TODO
348              
349             Method to delete existing dataset entries by index
350              
351             Method to validate linear separability of a dataset.
352              
353             =head1 CHANGES
354              
355              
356             =head1 COPYRIGHT
357              
358             Copyright (c) 2004-2005 Charles Colbourn. All rights reserved. This program is free software; you can redistribute it and/or modify
359             it under the same terms as Perl itself.
360              
361             =head1 CONTACT
362              
363             charlesc@nnflex.g0n.net
364              
365              
366              
367             =cut
368