/** * The average number of columns per input, taking into account the topology of the inputs and * columns. This value is used to calculate the inhibition radius. This function supports an * arbitrary number of dimensions. If the number of column dimensions does not match the number of * input dimensions, we treat the missing, or phantom dimensions as 'ones'. * * @param c the {@link Connections} (spatial pooler memory) * @return */ public double avgColumnsPerInput(Connections c) { int[] colDim = Arrays.copyOf(c.getColumnDimensions(), c.getColumnDimensions().length); int[] inputDim = Arrays.copyOf(c.getInputDimensions(), c.getInputDimensions().length); double[] columnsPerInput = ArrayUtils.divide( ArrayUtils.toDoubleArray(colDim), ArrayUtils.toDoubleArray(inputDim), 0, 0); return ArrayUtils.average(columnsPerInput); }
/** * Called to initialize the structural anatomy with configured values and prepare the anatomical * entities for activation. * * @param c */ public void initMatrices(final Connections c) { SparseObjectMatrix<Column> mem = c.getMemory(); c.setMemory(mem == null ? mem = new SparseObjectMatrix<>(c.getColumnDimensions()) : mem); c.setInputMatrix(new SparseBinaryMatrix(c.getInputDimensions())); // Calculate numInputs and numColumns int numInputs = c.getInputMatrix().getMaxIndex() + 1; int numColumns = c.getMemory().getMaxIndex() + 1; if (numColumns <= 0) { throw new InvalidSPParamValueException("Invalid number of columns: " + numColumns); } if (numInputs <= 0) { throw new InvalidSPParamValueException("Invalid number of inputs: " + numInputs); } c.setNumInputs(numInputs); c.setNumColumns(numColumns); // Fill the sparse matrix with column objects for (int i = 0; i < numColumns; i++) { mem.set(i, new Column(c.getCellsPerColumn(), i)); } c.setPotentialPools(new SparseObjectMatrix<Pool>(c.getMemory().getDimensions())); c.setConnectedMatrix(new SparseBinaryMatrix(new int[] {numColumns, numInputs})); // Initialize state meta-management statistics c.setOverlapDutyCycles(new double[numColumns]); c.setActiveDutyCycles(new double[numColumns]); c.setMinOverlapDutyCycles(new double[numColumns]); c.setMinActiveDutyCycles(new double[numColumns]); c.setBoostFactors(new double[numColumns]); Arrays.fill(c.getBoostFactors(), 1); }
/** * Maps a column to its respective input index, keeping to the topology of the region. It takes * the index of the column as an argument and determines what is the index of the flattened input * vector that is to be the center of the column's potential pool. It distributes the columns over * the inputs uniformly. The return value is an integer representing the index of the input bit. * Examples of the expected output of this method: * If the topology is one dimensional, and the * column index is 0, this method will return the input index 0. If the column index is 1, and * there are 3 columns over 7 inputs, this method will return the input index 3. * If the topology * is two dimensional, with column dimensions [3, 5] and input dimensions [7, 11], and the column * index is 3, the method returns input index 8. * * @param columnIndex The index identifying a column in the permanence, potential and connectivity * matrices. * @return A boolean value indicating that boundaries should be ignored. */ public int mapColumn(Connections c, int columnIndex) { int[] columnCoords = c.getMemory().computeCoordinates(columnIndex); double[] colCoords = ArrayUtils.toDoubleArray(columnCoords); double[] ratios = ArrayUtils.divide(colCoords, ArrayUtils.toDoubleArray(c.getColumnDimensions()), 0, 0); double[] inputCoords = ArrayUtils.multiply(ArrayUtils.toDoubleArray(c.getInputDimensions()), ratios, 0, 0); inputCoords = ArrayUtils.d_add( inputCoords, ArrayUtils.multiply( ArrayUtils.divide( ArrayUtils.toDoubleArray(c.getInputDimensions()), ArrayUtils.toDoubleArray(c.getColumnDimensions()), 0, 0), 0.5)); int[] inputCoordInts = ArrayUtils.clip(ArrayUtils.toIntArray(inputCoords), c.getInputDimensions(), -1); return c.getInputMatrix().computeIndex(inputCoordInts); }
/** * Performs inhibition. This method calculates the necessary values needed to actually perform * inhibition and then delegates the task of picking the active columns to helper functions. * * @param c the {@link Connections} matrix * @param overlaps an array containing the overlap score for each column. The overlap score for a * column is defined as the number of synapses in a "connected state" (connected synapses) * that are connected to input bits which are turned on. * @return */ public int[] inhibitColumns(Connections c, double[] overlaps) { overlaps = Arrays.copyOf(overlaps, overlaps.length); double density; double inhibitionArea; if ((density = c.getLocalAreaDensity()) <= 0) { inhibitionArea = Math.pow(2 * c.getInhibitionRadius() + 1, c.getColumnDimensions().length); inhibitionArea = Math.min(c.getNumColumns(), inhibitionArea); density = c.getNumActiveColumnsPerInhArea() / inhibitionArea; density = Math.min(density, 0.5); } // Add our fixed little bit of random noise to the scores to help break ties. // ArrayUtils.d_add(overlaps, c.getTieBreaker()); if (c.getGlobalInhibition() || c.getInhibitionRadius() > ArrayUtils.max(c.getColumnDimensions())) { return inhibitColumnsGlobal(c, overlaps, density); } return inhibitColumnsLocal(c, overlaps, density); }
/** * Update the inhibition radius. The inhibition radius is a measure of the square (or hypersquare) * of columns that each a column is "connected to" on average. Since columns are are not connected * to each other directly, we determine this quantity by first figuring out how many *inputs* a * column is connected to, and then multiplying it by the total number of columns that exist for * each input. For multiple dimension the aforementioned calculations are averaged over all * dimensions of inputs and columns. This value is meaningless if global inhibition is enabled. * * @param c the {@link Connections} (spatial pooler memory) */ public void updateInhibitionRadius(Connections c) { if (c.getGlobalInhibition()) { c.setInhibitionRadius(ArrayUtils.max(c.getColumnDimensions())); return; } TDoubleArrayList avgCollected = new TDoubleArrayList(); int len = c.getNumColumns(); for (int i = 0; i < len; i++) { avgCollected.add(avgConnectedSpanForColumnND(c, i)); } double avgConnectedSpan = ArrayUtils.average(avgCollected.toArray()); double diameter = avgConnectedSpan * avgColumnsPerInput(c); double radius = (diameter - 1) / 2.0d; radius = Math.max(1, radius); c.setInhibitionRadius((int) Math.round(radius)); }