Source for de.webdings.jannis.neuralnet.NeuralNet

   1: /* NeuralNet.java - Copyright (c) 2005 by Stefan Thesing
   2:  <p>This file is part of Jannis.</p>
   3:  <p>Jannis is free software; you can redistribute it and/or modify
   4:  it under the terms of the GNU General Public License as published by
   5:  the Free Software Foundation; either version 2 of the License, or
   6:  (at your option) any later version.</p>
   7: <p>Jannis is distributed in the hope that it will be useful,
   8: but WITHOUT ANY WARRANTY; without even the implied warranty of
   9: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10: GNU General Public License for more details.</p>
  11: <p>You should have received a copy of the GNU General Public License
  12: along with Jannis; if not, write to the<br>
  13: Free Software Foundation, Inc.,<br>
  14: 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA<br>
  15: */
  16: package de.webdings.jannis.neuralnet;
  17: 
  18: import java.io.IOException;
  19: 
  20: import de.webdings.jannis.exceptions.BadArgumentException;
  21: import de.webdings.jannis.exceptions.LowerLayersEmptyException;
  22: import de.webdings.jannis.exceptions.NeuronTypeMismatchException;
  23: import de.webdings.jannis.neuralnet.nnml.BiNetToNNML;
  24: import de.webdings.tools.StringSearch;
  25: import de.webdings.tools.files.TextFiles;
  26: /**
  27:  * NeuralNet is a wrapper for the actual neural net that is
  28:  * represented in {@link #layers layers}.<br>
  29:  * It provides functionality for setting up, using, training
  30:  * and reconfiguring the net easily as well as saving it
  31:  * to an NNML file.</p>
  32:  * <p>The net can consist of all known neuron types that are
  33:  * a subclass of the abstract 
  34:  * {@link de.webdings.jannis.neuralnet.Neuron}. It accepts
  35:  * only one such type at a time. So you can't mix different
  36:  * neuron types in one net.</p>
  37:  * <p>Currently only one neuron type is supported:</p>
  38:  * <ul>
  39:  * <li>{@link de.webdings.jannis.neuralnet.BiNeuron BiNeuron}</li>
  40:  * </ul> 
  41:  * 
  42:  * @author Stefan Thesing<br>
  43:  * Website: <a href="http://www.webdings.de">http://www.webdings.de</a>
  44:  * @version 0.1 10.08.2005
  45:  */
  46: public class NeuralNet {
  47:     //attributes
  48:     /**
  49:      * <code>layers</code> is an array containing layers
  50:      * of neurons. Each layer is an array containing neurons.
  51:      * So <code>layers</code> is the actual neural net 
  52:      * wrapped by this class. 
  53:      */
  54:     protected Neuron[][] layers;
  55:     /**
  56:      * <code>type</code> represents the type of neurons
  57:      * of which this net consists. For example, if a net
  58:      * consists of 
  59:      * {@link de.webdings.jannis.neuralnet.BiNeuron BiNeuron}s
  60:      * <code>type</code> reads 
  61:      * "de.webdings.jannis.neuralnet.BiNeuron"</p>
  62:      * <p>Mixing different neuron types is not allowed.
  63:      * 
  64:      */
  65:     protected String type;
  66:     //constructors
  67:     /**
  68:      * Constructs an empty NeuralNet of the specified type.
  69:      * @param type
  70:      * @throws NeuronTypeMismatchException
  71:      */
  72:     public NeuralNet(String type) throws NeuronTypeMismatchException {
  73:         if(type.equals("de.webdings.jannis.neuralnet.BiNeuron")) {
  74:            this.layers = new BiNeuron[0][];
  75:            this.type = type;
  76:         } else {
  77:             throw new NeuronTypeMismatchException("Unknown neuron type!");
  78:         }
  79:     }
  80:     /**
  81:      * Constructs an empty NeuralNet of the specified type.
  82:      * @param type
  83:      * @throws NeuronTypeMismatchException
  84:      */
  85:     public NeuralNet(Class type) throws NeuronTypeMismatchException {
  86:         this(new String(type.getName()));
  87:     }
  88:     /**
  89:      * Constructs a NeuralNet using a specified array containing layers
  90:      * of neurons. This constructor automatically determines the type of
  91:      * the neurons that the specified layers contain and rejects layers 
  92:      * that contain neurons of unsupported types as well as layers that 
  93:      * contain neurons of mixed types.
  94:      * @param layers
  95:      * @throws NeuronTypeMismatchException
  96:      */
  97:     public NeuralNet(Neuron[][] layers) throws NeuronTypeMismatchException {
  98:        if(areNeuronTypesConsistent(layers)) {
  99:           this.type = new String(layers[0][0].getClass().getName()); 
 100:           this.layers = layers; 
 101:        } else {
 102:            throw new NeuronTypeMismatchException
 103:                       ("Couldn't create neural net. There " +
 104:                        "are gaps in the specified layers " +
 105:                        "or they contain different neuron " +
 106:                        "types!");
 107:        }
 108:     }
 109:     /**
 110:      * Constructs a NeuralNet starting with a single specified neuron and automatically
 111:      * determines the type of this neuron. It rejects unsupported neuron types.
 112:      * @param aFirstInputNeuron
 113:      * @throws NeuronTypeMismatchException
 114:      */
 115:     public NeuralNet(Neuron aFirstInputNeuron) throws NeuronTypeMismatchException {
 116:         if(aFirstInputNeuron.getClass().getName().equals
 117:                 ("de.webdings.jannis.neuralNet.BiNeuron")){
 118:             this.layers = new BiNeuron[1][];
 119:             layers[0] = new BiNeuron[1];
 120:             layers[0][0]= aFirstInputNeuron;
 121:             this.type = new String(aFirstInputNeuron.getClass().getName());
 122:         } else {
 123:             throw new NeuronTypeMismatchException("Unsupported neuron type: "
 124:                     + aFirstInputNeuron.getClass().getName() + "!");
 125:         }
 126:     }
 127:     
 128:     /**
 129:      * This static method is called by other methods and constructors
 130:      * to ensure that the neuron types used in this net are consistent.
 131:      * @param layers The layers of the net that is checked for consistency.
 132:      * @return <code>true</code> if only one type of Neurons is used in this
 133:      * net, <code>false</code> if there are mixed types.
 134:      * @throws NeuronTypeMismatchException if the specified layers are empty.
 135:      */
 136:     public static boolean areNeuronTypesConsistent(Neuron[][] layers) 
 137:               throws NeuronTypeMismatchException {
 138:         String sType;
 139:         //Check if the first neuron exists
 140:         if(layers.length>0 
 141:            && layers[0].length>0 
 142:            && layers[0][0] != null) {
 143:             //use the type of the first neuron for comparison
 144:             sType = new String(layers[0][0].getClass().getName());
 145:             //Check if the other neurons are the same type
 146:             for(int i=0;i<layers.length;++i) {
 147:                 for(int j=0;j<layers[i].length;++j) {
 148:                     if(layers[i][j]==null
 149:                        ||!(layers[i][j].getClass().getName().
 150:                            equals(sType))) {
 151:                        return false;
 152:                     }
 153:                 }
 154:             }
 155:             //If all is well we can use the specified layers
 156:             return true;   
 157:         } else {
 158:             throw new NeuronTypeMismatchException("Could not determine " +
 159:                     "neuron type! Specified layers are empty.");
 160:         }
 161:      
 162:     }
 163:     //setters and getters
 164:     /**
 165:      * @return Returns the layers.
 166:      */
 167:     public Neuron[][] getLayers() {
 168:         return layers;
 169:     }
 170:     /**
 171:      * This methods replaces the actual neural net wrapped
 172:      * by this class with the specified array. It does
 173:      * essentially the same as the constructor with the same
 174:      * parameter.
 175:      * @param layers The layers to set.
 176:      * @throws NeuronTypeMismatchException
 177:      */
 178:     public void setLayers(Neuron[][] layers) throws NeuronTypeMismatchException {
 179:         if(areNeuronTypesConsistent(layers)) {
 180:             this.type = new String(layers[0][0].getClass().getName()); 
 181:             this.layers = layers; 
 182:          } else {
 183:              throw new NeuronTypeMismatchException
 184:                         ("Couldn't create neural net. There " +
 185:                          "are gaps in the specified layers " +
 186:                          "or they contain different neuron " +
 187:                          "types!");
 188:          }
 189:     }
 190:     /**
 191:      * @return Returns the neuron type of this net.
 192:      */
 193:     public String getType() {
 194:         return type;
 195:     }
 196:     //other
 197:     /**
 198:      * Adds a neuron to the specified layer
 199:      * @param neuron
 200:      * @param targetLayerID
 201:      * @throws LowerLayersEmptyException
 202:      * @throws NeuronTypeMismatchException
 203:      * @throws BadArgumentException
 204:      */
 205:     public void addNeuron(Neuron neuron, int targetLayerID)
 206:         throws LowerLayersEmptyException, 
 207:         NeuronTypeMismatchException, BadArgumentException {
 208:       //check if the neuron is the same type as this net
 209:       if(!neuron.getClass().getName().equals(this.type)) {
 210:           throw new NeuronTypeMismatchException("The " +
 211:                   "specified neuron doesn't match the type " +
 212:                   "of this net!");
 213:       }
 214:       //Does targetLayerID fit into the netsize?
 215:       if(targetLayerID>=layers.length) {
 216:           throw new BadArgumentException("The target layer " +
 217:                   "you specified does not exist!");
 218:       }
 219:       //If the layer with the specified ID hasn't been
 220:       //initialized yet, do it now...
 221:       if(layers[targetLayerID]==null) {
 222:           layers[targetLayerID] = new Neuron[0];
 223:       }
 224:       //check if the layers before targetLayerID are
 225:       //empty. If yes throw an exception
 226:       for(int i=0;i<targetLayerID;++i) {
 227:           if(layers[i].length<1) {
 228:               throw new LowerLayersEmptyException();
 229:           }
 230:       }
 231:       //if everything's ok add the new neuron to the
 232:       //specified layer
 233:       Neuron[] tempLayer = new Neuron[layers[targetLayerID].length+1];
 234:       for(int i=0; i<layers[targetLayerID].length; ++i) {
 235:           tempLayer[i] = layers[targetLayerID][i];
 236:       }
 237:       tempLayer[layers[targetLayerID].length] = neuron;
 238:       layers[targetLayerID] = tempLayer;
 239:     }
 240:     
 241:     /**
 242:      * Adds a new empty layer to the net.
 243:      * @throws NeuronTypeMismatchException
 244:      */
 245:     public void addLayer() throws NeuronTypeMismatchException {
 246:         if(this.getType().equals
 247:                 ("de.webdings.jannis.neuralnet.BiNeuron")) {
 248:             this.addLayer(new BiNeuron[0]);
 249:         } else {
 250:             throw new NeuronTypeMismatchException("Unsupported neuron type: "
 251:                     + this.getClass().getName() + "!");
 252:             
 253:         }
 254:     }
 255:     
 256:     /**
 257:      * Adds a specified number of empty layers to the net.
 258:      * @param numberOfLayersToAdd
 259:      * @throws NeuronTypeMismatchException
 260:      */
 261:     public void addLayers(int numberOfLayersToAdd) throws NeuronTypeMismatchException {
 262:         for(int i=0;i<numberOfLayersToAdd;++i) {
 263:             this.addLayer();
 264:         }
 265:     }
 266:     
 267:     /**
 268:      * Adds the specified layer to the net.
 269:      * @param l
 270:      * @throws NeuronTypeMismatchException
 271:      */
 272:     public void addLayer(Neuron[] l) throws NeuronTypeMismatchException {
 273:         this.addLayer(l, this.layers.length);
 274:     }
 275:     
 276:     
 277:     /**
 278:      * Adds the specified layer to the net using the
 279:      * specified layerID. If the net already contains
 280:      * a layer with this ID it (and the following layers)
 281:      * will be moved one step farther.<br>
 282:      * So the ID number of these layers will be increased
 283:      * by one.<br>
 284:      * If you don't want that, but want to replace the
 285:      * existing layer use the method replaceLayer.
 286:      * @param l
 287:      * @param layerID
 288:      * @throws NeuronTypeMismatchException
 289:      */
 290:     public void addLayer(Neuron[] l, int layerID) throws NeuronTypeMismatchException {
 291:         if(StringSearch.stringContainsCaseSensitive
 292:             (l.getClass().getName(), 
 293:              "de.webdings.jannis.neuralnet.BiNeuron")) {
 294:           Neuron[][] temp = new Neuron[layers.length+1][];
 295:           for(int i=0;i<layerID;++i) {
 296:               temp[i] = layers[i];
 297:           }
 298:           temp[layerID] = l;
 299:           for(int i=layerID+1;i<temp.length;++i) {
 300:               temp[i] = layers[i-1];
 301:           }
 302:           layers = temp;
 303:         } else {
 304:             throw new NeuronTypeMismatchException();
 305:         }
 306:         
 307:     }
 308:     
 309:     /**
 310:      * Replaces the layer of the specified layerID with the
 311:      * specified layer l.
 312:      * @param l
 313:      * @param layerID
 314:      * @throws NeuronTypeMismatchException
 315:      */
 316:     public void replaceLayer(Neuron[] l, int layerID) throws NeuronTypeMismatchException {
 317:         if(StringSearch.stringContainsCaseSensitive
 318:             (l.getClass().getName(), 
 319:              "de.webdings.jannis.neuralnet.BiNeuron")) {
 320:           Neuron[][] temp = new Neuron[layers.length][];
 321:           for(int i=0;i<layerID;++i) {
 322:               temp[i] = layers[i];
 323:           }
 324:           temp[layerID] = l;
 325:           for(int i=layerID+1;i<layers.length;++i) {
 326:               temp[i] = layers[i];
 327:           }
 328:           layers = temp;
 329:         } else {
 330:             throw new NeuronTypeMismatchException();
 331:         }
 332:     }
 333:     
 334:     /**
 335:      * Saves a NNML representation of the net to a file
 336:      * of the specified filename.
 337:      * @param fileName
 338:      * @throws NeuronTypeMismatchException if the neuron type
 339:      * of the net is not supported.
 340:      * @throws IOException
 341:      */
 342:     public void toFile(String fileName) throws NeuronTypeMismatchException, IOException {
 343:         if(this.getType().equals
 344:                 ("de.webdings.jannis.neuralnet.BiNeuron")) {
 345:             BiNetToNNML konverter = new BiNetToNNML();
 346:             try {
 347:                 TextFiles.writeToFile(fileName, konverter.generateString(layers));
 348:             } catch (Exception e) {
 349:                 // TODO Auto-generated catch block
 350:                 System.out.print(e.getClass());
 351:                 System.out.print(e.getMessage());
 352:                 //e.printStackTrace();;
 353:             } 
 354:         } else {
 355:             throw new NeuronTypeMismatchException("Saving of " 
 356:                     + "nets of this neuron type is not yet supported.");
 357:         }
 358:         
 359:     }

© 2005 by Stefan Thesing;
Verbatim copying and redistribution of this entire page are permitted provided this notice is preserved.