models.RandomProjection.java Source code

Java tutorial

Introduction

Here is the source code for models.RandomProjection.java

Source

/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

package models;

import java.util.Arrays;
import java.util.BitSet;
import java.util.Map;

import com.google.common.hash.Hashing;
import com.google.common.hash.HashFunction;

/**
 * Created with IntelliJ IDEA.
 * User: oyiptong
 * Date: 2012-09-07
 * Time: 2:12 PM
 */
public class RandomProjection {

    final static int HASH_BYTES = 4;
    final static double MAX_HASH_VALUE = Math.pow(2, 8 * HASH_BYTES);

    public static double[] project(Map<Integer, Double> input, int dimensions) {
        double[] projection = new double[dimensions];

        Arrays.fill(projection, 0.0);

        for (Map.Entry<Integer, Double> pair : input.entrySet()) {
            int key = pair.getKey().intValue();
            double value = pair.getValue();

            double[] randomRow = randomRow(key, dimensions, 0);

            // multiply by scalar
            for (int i = 0; i < randomRow.length; i++) {
                randomRow[i] = randomRow[i] * value;
            }

            // add to projection
            for (int i = 0; i < projection.length; i++) {
                projection[i] += randomRow[i];
            }
        }

        return projection;
    }

    public static double[] project(double[] input, int dimensions) {
        double[] projection = new double[dimensions];

        Arrays.fill(projection, 0.0);

        for (int index = 0; index < input.length; index++) {
            double value = input[index];
            double[] randomRow = randomRow(index, dimensions, 0);

            // multiply by scalar
            for (int i = 0; i < randomRow.length; i++) {
                randomRow[i] = randomRow[i] * value;
            }

            // add to projection
            for (int i = 0; i < projection.length; i++) {
                projection[i] += randomRow[i];
            }
        }

        return projection;
    }

    public static BitSet projectBinaryBytes(double[] input, int dimensions) {
        double[] projection = project(input, dimensions);

        BitSet bs = new BitSet(dimensions);
        for (int i = 0; i < projection.length; i++) {
            if (projection[i] > 0) {
                bs.set(i, true);
            }
        }

        return bs;
    }

    public static String projectString(double[] input, int dimensions) {
        double[] projection = project(input, dimensions);

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < projection.length; i++) {
            if (projection[i] > 0) {
                sb.append("1");
            } else {
                sb.append("0");
            }
        }

        return sb.toString();
    }

    public static double[] randomRow(int key, int dimensions, int randomSeed) {
        double[] values = new double[dimensions];

        for (int i = 0; i < dimensions; i++) {
            String matrixEntryName = String.format("%d-%d-%d", key, i, randomSeed);
            double randomValue = deterministicRandom(matrixEntryName);
            double gaussianValue = gaussianFromProbability(randomValue);
            values[i] = gaussianValue;
        }
        return values;
    }

    public static double deterministicRandom(String value) {
        // obtain a hash function that will generate a 32-bit long hash code
        HashFunction hf = Hashing.goodFastHash(32);

        long i = Hashing.padToLong(hf.hashString(value));

        return 1.0 * i / MAX_HASH_VALUE;
    }

    public static double gaussianFromProbability(double value) {
        double value2 = deterministicRandom(String.format("%1.10f-x2", value));
        return gaussianFromTwoProbabilities(value, value2);
    }

    public static double gaussianFromTwoProbabilities(double value1, double value2) {
        double theta = value1 * 2 * Math.PI;
        double rsq = (-1.0 / 0.5) * Math.log(value2);
        double y = Math.sqrt(rsq) * Math.cos(theta);
        return y;
    }
}