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 }