/* Copyright (C) 2003 Univ. of Massachusetts Amherst, Computer Science Dept. This file is part of "MALLET" (MAchine Learning for LanguagE Toolkit). http://www.cs.umass.edu/~mccallum/mallet This software is provided under the terms of the Common Public License, version 1.0, as published by http://www.opensource.org. For further information, see the file `LICENSE' included with this distribution. */ package edu.nd.nina.util; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.util.Random; import edu.nd.nina.types.FeatureSelection; import edu.nd.nina.types.FeatureVector; /** * A class of static utility functions for manipulating arrays of double. */ public final class MatrixOps { /** * Sets every element of a double array to a given value. * * @param m * The array to modify * @param v * The value */ public static void setAll(double[] m, double v) { java.util.Arrays.fill(m, v); } public static void set(double[] dest, double[] source) { if (source.length != dest.length) dest = new double[source.length]; System.arraycopy(source, 0, dest, 0, source.length); } /** * Multiplies every element in an array by a scalar. * * @param m * The array * @param factor * The scalar */ public static void timesEquals(double[] m, double factor) { for (int i = 0; i < m.length; i++) m[i] *= factor; } /* Calculates the Schur/Hadamard product */// JJW public static void timesEquals(double[] m1, double[] m2) { assert (m1.length == m2.length) : "unequal lengths\n"; for (int i = 0; i < m1.length; i++) { m1[i] *= m2[i]; } } /** * Adds a scalar to every element in an array. * * @param m * The array * @param toadd * The scalar */ public static void plusEquals(double[] m, double toadd) { for (int i = 0; i < m.length; i++) m[i] += toadd; } public static void plusEquals(double[] m1, double[] m2) { assert (m1.length == m2.length) : "unequal lengths\n"; for (int i = 0; i < m1.length; i++) { if (Double.isInfinite(m1[i]) && Double.isInfinite(m2[i]) && (m1[i] * m2[i] < 0)) m1[i] = 0.0; else m1[i] += m2[i]; } } public static void plusEquals(double[] m1, double[] m2, double factor) { assert (m1.length == m2.length) : "unequal lengths\n"; for (int i = 0; i < m1.length; i++) { double m1i = m1[i]; double m2i = m2[i]; if (Double.isInfinite(m1i) && Double.isInfinite(m2i) && (m1[i] * m2[i] < 0)) m1[i] = 0.0; else m1[i] += m2[i] * factor; } } public static void plusEquals(double[][] m1, double[][] m2, double factor) { assert (m1.length == m2.length) : "unequal lengths\n"; for (int i = 0; i < m1.length; i++) { for (int j = 0; j < m1[i].length; j++) { m1[i][j] += m2[i][j] * factor; } } } public static void log(double[] m) { for (int i = 0; i < m.length; i++) m[i] = Math.log(m[i]); } /** @deprecated Use dotProduct() */ public static double dot(double[] m1, double[] m2) { assert (m1.length == m2.length) : "m1.length != m2.length\n"; double ret = 0.0; for (int i = 0; i < m1.length; i++) ret += m1[i] * m2[i]; return ret; } public static double dotProduct(double[] m1, double[] m2) { assert (m1.length == m2.length) : "m1.length != m2.length\n"; double ret = 0.0; for (int i = 0; i < m1.length; i++) ret += m1[i] * m2[i]; return ret; } public static double absNorm(double[] m) { double ret = 0; for (int i = 0; i < m.length; i++) ret += Math.abs(m[i]); return ret; } public static double twoNorm(double[] m) { double ret = 0; for (int i = 0; i < m.length; i++) ret += m[i] * m[i]; return Math.sqrt(ret); } public static double twoNormSquared(double[] m) { double ret = 0; for (int i = 0; i < m.length; i++) ret += m[i] * m[i]; return ret; } public static double oneNorm(double[] m) { double ret = 0; for (int i = 0; i < m.length; i++) ret += m[i]; return ret; } public static double oneNormalize(double[] m) { double sum = oneNorm(m); for (int i = 0; i < m.length; i++) m[i] /= sum; return sum; } public static double normalize(double[] m) { return oneNormalize(m); } public static double infinityNorm(double[] m) { double ret = Double.NEGATIVE_INFINITY; for (int i = 0; i < m.length; i++) if (Math.abs(m[i]) > ret) ret = Math.abs(m[i]); return ret; } public static double absNormalize(double[] m) { double norm = absNorm(m); if (norm > 0) for (int i = 0; i < m.length; i++) m[i] /= norm; return norm; } public static double twoNormalize(double[] m) { double norm = twoNorm(m); if (norm > 0) for (int i = 0; i < m.length; i++) m[i] /= norm; return norm; } public static void substitute(double[] m, double oldValue, double newValue) { for (int i = m.length - 1; i >= 0; i--) if (m[i] == oldValue) m[i] = newValue; } /** * If "ifSelected" is false, it reverses the selection. If "fselection" is * null, this implies that all features are selected; all values in the row * will be changed unless "ifSelected" is false. */ public static final void rowSetAll(double[] m, int nc, int ri, double v, FeatureSelection fselection, boolean ifSelected) { if (fselection == null) { if (ifSelected == true) { for (int ci = 0; ci < nc; ci++) m[ri * nc + ci] = v; } } else { // xxx Temporary check for full selection // assert (fselection.nextDeselectedIndex (0) == nc); for (int ci = 0; ci < nc; ci++) if (fselection.contains(ci) ^ !ifSelected) m[ri * nc + ci] = v; } } public static double rowDotProduct(double[] m, int nc, int ri, FeatureVector v, int maxCi, FeatureSelection selection) { return rowDotProduct(m, nc, ri, v, 1, maxCi, selection); } public static double rowDotProduct(double[] m, int nc, int ri, FeatureVector v, double factor, int maxCi, FeatureSelection selection) { double ret = 0; if (selection != null) { int size = v.numLocations(); for (int cil = 0; cil < size; cil++) { int ci = v.indexAtLocation(cil); if (selection.contains(ci) && ci < nc && ci <= maxCi) ret += m[ri * nc + ci] * v.valueAtLocation(cil) * factor; } } else { int size = v.numLocations(); for (int cil = 0; cil < size; cil++) { int ci = v.indexAtLocation(cil); if (ci <= maxCi) ret += m[ri * nc + ci] * v.valueAtLocation(cil) * factor; } } return ret; } public static final void rowPlusEquals(double[] m, int nc, int ri, FeatureVector v, double factor) { for (int vli = 0; vli < v.numLocations(); vli++) m[ri * nc + v.indexAtLocation(vli)] += v.valueAtLocation(vli) * factor; } public static boolean isNaN(double[] m) { for (int i = 0; i < m.length; i++) if (Double.isNaN(m[i])) return true; return false; } // gsc: similar to isNan, but checks for inifinite values public static boolean isInfinite(double[] m) { for (int i = 0; i < m.length; i++) if (Double.isInfinite(m[i])) return true; return false; } // gsc: returns true if any value in the array is either NaN or infinite public static boolean isNaNOrInfinite(double[] m) { for (int i = 0; i < m.length; i++) if (Double.isInfinite(m[i]) || Double.isNaN(m[i])) return true; return false; } // gsc: returns true if any value in the array is greater than 0.0/-0.0 public static boolean isNonZero(double[] m) { for (int i = 0; i < m.length; i++) if (Math.abs(m[i]) > 0.0) return true; return false; } // gsc: returns true if any value in the array is 0.0/-0.0 public static boolean isZero(double[] m) { for (int i = 0; i < m.length; i++) if (Math.abs(m[i]) == 0.0) return true; return false; } public static double sum(double[][] m) { double sum = 0; for (int i = 0; i < m.length; i++) for (int j = 0; j < m[i].length; j++) sum += m[i][j]; return sum; } public static int sum(int[] m) { int sum = 0; for (int i = 0; i < m.length; i++) sum += m[i]; return sum; } public static double mean(double[] m) { double sum = 0; for (int i = 0; i < m.length; i++) sum += m[i]; return sum / m.length; } /** Return the standard deviation */ public static double stddev(double[] m) { double mean = mean(m); double s = 0; for (int i = 0; i < m.length; i++) s += (m[i] - mean) * (m[i] - mean); return Math.sqrt(s / m.length); // Some prefer dividing by (m.length-1), but this is also common } public static double stderr(double[] m) { return stddev(m) / Math.sqrt(m.length); } // gsc /** Return the variance */ public static double variance(double[] m) { double mean = mean(m); double s = 0; for (int i = 0; i < m.length; i++) s += (m[i] - mean) * (m[i] - mean); return s / m.length; // Some prefer dividing by (m.length-1), but this is also common } /** * Prints a double array to standard output * * @param m * Array to print. */ public static final void print(double[] m) { print(new PrintWriter(new OutputStreamWriter(System.out), true), m); } /** * Prints a double array to the given PrintWriter. * * @param out * Writer to print ouput to * @param m * Array to print. */ public static final void print(PrintWriter out, double[] m) { for (int i = 0; i < m.length; i++) { out.print(" " + m[i]); } out.println(""); } public static final void print(double[][] arr) { for (int i = 0; i < arr.length; i++) { double[] doubles = arr[i]; print(doubles); } } /** * Print a space-separated array of elements * * @param m * An array of any type */ public static final String toString(Object m) { StringBuffer sb = new StringBuffer(); int n = java.lang.reflect.Array.getLength(m) - 1; for (int i = 0; i < n; i++) { sb.append(java.lang.reflect.Array.get(m, i)); sb.append(" "); } if (n >= 0) sb.append(java.lang.reflect.Array.get(m, n)); return sb.toString(); } public static final void printInRows(double[] arr) { for (int i = 0; i < arr.length; i++) { System.out.println("[" + i + "] " + arr[i]); } } public static void setAll(double[][][] m, double v) { for (int i = 0; i < m.length; i++) { for (int j = 0; j < m[i].length; j++) { for (int k = 0; k < m[i][j].length; k++) { m[i][j][k] = v; } } } } public static void setAll(double[][] m, double v) { for (int i = 0; i < m.length; i++) { for (int j = 0; j < m[i].length; j++) { m[i][j] = v; } } } public static void print(int[][] arr) { for (int i = 0; i < arr.length; i++) { print(arr[i]); } } public static void print(int[] m) { for (int i = 0; i < m.length; i++) { System.out.print(" " + m[i]); } System.out.println(""); } public static double[] randomVector(int n, Random r) { double[] ret = new double[n]; for (int i = 0; i < n; i++) ret[i] = r.nextDouble(); return ret; } public static void timesEquals(double[][] m, double factor) { for (int i = 0; i < m.length; i++) { for (int j = 0; j < m[i].length; j++) { m[i][j] *= factor; } } } /** * Returns the maximum elementwise absolute difference between two vectors. * This is the same as infinityNorm (v1 - v2) (if that were legal Java). * * @param v1 * Input vector, as double[] * @param v2 * Input vector, as double[] * @return */ public static double maxAbsdiff(double[] v1, double[] v2) { double max = Double.NEGATIVE_INFINITY; for (int i = 0; i < v1.length; i++) { double val = Math.abs(v1[i] - v2[i]); if (val > max) max = val; } return max; } public static int max(int[][] m) { int maxval = m[0][0]; for (int i = 0; i < m.length; i++) { for (int j = 0; j < m[i].length; j++) { if (m[i][j] > maxval) { maxval = m[i][j]; } } } return maxval; } public static int max(int[] elems) { int max = Integer.MIN_VALUE; for (int i = 0; i < elems.length; i++) { int elem = elems[i]; if (elem > max) { max = elem; } } return max; } public static double max(double[] elems) { double max = Double.NEGATIVE_INFINITY; for (int i = 0; i < elems.length; i++) { double elem = elems[i]; if (elem > max) { max = elem; } } return max; } public static double min(double[] elems) { double min = Double.POSITIVE_INFINITY; for (int i = 0; i < elems.length; i++) { double elem = elems[i]; if (elem < min) { min = elem; } } return min; } public static int maxIndex(double[] elems) { double max = Double.NEGATIVE_INFINITY; int maxIndex = -1; for (int i = 0; i < elems.length; i++) { double elem = elems[i]; if (elem > max) { max = elem; maxIndex = i; } } return maxIndex; } public static int minIndex(double[] elems) { double min = Double.POSITIVE_INFINITY; int minIndex = -1; for (int i = 0; i < elems.length; i++) { double elem = elems[i]; if (elem < min) { min = elem; minIndex = i; } } return minIndex; } public static double[] append(double[] original, double newValue) { double[] ret = new double[original.length + 1]; System.arraycopy(original, 0, ret, 0, original.length); ret[original.length] = newValue; return ret; } public static double max(double[][] ds) { double max = Double.NEGATIVE_INFINITY; for (int i = 0; i < ds.length; i++) { for (int j = 0; j < ds[i].length; j++) { if (ds[i][j] > max) { max = ds[i][j]; } } } return max; } public static int[] maxIndex(double[][] ds) { int[] maxIndices = new int[] { -1, -1 }; double max = Double.NEGATIVE_INFINITY; for (int i = 0; i < ds.length; i++) { for (int j = 0; j < ds[i].length; j++) { if (ds[i][j] > max) { max = ds[i][j]; maxIndices[0] = i; maxIndices[1] = j; } } } return maxIndices; } public static void expNormalize(double[] scores) { double max = MatrixOps.max(scores); double sum = 0; for (int i = 0; i < scores.length; i++) sum += (scores[i] = Math.exp(scores[i] - max)); for (int i = 0; i < scores.length; i++) scores[i] /= sum; } }