jidt/java/source/infodynamics/utils/MatrixUtils.java

3242 lines
93 KiB
Java
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package infodynamics.utils;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.Vector;
/**
* Utilities for computations on matrices, represented as two-dimensional
* arrays of doubles (double[][] matrix) - it is assumed that all
* multidimensional matrices have consistent lengths in each dimension
* matrix[i].
*
* @author Joseph Lizier, joseph.lizier at gmail.com
*
*/
public class MatrixUtils {
/**
* Generate the identity matrix of the given size
*
* @param size (size along one dimension)
* @return two dimensional double array representing the identity matrix
*/
public static double[][] identityMatrix(int size) {
double[][] I = new double[size][size];
for (int r = 0; r < size; r++) {
I[r][r] = 1.0;
}
return I;
}
/**
* Return an array with values enumerated through the given range
*
* @param startValue first value for the array
* @param endValue last value for the array
* @return
*/
public static int[] range(int startValue, int endValue) {
int[] array = new int[endValue - startValue + 1];
for (int i = 0; i < endValue - startValue + 1; i++) {
array[i] = startValue + i;
}
return array;
}
public static double sum(double[] input) {
double total = 0;
for (int i = 0; i < input.length; i++) {
total += input[i];
}
return total;
}
public static double sum(double[] input, int startIndex, int length) {
double total = 0;
for (int i = startIndex; i < startIndex + length; i++) {
total += input[i];
}
return total;
}
public static double sumSpecificIndices(double[] input, int[] indices) {
double total = 0;
for (int i = 0; i < indices.length; i++) {
total += input[indices[i]];
}
return total;
}
public static double sumSpecificIndices(double[] input, int[][] indices, int columnInIndices) {
double total = 0;
for (int i = 0; i < indices.length; i++) {
total += input[indices[i][columnInIndices]];
}
return total;
}
public static double sumSpecificIndices(double[] input, int[][] indices, int columnInIndices,
int indicesOffset) {
double total = 0;
for (int i = 0; i < indices.length; i++) {
total += input[indices[i][columnInIndices] + indicesOffset];
}
return total;
}
public static double sum(double[][] input) {
double total = 0;
for (int i = 0; i < input.length; i++) {
for (int j = 0; j < input[i].length; j++) {
total += input[i][j];
}
}
return total;
}
public static double sum(double[][] input, int column) {
double total = 0;
for (int i = 0; i < input.length; i++) {
total += input[i][column];
}
return total;
}
public static int sum(int[] input) {
int total = 0;
for (int i = 0; i < input.length; i++) {
total += input[i];
}
return total;
}
public static int sum(int[][] input) {
int total = 0;
for (int i = 0; i < input.length; i++) {
for (int j = 0; j < input[i].length; j++) {
total += input[i][j];
}
}
return total;
}
/**
* Return an array of the sums for each column in the 2D input
*
* @param input
* @return
*/
public static double[] sums(double[][] input) {
double[] theSums = new double[input[0].length];
for (int r = 0; r < input.length; r++) {
for (int c = 0; c < input[r].length; c++) {
theSums[c] += input[r][c];
}
}
return theSums;
}
/**
* Return an array of the sums for each column in the 2D input
*
* @param input
* @param startRow which row to start from
* @param length how many rows to take the sum over
* @return
*/
public static double[] sums(double[][] input, int startRow, int length) {
double[] theSums = new double[input[0].length];
for (int r = startRow; r < startRow + length; r++) {
for (int c = 0; c < input[r].length; c++) {
theSums[c] += input[r][c];
}
}
return theSums;
}
public static int countIf(int[] input, int condition) {
int total = 0;
for (int i = 0; i < input.length; i++) {
if (input[i] == condition)
total++;
}
return total;
}
public static int countIf(int[][] input, int condition) {
int total = 0;
for (int i = 0; i < input.length; i++) {
for (int j = 0; j < input[0].length; j++) {
if (input[i][j] == condition)
total++;
}
}
return total;
}
public static int countIf(long[][] input, long condition) {
int total = 0;
for (int i = 0; i < input.length; i++) {
for (int j = 0; j < input[0].length; j++) {
if (input[i][j] == condition)
total++;
}
}
return total;
}
public static int countIf(int[] input1, int condition1, int[] input2, int condition2)
throws Exception {
if (input1.length != input2.length)
throw new Exception("MatrixUtils.sumIf() - arguments are not of equal length (" +
input1.length + " != " + input2.length + ")");
int total = 0;
for (int i = 0; i < input1.length; i++) {
if ((input1[i] == condition1) && (input2[i] == condition2))
total++;
}
return total;
}
public static int countIf(int[] input1, int condition1, int[] input2, int condition2,
int[] input3, int condition3) throws Exception {
if ((input1.length != input2.length) || (input1.length != input3.length))
throw new Exception("MatrixUtils.sumIf() - arguments are not of equal length (" +
input1.length + " != " + input2.length + " != " + input3.length + ")");
int total = 0;
for (int i = 0; i < input1.length; i++) {
if ((input1[i] == condition1) && (input2[i] == condition2) && (input3[i] == condition3))
total++;
}
return total;
}
public static int countIf(boolean[] input, boolean condition) {
int total = 0;
for (int i = 0; i < input.length; i++) {
if (input[i] == condition)
total++;
}
return total;
}
public static double mean(int[] input) {
return sum(input) / (double) input.length;
}
public static double mean(double[] input) {
return sum(input) / (double) input.length;
}
public static double mean(double[] input, int startIndex, int length) {
return sum(input, startIndex, length) / (double) length;
}
public static double mean(double[][] input) {
return sum(input) / (double) (input.length * input[0].length);
}
/**
* Compute the mean along the given column
*
* @param input
* @param column
* @return
*/
public static double mean(double[][] input, int column) {
return sum(input, column) / (double) input.length;
}
/**
* Return an array of the means of each column in the 2D input
*
* @param input
* @return
*/
public static double[] means(double[][] input) {
double[] theMeans = sums(input);
for (int i = 0; i < theMeans.length; i++) {
theMeans[i] = theMeans[i] / input.length;
}
return theMeans;
}
/**
* Return an array of the means of each column in the 2D input
*
* @param input
* @param startRow which row to start from
* @param length how many rows to take the mean over
* @return
*/
public static double[] means(double[][] input, int startRow, int length) {
double[] theMeans = sums(input, startRow, length);
for (int i = 0; i < theMeans.length; i++) {
theMeans[i] = theMeans[i] / length;
}
return theMeans;
}
/**
* Return an array of the means of each row in the 2D input matrix
*
* @param input
* @return
*/
public static double[] meansOfRows(double[][] input) {
double[] theMeans = new double[input.length];
for (int i = 0; i < input.length; i++) {
theMeans[i] = mean(input[i]);
}
return theMeans;
}
public static int[][] columnShift(int[][] input, int shiftBy){
if (shiftBy == 0) {
return input;
}
int rows = input.length;
int columns = input[0].length;
for ( ; shiftBy < 0; shiftBy += columns) {
// Using % mod operator to come back to a +ve column value wont work.
// So we're shifting the shiftBy value (above) until it's in the appropriate
// range 0 .. columns-1
}
int[][] output = new int[rows][columns];
for (int r = 0; r < rows; r++) {
for (int c = 0; c < columns; c++) {
output[r][(c + shiftBy) % columns] = input[r][c];
}
}
return output;
}
public static double[][] columnShift(double[][] input, int shiftBy){
if (shiftBy == 0) {
return input;
}
int rows = input.length;
int columns = input[0].length;
for ( ; shiftBy < 0; shiftBy += columns) {
// Using % mod operator to come back to a +ve column value wont work.
// So we're shifting the shiftBy value (above) until it's in the appropriate
// range 0 .. columns-1
}
double[][] output = new double[rows][columns];
for (int r = 0; r < rows; r++) {
for (int c = 0; c < columns; c++) {
output[r][(c + shiftBy) % columns] = input[r][c];
}
}
return output;
}
/**
* Converts a 2 dimensional array into a single dimension.
* Places each column on top of each other.
* Provides controllers for selecting a subset of rows or columns.
*
* @param input
* @param fromRow
* @param rows
* @param fromColumn
* @param colums
* @return Single dimensional array containing the required data
*/
public static int[] matrixToArray(int[][] input, int fromRow, int rows, int fromColumn, int columns) {
int[] output = new int[rows * columns];
for (int c = 0; c < columns; c++) {
for (int r = 0; r < rows; r++) {
output[c * rows + r] = input[r + fromRow][c + fromColumn];
}
}
return output;
}
/**
* Converts a 2 dimensional array into a single dimension.
* Places each column on top of each other.
* Provides controllers for selecting a subset of rows only.
*
* @param input
* @param fromRow
* @param rows
* @return Single dimensional array containing the required data
*/
public static int[] matrixToArray(int[][] input, int fromRow, int rows) {
return matrixToArray(input, fromRow, rows, 0, input[0].length);
}
/**
* Converts a 2 dimensional array into a single dimension.
* Places each column on top of each other.
*
* @param input
* @return Single dimensional array containing the required data
*/
public static int[] matrixToArray(int[][] input) {
return matrixToArray(input, 0, input.length, 0, input[0].length);
}
/**
* Converts a 2 dimensional array into a single dimension.
* Places each column on top of each other.
* Provides controllers for selecting a subset of rows or columns.
*
* @param input
* @param fromRow
* @param rows
* @param fromColumn
* @param colums
* @return Single dimensional array containing the required data
*/
public static double[] matrixToArray(double[][] input, int fromRow, int rows, int fromColumn, int columns) {
double[] output = new double[rows * columns];
for (int c = 0; c < columns; c++) {
for (int r = 0; r < rows; r++) {
output[c * rows + r] = input[r + fromRow][c + fromColumn];
}
}
return output;
}
/**
* Converts a 2 dimensional array into a single dimension.
* Places each column on top of each other.
* Provides controllers for selecting a subset of rows only.
*
* @param input
* @param fromRow
* @param rows
* @return Single dimensional array containing the required data
*/
public static double[] matrixToArray(double[][] input, int fromRow, int rows) {
return matrixToArray(input, fromRow, rows, 0, input[0].length);
}
/**
* Converts a 2 dimensional array into a single dimension.
* Places each column on top of each other.
*
* @param input
* @return Single dimensional array containing the required data
*/
public static double[] matrixToArray(double[][] input) {
return matrixToArray(input, 0, input.length, 0, input[0].length);
}
/**
* Adds two arrays together
*
* @param input1
* @param input2
* @return
*/
public static int[] add(int[] input1, int[] input2) throws Exception {
if (input1.length != input2.length) {
throw new Exception("Lengths of arrays are not equal");
}
int[] returnValues = new int[input1.length];
for (int i = 0; i < returnValues.length; i++) {
returnValues[i] = input1[i] + input2[i];
}
return returnValues;
}
/**
* Adds two arrays together
*
* @param input1
* @param input2
* @return
*/
public static double[] add(double[] input1, double[] input2) throws Exception {
if (input1.length != input2.length) {
throw new Exception("Lengths of arrays are not equal");
}
double[] returnValues = new double[input1.length];
for (int i = 0; i < returnValues.length; i++) {
returnValues[i] = input1[i] + input2[i];
}
return returnValues;
}
/**
* Adds two arrays together, returning the result in input1
*
* @param input1
* @param input2
*/
public static void addInPlace(double[] input1, double[] input2) throws Exception {
if (input1.length != input2.length) {
throw new Exception("Lengths of arrays are not equal");
}
for (int i = 0; i < input1.length; i++) {
input1[i] = input1[i] + input2[i];
}
}
/**
* Adds the squares of the second array to the first,
* returning the result in input1
*
* @param input1
* @param input2
*/
public static void addSquaresInPlace(double[] input1, double[] input2) throws Exception {
if (input1.length != input2.length) {
throw new Exception("Lengths of arrays are not equal");
}
for (int i = 0; i < input1.length; i++) {
input1[i] = input1[i] + input2[i] * input2[i];
}
}
/**
* Adds two matrices together
*
* @param input1
* @param input2
* @return
* @throws Exception
*/
public static int[][] add(int[][] input1, int[][] input2) throws Exception {
int rows = input1.length;
int columns = input1[0].length;
if (input2.length != rows) {
throw new Exception("Row length of arrays are not equal");
}
if (input2[0].length != columns) {
throw new Exception("Column length of arrays are not equal");
}
int[][] returnValues = new int[rows][columns];
for (int r = 0; r < rows; r++) {
for (int c = 0; c < columns; c++) {
returnValues[r][c] = input1[r][c] + input2[r][c];
}
}
return returnValues;
}
/**
* Adds two matrices together
*
* @param input1
* @param input2
* @return
* @throws Exception
*/
public static double[][] add(double[][] input1, double[][] input2) throws Exception {
int rows = input1.length;
int columns = input1[0].length;
if (input2.length != rows) {
throw new Exception("Row length of arrays are not equal");
}
if (input2[0].length != columns) {
throw new Exception("Column length of arrays are not equal");
}
double[][] returnValues = new double[rows][columns];
for (int r = 0; r < rows; r++) {
for (int c = 0; c < columns; c++) {
returnValues[r][c] = input1[r][c] + input2[r][c];
}
}
return returnValues;
}
/**
* Adds two matrices together
*
* @param input1
* @param input2
* @return
* @throws Exception
*/
public static double[][][] add(double[][][] input1, double[][][] input2) throws Exception {
int rows = input1.length;
int columns = input1[0].length;
int height = input1[0][0].length;
if (input2.length != rows) {
throw new Exception("Row length of arrays are not equal");
}
if (input2[0].length != columns) {
throw new Exception("Column length of arrays are not equal");
}
if (input2[0][0].length != height) {
throw new Exception("Heights (3rd dim) of arrays are not equal");
}
double[][][] returnValues = new double[rows][columns][height];
for (int r = 0; r < rows; r++) {
for (int c = 0; c < columns; c++) {
for (int h = 0; h < height; h++) {
returnValues[r][c][h] = input1[r][c][h] + input2[r][c][h];
}
}
}
return returnValues;
}
/**
* Subtracts second array from the first
*
* @param first
* @param second
* @return first - second
*/
public static double[] subtract(double[] first, double[] second) throws Exception {
if (first.length != second.length) {
throw new Exception("Lengths of arrays are not equal");
}
double[] returnValues = new double[first.length];
for (int i = 0; i < returnValues.length; i++) {
returnValues[i] = first[i] - second[i];
}
return returnValues;
}
/**
* Subtracts second array from the first, overwriting the
* values in first
*
* @param first
* @param second
*/
public static void subtractInPlace(double[] first, double[] second) throws Exception {
if (first.length != second.length) {
throw new Exception("Lengths of arrays are not equal");
}
for (int i = 0; i < first.length; i++) {
first[i] = first[i] - second[i];
}
}
/**
* Subtract one matrix from another
*
* @param input1
* @param input2
* @return input1 - input2
* @throws Exception
*/
public static int[][] subtract(int[][] input1, int[][] input2) throws Exception {
int rows = input1.length;
int columns = input1[0].length;
if (input2.length != rows) {
throw new Exception("Row length of arrays are not equal");
}
if (input2[0].length != columns) {
throw new Exception("Column length of arrays are not equal");
}
int[][] returnValues = new int[rows][columns];
for (int r = 0; r < rows; r++) {
for (int c = 0; c < columns; c++) {
returnValues[r][c] = input1[r][c] - input2[r][c];
}
}
return returnValues;
}
/**
* Return the matrix product A x B
*
* @param A mxn matrix
* @param B nxq matrix
* @return mxq matrix product of A and B
*/
public static double[][] matrixProduct(double[][] A, double[][] B) throws Exception {
if (A[0].length != B.length) {
throw new Exception("Number of columns of a " + A[0].length +
" does not match the number of rows of b " + B.length);
}
double[][] result = new double[A.length][B[0].length];
for (int r = 0; r < result.length; r++) {
for (int c = 0; c < result[r].length; c++) {
result[r][c] = 0;
for (int k = 0; k < A[r].length; k++) {
result[r][c] += A[r][k] * B[k][c];
}
}
}
return result;
}
/**
* Return the matrix product v A
* (i.e. a left multiplication of the 1xn vector and the nxm matrix A)
*
* @param v a 1xn vector
* @param A an nxm matrix
* @return a 1xm vector output
*/
public static double[] matrixProduct(double[] v, double[][] A) throws Exception {
if (v.length != A.length) {
throw new Exception("Number of entries of v " + v.length +
" does not match the number of rows of A " + A.length);
}
// Result length is the number of columns of A
double[] result = new double[A[0].length];
for (int c = 0; c < result.length; c++) {
result[c] = 0;
for (int r = 0; r < v.length; r++) {
result[c] += v[r]*A[r][c];
}
}
return result;
}
/**
* Return the matrix product A v
* (i.e. a right multiplication of the nxm matrix A and the 1xn vector)
*
* @param A an mxn matrix
* @param v a nx1 vector
* @return a mx1 vector output
*/
public static double[] matrixProduct(double[][] A, double[] v) throws Exception {
if (v.length != A[0].length) {
throw new Exception("Number of entries of v " + v.length +
" does not match the number of columns of A " + A[0].length);
}
// Result length is the number of rows of A
double[] result = new double[A.length];
for (int r = 0; r < result.length; r++) {
result[r] = 0;
for (int c = 0; c < v.length; c++) {
result[r] += A[r][c] * v[c];
}
}
return result;
}
/**
* Return the dot product of two vectors v u
*
* @param v a nx1 vector
* @param u a nx1 vector
* @return the scalar dot product
*/
public static double dotProduct(double[] v, double[] u) throws Exception {
if (v.length != u.length) {
throw new Exception("Number of entries of v " + v.length +
" does not match the number of entries of u " + u.length);
}
double result = 0;
for (int r = 0; r < v.length; r++) {
result += v[r] * u[r];
}
return result;
}
/**
* Duplicates a matrix; handles different number of columns
* for each row
*
* @param src
* @return
*/
public static int[][] duplicateMatrix(int[][] src) {
int[][] dest = new int[src.length][];
for (int r = 0; r < src.length; r++) {
dest[r] = new int[src[r].length];
System.arraycopy(src[r], 0, dest[r], 0, src[r].length);
}
return dest;
}
/**
* Copies all rows and columns between two double arrays
*
* @param src
* @param dest
*/
public static void arrayCopy(double[][] src, double[][] dest) {
for (int r = 0; r < src.length; r++) {
System.arraycopy(src[r], 0, dest[r], 0, src[r].length);
}
}
/**
* Copies all rows and columns between two double arrays
*
* @param src
* @param dest
*/
public static double[][] arrayCopy(double[][] src) {
double[][] dest = new double[src.length][];
for (int r = 0; r < src.length; r++) {
dest[r] = new double[src[r].length];
System.arraycopy(src[r], 0, dest[r], 0, src[r].length);
}
return dest;
}
/**
* Copies the required rows and columns between two
* double arrays
*
* @param src
* @param srcStartRow
* @param srcStartCol
* @param dest
* @param destStartRow
* @param destStartCol
* @param rows
* @param cols
*/
public static void arrayCopy(double[][] src, int srcStartRow, int srcStartCol,
double[][] dest, int destStartRow, int destStartCol,
int rows, int cols) {
for (int r = 0; r < rows; r++) {
System.arraycopy(src[srcStartRow + r], srcStartCol,
dest[destStartRow + r], destStartCol,
cols);
}
}
/**
* Copies all rows and columns between two int arrays
*
* @param src
* @param dest
*/
public static void arrayCopy(int[][] src, int[][] dest) {
for (int r = 0; r < src.length; r++) {
System.arraycopy(src[r], 0, dest[r], 0, src[r].length);
}
}
/**
* Copies the required rows and columns between two
* double arrays
*
* @param src
* @param srcStartRow
* @param srcStartCol
* @param dest
* @param destStartRow
* @param destStartCol
* @param rows
* @param cols
*/
public static void arrayCopy(int[][] src, int srcStartRow, int srcStartCol,
int[][] dest, int destStartRow, int destStartCol,
int rows, int cols) {
for (int r = 0; r < rows; r++) {
System.arraycopy(src[srcStartRow + r], srcStartCol,
dest[destStartRow + r], destStartCol,
cols);
}
}
/**
* Copies the given source array into the required column number of the destination
* @param destination
* @param column
* @param source
*/
public static void copyIntoColumn(int[][] destination, int column, int[] source) throws Exception {
if (source.length != destination.length) {
throw new Exception("Destination column is not of the same length as the source (" +
destination.length + " vs " + source.length + ")");
}
for (int r = 0; r < destination.length; r++) {
destination[r][column] = source[r];
}
}
/**
* Copies the given source array into the required column number of the destination
* @param destination
* @param column
* @param source
*/
public static void copyIntoColumn(double[][] destination, int column,
int destFromRowNumber, double[] source, int sourceFromRowNumber,
int rows) throws Exception {
if (sourceFromRowNumber + rows > source.length) {
throw new Exception("Attempting to copy too many rows " + rows +
" after the start row " + sourceFromRowNumber +
" from the source of length " + source.length);
}
if (destFromRowNumber + rows > destination.length) {
throw new Exception("Attempting to copy too many rows " + rows +
" after the start row " + destFromRowNumber +
" from the destination of length " + destination.length);
}
for (int r = 0; r < rows; r++) {
destination[r + destFromRowNumber][column] = source[r + sourceFromRowNumber];
}
}
/**
* Copies the given source array into the required column number of the destination
* @param destination
* @param column
* @param source
*/
public static void copyIntoColumn(double[][] destination, int column, double[] source) throws Exception {
if (source.length != destination.length) {
throw new Exception("Destination column is not of the same length as the source (" +
destination.length + " vs " + source.length + ")");
}
for (int r = 0; r < destination.length; r++) {
destination[r][column] = source[r];
}
}
/**
* Append the vector u to the vector v and return the result
*
* @param v vector 1
* @param u vector 2
* @return [v, u] appended result
*/
public static double[] append(double[] v, double[] u) {
double[] result = new double[v.length + u.length];
System.arraycopy(v, 0, result, 0, v.length);
System.arraycopy(u, 0, result, v.length, u.length);
return result;
}
/**
*
* @param separateValues
* @return Single dimensional matrix where each row
* has been combined into a single output value, unique
* to the input row. We basically multiply each column
* by a different power of the base.
*/
public static int[] computeCombinedValues(int separateValues[][], int base) throws Exception {
// Number of columns (second index) is sizeof first element
int columns = separateValues[0].length;
return computeCombinedValues(separateValues, columns, base);
/*
// rows = first index specifies rows
int rows = separateValues.length;
int[] combinedValues = new int[rows];
for (int r = 0; r < rows; r++) {
// For each row in vec1
int combinedRowValue = 0;
int multiplier = 1;
for (int c = columns - 1; c >= 0; c--) {
// Add in the contribution from each column
combinedRowValue += separateValues[r][c] * multiplier;
multiplier *= base;
}
combinedValues[r] = combinedRowValue;
}
return combinedValues;
*/
}
/**
*
* @param separateValues
* @return Single dimensional matrix where each row
* has been combined into a single output value, unique
* to the input row. We basically multiply the first "columbs" columns
* by a different power of the base.
*/
public static int[] computeCombinedValues(int separateValues[][], int columns, int base) throws Exception {
if (columns > separateValues[0].length) {
throw new Exception("computeCombinedValues: computation request across more columns " +
columns + " than are available " + separateValues[0].length);
}
// Make sure we won't get any overflow here
if (combinedValuesOverflow(columns, base)) {
// multiplier has overflown
throw new Exception("Too many columns " + columns + " for the given base " + base +
" for this call to computeCombinedValues");
}
// rows = first index specifies rows
int rows = separateValues.length;
int[] combinedValues = new int[rows];
for (int r = 0; r < rows; r++) {
// For each row in vec1
int combinedRowValue = 0;
int multiplier = 1;
for (int c = columns - 1; c >= 0; c--) {
// Add in the contribution from each column
combinedRowValue += separateValues[r][c] * multiplier;
multiplier *= base;
}
combinedValues[r] = combinedRowValue;
}
return combinedValues;
}
/**
*
* @param separateValues
* @return Single dimensional matrix where each row
* has been combined into a single output value, unique
* to the input row. We basically multiply each column
* by a different power of the base.
*/
public static long[] computeCombinedValuesLong(int separateValues[][], int base) throws Exception {
// Number of columns (second index) is sizeof first element
int columns = separateValues[0].length;
return computeCombinedValuesLong(separateValues, columns, base);
/*
// rows = first index specifies rows
int rows = separateValues.length;
long[] combinedValues = new long[rows];
for (int r = 0; r < rows; r++) {
// For each row in vec1
long combinedRowValue = 0;
long multiplier = 1;
for (int c = columns - 1; c >= 0; c--) {
// Add in the contribution from each column
combinedRowValue += ((long) separateValues[r][c]) * multiplier;
multiplier *= (long) base;
}
combinedValues[r] = combinedRowValue;
}
return combinedValues;
*/
}
/**
*
* @param separateValues
* @return Single dimensional matrix where each row
* has been combined into a single output value, unique
* to the input row. We basically multiply the first "columns" columns
* by a different power of the base.
*/
public static long[] computeCombinedValuesLong(int separateValues[][], int columns, int base) throws Exception {
if (columns > separateValues[0].length) {
throw new Exception("computeCombinedValuesLong: computation request across more columns " +
columns + " than are available " + separateValues[0].length);
}
// Make sure we won't get any overflow here
if (combinedValuesOverflowLong(columns, base)) {
// multiplier has overflown
throw new Exception("Too many columns " + columns + " for the given base " + base +
" for this call to computeCombinedValuesLong");
}
// rows = first index specifies rows
int rows = separateValues.length;
long[] combinedValues = new long[rows];
for (int r = 0; r < rows; r++) {
// For each row in vec1
long combinedRowValue = 0;
long multiplier = 1;
for (int c = columns - 1; c >= 0; c--) {
// Add in the contribution from each column
combinedRowValue += ((long) separateValues[r][c]) * multiplier;
multiplier *= (long) base;
}
combinedValues[r] = combinedRowValue;
}
return combinedValues;
}
public static boolean combinedValuesOverflow(int columns, int base) {
// Make sure we won't get any overflow here
int multiplier = 1;
for (int c = columns - 1; c >= 0; c--) {
if (multiplier < 0) {
// multiplier has overflown.
// Technically, it's possible to use one negative value if we were using base-2,
// but realistically it's safer if we just call it off now.
return true;
}
multiplier *= (long) base;
}
return false;
}
public static boolean combinedValuesOverflowLong(int columns, int base) {
// Make sure we won't get any overflow here
long multiplier = 1;
for (int c = columns - 1; c >= 0; c--) {
if (multiplier < 0) {
// multiplier has overflown.
// Technically, it's possible to use one negative value if we were using base-2,
// but realistically it's safer if we just call it off now.
return true;
}
multiplier *= (long) base;
}
return false;
}
/**
* Select out part of an array.
*
* @param data
* @param fromIndex
* @param length
* @return
*/
public static double[] select(double[] data, int fromIndex, int length) {
double[] returnData = new double[length];
System.arraycopy(data, fromIndex, returnData, 0, length);
return returnData;
}
/**
* Select out part of an array.
*
* @param data
* @param fromIndex
* @param length
* @return
*/
public static int[] select(int[] data, int fromIndex, int length) {
int[] returnData = new int[length];
System.arraycopy(data, fromIndex, returnData, 0, length);
return returnData;
}
public static int[] selectColumn(int matrix[][], int columnNo) {
int[] column = new int[matrix.length];
for (int r = 0; r < matrix.length; r++) {
column[r] = matrix[r][columnNo];
}
return column;
}
public static double[] selectColumn(double matrix[][], int columnNo) {
double[] column = new double[matrix.length];
for (int r = 0; r < matrix.length; r++) {
column[r] = matrix[r][columnNo];
}
return column;
}
/**
* Extract the required columns from the matrix
*
* @param matrix
* @param columns
* @return
*/
public static double[][] selectColumns(double matrix[][], int columns[]) {
double[][] data = new double[matrix.length][columns.length];
for (int r = 0; r < matrix.length; r++) {
for (int cIndex = 0; cIndex < columns.length; cIndex++) {
data[r][cIndex] = matrix[r][columns[cIndex]];
}
}
return data;
}
/**
* Extract the required columns from the matrix
*
* @param matrix
* @param includeColumnFlags
* @return
*/
public static double[][] selectColumns(double matrix[][], boolean includeColumnFlags[]) {
Vector<Integer> v = new Vector<Integer>();
for (int i = 0; i < includeColumnFlags.length; i++) {
if (includeColumnFlags[i]) {
v.add(new Integer(i));
}
}
double[][] data = new double[matrix.length][v.size()];
for (int r = 0; r < matrix.length; r++) {
for (int outputColumnIndex = 0; outputColumnIndex < v.size(); outputColumnIndex++) {
int outputColumn = v.get(outputColumnIndex);
data[r][outputColumnIndex] = matrix[r][outputColumn];
}
}
return data;
}
/**
* Extract the required columns from the matrix
*
* @param matrix
* @param columns
* @return
*/
public static double[][] selectColumns(double matrix[][], Vector<Integer> columns) {
double[][] data = new double[matrix.length][columns.size()];
for (int r = 0; r < matrix.length; r++) {
for (int cIndex = 0; cIndex < columns.size(); cIndex++) {
data[r][cIndex] = matrix[r][columns.elementAt(cIndex).intValue()];
}
}
return data;
}
/**
* Extract the required columns from the matrix
*
* @param matrix
* @param columns
* @return
*/
public static double[][] selectRows(double matrix[][], int fromRow, int rows) {
double[][] data = new double[rows][];
for (int rIndex = 0; rIndex < rows; rIndex++) {
data[rIndex] = matrix[rIndex + fromRow];
}
return data;
}
/**
* Extract the required columns from the matrix
*
* @param matrix
* @param columns
* @return
*/
public static double[][] selectRowsAndColumns(double matrix[][], int rows[], int columns[]) {
double[][] data = new double[rows.length][columns.length];
for (int rIndex = 0; rIndex < rows.length; rIndex++) {
for (int cIndex = 0; cIndex < columns.length; cIndex++) {
data[rIndex][cIndex] = matrix[rows[rIndex]][columns[cIndex]];
}
}
return data;
}
public static double[][] selectFirstTwoDimenions(double[][][][] matrix, int d2, int d3) {
double[][] newMatrix = new double[matrix.length][];
for (int i = 0; i < matrix.length; i++) {
newMatrix[i] = new double[matrix[i].length];
for (int j = 0; j < matrix[i].length; j++) {
newMatrix[i][j] = matrix[i][j][d2][d3];
}
}
return newMatrix;
}
public static double[][] copyMatrixEliminateRowAndColumn(double[][] matrix,
int rowToEliminate, int colToEliminate) {
double[][] newMatrix = new double[matrix.length - 1][matrix[0].length - 1];
for (int r = 0; r < matrix.length; r++) {
if (r == rowToEliminate) {
continue;
}
for (int c = 0; c < matrix.length; c++) {
if (c == colToEliminate) {
continue;
}
int newRow = r;
int newCol = c;
if (newRow > rowToEliminate) {
newRow--;
}
if (newCol > colToEliminate) {
newCol--;
}
newMatrix[newRow][newCol] = matrix[r][c];
}
}
return newMatrix;
}
public static double[] extractSelectedTimePoints(double[] data, int[] timePoints) {
double[] extracted = new double[timePoints.length];
for (int t = 0; t < timePoints.length; t++) {
extracted[t] = data[timePoints[t]];
}
return extracted;
}
public static int[] extractSelectedTimePoints(int[] data, int[] timePoints) {
int[] extracted = new int[timePoints.length];
for (int t = 0; t < timePoints.length; t++) {
extracted[t] = data[timePoints[t]];
}
return extracted;
}
public static double[][] extractSelectedTimePoints(double[][] data, int[] timePoints) {
int columns = data[0].length;
double[][] extracted = new double[timePoints.length][columns];
for (int t = 0; t < timePoints.length; t++) {
System.arraycopy(data[timePoints[t]], 0, extracted[t], 0, columns);
}
return extracted;
}
/**
* Extraxts the double[] vectors at each of the selected time points.
* The return double[][] array is an array of points to the existing
* double[] vectors.
*
* @param data
* @param timePoints
* @return
*/
public static double[][] extractSelectedTimePointsReusingArrays(double[][] data, int[] timePoints) {
double[][] extracted = new double[timePoints.length][];
for (int t = 0; t < timePoints.length; t++) {
extracted[t] = data[timePoints[t]];
}
return extracted;
}
/**
* Extraxts the boolean[] vectors at each of the selected time points.
* The return boolean[][] array is an array of points to the existing
* boolean[] vectors.
*
* @param data
* @param timePoints
* @return
*/
public static boolean[][] extractSelectedTimePointsReusingArrays(boolean[][] data, int[] timePoints) {
boolean[][] extracted = new boolean[timePoints.length][];
for (int t = 0; t < timePoints.length; t++) {
extracted[t] = data[timePoints[t]];
}
return extracted;
}
public static double[][] extractSelectedTimePoints(double[][] data, int[][] timePoints,
int columnInTimePoints) {
int columns = data[0].length;
double[][] extracted = new double[timePoints.length][columns];
for (int t = 0; t < timePoints.length; t++) {
System.arraycopy(data[timePoints[t][columnInTimePoints]], 0, extracted[t], 0, columns);
}
return extracted;
}
/**
* Extract from data the vectors for rows corresponding to the time values in
* column columnInTimePoints of each row of timePoints.
*
* @param data
* @param timePoints
* @param columnInTimePoints
* @param timeOffset
* @return a 2D array of doubles, with timePoints.length rows and data[0].length columns
*/
public static double[][] extractSelectedTimePoints(double[][] data, int[][] timePoints,
int columnInTimePoints, int timeOffset) {
int columns = data[0].length;
double[][] extracted = new double[timePoints.length][columns];
for (int t = 0; t < timePoints.length; t++) {
System.arraycopy(data[timePoints[t][columnInTimePoints] + timeOffset], 0, extracted[t], 0, columns);
}
return extracted;
}
/**
* Return the rows of data, where the conditionalData matched the
* conditionalValue for that given row.
* Assumes data.length == conditionalData.length.
*
* @param data
* @param conditionalData
* @param conditionalValue
* @return a 2D array of doubles where the conditionalData matched the
* conditionalValue for those rows.
*/
public static double[][] extractSelectedPointsMatchingCondition(
double[][] data, int[] conditionalData, int conditionalValue) {
// Count the number of matching points first.
int numNewRows = 0;
for (int t = 0; t < data.length; t++) {
if (conditionalData[t] == conditionalValue) {
numNewRows++;
}
}
// Create the new extracted data
return extractSelectedPointsMatchingCondition(data, conditionalData,
conditionalValue, numNewRows);
}
/**
* Return the rows of data, where the conditionalData matched the
* conditionalValue for that given row.
* Assumes data.length == conditionalData.length.
* Here, the caller knows that there will be at minimum knownNumExtractedValues
* values to be extracted, and only wants those values.
*
* @param data
* @param conditionalData
* @param conditionalValue
* @param knownNumExtractedValues the known number of matching values
* @return a 2D array of doubles where the conditionalData matched the
* conditionalValue for those rows.
*/
public static double[][] extractSelectedPointsMatchingCondition(
double[][] data, int[] conditionalData, int conditionalValue,
int knownNumExtractedValues) {
// Create the new extracted data
int columns = data[0].length;
double[][] extracted = new double[knownNumExtractedValues][columns];
int rowsCopied = 0;
if (knownNumExtractedValues == 0) {
return extracted;
}
for (int t = 0; t < data.length; t++) {
if (conditionalData[t] == conditionalValue) {
System.arraycopy(data[t], 0, extracted[rowsCopied++],
0, columns);
}
if (rowsCopied == knownNumExtractedValues) {
// We've extracted enough values
break;
}
}
return extracted;
}
/**
* Inserts the given time points (in the order prescribed in timePoints)
* from the vector originalSourceValuesInJoint into the given column in matrix
*
* @param inputValues
* @param timePoints
* @param matrix
* @param column
*/
public static void reorderVectorIntoMatrix(double[] inputValues, int[] timePoints,
double[][] matrix, int column) {
for (int i = 0; i < timePoints.length; i++) {
int t = timePoints[i];
matrix[i][column] = inputValues[t];
}
}
/**
* Return data[x][y]:
* - y==0: inputValues[x][0]
* - y>0: inputValues[reordering[y-1][x]][y]
*
* @param inputValues holds the raw data values
* @param reordering outlines how to rearrange the raw data values for each variable or column.
* First index is variable
* or column number. Reorderings may be supplied for all of the columns of the inputValues,
* or for one less than all of the columns, in which case the first column is not
* reordered. Second index is for the row number or time step. The value at that
* point states which row number to pull the data from.
* @return
*/
public static double[][] reorderDataForVariables(double[][] inputValues, int[][] reordering) {
int rows = inputValues.length;
int columns = inputValues[0].length;
boolean reorderingFirstColumn = (reordering.length == columns);
double[][] data = new double[rows][columns];
for (int r = 0; r < rows; r++) {
int reorderIndex = 0;
if (reorderingFirstColumn) {
data[r][0] = inputValues[reordering[reorderIndex++][r]][0];
} else {
data[r][0] = inputValues[r][0];
}
for (int c = 1; c < columns; c++) {
data[r][c] = inputValues[reordering[reorderIndex++][r]][c];
}
}
return data;
}
/**
* Reshapes the given single dimensional array into a 2D array of the given
* size
*
* @param data
* @param rows
* @param columns
* @return
*/
public static double[][] reshape(double[] data, int rows, int columns) {
double[][] matrix = new double[rows][columns];
int i = 0;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < columns; c++) {
matrix[r][c] = data[i++];
}
}
return matrix;
}
/**
* Constructs all embedding vectors of size k for the data.
* Will be data.length - k + 1 of these
*
* @param data
* @param k
* @return
*/
public static double[][] makeDelayEmbeddingVector(double[] data, int k) {
try {
return makeDelayEmbeddingVector(data, k, k - 1, data.length - k + 1);
} catch (Exception e) {
// The above call should not throw an Exception, handle here
// in a RuntimeException so this method doesn't throw one
throw new RuntimeException(e);
}
}
/**
* Constructs numEmbeddingVectors embedding vectors of size k for the data,
* with the first embedding vector having it's last time point at t=startKthPoint
*
* @param data
* @param k
* @param startKthPoint
* @param numEmbeddingVectors
* @return
*/
public static double[][] makeDelayEmbeddingVector(double[] data, int k,
int startKthPoint, int numEmbeddingVectors) throws Exception {
if (startKthPoint < k - 1) {
throw new Exception("Start point t=" + startKthPoint + " is too early for a " +
k + " length embedding vector");
}
if (numEmbeddingVectors + startKthPoint > data.length) {
throw new Exception("Too many embedding vectors " + numEmbeddingVectors +
" requested for the given startPoint " + startKthPoint +
" and time series length " + data.length);
}
double[][] embeddingVectors = new double[numEmbeddingVectors][k];
for (int t = startKthPoint; t < numEmbeddingVectors + startKthPoint; t++) {
for (int i = 0; i < k; i++) {
embeddingVectors[t - startKthPoint][i] = data[t - i];
}
}
return embeddingVectors;
}
/**
* Constructs all embedding vectors of size k for the data.
* Will be data.length - k + 1 of these
*
* @param data
* @param k
* @return
*/
public static double[][] makeDelayEmbeddingVector(double[][] data, int k) {
try {
return makeDelayEmbeddingVector(data, k, k - 1, data.length - k + 1);
} catch (Exception e) {
// The above call should not throw an Exception, handle here
// in a RuntimeException so this method doesn't throw one
throw new RuntimeException(e);
}
}
/**
* Constructs numEmbeddingVectors embedding vectors of size k for the data,
* with the first embedding vector having it's last time point at t=startKthPoint
*
* @param data
* @param k
* @param startKthPoint
* @param numEmbeddingVectors
* @return
*/
public static double[][] makeDelayEmbeddingVector(double[][] data, int k,
int startKthPoint, int numEmbeddingVectors) throws Exception {
if (startKthPoint < k - 1) {
throw new Exception("Start point t=" + startKthPoint + " is too early for a " +
k + " length embedding vector");
}
if (numEmbeddingVectors + startKthPoint > data.length) {
throw new Exception("Too many embedding vectors " + numEmbeddingVectors +
" requested for the given startPoint " + startKthPoint +
" and time series length " + data.length);
}
int columns = data[0].length;
double[][] embeddingVectors = new double[numEmbeddingVectors][k * columns];
for (int t = startKthPoint; t < numEmbeddingVectors + startKthPoint; t++) {
for (int i = 0; i < k; i++) {
for (int c = 0; c < columns; c++) {
embeddingVectors[t - startKthPoint][i*columns + c] = data[t - i][c];
}
}
}
return embeddingVectors;
}
public static int[] subArray(int[] array, int startIndex, int theLength) {
int[] sub = new int[theLength];
for (int r = 0; r < theLength; r++) {
sub[r] = array[startIndex + r];
}
return sub;
}
public static double stdDev(double[] array) {
double mean = 0.0;
double total = 0.0;
for (int m = 0; m < array.length; m++) {
total += array[m];
}
mean = total / (double) array.length;
return stdDev(array, mean);
}
public static double stdDev(double[][] matrix, int column) {
double mean = 0.0;
double total = 0.0;
for (int m = 0; m < matrix.length; m++) {
total += matrix[m][column];
}
mean = total / (double) matrix.length;
return stdDev(matrix, column, mean);
}
/**
* Return the standard deviation of all the elements in array
*
* @param array
* @param mean
* @return
*/
public static double stdDev(double[] array, double mean) {
return stdDev(array, mean, array.length);
}
/**
* Standard deviation for the first arrayLength terms of array
*
* @param array
* @param mean
* @param arrayLength
* @return
*/
public static double stdDev(double[] array, double mean, int arrayLength) {
if (arrayLength == 0) {
return 0.0;
}
double sumSqs = 0.0;
for (int m = 0; m < arrayLength; m++) {
sumSqs += (array[m] - mean) * (array[m] - mean);
}
double std = sumSqs / (double) (arrayLength - 1);
std = Math.sqrt(std);
return std;
}
/**
* Compute the standard deviation along the given column, with the known
* given mean.
*
* @param matrix
* @param column
* @param mean
* @return
*/
public static double stdDev(double[][] matrix, int column, double mean) {
if (matrix.length == 0) {
return 0.0;
}
double sumSqs = 0.0;
for (int m = 0; m < matrix.length; m++) {
sumSqs += (matrix[m][column] - mean) * (matrix[m][column] - mean);
}
double std = sumSqs / (double) (matrix.length - 1);
std = Math.sqrt(std);
return std;
}
/**
* Compute the standard deviation across all values in the 2D matrix
*
* @param matrix
* @return
*/
public static double stdDev(double[][] matrix) {
double mean = mean(matrix);
return stdDev(matrix, mean);
}
/**
* Compute the standard deviation across all values in the 2D matrix
*
* @param matrix
* @param mean
* @return
*/
public static double stdDev(double[][] matrix, double mean) {
if (matrix.length == 0) {
return 0.0;
}
double sumSqs = 0.0;
for (int m = 0; m < matrix.length; m++) {
for (int c = 0; c < matrix[m].length; c++) {
sumSqs += (matrix[m][c] - mean) * (matrix[m][c] - mean);
}
}
double std = sumSqs / (double) ((matrix.length * matrix[0].length) - 1);
std = Math.sqrt(std);
return std;
}
/**
* Compute the standard deviations along each column
*
* @param matrix
* @param means
* @return
*/
public static double[] stdDevs(double[][] matrix, double[] means) {
double[] sumSqs = new double[means.length];
for (int m = 0; m < matrix.length; m++) {
for (int c = 0; c < matrix[m].length; c++) {
sumSqs[c] += (matrix[m][c] - means[c]) * (matrix[m][c] - means[c]);
}
}
double[] stds = new double[means.length];
for (int c = 0; c < stds.length; c++) {
stds[c] = sumSqs[c] / (double) (matrix.length - 1);
stds[c] = Math.sqrt(stds[c]);
}
return stds;
}
/**
* Compute the standard deviations along each row
*
* @param matrix
* @param means
* @return
*/
public static double[] stdDevsOfRows(double[][] matrix, double[] means) {
double[] stds = new double[matrix.length];
for (int r = 0; r < matrix.length; r++) {
double sumSqs = 0.0;
for (int c = 0; c < matrix[r].length; c++) {
sumSqs += (matrix[r][c] - means[r]) * (matrix[r][c] - means[r]);
}
stds[r] = sumSqs / (double) (matrix[r].length - 1);
stds[r] = Math.sqrt(stds[r]);
}
return stds;
}
public static double max(double[][][] matrix) {
// double max = 0.0;
double max = matrix[0][0][0];
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
for (int k = 0; k < matrix[i][j].length; k++) {
if (matrix[i][j][k] > max) {
max = matrix[i][j][k];
}
}
}
}
return max;
}
/**
* Normalises the elements in the given array
*
* @param array
*/
public static void normalise(double[] array) {
double mean = MatrixUtils.mean(array);
double stdDev = MatrixUtils.stdDev(array, mean);
if (Double.isInfinite(1.0 / stdDev)) {
// The stdDev is 0, just subtract off mean
for (int t = 0; t < array.length; t++) {
array[t] = (array[t] - mean);
}
} else {
// stdDev is non zero
for (int t = 0; t < array.length; t++) {
array[t] = (array[t] - mean) / stdDev;
}
}
}
/**
* Returns a normalised array of the elements in the given array
*
* @param array
*/
public static double[] normaliseIntoNewArray(double[] array) {
double[] newArray = new double[array.length];
double mean = MatrixUtils.mean(array);
double stdDev = MatrixUtils.stdDev(array, mean);
if (Double.isInfinite(1.0 / stdDev)) {
// The stdDev is 0, just subtract off mean
for (int t = 0; t < array.length; t++) {
newArray[t] = (array[t] - mean);
}
} else {
// stdDev is non zero
for (int t = 0; t < array.length; t++) {
newArray[t] = (array[t] - mean) / stdDev;
}
}
return newArray;
}
/**
* Normalises the elements in the given column of the matrix
*
* @param matrix 2D matrix of doubles
* @param column column number to be normalised
*/
public static void normalise(double[][] matrix, int column) {
double mean = MatrixUtils.mean(matrix, column);
double stdDev = MatrixUtils.stdDev(matrix, column, mean);
if (Double.isInfinite(1.0 / stdDev)) {
// The stdDev is 0, just subtract off mean
for (int t = 0; t < matrix.length; t++) {
matrix[t][column] = (matrix[t][column] - mean);
}
} else {
// stdDev is non zero
for (int t = 0; t < matrix.length; t++) {
matrix[t][column] = (matrix[t][column] - mean) / stdDev;
}
}
}
/**
* Normalises the elements in the given column of the matrix
*
* @param matrix 2D matrix of doubles
* @param column column number to be normalised
*/
public static double[] normaliseIntoNewArray(double[][] matrix, int column) {
double[] newArray = new double[matrix.length];
double mean = MatrixUtils.mean(matrix, column);
double stdDev = MatrixUtils.stdDev(matrix, column, mean);
if (Double.isInfinite(1.0 / stdDev)) {
// The stdDev is 0, just subtract off mean
for (int t = 0; t < matrix.length; t++) {
newArray[t] = (matrix[t][column] - mean);
}
} else {
// stdDev is non zero
for (int t = 0; t < matrix.length; t++) {
newArray[t] = (matrix[t][column] - mean) / stdDev;
}
}
return newArray;
}
/**
* Normalises the elements along each column of the matrix
*
* @param matrix 2D matrix of doubles
*/
public static double[][] normaliseIntoNewArray(double[][] matrix) {
double[][] newMatrix = new double[matrix.length][matrix[0].length];
double[] means = means(matrix);
double[] stds = stdDevs(matrix, means);
for (int r = 0; r < newMatrix.length; r++) {
for (int c = 0; c < newMatrix[r].length; c++) {
newMatrix[r][c] = matrix[r][c] - means[c];
if (!Double.isInfinite(1.0 / stds[c])) {
newMatrix[r][c] /= stds[c];
} // else we just subtract off the mean
}
}
return newMatrix;
}
public static double max(double[][] matrix) {
// double max = 0.0;
double max = matrix[0][0];
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
if (Double.isNaN(max) || (matrix[i][j] > max)) {
max = matrix[i][j];
}
}
}
return max;
}
public static int max(int[][] matrix) {
// int max = 0;
int max = matrix[0][0];
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
if (matrix[i][j] > max) {
max = matrix[i][j];
}
}
}
return max;
}
public static double max(double[] array) {
return maxStartFromIndex(array, 0);
}
public static double maxStartFromIndex(double[] array, int startFromIndex) {
// double max = 0.0;
double max = array[startFromIndex];
for (int i = startFromIndex; i < array.length; i++) {
if (Double.isNaN(max) || (array[i] > max)) {
max = array[i];
}
}
return max;
}
public static int max(int[] array) {
// int max = 0;
int max = array[0];
for (int i = 0; i < array.length; i++) {
if (array[i] > max) {
max = array[i];
}
}
return max;
}
/**
* Works out the maximum value in the matrix in a given column
*
* @param matrix
* @param column
* @return
*/
public static double max(double[][] matrix, int column) {
// double max = 0.0;
// Allow ArrayIndexOutOfBoundsException if matrix is size 0
double max = matrix[0][column];
for (int i = 1; i < matrix.length; i++) {
if (Double.isNaN(max) || (matrix[i][column] > max)) {
max = matrix[i][column];
}
}
return max;
}
/**
* Works out the maximum value in the matrix in a given column
*
* @param matrix
* @param column
* @return
*/
public static int max(int[][] matrix, int column) {
// double max = 0.0;
// Allow ArrayIndexOutOfBoundsException if matrix is size 0
int max = matrix[0][column];
for (int i = 1; i < matrix.length; i++) {
if (matrix[i][column] > max) {
max = matrix[i][column];
}
}
return max;
}
public static double min(double[][] matrix) {
// double min = 0.0;
double min = matrix[0][0];
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
if (Double.isNaN(min) || (matrix[i][j] < min)) {
min = matrix[i][j];
}
}
}
return min;
}
public static int min(int[][] matrix) {
// int min = 0;
int min = matrix[0][0];
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
if (matrix[i][j] < min) {
min = matrix[i][j];
}
}
}
return min;
}
public static double min(double[] array) {
return minStartFromIndex(array, 0);
}
/**
* Find the kth minimum value in the array.
*
* @param array
* @param k
* @return
* @throws Exception
*/
public static double kthMin(double[] array, int k) throws Exception {
if (k == 1) {
return min(array);
}
if (array.length < k) {
throw new Exception(String.format("Length of array (%d) is less than k (%d)",
array.length, k));
}
// Hold the k minimum elements in strictly increasing order from 0 .. k-1
double[] mins = new double[k];
for (int i = 0; i < k; i++) {
mins[i] = Double.POSITIVE_INFINITY;
}
for (int t = 0; t < array.length; t++) {
// Assume that k is small enough that there is no point doing binary
// searches to find the best place to insert this element in the minimums (if required).
// First check if it's smaller than the current kth min:
if (array[t] < mins[k - 1]) {
mins[k - 1] = array[t];
// Now check if we need to reorder the array of minimums, keeping it sorted
for (int i = k - 2; i >= 0; i--) {
if (array[t] < mins[i]) {
// Swap array[t] along from mins[i+1]:
mins[i+1] = mins[i];
mins[i] = array[t];
continue;
}
// else no need to keep checking the array is sorted correctly
break;
}
}
}
// Return the kth min
return mins[k-1];
}
/**
* Find the kth minimum value in the array subject to
* a given condition.
* Assumes that the condition is satisfied at least k
* times in the array (this is not checked in here)
*
* @param array
* @param k
* @param extraData
* @param extraCondition
* @return
* @throws Exception
*/
public static double kthMinSubjectTo(double[] array, int k, int[] extraData, int condition) throws Exception {
// Can't do a quickie for k==1 here since we're subject to
// checking the condition
if (array.length < k) {
throw new Exception(String.format("Length of array (%d) is less than k (%d)",
array.length, k));
}
// Hold the k minimum elements in strictly increasing order from 0 .. k-1
double[] mins = new double[k];
for (int i = 0; i < k; i++) {
mins[i] = Double.POSITIVE_INFINITY;
}
for (int t = 0; t < array.length; t++) {
if (extraData[t] != condition) {
continue;
}
// Assume that k is small enough that there is no point doing binary
// searches to find the best place to insert this element in the minimums (if required).
// First check if it's smaller than the current kth min:
if (array[t] < mins[k - 1]) {
mins[k - 1] = array[t];
// Now check if we need to reorder the array of minimums, keeping it sorted
for (int i = k - 2; i >= 0; i--) {
if (array[t] < mins[i]) {
// Swap array[t] along from mins[i+1]:
mins[i+1] = mins[i];
mins[i] = array[t];
continue;
}
// else no need to keep checking the array is sorted correctly
break;
}
}
}
// Return the kth min
return mins[k-1];
}
public static double minIgnoreIndex(double[] array, int indexToIgnore) {
// double min = 0.0;
double min;
if (indexToIgnore != 0) {
min = array[0];
} else {
min = array[1];
}
for (int i = 0; i < array.length; i++) {
if (indexToIgnore == i) {
continue;
}
if (Double.isNaN(min) || (array[i] < min)) {
min = array[i];
}
}
return min;
}
public static double minStartFromIndex(double[] array, int startFromIndex) {
// double min = 0.0;
double min = array[startFromIndex];
for (int i = startFromIndex; i < array.length; i++) {
if (Double.isNaN(min) || (array[i] < min)) {
min = array[i];
}
}
return min;
}
public static int min(int[] array) {
// int min = 0;
int min = array[0];
for (int i = 0; i < array.length; i++) {
if (array[i] < min) {
min = array[i];
}
}
return min;
}
/**
* Works out the minimum value in the matrix in a given column
*
* @param matrix
* @param column
* @return
*/
public static double min(double[][] matrix, int column) {
// double min = 0.0;
// Allow ArrayIndexOutOfBoundsException if matrix is size 0
double min = matrix[0][column];
for (int i = 1; i < matrix.length; i++) {
if (Double.isNaN(min) || (matrix[i][column] < min)) {
min = matrix[i][column];
}
}
return min;
}
/**
* Works out the minimum value in the matrix in a given column
*
* @param matrix
* @param column
* @return
*/
public static int min(int[][] matrix, int column) {
// double min = 0.0;
// Allow ArrayIndexOutOfBoundsException if matrix is size 0
int min = matrix[0][column];
for (int i = 1; i < matrix.length; i++) {
if (matrix[i][column] < min) {
min = matrix[i][column];
}
}
return min;
}
/**
* Works out the index of the minimum value in the matrix in a given column
*
* @param matrix
* @param column
* @return
*/
public static int minIndex(double[][] matrix, int column) {
// double min = 0.0;
// Allow ArrayIndexOutOfBoundsException if matrix is size 0
double min = matrix[0][column];
int minIndex = 0;
for (int i = 1; i < matrix.length; i++) {
if (Double.isNaN(min) || (matrix[i][column] < min)) {
min = matrix[i][column];
minIndex = i;
}
}
return minIndex;
}
/**
* Works out the index of the k minimum values in the matrix in a given column
*
* @param matrix
* @param column
* @param k
* @return
* @throws Exception
*/
public static int[] kMinIndices(double[][] matrix, int column, int k) throws Exception {
if (matrix.length < k) {
throw new Exception(String.format("Length of array (%d) is less than k (%d)",
matrix.length, k));
}
// Hold the k minimum elements in strictly increasing order from 0 .. k-1
double[] mins = new double[k];
int[] minIndices = new int[k];
if (k == 1) {
minIndices[0] = minIndex(matrix, column);
return minIndices;
}
for (int i = 0; i < k; i++) {
mins[i] = Double.POSITIVE_INFINITY;
minIndices[i] = -1;
}
for (int t = 0; t < matrix.length; t++) {
// Assume that k is small enough that there is no point doing binary
// searches to find the best place to insert this element in the minimums (if required).
// First check if it's smaller than the current kth min:
if (matrix[t][column] < mins[k - 1]) {
mins[k - 1] = matrix[t][column];
minIndices[k-1] = t;
// Now check if we need to reorder the array of minimums, keeping it sorted
for (int i = k - 2; i >= 0; i--) {
if (matrix[t][column] < mins[i]) {
// Swap array[t] along from mins[i+1]:
mins[i+1] = mins[i];
minIndices[i+1] = minIndices[i];
mins[i] = matrix[t][column];
minIndices[i] = t;
continue;
}
// else no need to keep checking the array is sorted correctly
break;
}
}
}
// Return the index of the kth min
return minIndices;
}
/**
* Works out the index of the k minimum values in the matrix in a given column
* subject to the extraData matching a given condition.
* We do not check whether there are k matches for the extraData to
* the condition here - the caller should check this themselves.
*
* @param matrix
* @param column
* @param k
* @param extraData
* @param condition
* @return
* @throws Exception
*/
public static int[] kMinIndicesSubjectTo(double[][] matrix, int column,
int k, int[] extraData, int condition) throws Exception {
if (matrix.length < k) {
throw new Exception(String.format("Length of array (%d) is less than k (%d)",
matrix.length, k));
}
// Hold the k minimum elements in strictly increasing order from 0 .. k-1
double[] mins = new double[k];
int[] minIndices = new int[k];
// no quick check for k==1 since we need to check the extra condition
for (int i = 0; i < k; i++) {
mins[i] = Double.POSITIVE_INFINITY;
minIndices[i] = -1;
}
for (int t = 0; t < matrix.length; t++) {
if (extraData[t] != condition) {
continue;
}
// Assume that k is small enough that there is no point doing binary
// searches to find the best place to insert this element in the minimums (if required).
// First check if it's smaller than the current kth min:
if (matrix[t][column] < mins[k - 1]) {
mins[k - 1] = matrix[t][column];
minIndices[k-1] = t;
// Now check if we need to reorder the array of minimums, keeping it sorted
for (int i = k - 2; i >= 0; i--) {
if (matrix[t][column] < mins[i]) {
// Swap array[t] along from mins[i+1]:
mins[i+1] = mins[i];
minIndices[i+1] = minIndices[i];
mins[i] = matrix[t][column];
minIndices[i] = t;
continue;
}
// else no need to keep checking the array is sorted correctly
break;
}
}
}
// Return the index of the kth min
return minIndices;
}
/**
* Mirrors the matrix in both coordinates
*
* @param matrix
* @return
*/
public static int[][] mirrorMatrixBothCoords(int[][] matrix) {
int rows = matrix.length;
int cols = matrix[0].length;
int[][] mirrored = new int[rows][cols];
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
mirrored[(rows - 1) - r][(cols - 1) - c] = matrix[r][c];
}
}
return mirrored;
}
/**
* Mirrors the matrix in both coordinates
*
* @param matrix
* @return
*/
public static double[][] mirrorMatrixBothCoords(double[][] matrix) {
int rows = matrix.length;
int cols = matrix[0].length;
double[][] mirrored = new double[rows][cols];
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
mirrored[(rows - 1) - r][(cols - 1) - c] = matrix[r][c];
}
}
return mirrored;
}
/**
* Moves the rows of the array up by upBy.
* Inserts zeros at the bottom
*
* @param matrix
* @param upBy
*/
public static void moveRowsUp(double[][] matrix, int upBy) {
int rows = matrix.length;
int cols = matrix[0].length;
for (int r = 0; r < rows - upBy; r++) {
for (int c = 0; c < cols; c++) {
matrix[r][c] = matrix[r + upBy][c];
}
}
for (int r = rows - upBy; r < rows; r++) {
for (int c = 0; c < cols; c++) {
matrix[r][c] = 0;
}
}
}
/**
* <p>Returns the covariance between the two arrays of data.</p>
* <p>See - <a href="http://mathworld.wolfram.com/Covariance.html">Mathworld</a>
* </p>
*
* @param x
* @param y
* @return the covariance
*/
public static double covariance(double[] x, double[] y) {
double c = 0;
double meanX = mean(x);
double meanY = mean(y);
for (int t = 0; t < x.length; t++) {
c += (x[t] - meanX)*(y[t]-meanY);
}
return c / (double) x.length;
}
/**
* <p>Returns the covariance between the first two columns of data.</p>
*
* @param data
* @return the covariance
* @see <a href="http://mathworld.wolfram.com/Covariance.html">Mathworld</a>
*/
public static double covarianceFirstTwoColumns(double[][] data) {
return covarianceTwoColumns(data, 0, 1);
}
/**
* <p>Returns the covariance between two columns of data in
* a multivariate array.</p>
* <p>See - <a href="http://mathworld.wolfram.com/Covariance.html">Mathworld</a>
* </p>
*
* @param data multivariate array of data; first index is time, second is
* variable number
* @param col1 variable number 1 to compute the covariance to
* @param col2 variable number 2 to compute the covariance to
* @return the covariance
*/
public static double covarianceTwoColumns(double[][] data, int col1, int col2) {
double mean1 = mean(data, col1);
double mean2 = mean(data, col2);
return covarianceTwoColumns(data, col1, col2, mean1, mean2);
}
/**
* <p>Returns the covariance between two columns of data in
* a multivariate array.</p>
* <p>See - <a href="http://mathworld.wolfram.com/Covariance.html">Mathworld</a>
* </p>
*
* @param data multivariate array of data; first index is time, second is
* variable number
* @param col1 variable number 1 to compute the covariance to
* @param col2 variable number 2 to compute the covariance to
* @param mean1 mean of variable 1
* @param mean2 mean of variable 2
* @return the covariance
*/
public static double covarianceTwoColumns(double[][] data, int col1, int col2,
double mean1, double mean2) {
double c = 0;
for (int t = 0; t < data.length; t++) {
c += (data[t][col1] - mean1)*(data[t][col2]-mean2);
}
return c / (double) data.length;
}
/**
* <p>Returns the covariance between two columns of data in
* two multivariate arrays.</p>
* <p>See - <a href="http://mathworld.wolfram.com/Covariance.html">Mathworld</a>
* </p>
*
* @param data1 first multivariate array of data; first index is time, second is
* variable number
* @param data2 second multivariate array of data; first index is time, second is
* variable number
* @param col1 variable number 1 to compute the covariance to
* @param col2 variable number 2 to compute the covariance to
* @param mean1 mean of variable 1
* @param mean2 mean of variable 2
* @return the covariance
*/
public static double covarianceTwoColumns(
double[][] data1, double[][] data2, int col1, int col2,
double mean1, double mean2) {
double c = 0;
for (int t = 0; t < data1.length; t++) {
c += (data1[t][col1] - mean1)*(data2[t][col2]-mean2);
}
return c / (double) data1.length;
}
/**
* Compute the covariance matrix between all column pairs (variables) in the
* multivariate data set
*
* @param data multivariate array of data; first index is time, second is
* variable number
* @return covariance matrix
*/
public static double[][] covarianceMatrix(double[][] data) {
return covarianceMatrix(data, means(data));
}
/**
* Compute the covariance matrix between all column pairs (variables) in the
* multivariate data set
*
* @param data multivariate array of data; first index is time, second is
* variable number
* @param means the mean of each variable (column) in the data
* @return covariance matrix
*/
public static double[][] covarianceMatrix(double[][] data, double[] means) {
int numVariables = data[0].length;
double[][] covariances = new double[numVariables][numVariables];
for (int r = 0; r < numVariables; r++) {
for (int c = r; c < numVariables; c++) {
// Compute the covariance between variable r and c:
covariances[r][c] = covarianceTwoColumns(data, r, c,
means[r], means[c]);
// And of course this is symmetric between c and r:
covariances[c][r] = covariances[r][c];
}
}
return covariances;
}
/**
* Compute the covariance matrix between all column pairs (variables) in the
* multivariate data set, which consists of two separate
* multivariate vectors.
*
* @param data1 multivariate array of data; first index is time, second is
* variable number
* @param data2 a second multivariate array of data, which can be though
* of as extensions of rows of the first.
* @return covariance matrix, where the columns of dat1 are numbered
* first, and the columns of data2 after that.
*/
public static double[][] covarianceMatrix(
double[][] data1, double[][] data2) {
return covarianceMatrix(data1, data2, 0);
}
/**
* Compute the covariance matrix between all column pairs (variables) in the
* multivariate data set, which consists of two separate
* multivariate vectors.
*
* @param data1 multivariate array of data; first index is time, second is
* variable number
* @param data2 a second multivariate array of data, which can be though
* of as extensions of rows of the first.
* @param delay compute the lagged covariance of the given delay from
* data1 to data2 (assumes delay >= 0); i.e. compute correlation
* between data1[x] and data2[x+delay].
* @return covariance matrix, where the columns of dat1 are numbered
* first, and the columns of data2 after that.
*/
public static double[][] covarianceMatrix(
double[][] data1, double[][] data2, int delay) {
if (delay > 0) {
// Trim out the last delay rows of data1, and the
// first delay rows of data2:
double[][] data1Trimmed = new double[data1.length - delay][];
double[][] data2Trimmed = new double[data2.length - delay][];
for (int x = 0; x < data1.length - delay; x++) {
data1Trimmed[x] = data1[x];
data2Trimmed[x] = data2[x + delay];
}
// Just overwrite our local copy of the pointers to the
// original data
data1 = data1Trimmed;
data2 = data2Trimmed;
}
int numVariables1 = data1[0].length;
int numVariables2 = data2[0].length;
int numVariables = numVariables1 + numVariables2;
double[][] covariances = new double[numVariables][numVariables];
// Compute means of each variable once up front to save time
double[] means1 = new double[numVariables1];
double[] means2 = new double[numVariables2];
for (int r = 0; r < numVariables1; r++) {
means1[r] = mean(data1, r);
}
for (int r = 0; r < numVariables2; r++) {
means2[r] = mean(data2, r);
}
// Now compute the covariances:
for (int r = 0; r < numVariables1; r++) {
// Compute the covariances internal to data1:
for (int c = r; c < numVariables1; c++) {
// Compute the covariance between variable r and c:
covariances[r][c] = covarianceTwoColumns(data1, r, c,
means1[r], means1[c]);
// And of course this is symmetric between c and r:
covariances[c][r] = covariances[r][c];
}
// Compute the covariances between data1 and data2
for (int c = 0; c < numVariables2; c++) {
// Compute the covariance between variable r and c:
covariances[r][numVariables1 + c] =
covarianceTwoColumns(data1, data2,
r, c, means1[r], means2[c]);
// And of course this is symmetric between c and r:
covariances[numVariables1 + c][r] =
covariances[r][numVariables1 + c];
}
}
// Now compute the covariances internal to data2:
for (int r = 0; r < numVariables2; r++) {
for (int c = r; c < numVariables2; c++) {
// Compute the covariance between variable r and c:
covariances[numVariables1 + r][numVariables1 + c] =
covarianceTwoColumns(data2, r, c,
means2[r], means2[c]);
// And of course this is symmetric between c and r:
covariances[numVariables1 + c][numVariables1 + r] =
covariances[numVariables1 + r][numVariables1 + c];
}
}
return covariances;
}
/**
* <p>Returns the correlation between the two arrays of data.</p>
* <p>The arrays are asssumed to have the same lengths</p>
* <p>See - <a href="http://en.wikipedia.org/wiki/Correlation">Wikipedia</a>
* </p>
*
* @param x
* @param y
* @return the correlation
*/
public static double correlation(double[] x, double[] y) {
return correlation(x, y, x.length);
}
/**
* <p>Returns the correlation between the two arrays of data.</p>
* <p>See - <a href="http://en.wikipedia.org/wiki/Correlation">Wikipedia</a>
* </p>
*
* @param x
* @param y
* @param dataLength - number of terms in each vector to consider (we look at the first dataLength terms).
* Precondition: dataLength is less than min(x.length, y.length)
* @return the correlation
*/
public static double correlation(double[] x, double[] y, int dataLength) {
// return covariance(x, y) / stdDev(x) / stdDev(y);
// Save some code time by reusing the code from inside covariance:
double c = 0;
double meanX = mean(x, 0, dataLength);
double meanY = mean(y, 0, dataLength);
for (int t = 0; t < dataLength; t++) {
c += (x[t] - meanX)*(y[t]-meanY);
}
double covariance = c / (double) (dataLength - 1);
return covariance / stdDev(x, meanX, dataLength) / stdDev(y, meanY, dataLength);
}
/**
* <p>Returns the correlation between the two arrays of data,
* ignoring any Nan values</p>
* <p>See - <a href="http://en.wikipedia.org/wiki/Correlation">Wikipedia</a>
* </p>
*
* @param x
* @param y
* @param dataLength - number of terms in each vector to consider (we look at the first dataLength terms).
* Precondition: dataLength is less than min(x.length, y.length)
* @return the covariance
*/
public static double correlationIgnoreNans(double[] x, double[] y, int dataLength) {
// return covariance(x, y) / stdDev(x) / stdDev(y);
// Save some code time by reusing the code from inside covariance:
double c = 0;
double meanX = 0;
double meanY = 0;
int count = 0;
for (int i = 0; i < dataLength; i++) {
if ((!Double.isNaN(x[i])) && (!Double.isNaN(y[i]))) {
// Only add the values in if they are not NaN
meanX += x[i];
meanY += y[i];
count++;
}
}
// Adjust for the values we've skipped:
meanX = meanX / count;
meanY = meanY / count;
for (int t = 0; t < dataLength; t++) {
if ((!Double.isNaN(x[t])) && (!Double.isNaN(y[t]))) {
// Only add the product in if it is not NaN
c += (x[t] - meanX)*(y[t]-meanY);
}
}
double covariance = c / (double) (count - 1);
// Now work out the std devs of each:
double sumSqsX = 0.0;
double sumSqsY = 0.0;
for (int m = 0; m < dataLength; m++) {
if ((!Double.isNaN(x[m])) && (!Double.isNaN(y[m]))) {
// Ignore if one is NaN
sumSqsX += (x[m] - meanX) * (x[m] - meanX);
sumSqsY += (y[m] - meanY) * (y[m] - meanY);
}
}
double stdX = sumSqsX / (double) (count - 1);
stdX = Math.sqrt(stdX);
double stdY = sumSqsY / (double) (count - 1);
stdY = Math.sqrt(stdY);
return covariance / stdX / stdY;
}
/**
* Initialises all values in the matrix to the given value
*
* @param matrix
* @param value
*/
public static void fill(int[] matrix, int value) {
int rows = matrix.length;
for (int r = 0; r < rows; r++) {
matrix[r] = value;
}
}
/**
* Initialises all values in the matrix to the given value
*
* @param matrix
* @param value
* @param offset where in the array to start from
* @param length length in the array to fill
*/
public static void fill(int[] matrix, int value, int offset, int length) {
for (int r = offset; r < offset + length; r++) {
matrix[r] = value;
}
}
/**
* Initialises all values in the matrix to the given value
*
* @param matrix
* @param value
*/
public static void fill(int[][] matrix, int value) {
int rows = matrix.length;
for (int r = 0; r < rows; r++) {
int cols = matrix[r].length;
for (int c = 0; c < cols; c++) {
matrix[r][c] = value;
}
}
}
/**
* Initialises all values in the matrix to the given value
*
* @param matrix
* @param value
*/
public static void fill(int[][][] matrix, int value) {
int rows = matrix.length;
for (int r = 0; r < rows; r++) {
int cols = matrix[r].length;
for (int c = 0; c < cols; c++) {
int height = matrix[r][c].length;
for (int h = 0; h < height; h++) {
matrix[r][c][h] = value;
}
}
}
}
/**
* Initialises all values in the matrix to the given value
*
* @param matrix
* @param value
*/
public static void fill(int[][][][] matrix, int value) {
int rows = matrix.length;
for (int r = 0; r < rows; r++) {
int cols = matrix[r].length;
for (int c = 0; c < cols; c++) {
int height = matrix[r][c].length;
for (int h = 0; h < height; h++) {
int depth = matrix[r][c][h].length;
for (int d = 0; d < depth; d++) {
matrix[r][c][h][d] = value;
}
}
}
}
}
/**
* Initialises all values in the matrix to the given value
*
* @param matrix
* @param value
*/
public static void fill(long[] matrix, long value) {
int rows = matrix.length;
for (int r = 0; r < rows; r++) {
matrix[r] = value;
}
}
/**
* Initialises all values in the matrix to the given value
*
* @param matrix
* @param value
*/
public static void fill(long[][] matrix, long value) {
int rows = matrix.length;
for (int r = 0; r < rows; r++) {
int cols = matrix[r].length;
for (int c = 0; c < cols; c++) {
matrix[r][c] = value;
}
}
}
/**
* Initialises all values in the matrix to the given value
*
* @param matrix
* @param value
*/
public static void fill(long[][][] matrix, long value) {
int rows = matrix.length;
for (int r = 0; r < rows; r++) {
int cols = matrix[r].length;
for (int c = 0; c < cols; c++) {
int height = matrix[r][c].length;
for (int h = 0; h < height; h++) {
matrix[r][c][h] = value;
}
}
}
}
/**
* Initialises all values in the matrix to the given value
*
* @param matrix
* @param value
*/
public static void fill(long[][][][] matrix, long value) {
int rows = matrix.length;
for (int r = 0; r < rows; r++) {
int cols = matrix[r].length;
for (int c = 0; c < cols; c++) {
int height = matrix[r][c].length;
for (int h = 0; h < height; h++) {
int depth = matrix[r][c][h].length;
for (int d = 0; d < depth; d++) {
matrix[r][c][h][d] = value;
}
}
}
}
}
public static double[][] transpose(double[][] matrix) {
double[][] newMatrix = new double[matrix[0].length][matrix.length];
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
newMatrix[j][i] = matrix[i][j];
}
}
return newMatrix;
}
public static int[][] transpose(int[][] matrix) {
int[][] newMatrix = new int[matrix[0].length][matrix.length];
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
newMatrix[j][i] = matrix[i][j];
}
}
return newMatrix;
}
/**
* Converts an int array to a double array
*
* @param input
* @return
*/
public static double[][] convertMatrix(int[][] input) {
double[][] outputArray = new double[input.length][];
for (int i = 0; i < input.length; i++) {
outputArray[i] = new double[input[i].length];
for (int j = 0; j < input[i].length; j++) {
outputArray[i][j] = input[i][j];
}
}
return outputArray;
}
/**
* Converts a double array to an int array
*
* @param input
* @param valueOffset value to be subtracted from each value
* @return
*/
public static int[] convertMatrix(double[] input, int valueOffset) {
int[] outputArray = new int[input.length];
for (int i = 0; i < input.length; i++) {
outputArray[i] = (int) (input[i]) - valueOffset;
}
return outputArray;
}
/**
* Converts a double array to an int array
*
* @param input
* @return
*/
public static int[] convertMatrix(double[] input) {
return convertMatrix(input, 0);
}
/**
* <p>Returns the determinant of the input matrix.
* </p>
*
* <p>This uses a fairly naive calculation - it will work for small sized
* matrices but will not be efficient enough for larger sizes.</p>
*
* @param matrix
* @return determinant of matrix
* @throws Exception if supplied a non-square matrix
*/
public static double determinant(double[][] matrix) throws Exception {
int rows = matrix.length;
for (int r = 0; r < rows; r++) {
if (matrix[r].length != rows) {
throw new Exception("Cannot compute the determinant of a non-square matrix");
}
}
return recursiveDeterminant(matrix);
}
/**
* <p>Private method to compute the determinant recursively.
* {@link determinant()} calls this after checking the matrix dimensions. <br/>
* @see {@link http://mathworld.wolfram.com/Determinant.html}
* </p>
*
* @param matrix
* @return
*/
private static double recursiveDeterminant(double[][] matrix) {
int rows = matrix.length;
double result = 0;
// Base cases:
if (rows == 1) {
return matrix[0][0];
}
if (rows == 2) {
return (matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0]);
}
// Recursive case
int multiplier = 1;
for(int col = 0; col < rows; col++) {
// Construct the next sub-matrix to compute the determinant of
double minor[][] = copyMatrixEliminateRowAndColumn(matrix, 0, col);
result += (double) multiplier * matrix[0][col] * recursiveDeterminant(minor);
multiplier *= -1;
}
return result;
}
/**
* <p>Make the Cholesky decomposition L of a given input matrix A,
* where:
* <ol>
* <li>A is symmetric and positive definite (has full rank)</li>
* <li>A = L L^T (L^T is the transpose of L - here A has real
* entries only, though a Cholesky decomposition is possible
* with complex entries)</li>
* <li>L is a lower triangular matrix</li>
* </ol>
* We perform the decomposition using the CholeskyBanachiewicz
* algorithm, computing L from the top left, row by row (see wikipedia)
* </p>
*
* <p>This method has been adapted from the JAMA project (public domain software)
* </p>
*
* @param A input matrix
* @return L
* @throws Exception when the matrix A is not symmetric, or
* not positive definite
* @see {@link en.wikipedia.org/wiki/Cholesky_decomposition}
* @see {@link http://mathworld.wolfram.com/CholeskyDecomposition.html}
* @see {@link http://en.wikipedia.org/wiki/Positive-definite_matrix}
* @see {@link http://math.nist.gov/javanumerics/jama/}
*/
public static double[][] CholeskyDecomposition(double[][] A) throws Exception {
int n = A.length;
double[][] L = new double[n][n];
// Loop over all rows:
for (int j = 0; j < n; j++) {
// Check length of row keeps this a square matrix:
if (A[j].length != n) {
throw new Exception("CholeskyDecomposition is only performed on square matrices");
}
double d = 0.0;
for (int k = 0; k < j; k++) {
double s = 0.0;
for (int i = 0; i < k; i++) {
s += L[k][i]*L[j][i];
}
L[j][k] = s = (A[j][k] - s)/L[k][k];
d = d + s*s;
// Check that these matrix entries remain symmetric:
if (A[k][j] != A[j][k]) {
throw new Exception("CholeskyDecomposition is only performed on symmetric matrices");
}
}
d = A[j][j] - d;
// Check the positive definite condition:
if (d <= 0.0) {
throw new Exception("CholeskyDecomposition is only performed on positive-definite matrices");
}
L[j][j] = Math.sqrt(d);
// Set the upper triangular part to all zeros:
for (int k = j+1; k < n; k++) {
L[j][k] = 0.0;
}
}
return L;
}
/**
* Compute matrix inversion of a symmetric, positive definite matrix
* by using the Cholesky Decomposition L of the matrix A.
* Since A = L L^T, then A^-1 = (L^T)^-1 L^-1, and the inverses
* of
*
* @param A matrix to be inverted
* @return the inverse of A
* @throws Exception when the matrix is not symmetric or positive definite
*/
public static double[][] invertSymmPosDefMatrix(double[][] A) throws Exception {
// First do the Cholesky Decomposition:
double[][] L = CholeskyDecomposition(A);
return solveViaCholeskyResult(L, identityMatrix(A.length));
}
// TODO implement solve for identity matrix
/**
* <p>Solve A*X = B, where A = L*L^T via Cholesky decomposition.
* </p>
*
* <p>This method has been adapted from the JAMA project (public domain software)
* </p>
*
* @param L Cholesky decomposition of the matrix A
* @param B matrix with as many rows as A and any number of columns
* @return X so that A*X = B
* @see {@link http://math.nist.gov/javanumerics/jama/}
* @see #CholeskyDecomposition(double[][])
*/
public static double[][] solveViaCholeskyResult(double[][] L, double[][] B) {
int aRows = L.length;
if (aRows != B.length) {
throw new IllegalArgumentException("Matrix row dimensions must agree.");
}
// Copy B matrix
double[][] X = MatrixUtils.arrayCopy(B);
int bCols = B[0].length;
// Solve L*Y = B;
for (int k = 0; k < aRows; k++) {
for (int j = 0; j < bCols; j++) {
for (int i = 0; i < k ; i++) {
X[k][j] -= X[i][j]*L[k][i];
}
X[k][j] /= L[k][k];
}
}
// Solve L'*X = Y;
for (int k = aRows-1; k >= 0; k--) {
for (int j = 0; j < bCols; j++) {
for (int i = k+1; i < aRows; i++) {
X[k][j] -= X[i][j]*L[i][k];
}
X[k][j] /= L[k][k];
}
}
return X;
}
public static void printMatrix(PrintStream out, double[][] matrix) {
for (int r = 0; r < matrix.length; r++) {
for (int c = 0; c < matrix[r].length; c++) {
out.print(matrix[r][c] + " ");
}
out.println();
}
}
public static void printMatrix(PrintStream out, int[][] matrix) {
for (int r = 0; r < matrix.length; r++) {
for (int c = 0; c < matrix[r].length; c++) {
out.print(matrix[r][c] + " ");
}
out.println();
}
}
public static void printArray(PrintStream out, double[] array) {
for (int r = 0; r < array.length; r++) {
out.print(array[r] + " ");
}
out.println();
}
public static void printArray(PrintStream out, int[] array) {
for (int r = 0; r < array.length; r++) {
out.print(array[r] + " ");
}
out.println();
}
/**
* Discretizes using even bin sizes
*
* @param data
* @param base
* @return
*/
public static int[] discretise(double data[], int base) {
int[] discretised = new int[data.length];
double min = min(data);
double max = max(data);
double binInterval = (max - min) / base;
for (int t = 0; t < data.length; t++) {
discretised[t] = (int) ((data[t] - min) / binInterval);
if (discretised[t] == base) {
// This occurs for the maximum value; put it in the largest bin (base - 1)
discretised[t]--;
}
}
return discretised;
}
/**
* Discretizes each column of the data independently,
* using a maximum entropy partitioning
*
* @param data
* @param base
* @return
*/
public static int[][] discretiseMaxEntropy(double data[][], int base){
int lastCol = data[0].length;
int lastRow = data.length;
int[][] newData = new int[lastRow][lastCol];
for(int j=0;j<lastCol;j++){
double[] tempData = new double[lastRow];
for (int i=0;i<lastRow;i++){
tempData[i] = data[i][j];
}
Arrays.sort(tempData);
int compartmentSize;
double[] cutOffValues = new double[base];
for(int i=0;i<base;i++){
compartmentSize = (int)((double)(i+1)*(double)(lastRow)/(double)base)-1;
// System.out.println(compartmentSize);
cutOffValues[i]=tempData[compartmentSize];
}
for (int i=0;i<lastRow;i++){
for(int m=0;m<base;m++){
if (data[i][j] <= cutOffValues[m]){
newData[i][j] = m;
m = base;
}
}
}
}
return newData;
}
/**
* Take the logical AND of all variables in each row
*
* @param data
* @return
*/
public static boolean[] andRows(boolean[][] data) {
boolean[] result = new boolean[data.length];
for (int i = 0; i < data.length; i++) {
result[i] = true;
for (int j = 0; j < data[i].length; j++) {
result[i] &= data[i][j];
}
}
return result;
}
/**
* Take the logical AND of selected variables in each row
*
* @param data
* @param columns which variables to take the AND over
* @return
*/
public static boolean[] andRowsOverSelectedColumns(boolean[][] data, int[] columns) {
boolean[] result = new boolean[data.length];
for (int i = 0; i < data.length; i++) {
result[i] = true;
for (int c = 0; c < columns.length; c++) {
result[i] &= data[i][columns[c]];
}
}
return result;
}
/**
* Convert a double array to an int array.
* This is designed specifically for use of the toolkit in Octave
* where all native arrays are considered as doubles for Java,
* and octave-java can't properly identify valid method signatures
* unless the arrays are converted to int arrays first.
*
* @param array
* @return
*/
public static int[] doubleToIntArray(double[] array) {
if (array == null) {
return null;
}
int[] intArray = new int[array.length];
for (int i = 0; i < array.length; i++) {
intArray[i] = (int) array[i];
}
return intArray;
}
/**
* Convert a 2D double array to an int array.
* This is designed specifically for use of the toolkit in Octave
* where all native arrays are considered as doubles for Java,
* and octave-java can't properly identify valid method signatures
* unless the arrays are converted to int arrays first.
*
* @param array
* @return
*/
public static int[][] doubleToIntArray(double[][] array) {
if (array == null) {
return null;
}
int[][] intArray = new int[array.length][];
for (int i = 0; i < array.length; i++) {
if (array[i] == null) {
intArray[i] = null;
} else {
intArray[i] = new int[array[i].length];
for (int j = 0; j < array[i].length; j++) {
intArray[i][j] = (int) array[i][j];
}
}
}
return intArray;
}
}