/** * Constructor with restricted access, solely used for deserialization. * * @param wrapRowDim Whether to wrap the first dimension (i.e the first and last neurons will be * linked together). * @param wrapColDim Whether to wrap the second dimension (i.e the first and last neurons will be * linked together). * @param neighbourhoodType Neighbourhood type. * @param featuresList Arrays that will initialize the features sets of the network's neurons. * @throws NumberIsTooSmallException if {@code numRows < 2} or {@code numCols < 2}. */ NeuronSquareMesh2D( boolean wrapRowDim, boolean wrapColDim, SquareNeighbourhood neighbourhoodType, double[][][] featuresList) { numberOfRows = featuresList.length; numberOfColumns = featuresList[0].length; if (numberOfRows < 2) { throw new NumberIsTooSmallException(numberOfRows, 2, true); } if (numberOfColumns < 2) { throw new NumberIsTooSmallException(numberOfColumns, 2, true); } wrapRows = wrapRowDim; wrapColumns = wrapColDim; neighbourhood = neighbourhoodType; final int fLen = featuresList[0][0].length; network = new Network(0, fLen); identifiers = new long[numberOfRows][numberOfColumns]; // Add neurons. for (int i = 0; i < numberOfRows; i++) { for (int j = 0; j < numberOfColumns; j++) { identifiers[i][j] = network.createNeuron(featuresList[i][j]); } } // Add links. createLinks(); }
/** * Retrieves the neuron at location {@code (i, j)} in the map. The neuron at position {@code (0, * 0)} is located at the upper-left corner of the map. * * @param i Row index. * @param j Column index. * @return the neuron at {@code (i, j)}. * @throws OutOfRangeException if {@code i} or {@code j} is out of range. * @see #getNeuron(int,int,HorizontalDirection,VerticalDirection) */ public Neuron getNeuron(int i, int j) { if (i < 0 || i >= numberOfRows) { throw new OutOfRangeException(i, 0, numberOfRows - 1); } if (j < 0 || j >= numberOfColumns) { throw new OutOfRangeException(j, 0, numberOfColumns - 1); } return network.getNeuron(identifiers[i][j]); }
/** * Performs a deep copy of this instance. Upon return, the copied and original instances will be * independent: Updating one will not affect the other. * * @return a new instance with the same state as this instance. * @since 3.6 */ public synchronized NeuronSquareMesh2D copy() { final long[][] idGrid = new long[numberOfRows][numberOfColumns]; for (int r = 0; r < numberOfRows; r++) { for (int c = 0; c < numberOfColumns; c++) { idGrid[r][c] = identifiers[r][c]; } } return new NeuronSquareMesh2D(wrapRows, wrapColumns, neighbourhood, network.copy(), idGrid); }
/** * Creates a two-dimensional network composed of square cells: Each neuron not located on the * border of the mesh has four neurons linked to it. <br> * The links are bi-directional. <br> * The topology of the network can also be a cylinder (if one of the dimensions is wrapped) or a * torus (if both dimensions are wrapped). * * @param numRows Number of neurons in the first dimension. * @param wrapRowDim Whether to wrap the first dimension (i.e the first and last neurons will be * linked together). * @param numCols Number of neurons in the second dimension. * @param wrapColDim Whether to wrap the second dimension (i.e the first and last neurons will be * linked together). * @param neighbourhoodType Neighbourhood type. * @param featureInit Array of functions that will initialize the corresponding element of the * features set of each newly created neuron. In particular, the size of this array defines * the size of feature set. * @throws NumberIsTooSmallException if {@code numRows < 2} or {@code numCols < 2}. */ public NeuronSquareMesh2D( int numRows, boolean wrapRowDim, int numCols, boolean wrapColDim, SquareNeighbourhood neighbourhoodType, FeatureInitializer[] featureInit) { if (numRows < 2) { throw new NumberIsTooSmallException(numRows, 2, true); } if (numCols < 2) { throw new NumberIsTooSmallException(numCols, 2, true); } numberOfRows = numRows; wrapRows = wrapRowDim; numberOfColumns = numCols; wrapColumns = wrapColDim; neighbourhood = neighbourhoodType; identifiers = new long[numberOfRows][numberOfColumns]; final int fLen = featureInit.length; network = new Network(0, fLen); // Add neurons. for (int i = 0; i < numRows; i++) { for (int j = 0; j < numCols; j++) { final double[] features = new double[fLen]; for (int fIndex = 0; fIndex < fLen; fIndex++) { features[fIndex] = featureInit[fIndex].value(); } identifiers[i][j] = network.createNeuron(features); } } // Add links. createLinks(); }
/** Creates the neighbour relationships between neurons. */ private void createLinks() { // "linkEnd" will store the identifiers of the "neighbours". final List<Long> linkEnd = new ArrayList<Long>(); final int iLast = numberOfRows - 1; final int jLast = numberOfColumns - 1; for (int i = 0; i < numberOfRows; i++) { for (int j = 0; j < numberOfColumns; j++) { linkEnd.clear(); switch (neighbourhood) { case MOORE: // Add links to "diagonal" neighbours. if (i > 0) { if (j > 0) { linkEnd.add(identifiers[i - 1][j - 1]); } if (j < jLast) { linkEnd.add(identifiers[i - 1][j + 1]); } } if (i < iLast) { if (j > 0) { linkEnd.add(identifiers[i + 1][j - 1]); } if (j < jLast) { linkEnd.add(identifiers[i + 1][j + 1]); } } if (wrapRows) { if (i == 0) { if (j > 0) { linkEnd.add(identifiers[iLast][j - 1]); } if (j < jLast) { linkEnd.add(identifiers[iLast][j + 1]); } } else if (i == iLast) { if (j > 0) { linkEnd.add(identifiers[0][j - 1]); } if (j < jLast) { linkEnd.add(identifiers[0][j + 1]); } } } if (wrapColumns) { if (j == 0) { if (i > 0) { linkEnd.add(identifiers[i - 1][jLast]); } if (i < iLast) { linkEnd.add(identifiers[i + 1][jLast]); } } else if (j == jLast) { if (i > 0) { linkEnd.add(identifiers[i - 1][0]); } if (i < iLast) { linkEnd.add(identifiers[i + 1][0]); } } } if (wrapRows && wrapColumns) { if (i == 0 && j == 0) { linkEnd.add(identifiers[iLast][jLast]); } else if (i == 0 && j == jLast) { linkEnd.add(identifiers[iLast][0]); } else if (i == iLast && j == 0) { linkEnd.add(identifiers[0][jLast]); } else if (i == iLast && j == jLast) { linkEnd.add(identifiers[0][0]); } } // Case falls through since the "Moore" neighbourhood // also contains the neurons that belong to the "Von // Neumann" neighbourhood. // fallthru (CheckStyle) case VON_NEUMANN: // Links to preceding and following "row". if (i > 0) { linkEnd.add(identifiers[i - 1][j]); } if (i < iLast) { linkEnd.add(identifiers[i + 1][j]); } if (wrapRows) { if (i == 0) { linkEnd.add(identifiers[iLast][j]); } else if (i == iLast) { linkEnd.add(identifiers[0][j]); } } // Links to preceding and following "column". if (j > 0) { linkEnd.add(identifiers[i][j - 1]); } if (j < jLast) { linkEnd.add(identifiers[i][j + 1]); } if (wrapColumns) { if (j == 0) { linkEnd.add(identifiers[i][jLast]); } else if (j == jLast) { linkEnd.add(identifiers[i][0]); } } break; default: throw new MathInternalError(); // Cannot happen. } final Neuron aNeuron = network.getNeuron(identifiers[i][j]); for (long b : linkEnd) { final Neuron bNeuron = network.getNeuron(b); // Link to all neighbours. // The reverse links will be added as the loop proceeds. network.addLink(aNeuron, bNeuron); } } } }
/** {@inheritDoc} */ @Override public Iterator<Neuron> iterator() { return network.iterator(); }