001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.math3.ml.neuralnet.oned; 019 020import java.io.Serializable; 021import java.io.ObjectInputStream; 022import org.apache.commons.math3.ml.neuralnet.Network; 023import org.apache.commons.math3.ml.neuralnet.FeatureInitializer; 024import org.apache.commons.math3.exception.NumberIsTooSmallException; 025import org.apache.commons.math3.exception.OutOfRangeException; 026 027/** 028 * Neural network with the topology of a one-dimensional line. 029 * Each neuron defines one point on the line. 030 * 031 * @since 3.3 032 */ 033public class NeuronString implements Serializable { 034 /** Serial version ID */ 035 private static final long serialVersionUID = 1L; 036 /** Underlying network. */ 037 private final Network network; 038 /** Number of neurons. */ 039 private final int size; 040 /** Wrap. */ 041 private final boolean wrap; 042 043 /** 044 * Mapping of the 1D coordinate to the neuron identifiers 045 * (attributed by the {@link #network} instance). 046 */ 047 private final long[] identifiers; 048 049 /** 050 * Constructor with restricted access, solely used for deserialization. 051 * 052 * @param wrap Whether to wrap the dimension (i.e the first and last 053 * neurons will be linked together). 054 * @param featuresList Arrays that will initialize the features sets of 055 * the network's neurons. 056 * @throws NumberIsTooSmallException if {@code num < 2}. 057 */ 058 NeuronString(boolean wrap, 059 double[][] featuresList) { 060 size = featuresList.length; 061 062 if (size < 2) { 063 throw new NumberIsTooSmallException(size, 2, true); 064 } 065 066 this.wrap = wrap; 067 068 final int fLen = featuresList[0].length; 069 network = new Network(0, fLen); 070 identifiers = new long[size]; 071 072 // Add neurons. 073 for (int i = 0; i < size; i++) { 074 identifiers[i] = network.createNeuron(featuresList[i]); 075 } 076 077 // Add links. 078 createLinks(); 079 } 080 081 /** 082 * Creates a one-dimensional network: 083 * Each neuron not located on the border of the mesh has two 084 * neurons linked to it. 085 * <br/> 086 * The links are bi-directional. 087 * Neurons created successively are neighbours (i.e. there are 088 * links between them). 089 * <br/> 090 * The topology of the network can also be a circle (if the 091 * dimension is wrapped). 092 * 093 * @param num Number of neurons. 094 * @param wrap Whether to wrap the dimension (i.e the first and last 095 * neurons will be linked together). 096 * @param featureInit Arrays that will initialize the features sets of 097 * the network's neurons. 098 * @throws NumberIsTooSmallException if {@code num < 2}. 099 */ 100 public NeuronString(int num, 101 boolean wrap, 102 FeatureInitializer[] featureInit) { 103 if (num < 2) { 104 throw new NumberIsTooSmallException(num, 2, true); 105 } 106 107 size = num; 108 this.wrap = wrap; 109 identifiers = new long[num]; 110 111 final int fLen = featureInit.length; 112 network = new Network(0, fLen); 113 114 // Add neurons. 115 for (int i = 0; i < num; i++) { 116 final double[] features = new double[fLen]; 117 for (int fIndex = 0; fIndex < fLen; fIndex++) { 118 features[fIndex] = featureInit[fIndex].value(); 119 } 120 identifiers[i] = network.createNeuron(features); 121 } 122 123 // Add links. 124 createLinks(); 125 } 126 127 /** 128 * Retrieves the underlying network. 129 * A reference is returned (enabling, for example, the network to be 130 * trained). 131 * This also implies that calling methods that modify the {@link Network} 132 * topology may cause this class to become inconsistent. 133 * 134 * @return the network. 135 */ 136 public Network getNetwork() { 137 return network; 138 } 139 140 /** 141 * Gets the number of neurons. 142 * 143 * @return the number of neurons. 144 */ 145 public int getSize() { 146 return size; 147 } 148 149 /** 150 * Retrieves the features set from the neuron at location 151 * {@code i} in the map. 152 * 153 * @param i Neuron index. 154 * @return the features of the neuron at index {@code i}. 155 * @throws OutOfRangeException if {@code i} is out of range. 156 */ 157 public double[] getFeatures(int i) { 158 if (i < 0 || 159 i >= size) { 160 throw new OutOfRangeException(i, 0, size - 1); 161 } 162 163 return network.getNeuron(identifiers[i]).getFeatures(); 164 } 165 166 /** 167 * Creates the neighbour relationships between neurons. 168 */ 169 private void createLinks() { 170 for (int i = 0; i < size - 1; i++) { 171 network.addLink(network.getNeuron(i), network.getNeuron(i + 1)); 172 } 173 for (int i = size - 1; i > 0; i--) { 174 network.addLink(network.getNeuron(i), network.getNeuron(i - 1)); 175 } 176 if (wrap) { 177 network.addLink(network.getNeuron(0), network.getNeuron(size - 1)); 178 network.addLink(network.getNeuron(size - 1), network.getNeuron(0)); 179 } 180 } 181 182 /** 183 * Prevents proxy bypass. 184 * 185 * @param in Input stream. 186 */ 187 private void readObject(ObjectInputStream in) { 188 throw new IllegalStateException(); 189 } 190 191 /** 192 * Custom serialization. 193 * 194 * @return the proxy instance that will be actually serialized. 195 */ 196 private Object writeReplace() { 197 final double[][] featuresList = new double[size][]; 198 for (int i = 0; i < size; i++) { 199 featuresList[i] = getFeatures(i); 200 } 201 202 return new SerializationProxy(wrap, 203 featuresList); 204 } 205 206 /** 207 * Serialization. 208 */ 209 private static class SerializationProxy implements Serializable { 210 /** Serializable. */ 211 private static final long serialVersionUID = 20130226L; 212 /** Wrap. */ 213 private final boolean wrap; 214 /** Neurons' features. */ 215 private final double[][] featuresList; 216 217 /** 218 * @param wrap Whether the dimension is wrapped. 219 * @param featuresList List of neurons features. 220 * {@code neuronList}. 221 */ 222 SerializationProxy(boolean wrap, 223 double[][] featuresList) { 224 this.wrap = wrap; 225 this.featuresList = featuresList; 226 } 227 228 /** 229 * Custom serialization. 230 * 231 * @return the {@link Neuron} for which this instance is the proxy. 232 */ 233 private Object readResolve() { 234 return new NeuronString(wrap, 235 featuresList); 236 } 237 } 238}