All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.numenta.nupic.encoders.CoordinateEncoder Maven / Gradle / Ivy

There is a newer version: 0.6.13
Show newest version
/* ---------------------------------------------------------------------
 * Numenta Platform for Intelligent Computing (NuPIC)
 * Copyright (C) 2014, Numenta, Inc.  Unless you have an agreement
 * with Numenta, Inc., for a separate license for this software code, the
 * following terms and conditions apply:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero Public License for more details.
 *
 * You should have received a copy of the GNU Affero Public License
 * along with this program.  If not, see http://www.gnu.org/licenses.
 *
 * http://numenta.org/licenses/
 * ---------------------------------------------------------------------
 */

package org.numenta.nupic.encoders;

import org.numenta.nupic.util.ArrayUtils;
import org.numenta.nupic.util.MersenneTwister;
import org.numenta.nupic.util.SortablePair;
import org.numenta.nupic.util.Tuple;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class CoordinateEncoder extends Encoder implements CoordinateOrder {
	private static final long serialVersionUID = 1L;
    
	private static MersenneTwister random = new MersenneTwister();

	/**
	 * Package private to encourage construction using the Builder Pattern
	 * but still allow inheritance.
	 */
	CoordinateEncoder() {
        /*
        *description has a {@link List} of {@link Tuple}s containing
        */
        Tuple desc = new Tuple("coordinate", 0);
        Tuple desc2 = new Tuple("radius", 1);
        description.add(desc);
        description.add(desc2);
    }

	/**
	 * @see Encoder for more information
	 */
	@Override
	public int getWidth() {
		return n;
	}

	/**
	 * @see Encoder for more information
	 */
	@Override
	public boolean isDelta() {
		return false;
	}


	/**
	 * Returns a builder for building ScalarEncoders.
	 * This builder may be reused to produce multiple builders
	 *
	 * @return a {@code CoordinateEncoder.Builder}
	 */
	public static Encoder.Builder builder() {
		return new CoordinateEncoder.Builder();
	}

	/**
	 * Returns coordinates around given coordinate, within given radius.
     * Includes given coordinate.
     *
	 * @param coordinate	Coordinate whose neighbors to find
	 * @param radius		Radius around `coordinate`
	 * @return
	 */
	public List neighbors(int[] coordinate, double radius) {
		int[][] ranges = new int[coordinate.length][];
		for(int i = 0;i < coordinate.length;i++) {
			ranges[i] = ArrayUtils.range(coordinate[i] - (int)radius, coordinate[i] + (int)radius + 1);
		}

		List retVal = new ArrayList();
		int len = ranges.length == 1 ? 1 : ranges[0].length;
		for(int k = 0;k < ranges[0].length;k++) {
			for(int j = 0;j < len;j++) {
				int[] entry = new int[ranges.length];
				entry[0] = ranges[0][k];
				for(int i = 1;i < ranges.length;i++) {
					entry[i] = ranges[i][j];
				}
				retVal.add(entry);
			}
		}
		return retVal;
	}

	/**
	 * Returns the top W coordinates by order.
	 *
	 * @param co			Implementation of {@link CoordinateOrder}
	 * @param coordinates	A 2D array, where each element
                            is a coordinate
	 * @param w				(int) Number of top coordinates to return
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public int[][] topWCoordinates(CoordinateOrder co, int[][] coordinates, int w) {
		SortablePair[] pairs = new SortablePair[coordinates.length];
		for(int i = 0; i < coordinates.length;i++) {
		    pairs[i] = new SortablePair(co.orderForCoordinate(coordinates[i]), i);
		}

		Arrays.sort(pairs);

		int[][] topCoordinates = new int[w][];
		for(int i = 0, wIdx = pairs.length - w; i < w; i++, wIdx++) {
		    int index = pairs[wIdx].second();
		    topCoordinates[i] = coordinates[index];
		}
		return topCoordinates;
	}

	/**
	 * Returns the order for a coordinate.
	 *
	 * @param coordinate	coordinate array
	 *
	 * @return	A value in the interval [0, 1), representing the
     *          order of the coordinate
	 */
	@Override
	public double orderForCoordinate(int[] coordinate) {
		random.setSeed(coordinate);
		return random.nextDouble();
	}

	/**
	 * Returns the order for a coordinate.
	 *
	 * @param coordinate	coordinate array
	 * @param n				the number of available bits in the SDR
	 *
	 * @return	The index to a bit in the SDR
	 */
	public static int bitForCoordinate(int[] coordinate, int n) {
		random.setSeed(coordinate);
		return random.nextInt(n);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void encodeIntoArray(Tuple inputData, int[] output) {
		List neighs = neighbors((int[])inputData.get(0), (double)inputData.get(1));
		int[][] neighbors = new int[neighs.size()][];
		for(int i = 0;i < neighs.size();i++) neighbors[i] = neighs.get(i);

		int[][] winners = topWCoordinates(this, neighbors, w);

		for(int i = 0;i < winners.length;i++) {
			int bit = bitForCoordinate(winners[i], n);
			output[bit] = 1;
		}
	}

	@Override
	public  List getBucketValues(Class returnType) {
		return null;
	}

	/**
	 * Returns a {@code Builder} for constructing {@link CoordinateEncoder}s
	 *
	 * The base class architecture is put together in such a way where boilerplate
	 * initialization can be kept to a minimum for implementing subclasses, while avoiding
	 * the mistake-proneness of extremely long argument lists.
	 *
	 * @see ScalarEncoder.Builder#setStuff(int)
	 */
	public static class Builder extends Encoder.Builder {
		private Builder() {}

		@Override
		public CoordinateEncoder build() {
			//Must be instantiated so that super class can initialize
			//boilerplate variables.
			encoder = new CoordinateEncoder();

			//Call super class here
			super.build();

			////////////////////////////////////////////////////////
			//  Implementing classes would do setting of specific //
			//  vars here together with any sanity checking       //
			////////////////////////////////////////////////////////

			if(w <= 0 || w % 2 == 0) {
				throw new IllegalArgumentException("w must be odd, and must be a positive integer");
			}

			if(n <= 6 * w) {
				throw new IllegalArgumentException(
					"n must be an int strictly greater than 6*w. For " +
                       "good results we recommend n be strictly greater than 11*w");
			}

			if(name == null || name.equals("None")) {
				name = new StringBuilder("[").append(n).append(":").append(w).append("]").toString();
			}

			return (CoordinateEncoder)encoder;
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy