/*
This file is part of the software framework JStatCom,
a library for building applications for data based analysis.
Copyright (C) 2000-2005 Markus Kraetzig
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA
*/
package com.jstatcom.util;
import java.util.Arrays;
/**
* A collection of static methods that are related to arrays of numbers. This
* set of methods contains mainly general array manipulation routines as well as
* some light-weight mathematical functions.
*
* All methods implemented do not modify the original input. Results are always
* newly created arrays. If the input is somehow wrong an appropriate exception
* is thrown. All methods require that the input arrays have the same number of
* elements in each row.
*
* @author Markus Kraetzig
*/
public final class UMatrix {
/**
* Not to be invoked.
*/
private UMatrix() {
}
/**
* Adds the scalar toAdd to a copy of the array
* arg.
*
* @param arg
* the original array
* @param toAdd
* the number to add to all elements of arg
* @return a new array with toAdd added; if
* toAdd is NaN, then the resulting
* array will contain only NaN's
* @throws IllegalArgumentException
* if (arg == null) or if rows of argument have
* different lengths
*/
public static double[][] add(double[][] arg, double toAdd) {
if (arg == null)
throw new IllegalArgumentException("Array argument was null.");
checkRowLengths(arg);
double[][] m = cloneDoubleArray(arg);
for (int i = 0; i < m.length; i++)
for (int j = 0; j < m[0].length; j++)
m[i][j] += toAdd;
return m;
}
/**
* Appends toAppend to the columns of orig and
* returns the new merged array. This only works, if orig and
* toAppend have the same number of rows.
*
* @param orig
* the array to append the columns of toAppend to
* @param toAppend
* the arrays to be appended to orig
* @return a new array orig~toAppend
* @throws IllegalArgumentException
* if (orig.length != toAppend.length) or
* if (orig == null || toAppend == null) or if
* rows of an argument have different lengths
*/
public static double[][] appendDoubleCols(double[][] orig,
double[][] toAppend) {
if (orig == null || toAppend == null)
throw new IllegalArgumentException("Argument was null.");
checkRowLengths(orig);
checkRowLengths(toAppend);
if (orig.length != toAppend.length)
throw new IllegalArgumentException(
"Different number of rows (orig:" + orig.length
+ ", toAppend:" + toAppend.length + ").");
int origCols = orig[0].length;
int toAppendCols = toAppend[0].length;
double[][] newMat = new double[orig.length][origCols + toAppendCols];
for (int i = 0; i < newMat.length; i++) {
System.arraycopy(orig[i], 0, newMat[i], 0, origCols);
System.arraycopy(toAppend[i], 0, newMat[i], origCols, toAppendCols);
}
return newMat;
}
/**
* Appends toAppend to the rows of orig and
* returns the new merged array. This only works, if orig and
* toAppend have the same number of columns.
*
* @param orig
* the array to append the rows of toAppend to
* @param toAppend
* the arrays to be appended to orig
* @return a new array orig|toAppend
* @throws IllegalArgumentException
* if (orig[0].length != toAppend[0].length) or
* if (orig == null || toAppend == null) or if
* rows of an argument have different lengths
*/
public static double[][] appendDoubleRows(double[][] orig,
double[][] toAppend) {
if (orig == null || toAppend == null)
throw new IllegalArgumentException("Argument was null.");
checkRowLengths(orig);
checkRowLengths(toAppend);
if (orig.length == 0)
return cloneDoubleArray(toAppend);
if (toAppend.length == 0)
return cloneDoubleArray(orig);
if (orig[0].length != toAppend[0].length)
throw new IllegalArgumentException(
"Different number of columns for appendDoubleRows (orig:"
+ orig[0].length + ", toAppend:"
+ toAppend[0].length + ").");
int origRows = orig.length;
int toAppendRows = toAppend.length;
double[][] newMat = new double[origRows + toAppendRows][];
for (int i = 0; i < origRows; i++) {
int l = orig[i].length;
double[] arr = new double[l];
System.arraycopy(orig[i], 0, arr, 0, l);
newMat[i] = arr;
}
for (int i = 0; i < toAppendRows; i++) {
int l = toAppend[i].length;
double[] arr = new double[l];
System.arraycopy(toAppend[i], 0, arr, 0, l);
newMat[origRows + i] = arr;
}
return newMat;
}
/**
* Checks whether all rows of arg have the same number of
* columns. If the check fails, an exception is thrown. This is to enforce
* the mathematical definition of a matrix.
*
* @param arg
* the double[][] to check
* @throws IllegalArgumentException
* if the rows of arg have different lengths
*/
public static void checkRowLengths(double[][] arg) {
if (arg != null && arg.length > 0) {
int n = arg[0].length;
for (int i = 0; i < arg.length; i++)
if (arg[i].length != n)
throw new IllegalArgumentException(
"Rows have different lengths.");
}
}
/**
* Checks whether all rows of arg have the same number of
* columns. If the check fails, an exception is thrown. This is to enforce
* the mathematical definition of a matrix.
*
* @param arg
* the int[][] to check
* @throws IllegalArgumentException
* if the rows of arg have different lengths
*/
public static void checkRowLengths(int[][] arg) {
if (arg != null && arg.length > 0) {
int n = arg[0].length;
for (int i = 0; i < arg.length; i++)
if (arg[i].length != n)
throw new IllegalArgumentException(
"Rows have different lengths.");
}
}
/**
* Gets an identical copy of x.
*
* @return the cloned array or
*
* null if (x == null)
* -
*
new double[0][0] if (x.length == 0 || x[0].length == 0)
*
*/
public static double[][] cloneDoubleArray(double[][] x) {
if (x == null)
return null;
if (x.length == 0 || x[0].length == 0)
return new double[0][0];
double[][] y = new double[x.length][];
for (int i = 0; i < x.length; i++) {
double[] x_i = x[i];
int l = x_i.length;
double[] arr = new double[x[i].length];
System.arraycopy(x_i, 0, arr, 0, l);
y[i] = arr;
}
return y;
}
/**
* Gets an identical copy of x.
*
* @return the cloned array or
*
* null if (x == null)
* -
*
new int[0][0] if (x.length == 0 || x[0].length == 0)
*
*/
public static int[][] cloneIntArray(int[][] x) {
if (x == null)
return null;
if (x.length == 0 || x[0].length == 0)
return new int[0][0];
int[][] y = new int[x.length][];
for (int i = 0; i < x.length; i++) {
int[] x_i = x[i];
int l = x_i.length;
int[] arr = new int[x[i].length];
System.arraycopy(x_i, 0, arr, 0, l);
y[i] = arr;
}
return y;
}
/**
* Compares two double arrays and returns true. if the
* dimensions are the same and all elements are equal. If two elements of
* arg1 and arg2 are Double.NaN,
* they are considered to be equal, whereas arg1, arg2 are
* considered to be unequal if at least one of them is null.
*
* @param arg1
* double array to compare
* @param arg2
* double array to compare
* @return true if dimensions and all elements are equal or
* if arg1, arg2 have both at least one dimension of
* zero,
* false otherwise
* @throws IllegalArgumentException
* if rows of an argument have different lengths
*/
public static boolean compareDoubleArrays(double[][] arg1, double[][] arg2) {
if (arg1 == null || arg2 == null)
return false;
checkRowLengths(arg1);
checkRowLengths(arg2);
// Tests whether at least one dimension is 0 in both arguments.
if ((arg1.length == 0 || arg1[0].length == 0)
&& (arg2.length == 0 || arg2[0].length == 0))
return true;
if (arg1.length != arg2.length || arg1[0].length != arg2[0].length)
return false;
for (int i = 0; i < arg1.length; i++)
for (int j = 0; j < arg1[0].length; j++)
if (Double.doubleToLongBits(arg1[i][j]) != Double
.doubleToLongBits(arg2[i][j])
&& !(arg1[i][j] == 0 && arg2[i][j] == 0))
return false;
return true;
}
/**
* Compares two int arrays and returns true. if the
* dimensions are the same and all elements are equal.
*
* @param arg1
* int array to compare
* @param arg2
* int array to compare
* @return true if dimensions and all elements are equal or
* if arg1, arg2 have both at least one dimension of
* zero,
* false otherwise or if at least one argument is
* null
* @throws IllegalArgumentException
* if rows of an argument have different lengths
*/
public static boolean compareIntArrays(int[][] arg1, int[][] arg2) {
if (arg1 == null || arg2 == null)
return false;
checkRowLengths(arg1);
checkRowLengths(arg2);
// Tests whether at least one dimension is 0 in both arguments.
if ((arg1.length == 0 || arg1[0].length == 0)
&& (arg2.length == 0 || arg2[0].length == 0))
return true;
if (arg1.length != arg2.length || arg1[0].length != arg2[0].length)
return false;
for (int i = 0; i < arg1.length; i++)
for (int j = 0; j < arg1[0].length; j++)
if (arg1[i][j] != arg2[i][j])
return false;
return true;
}
/**
* Deletes the col colIndex from arg.
*
* @param arg
* the array to delete the col from
* @param colIndex
* index of the col
* @return new double array with the deleted col or
* new double[0][0] if the array would be empty
* afterwards
* @throws IllegalArgumentException
* if (arg == null) or
* if (colIndex < 0 || arg[0].length < colIndex)
* or if (arg.length == 0 || arg[0].length == 0)
* or if rows of argument have different lengths
*/
public static double[][] delCol(double[][] arg, int colIndex) {
if (arg == null)
throw new IllegalArgumentException("Argument was null.");
if (arg.length == 0 || arg[0].length == 0)
throw new IllegalArgumentException("Argument was empty.");
checkRowLengths(arg);
if (colIndex < 0 || arg[0].length <= colIndex)
throw new IllegalArgumentException("Bad column index: " + colIndex
+ ".");
if (arg[0].length - 1 == 0)
return new double[0][0];
double[][] newArray = new double[arg.length][arg[0].length - 1];
for (int i = 0; i < arg.length; i++)
for (int j = 0, k = 0; j < arg[0].length; j++) {
if (j != colIndex)
newArray[i][k++] = arg[i][j];
}
return newArray;
}
/**
* Deletes columns of arg that have been selected by
* index and returns a new array with the remaining columns.
* A column is selected for deletion if the corresponding index entry is
* nonzero.
*
* @param arg
* the array to delete columns from
* @param index
* the arg[0].length x 1 int array
*
* @return a new array with the selected columns deleted or
* new double[0][0] if all columns where selected for
* deletion or if arg.length == 0
*
* @throws IllegalArgumentException
* if (arg == null || index == null) or
* if ((arg.length == 0 || arg[0].length == 0) && index.length > 0)
* or if (arg.length == 0 || arg[0].length == 0)
* or if rows of argument have different lengths
*/
public static double[][] delColsIf(double[][] arg, int... index) {
if (arg == null || index == null)
throw new IllegalArgumentException("Argument was null.");
if (index.length == 0 && (arg.length == 0 || arg[0].length == 0))
return new double[0][0];
if (arg.length == 0 || arg[0].length == 0)
throw new IllegalArgumentException(
"Argument was empty but not index.");
checkRowLengths(arg);
return selColsIf(arg, flipIndex(index));
}
/**
* Deletes the row rowIndex from arg.
*
* @param arg
* the array to delete the row from
* @param rowIndex
* index of the row
* @return new double array with the deleted row or
* new double[0][0] if the array would be empty
* afterwards
* @throws IllegalArgumentException
* if (arg == null) or
* if (rowIndex < 0 || arg.length < rowIndex)
* or if (arg.length == 0 || arg[0].length == 0)
* or if rows of argument have different lengths
*/
public static double[][] delRow(double[][] arg, int rowIndex) {
if (arg == null)
throw new IllegalArgumentException("Argument was null.");
if (arg.length == 0 || arg[0].length == 0)
throw new IllegalArgumentException("Argument was empty.");
checkRowLengths(arg);
if (rowIndex < 0 || arg.length <= rowIndex)
throw new IllegalArgumentException("Bad row index: " + rowIndex
+ ".");
if (arg.length - 1 == 0 || arg[0].length == 0)
return new double[0][0];
double[][] newArray = new double[arg.length - 1][];
for (int i = 0, k = 0; i < arg.length; i++)
if (i != rowIndex) {
double[] arg_i = arg[i];
int l = arg_i.length;
double[] arr = new double[l];
System.arraycopy(arg_i, 0, arr, 0, l);
newArray[k++] = arr;
}
return newArray;
}
/**
* Deletes rows of arg that have been selected by
* index and returns a new array with the remaining rows. A
* row is selected for deletion if the corresponding index entry is nonzero.
*
* @param arg
* the array to delete rows from
* @param index
* the arg[0].length x 1 int array
*
* @return a new array with the selected rows deleted or
* new double[0][0] if all rows where selected for
* deletion or if arg.length == 0
*
* @throws IllegalArgumentException
* if (arg == null || index == null) or
* if ((arg.length == 0 || arg[0].length == 0) && index.length > 0)
* or if (arg.length == 0 || arg[0].length == 0)
* or if rows of arg have different lengths
*/
public static double[][] delRowsIf(double[][] arg, int... index) {
if (arg == null || index == null)
throw new IllegalArgumentException("Argument was null.");
if (index.length == 0 && (arg.length == 0 || arg[0].length == 0))
return new double[0][0];
if (arg.length == 0 || arg[0].length == 0)
throw new IllegalArgumentException("Argument was empty.");
checkRowLengths(arg);
return selRowsIf(arg, flipIndex(index));
}
/**
* Gets an identity matrix of dimension dim.
*
* @param dim
* the dimension of the quadratic matrix to create
* @return the created identity matrix
* @throws IllegalArgumentException
* if (dim < 0)
*/
public static double[][] eye(int dim) {
if (dim < 0)
throw new IllegalArgumentException("Dimension argument " + dim
+ " < 0.");
double[][] d = new double[dim][dim];
for (int i = 0; i < dim; i++)
d[i][i] = 1;
return d;
}
/**
* Gets a new array with all zero elements of arg set to one
* and all nonzero elements set to zero. If arg is a
* selection index then this just reverses the selection.
*
* @param arg
* the original index, usually with 1's and 0's, but any values !=
* 0 are set to 0
*
* @return the reversed index or new int[0] if
* arg.length == 0
*
* @throws IllegalArgumentException
* if (arg == null)
*/
public static int[] flipIndex(int... arg) {
if (arg == null)
throw new IllegalArgumentException("Argument was null.");
int[] reversed = new int[arg.length];
for (int i = 0; i < arg.length; i++)
if (arg[i] == 0.0)
reversed[i] = 1;
return reversed;
}
/**
* Gets a string that contains a printed version of arg.
*
* @param arg
* the array to print
* @return a string containing with all elements of arg
* @throws IllegalArgumentException
* if rows of argument have different lengths
*/
public static String format(double[][] arg) {
checkRowLengths(arg);
StringBuffer buffer = new StringBuffer();
buffer.append("rows: " + arg.length + "\n");
if (arg.length > 0)
buffer.append("cols: " + arg[0].length + "\n");
for (int i = 0; i < arg.length; i++) {
for (int j = 0; j < arg[0].length; j++)
buffer.append(new PrintfFormat("%- 13.4f").sprintf(arg[i][j]));
buffer.append("\n");
}
return buffer.toString();
}
/**
* Gets the column of the array arg specified with
* colIndex. The index starts with 0 as usual.
*
* @param arg
* the array to extract a column from
* @param colIndex
* the index of the column to extract (starting from 0)
* @return a one dimensional double array with the column data
* @throws IllegalArgumentException
* if (arg == null) or
* if (arg.length == 0) or if the index is
* outside the valid array bounds or if rows of argument have
* different lengths
*/
public static double[] getDoubleCol(double[][] arg, int colIndex) {
if (arg == null)
throw new IllegalArgumentException("Argument was null.");
checkRowLengths(arg);
if (arg.length == 0)
throw new IllegalArgumentException("Argument has zero rows.");
if (colIndex < 0 || colIndex >= arg[0].length)
throw new IllegalArgumentException("Invalid index: " + colIndex
+ ".");
double[] result = new double[arg.length];
for (int i = 0; i < result.length; i++)
result[i] = arg[i][colIndex];
return result;
}
/**
* Gets the row of the array arg specified with
* rowIndex. The index starts with 0 as usual.
*
* @param arg
* the array to extract a row from
* @param rowIndex
* the index of the row to extract (starting from 0)
* @return a one dimensional double array with the row data
* @throws IllegalArgumentException
* if (arg == null) or
* if (arg.length == 0) or if the index is
* outside the valid array bounds or if rows of argument have
* different lengths
*/
public static double[] getDoubleRow(double[][] arg, int rowIndex) {
if (arg == null)
throw new IllegalArgumentException("Argument was null.");
checkRowLengths(arg);
if (arg.length == 0)
throw new IllegalArgumentException("Argument has zero rows.");
if (rowIndex < 0 || rowIndex >= arg.length)
throw new IllegalArgumentException("Invalid index: " + rowIndex
+ ".");
double[] arg_i = arg[rowIndex];
double[] result = new double[arg_i.length];
System.arraycopy(arg_i, 0, result, 0, arg_i.length);
return result;
}
/**
* Gets all columns of the array arg defined by
* startCol:endCol. The indices start with 0 as usual.
*
* @param arg
* the array to extract columns from
* @param startCol
* the index of the first column to extract (starting from 0)
* @param endCol
* the index of the last column to extract (starting from 0)
* @return a two dimensional double array with the column data
* @throws IllegalArgumentException
* if (arg == null) or
* if (arg.length == 0) or
* if (startCol > endCol) or if the indices
* are outside the valid array bounds or if rows of argument
* have different lengths
*/
public static double[][] getDoubleCols(double[][] arg, int startCol,
int endCol) {
if (arg == null)
throw new IllegalArgumentException("Argument was null.");
checkRowLengths(arg);
if (arg.length == 0)
throw new IllegalArgumentException("Argument has zero rows.");
if (startCol < 0 || startCol >= arg[0].length)
throw new IllegalArgumentException("Invalid start index: "
+ startCol + ".");
if (endCol < 0 || endCol >= arg[0].length)
throw new IllegalArgumentException("Invalid end index: " + endCol
+ ".");
if (endCol < startCol)
throw new IllegalArgumentException("Invalid indices [start:"
+ startCol + " > end:" + endCol + "].");
int c = endCol - startCol + 1;
double[][] newMat = new double[arg.length][c];
for (int i = 0; i < newMat.length; i++)
System.arraycopy(arg[i], startCol, newMat[i], 0, c);
return newMat;
}
/**
* Gets all rows of the array arg defined by
* startRow:endRow. The indices start with 0 as usual.
*
* @param arg
* the array to extract rows from
* @param startRow
* the index of the first row to extract (starting from 0)
* @param endRow
* the index of the last row to extract (starting from 0)
* @return a two dimensional double array with the row data
* @throws IllegalArgumentException
* if (arg == null) or
* if (arg.length == 0) or
* if (startRow > endRow) or if the indices
* are outside the valid array bounds or if rows of argument
* have different lengths
*/
public static double[][] getDoubleRows(double[][] arg, int startRow,
int endRow) {
if (arg == null)
throw new IllegalArgumentException("Argument was null.");
checkRowLengths(arg);
if (arg.length == 0)
throw new IllegalArgumentException("Argument has zero rows.");
if (startRow < 0 || startRow >= arg.length)
throw new IllegalArgumentException("Invalid start index: "
+ startRow + ".");
if (endRow < 0 || endRow >= arg.length)
throw new IllegalArgumentException("Invalid end index: " + endRow
+ ".");
if (endRow < startRow)
throw new IllegalArgumentException("Invalid indices [start:"
+ startRow + " > end:" + endRow + "].");
int r = endRow - startRow + 1;
double[][] newMat = new double[r][];
System.arraycopy(arg, startRow, newMat, 0, r);
return newMat;
}
/**
* Gets the index of the first nonzero element in arg.
*
* @param arg
* the array to check
* @return the index of the 1st nonzero element or -1 if there is none
* @throws IllegalArgumentException
* if (arg == null)
*/
public static int getFirstNonzeroIndex(double[] arg) {
if (arg == null)
throw new IllegalArgumentException("Argument was null.");
for (int i = 0; i < arg.length; i++)
if (arg[i] != 0)
return i;
return -1;
}
/**
* Gets the index of the last nonzero element in arg.
*
* @param arg
* the array to check
* @return the index of the last nonzero element or -1 if there is none
* @throws IllegalArgumentException
* if (arg == null)
*/
public static int getLastNonzeroIndex(double[] arg) {
if (arg == null)
throw new IllegalArgumentException("Argument was null.");
for (int i = arg.length - 1; i >= 0; i--)
if (arg[i] != 0)
return i;
return -1;
}
/**
* Gets the number of nonzero elements in arg.
*
* @param arg
* the array to check
* @return int the number of elements in arg that are != 0
* @throws IllegalArgumentException
* if (arg == null)
*/
public static int getNonzeroDoubleCount(double[] arg) {
if (arg == null)
throw new IllegalArgumentException("Argument was null.");
int count = 0;
for (int i = 0; i < arg.length; i++)
if (arg[i] != 0)
count++;
return count;
}
/**
* Gets the number of nonzero elements in arg.
*
* @param arg
* the array to check, usually an index
* @return the number of elements in arg that are != 0
* @throws IllegalArgumentException
* if (arg == null)
*/
public static int getNonzeroIntCount(int[] arg) {
if (arg == null)
throw new IllegalArgumentException("Argument was null.");
int count = 0;
for (int i = 0; i < arg.length; i++)
if (arg[i] != 0)
count++;
return count;
}
/**
* Gets a quadratic double array of dimension dim with all
* elements on and below the diagonal set to value.
*
* @param value
* the double to store in the lower part of the
* array
* @param dim
* the dimension of the quadratic array
* @return a dim x dim lower triangular array
* @throws IllegalArgumentException
* if (dim < 0),
*/
public static double[][] lowerTringular(double value, int dim) {
if (dim < 0)
throw new IllegalArgumentException("Dimension argument " + dim
+ " < 0.");
double[][] triang = new double[dim][dim];
for (int i = 0; i < dim; i++)
for (int j = 0; j <= i; j++)
triang[i][j] = value;
return triang;
}
/**
* Gets a vector with the maxima of all columns of arg.
*
* @param arg
* the original array
* @return a arg[0].length vector the maxima of
* arg, if a column contains Double.NaN
* and other double values, then the smallest double value that is
* not a Double.NaN is returned
*
* @throws IllegalArgumentException
* if (arg == null) or if rows of argument have
* different lengths
*/
public static double[] maxc(double[][] arg) {
if (arg == null)
throw new IllegalArgumentException("Array argument was null.");
checkRowLengths(arg);
if (arg.length == 0)
return new double[0];
double[] m = new double[arg[0].length];
for (int i = 0; i < m.length; i++) {
m[i] = arg[0][i];
for (int j = 0; j < arg.length; j++)
if (arg[j][i] > m[i] || Double.isNaN(m[i]))
m[i] = arg[j][i];
}
return m;
}
/**
* Gets a vector with the mean of all columns of arg.
*
* @param arg
* the original array
* @return a arg[0].length vector the mean of
* arg
*
* @throws IllegalArgumentException
* if (arg == null) or if rows of argument have
* different lengths
*/
public static double[] meanc(double[][] arg) {
if (arg == null)
throw new IllegalArgumentException("Array argument was null.");
checkRowLengths(arg);
if (arg.length == 0)
return new double[0];
double[] m = sumc(arg);
for (int i = 0; i < m.length; i++)
m[i] = m[i] / arg.length;
return m;
}
/**
* Gets a vector with the minima of all columns of arg.
*
* @param arg
* the original array
* @return a arg[0].length vector the minima of
* arg, if a column contains Double.NaN
* and other double values, then the smallest double value that is
* not a Double.NaN is returned
*
* @throws IllegalArgumentException
* if (arg == null) or if rows of argument have
* different lengths
*/
public static double[] minc(double[][] arg) {
if (arg == null)
throw new IllegalArgumentException("Array argument was null.");
checkRowLengths(arg);
if (arg.length == 0)
return new double[0];
double[] m = new double[arg[0].length];
for (int i = 0; i < m.length; i++) {
m[i] = arg[0][i];
for (int j = 0; j < arg.length; j++)
if (arg[j][i] < m[i] || Double.isNaN(m[i]))
m[i] = arg[j][i];
}
return m;
}
/**
* Multiplies the scalar toMult with a copy of the array
* arg.
*
* @param arg
* the original array
* @param toMult
* the number to multiply all elements of arg with
* @return a new array multiplied with toMult; if
* toMult is NaN, then the resulting
* array will contain only NaN's
* @throws IllegalArgumentException
* if (arg == null) or if rows of argument have
* different lengths
*/
public static double[][] multiply(double[][] arg, double toMult) {
if (arg == null)
throw new IllegalArgumentException("Array argument was null.");
checkRowLengths(arg);
double[][] m = cloneDoubleArray(arg);
for (int i = 0; i < m.length; i++)
for (int j = 0; j < m[0].length; j++)
m[i][j] *= toMult;
return m;
}
/**
* Gets a double array filled with NaN's.
*
* @param r
* rows of array to create
* @param c
* cols of array to create
* @return the r x c double array filled with NaN's or
* new double[0][0] if (r == 0 || c == 0)
* @throws IllegalArgumentException
* if (r < 0 || c < 0)
*/
public static double[][] missings(int r, int c) {
if (r < 0 || c < 0)
throw new IllegalArgumentException("Invalid dimension " + r + ":"
+ c + " specified.");
if (r == 0 || c == 0)
return new double[0][0];
double[][] d = new double[r][c];
for (int i = 0; i < r; i++)
Arrays.fill(d[i], Double.NaN);
return d;
}
/**
* Gets a double array filled with 1's.
*
* @param r
* rows of array to create
* @param c
* cols of array to create
* @return the r x c double array filled with 1's or
* new double[0][0] if (r == 0 || c == 0)
* @throws IllegalArgumentException
* if (r < 0 || c < 0)
*/
public static double[][] ones(int r, int c) {
if (r < 0 || c < 0)
throw new IllegalArgumentException("Invalid dimension " + r + ":"
+ c + " specified.");
if (r == 0 || c == 0)
return new double[0][0];
double[][] d = new double[r][c];
for (int i = 0; i < r; i++)
Arrays.fill(d[i], 1);
return d;
}
/**
* Applies Math.pow(arg[i][j], power) to all elements of
* arg.
*
* @param arg
* the original array
* @param power
* the 2nd argument to be applied with Math.pow()
* @return a new array with all elements raised to the power of
* power
*
* @throws IllegalArgumentException
* if (arg == null) or if rows of argument have
* different lengths
*/
public static double[][] pow(double[][] arg, double power) {
if (arg == null)
throw new IllegalArgumentException("Array argument was null.");
checkRowLengths(arg);
double[][] m = cloneDoubleArray(arg);
for (int i = 0; i < m.length; i++)
for (int j = 0; j < m[0].length; j++)
m[i][j] = Math.pow(m[i][j], power);
return m;
}
/**
* Get the rank of arg.
*
* @param arg
* the array to compute the rank from
* @return the rank computed by Jama, 0
* if (arg.length == 0 || arg[0].length == 0)
*
* @throws IllegalArgumentException
* if (arg == null) or if rows of argument have
* different lengths
*/
public static int rank(double[][] arg) {
if (arg == null)
throw new IllegalArgumentException("Array argument was null.");
checkRowLengths(arg);
if (arg.length == 0 || arg[0].length == 0)
return 0;
return new Jama.Matrix(arg).rank();
}
/**
* Gets a double array filled with random numbers generated by
* Math.random(). The random numbers are equally distributed
* between 0 and 1.
*
* @param r
* rows of array to create
* @param c
* cols of array to create
* @return the r x c double array filled with
* Math.random() or
* new double[0][0] if (r == 0 || c == 0)
* @throws IllegalArgumentException
* if (r < 0 || c < 0)
*/
public static double[][] rndu(int r, int c) {
if (r < 0 || c < 0)
throw new IllegalArgumentException("Invalid dimension " + r + ":"
+ c + " specified.");
if (r == 0 || c == 0)
return new double[0][0];
double[][] d = new double[r][c];
for (int i = 0; i < d.length; i++)
for (int j = 0; j < d[0].length; j++)
d[i][j] = Math.random();
return d;
}
/**
* Gets all columns of the array arg that have a nonzero
* corresponding element in index.
*
* @param arg
* the array to extract columns from
* @param index
* arg[0].length x 1 vector selecting columns from
* arg
*
* @return new array with the extracted columns,
* new double[0][0] if index contains only 0's, a
* copy of arg if index contains only
* nonzero elements
*
* @throws IllegalArgumentException
* if (arg == null || index == null) or
* if ((arg.length == 0 || arg[0].length == 0) && index.length > 0)
* or if (arg[0].length != index.length) or if
* rows of argument have different lengths
*/
public static double[][] selColsIf(double[][] arg, int... index) {
if (arg == null || index == null)
throw new IllegalArgumentException("Argument was null.");
if (index.length == 0 && (arg.length == 0 || arg[0].length == 0))
return new double[0][0];
if (arg.length == 0 || arg[0].length == 0)
throw new IllegalArgumentException(
"Argument was empty but index not.");
checkRowLengths(arg);
if (arg[0].length != index.length)
throw new IllegalArgumentException(
"Columns of array do not match with dimension of index (array: "
+ arg[0].length + ", index: " + index.length + ").");
int num = getNonzeroIntCount(index);
// Nothing selected.
if (num == 0)
return new double[0][0];
// Everything selected.
if (num == arg[0].length)
return cloneDoubleArray(arg);
double[][] ret = new double[arg.length][num];
for (int i = 0, k = 0; i < index.length; i++)
if (index[i] != 0.0) {
for (int j = 0; j < ret.length; j++)
ret[j][k] = arg[j][i];
k++;
}
return ret;
}
/**
* Gets all rows of the array arg that have a nonzero
* corresponding element in index.
*
* @param arg
* the array to extract rows from
* @param index
* arg.length x 1 vector selecting rows from
* arg
*
* @return new array with the extracted rows, new double[0][0]
* if index contains only 0's, a copy of arg if
* index contains only nonzero elements
*
* @throws IllegalArgumentException
* if (arg == null || index == null) or
* if ((arg.length == 0 || arg[0].length == 0) && index.length > 0)
* or if (arg.length != index.length) or if rows
* of argument have different lengths
*/
public static double[][] selRowsIf(double[][] arg, int... index) {
if (arg == null || index == null)
throw new IllegalArgumentException("Argument was null.");
if (index.length == 0 && (arg.length == 0 || arg[0].length == 0))
return new double[0][0];
if (arg.length == 0 || arg[0].length == 0)
throw new IllegalArgumentException(
"Argument was empty but index not.");
checkRowLengths(arg);
if (arg.length != index.length)
throw new IllegalArgumentException(
"Rows of array do not match with dimension of index (array: "
+ arg.length + ", index: " + index.length + ").");
int num = getNonzeroIntCount(index);
// Nothing selected.
if (num == 0)
return new double[0][0];
// Everything selected.
if (num == arg.length)
return cloneDoubleArray(arg);
double[][] ret = new double[num][arg[0].length];
for (int i = 0, k = 0; i < index.length; i++)
if (index[i] != 0.0) {
double[] arg_i = arg[i];
double[] arr = new double[arg_i.length];
System.arraycopy(arg_i, 0, arr, 0, arg_i.length);
ret[k++] = arr;
}
return ret;
}
/**
* Gets an array with the sequence of numbers starting from
* start being n - 1 times incremented by
* increment.
*
* @param start
* the first element of the sequence
* @param increment
* the difference between two successive elements of the sequence
* @param n
* the number of elements in the sequence
*
* @return the sequence as a n x 1 double array
* @throws IllegalArgumentException
* if (n < 0), or if
* start || increment are either
* Double.NaN,
* Double.NEGATIVE_INFINITY or
* Double.POSITIVE_INFINITY,
*
*/
public static double[] seqa(double start, double increment, int n) {
if (start == Double.NEGATIVE_INFINITY
|| start == Double.POSITIVE_INFINITY || Double.isNaN(start))
throw new IllegalArgumentException("Start argument: " + start
+ " invalid.");
if (increment == Double.NEGATIVE_INFINITY
|| increment == Double.POSITIVE_INFINITY
|| Double.isNaN(increment))
throw new IllegalArgumentException("Increment argument: "
+ increment + " invalid.");
if (n < 0)
throw new IllegalArgumentException("Number argument " + n + " < 0.");
double[] d = new double[n];
for (int i = 0; i < n; i++)
d[i] = start + i * increment;
return d;
}
/**
* Gets a new array with the elements of arg divided by the
* standard devitation of the respective columns of arg.
*
* @param arg
* the original array
*
* @throws IllegalArgumentException
* if (arg == null) or if rows of argument have
* different lengths
*/
public static double[][] standardize(double[][] arg) {
if (arg == null)
throw new IllegalArgumentException("Array argument was null.");
checkRowLengths(arg);
if (arg.length == 0)
return new double[0][0];
double[] m = stdc(arg);
double[][] std = UMatrix.cloneDoubleArray(arg);
for (int i = 0; i < std.length; i++)
for (int j = 0; j < std[0].length; j++)
std[i][j] = std[i][j] / m[j];
return std;
}
/**
* Gets a vector with the standard deviations of all columns of
* arg. The standard deviation divisor is
* arg.length.
*
* @param arg
* the original array
* @return a arg[0].length vector the std. dev. of
* arg
*
* @throws IllegalArgumentException
* if (arg == null) or if rows of argument have
* different lengths
*/
public static double[] stdc(double[][] arg) {
if (arg == null)
throw new IllegalArgumentException("Array argument was null.");
checkRowLengths(arg);
if (arg.length == 0)
return new double[0];
double[] m = meanc(arg);
double[] std = new double[m.length];
for (int i = 0; i < std.length; i++) {
for (int j = 0; j < arg.length; j++)
std[i] += Math.pow(arg[j][i] - m[i], 2);
std[i] /= arg.length;
std[i] = Math.pow(std[i], 0.5);
}
return std;
}
/**
* Gets a vector with the sum of all elements in the single columns of
* arg.
*
* @param arg
* the original array
* @return a arg[0].length vector the column sums of
* arg
*
* @throws IllegalArgumentException
* if (arg == null) or if rows of argument have
* different lengths
*/
public static double[] sumc(double[][] arg) {
if (arg == null)
throw new IllegalArgumentException("Array argument was null.");
checkRowLengths(arg);
if (arg.length == 0)
return new double[0];
double[] m = new double[arg[0].length];
for (int i = 0; i < arg[0].length; i++)
for (int j = 0; j < arg.length; j++)
m[i] += arg[j][i];
return m;
}
/**
* Transforms an int array into a double
* array. This is sometimes needed to prepare arguments for methods that
* take double[][] instead of int[][].
*
* @param arg
* the int array to transform
* @return double array or
*
* null if (arg == null)
* -
*
new double[0][0] if (arg.length == 0 || arg[0].length == 0)
*
* @throws IllegalArgumentException
* if rows of argument have different lengths
*/
public static double[][] toDoubleMatrix(int[][] arg) {
if (arg == null)
return null;
checkRowLengths(arg);
if (arg.length == 0 || arg[0].length == 0)
return new double[0][0];
double[][] m = new double[arg.length][arg[0].length];
for (int i = 0; i < arg.length; i++)
for (int j = 0; j < arg[0].length; j++)
m[i][j] = arg[i][j];
return m;
}
/**
* Transforms a one-dimensional array into a K x 1 pseudo-two-dimensional
* array. This is sometimes needed to prepare arguments for methods that
* take double[][] instead of double[].
*
* @param arg
* the vector-like array to transform
* @return two-dimensional array with dimensions arg.length x 1
* or
*
* null if (arg == null)
* new double[0][0] if (arg.length == 0)
*
*/
public static double[][] toDoubleMatrix(double[] arg) {
if (arg == null)
return null;
if (arg.length == 0)
return new double[0][0];
double[][] m = new double[arg.length][1];
for (int i = 0; i < arg.length; i++)
m[i][0] = arg[i];
return m;
}
/**
* Transforms a one-dimensional array into a K x 1 pseudo-two-dimensional
* array. This is sometimes needed to prepare arguments for methods that
* take double[][] instead of int[].
*
* @param arg
* the vector-like array to transform
* @return two-dimensional array with dimensions arg.length x 1
* or
*
* null if (arg == null)
* new double[0][0] if (arg.length == 0)
*
*/
public static double[][] toDoubleMatrix(int[] arg) {
if (arg == null)
return null;
if (arg.length == 0)
return new double[0][0];
double[][] m = new double[arg.length][1];
for (int i = 0; i < arg.length; i++)
m[i][0] = arg[i];
return m;
}
/**
* Transforms arg into an int array by applying a cast to int
* from double to each element of arg. Note that during this
* operation information is potentially lost. Only the integer part is
* preserved, which is different from rounding. The following special
* int values are returned:
*
* - 0 if
value == Double.NaN
* Integer.MAX_VALUE if value == Double.POSITIVE_INFINITY
* Integer.MIN_VALUE if value == Double.NEGATIVE_INFINITY
*
*
* @param arg
* the array to transform
* @return two-dimensional int array or
*
* null if (arg == null)
* -
*
new int[0][0] if (g.length == 0 || g[0].length == 0)
*
* @throws IllegalArgumentException
* if rows of argument have different lengths
*/
public static int[][] toIntMatrix(double[][] arg) {
if (arg == null)
return null;
checkRowLengths(arg);
if (arg.length == 0 || arg[0].length == 0)
return new int[0][0];
int[][] m = new int[arg.length][arg[0].length];
for (int i = 0; i < arg.length; i++)
for (int j = 0; j < arg[0].length; j++)
m[i][j] = (int) arg[i][j];
return m;
}
/**
* Gets a new array which is the transpose arg, which means
* that all columns of arg are now the rows of the new array.
*
* @param arg
* the original array
* @return the transpose of arg, or
* new double[0][0]
* if (arg.length == 0 || arg[0].length == 0)
*
* @throws IllegalArgumentException
* if (arg == null) or if rows of argument have
* different lengths
*/
public static double[][] transpose(double[][] arg) {
if (arg == null)
throw new IllegalArgumentException("Array argument was null.");
checkRowLengths(arg);
if (arg.length == 0 || arg[0].length == 0)
return new double[0][0];
double[][] ret = new double[arg[0].length][arg.length];
for (int i = 0; i < arg.length; i++)
for (int j = 0; j < arg[0].length; j++)
ret[j][i] = arg[i][j];
return ret;
}
/**
* Get a one dimensional array with to columns of arg stacked
* into it.
*
* @param arg
* the array with data
* @return a arg.length * arg[0].length x 1 array with the
* columns of arg stacked into a vector
*
* @throws IllegalArgumentException
* if (arg == null) or if rows of argument have
* different lengths
*/
public static double[] vec(double[][] arg) {
if (arg == null)
throw new IllegalArgumentException("Array argument was null.");
checkRowLengths(arg);
if (arg.length == 0 || arg[0].length == 0)
return new double[0];
double[] res = new double[arg.length * arg[0].length];
for (int j = 0, k = 0; j < arg[0].length; j++)
for (int i = 0; i < arg.length; i++)
res[k++] = arg[i][j];
return res;
}
/**
* Get a one dimensional array with to columns of arg stacked
* into it.
*
* @param arg
* the array with data
* @return a arg.length * arg[0].length x 1 array with the
* columns of arg stacked into a vector
*
* @throws IllegalArgumentException
* if (arg == null) or if rows of argument have
* different lengths
*/
public static int[] vec(int[][] arg) {
if (arg == null)
throw new IllegalArgumentException("Array argument was null.");
checkRowLengths(arg);
if (arg.length == 0 || arg[0].length == 0)
return new int[0];
int[] res = new int[arg.length * arg[0].length];
for (int j = 0, k = 0; j < arg[0].length; j++)
for (int i = 0; i < arg.length; i++)
res[k++] = arg[i][j];
return res;
}
/**
* Computes the discrete convolution function for the vectors x
* and z from start to end.
* The function is defined as
*
* (x*z)[m] = sum_n ( x[n]z[m-n] ); m, n start with 0.
*
*
* @param x
* Nx1 vector
* @param z
* Lx1 vector
* @param start
* the first convolution to compute, zero based
* @param end
* the last convolution to compute, zero based, max number is
* x.length + z.length - 2;
* if end < 0, then max number is used
*
* @return Qx1 result, where Q = (end - start+ 1), if
* end < 0, the start 'th to the last
* convolutions are computed
*
* @throws IllegalArgumentException
*
* if (x == null || z == null) or
* if (x.length == 0 || z.length == 0) or
* if (start < 0) or
* if (start > end && end >= 0) or
* if (end > x.length + z.length - 2)
*
*/
public static double[] conv(double[] x, double[] z, int start, int end) {
if (x == null || z == null)
throw new IllegalArgumentException("Array argument was null.");
if (x.length == 0 || z.length == 0)
throw new IllegalArgumentException(
"Array argument contained zero elements.");
if (start < 0)
throw new IllegalArgumentException("Start index was < 0.");
if (start > end && end >= 0)
throw new IllegalArgumentException(
"Wrong index order: start > end.");
if (end > x.length + z.length - 2)
throw new IllegalArgumentException("End index [" + end
+ "] exceeds maximum [" + (x.length + z.length - 2) + "].");
// set end to max if < 0
end = (end < 0) ? x.length + z.length - 2 : end;
double[] conv = new double[end - start + 1];
for (int i = start; i <= end; i++)
for (int j = 0; j <= i; j++) {
// zeros if arrays contain no elements at some position
double xx = (j < x.length) ? xx = x[j] : 0;
double zz = (i - j < z.length) ? z[i - j] : 0;
conv[i - start] += xx * zz;
}
return conv;
}
/**
* Implementation of the fractional difference operator, see
* J. R. M. Hosking "Fractional Differencing", Biometrika (1981), 68 (1),
* pp. 165-76 . equation 2.1.
*
*
* @param y
* Tx1 time series to be differences
* @param d
* order of differencing
* @return Tx1 vector with differences series
* @throws IllegalArgumentException
* if (y == null) or if d equals
* Double.NaN
*/
public static double[] fracdiff(double[] y, double d) {
if (y == null)
throw new IllegalArgumentException("Array argument was null.");
if (Double.isNaN(d))
throw new IllegalArgumentException("Differencing argument was NaN.");
int T = y.length;
if (T == 0)
return new double[0];
double[] res = new double[T + 1];
res[0] = 1;
double[] trend = UMatrix.seqa(1, 1, T - 1);
double[] mat1 = new double[trend.length];
for (int i = 0; i < mat1.length; i++)
mat1[i] = (trend[i] - 1 - d) / trend[i];
res[1] = mat1[0];
for (int i = 1; i < T - 1; i++)
res[i + 1] = res[i] * mat1[i];
double[] fDiff = conv(y, res, 0, T - 1);
return fDiff;
}
}
Ads help maintain this website.