View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.math4.neuralnet.oned;
19  
20  import org.apache.commons.math4.neuralnet.internal.NeuralNetException;
21  import org.apache.commons.math4.neuralnet.FeatureInitializer;
22  import org.apache.commons.math4.neuralnet.Network;
23  
24  /**
25   * Neural network with the topology of a one-dimensional line.
26   * Each neuron defines one point on the line.
27   *
28   * @since 3.3
29   */
30  public class NeuronString {
31      /** Minimal number of neurons. */
32      private static final int MIN_NEURONS = 2;
33      /** Underlying network. */
34      private final Network network;
35      /** Number of neurons. */
36      private final int size;
37      /** Wrap. */
38      private final boolean wrap;
39  
40      /**
41       * Mapping of the 1D coordinate to the neuron identifiers
42       * (attributed by the {@link #network} instance).
43       */
44      private final long[] identifiers;
45  
46      /**
47       * Constructor with restricted access, solely used for deserialization.
48       *
49       * @param wrap Whether to wrap the dimension (i.e the first and last
50       * neurons will be linked together).
51       * @param featuresList Arrays that will initialize the features sets of
52       * the network's neurons.
53       * @throws IllegalArgumentException if {@code num < 2}.
54       */
55      NeuronString(boolean wrap,
56                   double[][] featuresList) {
57          size = featuresList.length;
58  
59          if (size < MIN_NEURONS) {
60              throw new NeuralNetException(NeuralNetException.TOO_SMALL, size, MIN_NEURONS);
61          }
62  
63          this.wrap = wrap;
64  
65          final int fLen = featuresList[0].length;
66          network = new Network(0, fLen);
67          identifiers = new long[size];
68  
69          // Add neurons.
70          for (int i = 0; i < size; i++) {
71              identifiers[i] = network.createNeuron(featuresList[i]);
72          }
73  
74          // Add links.
75          createLinks();
76      }
77  
78      /**
79       * Creates a one-dimensional network:
80       * Each neuron not located on the border of the mesh has two
81       * neurons linked to it.
82       * <br>
83       * The links are bi-directional.
84       * Neurons created successively are neighbours (i.e. there are
85       * links between them).
86       * <br>
87       * The topology of the network can also be a circle (if the
88       * dimension is wrapped).
89       *
90       * @param num Number of neurons.
91       * @param wrap Whether to wrap the dimension (i.e the first and last
92       * neurons will be linked together).
93       * @param featureInit Arrays that will initialize the features sets of
94       * the network's neurons.
95       * @throws IllegalArgumentException if {@code num < 2}.
96       */
97      public NeuronString(int num,
98                          boolean wrap,
99                          FeatureInitializer[] featureInit) {
100         if (num < MIN_NEURONS) {
101             throw new NeuralNetException(NeuralNetException.TOO_SMALL, num, MIN_NEURONS);
102         }
103 
104         size = num;
105         this.wrap = wrap;
106         identifiers = new long[num];
107 
108         final int fLen = featureInit.length;
109         network = new Network(0, fLen);
110 
111         // Add neurons.
112         for (int i = 0; i < num; i++) {
113             final double[] features = new double[fLen];
114             for (int fIndex = 0; fIndex < fLen; fIndex++) {
115                 features[fIndex] = featureInit[fIndex].value();
116             }
117             identifiers[i] = network.createNeuron(features);
118         }
119 
120         // Add links.
121         createLinks();
122     }
123 
124     /**
125      * Retrieves the underlying network.
126      * A reference is returned (enabling, for example, the network to be
127      * trained).
128      * This also implies that calling methods that modify the {@link Network}
129      * topology may cause this class to become inconsistent.
130      *
131      * @return the network.
132      */
133     public Network getNetwork() {
134         return network;
135     }
136 
137     /**
138      * Gets the number of neurons.
139      *
140      * @return the number of neurons.
141      */
142     public int getSize() {
143         return size;
144     }
145 
146     /**
147      * Indicates whether the line of neurons is wrapped.
148      *
149      * @return {@code true} if the last neuron is linked to the first neuron.
150      */
151     public boolean isWrapped() {
152         return wrap;
153     }
154 
155     /**
156      * Retrieves the features set from the neuron at location
157      * {@code i} in the map.
158      *
159      * @param i Neuron index.
160      * @return the features of the neuron at index {@code i}.
161      * @throws IllegalArgumentException if {@code i} is out of range.
162      */
163     public double[] getFeatures(int i) {
164         if (i < 0 ||
165             i >= size) {
166             throw new NeuralNetException(NeuralNetException.OUT_OF_RANGE, i, 0, size - 1);
167         }
168 
169         return network.getNeuron(identifiers[i]).getFeatures();
170     }
171 
172     /**
173      * Creates the neighbour relationships between neurons.
174      */
175     private void createLinks() {
176         for (int i = 0; i < size - 1; i++) {
177             network.addLink(network.getNeuron(i), network.getNeuron(i + 1));
178         }
179         for (int i = size - 1; i > 0; i--) {
180             network.addLink(network.getNeuron(i), network.getNeuron(i - 1));
181         }
182         if (wrap) {
183             network.addLink(network.getNeuron(0), network.getNeuron(size - 1));
184             network.addLink(network.getNeuron(size - 1), network.getNeuron(0));
185         }
186     }
187 }