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

2757 lines
77 KiB
Java
Executable File

package infodynamics.utils;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.Vector;
/**
* Utilities for computations on matrices.
* All multidimensional matrices are assumed to have consistent lengths in each dimension
*
* @author Joseph Lizier, joseph.lizier at gmail.com
*
*/
public class MatrixUtils {
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;
}
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 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
* @param b
* @return
*/
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;
}
/**
* 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 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];
}
}
/**
*
* @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 columns of data.</p>
* <p>See - <a href="http://mathworld.wolfram.com/Covariance.html">Mathworld</a>
* </p>
*
* @param data
* @return the covariance
*/
public static double covariance(double[][] data) {
double c = 0;
double mean0 = mean(data, 0);
double mean1 = mean(data, 1);
for (int t = 0; t < data.length; t++) {
c += (data[t][0] - mean0)*(data[t][1]-mean1);
}
return c / (double) data.length;
}
/**
* <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 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 covariance
*/
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 covariance
*/
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>
*
* @param matrix
* @return determinant of 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 function to compute the determinant recursively.
* determinant() calls this after checking the matrix dimensions. <br/>
* See - 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;
}
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;
}
}