neuralnet.cpp
1 /********************************************************************************
2  * Neural Network Framework. *
3  * Copyright (C) 2005-2011 Gianluca Massera <emmegian@yahoo.it> *
4  * *
5  * This program is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the Free Software *
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
18  ********************************************************************************/
19 
20 #include "neuralnet.h"
21 //#include "neuralnetconfwidget.h"
22 
23 namespace farsa {
24 
26  dimUps = 0;
27 }
28 
30 }
31 
32 void NeuralNet::addCluster( Cluster* c, bool isInput, bool isOutput ) {
33 #ifdef FARSA_DEBUG
34  if ( !c ) {
35  qWarning() << "Null Pointer passed to addCluster! This operation will be ignored" ;
36  return;
37  }
38 #endif
39  // Check if the Cluster is already added
40  if ( find( c ) ) {
41 #ifdef FARSA_DEBUG
42  qWarning() << "Cluster already added! addCluster will be ignored" ;
43 #endif
44  return;
45  }
46  clustersv.append( c );
47  if ( isInput ) {
48  inclusters.append( c );
49  }
50  if ( isOutput ) {
51  outclusters.append( c );
52  }
53  if ( !isInput && !isOutput ) {
54  hidclusters.append( c );
55  }
56  clsMap[c->name()] = c;
57  return;
58 }
59 
61 #ifdef FARSA_DEBUG
62  if ( !c ) {
63  qWarning() << "Null Pointer passed to removeCluster! This operation will return false" ;
64  return false;
65  }
66 #endif
67  if ( !find( c ) ) {
68  return false;
69  }
70  clustersv.removeOne( c );
71  inclusters.removeOne( c );
72  outclusters.removeOne( c );
73  hidclusters.removeOne( c );
74  clsMap.remove( c->name() );
75  return true;
76 }
77 
79 #ifdef FARSA_DEBUG
80  if ( !c ) {
81  qWarning() << "Null Pointer passed to addCluster! This operation will be ignored" ;
82  return;
83  }
84 #endif
85  // Check if the Cluster exists
86  if ( !find( c ) ) {
87 #ifdef FARSA_DEBUG
88  qWarning() << "attempt to mark a Cluster not present in this net!" ;
89 #endif
90  return;
91  }
92  if ( inclusters.contains( c ) ) {
93  return;
94  }
95  inclusters.append( c );
96  hidclusters.removeOne( c );
97 }
98 
100 #ifdef FARSA_DEBUG
101  if ( !c ) {
102  qWarning() << "Null Pointer passed to addCluster! This operation will be ignored" ;
103  return;
104  }
105 #endif
106  // Check if the Cluster exists
107  if ( !find( c ) ) {
108 #ifdef FARSA_DEBUG
109  qWarning() << "attempt to mark a Cluster not present in this net!" ;
110 #endif
111  return;
112  }
113  if ( outclusters.contains( c ) ) {
114  return;
115  }
116  outclusters.append( c );
117  hidclusters.removeOne( c );
118 }
119 
121 #ifdef FARSA_DEBUG
122  if ( !c ) {
123  qWarning() << "Null Pointer passed to addCluster! This operation will be ignored" ;
124  return;
125  }
126 #endif
127  // Check if the Cluster exists
128  if ( !find( c ) ) {
129 #ifdef FARSA_DEBUG
130  qWarning() << "attempt to unmark a Cluster not present in this net!" ;
131 #endif
132  return;
133  }
134  inclusters.removeOne( c );
135  outclusters.removeOne( c );
136  hidclusters.append( c );
137  return;
138 }
139 
141  inclusters.clear();
142  outclusters.clear();
144  return;
145 }
146 
147 bool NeuralNet::isIsolated( Cluster* c ) const {
148 #ifdef FARSA_DEBUG
149  if ( !c ) {
150  qWarning() << "Null Pointer passed to isIsolato! This operation will return false" ;
151  return false;
152  }
153 #endif
154  return ( inLinks.count( c ) == 0 && outLinks.count( c ) == 0 );
155 }
156 
157 ClusterList NeuralNet::clusters() const {
158  return clustersv;
159 }
160 
161 ClusterList NeuralNet::inputClusters() const {
162  return inclusters;
163 }
164 
165 ClusterList NeuralNet::outputClusters() const {
166  return outclusters;
167 }
168 
169 ClusterList NeuralNet::hiddenClusters() const {
170  return hidclusters;
171 }
172 
174 #ifdef FARSA_DEBUG
175  if ( !l ) {
176  qWarning() << "Null Pointer passed to addLinker! This operation will be ignored" ;
177  return;
178  }
179 #endif
180  // Check if the Linker is already added
181  if ( find( l ) ) {
182 #ifdef FARSA_DEBUG
183  qWarning() << "Linker already added! addLinker will be ignored" ;
184 #endif
185  return;
186  }
187 #ifdef FARSA_DEBUG
188  // --- Check: Are There in this net the Clusters that linker l connects ???
189  if ( ! find( l->from() ) ) {
190  qWarning() << "The linker that you want add links cluster" << l->from()->name() << "that doesn't exist in this net! This operation will be ignored" ;
191  return;
192  }
193  if ( ! find( l->to() ) ) {
194  qWarning() << "The linker that you want add links cluster" << l->to()->name() << "that doesn't exist in this net! This operation will be ignored" ;
195  return;
196  }
197 #endif
198  linkersv.append( l );
199  // Adding information in outLinks map
200  outLinks[ l->from() ].append( l );
201  // Adding information in inLinks map
202  inLinks[ l->to() ].append( l );
203  lksMap[l->name()] = l;
204  return;
205 }
206 
208 #ifdef FARSA_DEBUG
209  if ( !l ) {
210  qWarning() << "Null Pointer passed to removeLinker! This operation will return false" ;
211  return false;
212  }
213 #endif
214  if ( !find(l) ) {
215  return false;
216  }
217  linkersv.removeOne( l );
218  outLinks[ l->from() ].removeOne( l );
219  inLinks[ l->to() ].removeOne( l );
220  lksMap.remove( l->name() );
221  return true;
222 }
223 
224 LinkerList NeuralNet::linkers() const {
225  return linkersv;
226 }
227 
228 LinkerList NeuralNet::linkers( Cluster* c, bool out ) const {
229 #ifdef FARSA_DEBUG
230  if ( !c ) {
231  qWarning() << "Null Pointer passed to linkers! This operation will return an empty LinkerList" ;
232  return LinkerList();
233  }
234 #endif
235  if ( out ) {
236  // Return outgoing linkers
237  if ( outLinks.contains( c ) ) {
238  return outLinks[c];
239  }
240  } else {
241  // Return incoming linkers
242  if ( inLinks.contains( c ) ) {
243  return inLinks[c];
244  }
245  }
246  return LinkerList();
247 }
248 
249 void NeuralNet::setOrder( Updatable* u[], unsigned int dim ) {
250  ups.clear();
251  for( unsigned int i = 0; i<dim; i++ ) {
252  if ( find( u[i] ) ) {
253  ups.append( u[i] );
254  }
255 #ifdef FARSA_DEBUG
256  else {
257  qWarning() << "In the Updatable order list passed there are some Clusters and/or Linkers not present in this NeuralNet";
258  }
259 #endif
260  }
261  dimUps = ups.size();
262  return;
263 }
264 
265 void NeuralNet::setOrder( const UpdatableList& u ) {
266  ups.clear();
267  unsigned int dim = u.size();
268  for( unsigned int i = 0; i<dim; i++ ) {
269  if ( find( u[i] ) ) {
270  ups.append( u[i] );
271  }
272 #ifdef FARSA_DEBUG
273  else {
274  qWarning() << "In the Updatable order list passed there are some Clusters and/or Linkers not present in this NeuralNet";
275  }
276 #endif
277  }
278  dimUps = ups.size();
279  return;
280 }
281 
282 void NeuralNet::randomize( double min, double max ) {
283  int dim = clustersv.size();
284  for( int i=0; i<dim; i++ ) {
285  clustersv[i]->randomize( min, max );
286  }
287  dim = linkersv.size();
288  for( int i=0; i<dim; i++ ) {
289  linkersv[i]->randomize( min, max );
290  }
291 }
292 
293 Updatable* NeuralNet::getByName( QString name ) {
294  if ( clsMap.contains( name ) ) {
295  return clsMap[name];
296  }
297  if ( lksMap.contains( name ) ) {
298  return lksMap[name];
299  }
300 #ifdef FARSA_DEBUG
301  qWarning() << "getByName: Updatable " << name << " not present in BaseNeuralNet";
302 #endif
303  return NULL;
304 }
305 
306 bool NeuralNet::find( const Cluster* cl ) const {
307  return clustersv.contains( (Cluster*)cl );
308 }
309 
310 bool NeuralNet::find( const Linker* l ) const {
311  return linkersv.contains( (Linker*)l );
312 }
313 
314 bool NeuralNet::find( const Updatable* u ) const {
315  return (
316  clustersv.contains( (Cluster*)u ) ||
317  linkersv.contains( (Linker*)u )
318  );
319 }
320 
321 void NeuralNet::configure(ConfigurationParameters& params, QString prefix) {
323  // the name will correspond to the group where the declaration of NeuralNet is
324  QString myname = prefix;
325  if ( myname.startsWith( ConfigurationParameters::GroupSeparator() ) ) {
326  myname.remove( 0, 1 );
327  }
328  if ( myname.endsWith( ConfigurationParameters::GroupSeparator() ) ) {
329  myname.chop( 1 );
330  }
331  setName( myname );
332 
333  // All Cluster has to be added before the creation of linkers, that's why the insertion is done after
334  ClusterList clsToAdd;
335  ClusterList clsInput;
336  ClusterList clsOutput;
337  LinkerList lnsToAdd;
338 
339  //--- get all subgroups, merge this list with clustersList and linkersList
340  QStringList subgroups;
341  foreach( QString sub, params.getGroupsList( prefix ) ) {
342  // append the full path
343  subgroups << (prefix+sub);
344  }
345  //--- clustersList and linkersList are supposed to be full path
346  QString str = params.getValue(prefix + "clustersList");
347  if (!str.isEmpty()) {
348  subgroups << str.split(QRegExp("\\s+"), QString::SkipEmptyParts);
349  }
350  str = params.getValue(prefix + "linkersList");
351  if (!str.isEmpty()) {
352  subgroups << str.split(QRegExp("\\s+"), QString::SkipEmptyParts);
353  }
354  foreach( QString sub, subgroups ) {
355  Updatable* up = params.getObjectFromGroup<Updatable>( sub, true );
356  //--- check if is a Cluster
357  Cluster* cl = dynamic_cast<Cluster*>(up);
358  if ( cl && !clsToAdd.contains( cl ) ) clsToAdd << cl;
359  //--- check if is a Linker
360  Linker* ln = dynamic_cast<Linker*>(up);
361  if ( ln && !lnsToAdd.contains( ln ) ) lnsToAdd << ln;
362  }
363  //--- parse the parameter inputClusters
364  str = params.getValue(prefix + "inputClusters");
365  if (!str.isEmpty()) {
366  QStringList list = str.split(QRegExp("\\s+"), QString::SkipEmptyParts);
367  foreach( QString sub, list ) {
368  Cluster* cl = params.getObjectFromGroup<Cluster>( sub, true );
369  if ( !clsToAdd.contains( cl ) ) clsToAdd << cl;
370  clsInput << cl;
371  }
372  }
373  //--- parse the parameter outputClusters
374  str = params.getValue(prefix + "outputClusters");
375  if (!str.isEmpty()) {
376  QStringList list = str.split(QRegExp("\\s+"), QString::SkipEmptyParts);
377  foreach( QString sub, list ) {
378  Cluster* cl = params.getObjectFromGroup<Cluster>( sub, true );
379  if ( !clsToAdd.contains( cl ) ) clsToAdd << cl;
380  clsOutput << cl;
381  }
382  }
383  //--- parse the parameter spreadOrder
384  str = params.getValue(prefix + "spreadOrder");
385  if (!str.isEmpty()) {
386  QStringList list = str.split(QRegExp("\\s+"), QString::SkipEmptyParts);
387  ups.clear();
388  foreach( QString sub, list ) {
389  Updatable* up = params.getObjectFromGroup<Updatable>( sub, true );
390  // add it to the list of objects to add
391  Cluster* cl = dynamic_cast<Cluster*>(up);
392  if ( cl && !clsToAdd.contains( cl ) ) clsToAdd << cl;
393  //--- check if is a Linker
394  Linker* ln = dynamic_cast<Linker*>(up);
395  if ( ln && !lnsToAdd.contains( ln ) ) lnsToAdd << ln;
396  ups.append( up );
397  }
398  dimUps = ups.size();
399  }
400  foreach( Cluster* cl, clsToAdd ) {
401  addCluster( cl );
402  }
403  foreach( Cluster* cl, clsInput ) {
404  markAsInput( cl );
405  }
406  foreach( Cluster* cl, clsOutput ) {
407  markAsOutput( cl );
408  }
409  foreach( Linker* ln, lnsToAdd ) {
410  addLinker( ln );
411  }
413 }
414 
415 void NeuralNet::save(ConfigurationParameters& params, QString prefix) {
416  params.startObjectParameters( prefix, "NeuralNet", this );
417  //--- save all Clusters and generate parameter clustersList
418  QStringList list;
419  list.clear();
420  foreach( Cluster* cl, clustersv ) {
421  params.createGroup( cl->name() );
422  cl->save( params, cl->name() );
423  list << cl->name();
424  }
425  params.createParameter( prefix, "clustersList", list.join(" ") );
426  //--- save all Linkers and generate parameter linkersList
427  list.clear();
428  foreach( Linker* ln, linkersv ) {
429  params.createGroup( ln->name() );
430  ln->save( params, ln->name() );
431  list << ln->name();
432  }
433  params.createParameter( prefix, "linkersList", list.join(" ") );
434  //--- save parameter inputClusters
435  list.clear();
436  foreach( Cluster* cl, inclusters ) {
437  list << cl->name();
438  }
439  params.createParameter( prefix, "inputClusters", list.join(" ") );
440  //--- save parameter outputClusters
441  list.clear();
442  foreach( Cluster* cl, outclusters ) {
443  list << cl->name();
444  }
445  params.createParameter( prefix, "outputClusters", list.join(" ") );
446  //--- save parameter spreadOrder
447  list.clear();
448  foreach( Updatable* up, ups ) {
449  list << up->name();
450  }
451  params.createParameter( prefix, "spreadOrder", list.join(" ") );
452 }
453 
454 void NeuralNet::describe( QString type ) {
455  Descriptor d = addTypeDescription( type, "Neural Network", "The neural network is a container for Clusters and Linkers. The topology and connectivity of the neural network is specified by the Linkers contained, while the order on which the Clusters and Linkers are updated is specified by the spreadOrder parameter of neural network" );
456  d.describeObject( "clustersList" ).type( "Cluster" ).props( IsList ).help( "The list of all Clusters" );
457  d.describeObject( "linkersList" ).type( "Linker" ).props( IsList ).help( "The list of all Linkers" );
458  d.describeObject( "inputClusters" ).type( "Cluster" ).props( IsList ).help( "The list of Clusters marked as input of the neural network" );
459  d.describeObject( "outputClusters" ).type( "Cluster" ).props( IsList ).help( "The list of Clusters marked as output of the neural network" );
460  d.describeObject( "spreadOrder" ).type( "Updatable" ).props( IsMandatory | IsList ).help( "The order on which the Clusters and Linkers are updated", "All Clusters and Linkers specified here are also automatically added into the neural network. If this list contains all Clusters and Linkers, then the clustersList and the linkersList parameters are superfluous" );
461 
462  // set the graphical editor
463  //setGraphicalEditor<NeuralNetConfWidget>(type);
464 }
465 
466 }