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.math4.neuralnet.oned; 019 020import org.apache.commons.math4.neuralnet.internal.NeuralNetException; 021import org.apache.commons.math4.neuralnet.FeatureInitializer; 022import org.apache.commons.math4.neuralnet.Network; 023 024/** 025 * Neural network with the topology of a one-dimensional line. 026 * Each neuron defines one point on the line. 027 * 028 * @since 3.3 029 */ 030public class NeuronString { 031 /** Minimal number of neurons. */ 032 private static final int MIN_NEURONS = 2; 033 /** Underlying network. */ 034 private final Network network; 035 /** Number of neurons. */ 036 private final int size; 037 /** Wrap. */ 038 private final boolean wrap; 039 040 /** 041 * Mapping of the 1D coordinate to the neuron identifiers 042 * (attributed by the {@link #network} instance). 043 */ 044 private final long[] identifiers; 045 046 /** 047 * Constructor with restricted access, solely used for deserialization. 048 * 049 * @param wrap Whether to wrap the dimension (i.e the first and last 050 * neurons will be linked together). 051 * @param featuresList Arrays that will initialize the features sets of 052 * the network's neurons. 053 * @throws IllegalArgumentException if {@code num < 2}. 054 */ 055 NeuronString(boolean wrap, 056 double[][] featuresList) { 057 size = featuresList.length; 058 059 if (size < MIN_NEURONS) { 060 throw new NeuralNetException(NeuralNetException.TOO_SMALL, size, MIN_NEURONS); 061 } 062 063 this.wrap = wrap; 064 065 final int fLen = featuresList[0].length; 066 network = new Network(0, fLen); 067 identifiers = new long[size]; 068 069 // Add neurons. 070 for (int i = 0; i < size; i++) { 071 identifiers[i] = network.createNeuron(featuresList[i]); 072 } 073 074 // Add links. 075 createLinks(); 076 } 077 078 /** 079 * Creates a one-dimensional network: 080 * Each neuron not located on the border of the mesh has two 081 * neurons linked to it. 082 * <br> 083 * The links are bi-directional. 084 * Neurons created successively are neighbours (i.e. there are 085 * links between them). 086 * <br> 087 * The topology of the network can also be a circle (if the 088 * dimension is wrapped). 089 * 090 * @param num Number of neurons. 091 * @param wrap Whether to wrap the dimension (i.e the first and last 092 * neurons will be linked together). 093 * @param featureInit Arrays that will initialize the features sets of 094 * the network's neurons. 095 * @throws IllegalArgumentException if {@code num < 2}. 096 */ 097 public NeuronString(int num, 098 boolean wrap, 099 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}