/* Copyright (C) 2002 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. */ /** @author Andrew McCallum <a href="mailto:mccallum@cs.umass.edu">mccallum@cs.umass.edu</a> */ package cc.mallet.types; import java.io.*; import cc.mallet.util.Maths; public abstract class DenseMatrix implements Matrix, Serializable { double[] values; protected boolean hasInfinite; // if true, at least one value = -Inf or +Inf public abstract int getNumDimensions (); public abstract int getDimensions (int[] sizes); public abstract double value (int[] indices); public abstract void setValue (int[] indices, double value); public abstract ConstantMatrix cloneMatrix (); public abstract int singleIndex (int[] indices); public abstract void singleToIndices (int i, int[] indices); public double singleValue (int i) { return values[i]; } public void setSingleValue (int i, double value) { values[i] = value; } public void incrementSingleValue (int i, double delta) { values[i] += delta; } public void setValueAtLocation (int loc, double value) { // indices == locations setSingleValue (loc, value); } public int singleSize () { return values.length; } public int numLocations () { return values.length; } public int location (int index) { return index; } public double valueAtLocation (int location) { return values[location]; } // Returns a "singleIndex" public int indexAtLocation (int location) { return location; } public void setAll (double v) { for (int i = 0; i < values.length; i++) values[i] = v; } public void set (ConstantMatrix m) { if (m instanceof DenseMatrix) { assert (m.singleSize() == values.length); System.arraycopy (((DenseMatrix)m).values, 0, values, 0, values.length); } else for (int i = m.numLocations()-1; i >= 0; i--) values[m.indexAtLocation(i)] = m.valueAtLocation(i); } public void setWithAddend (ConstantMatrix m, double addend) { if (m instanceof DenseMatrix) { assert (m.singleSize() == values.length); for (int i = 0; i < values.length; i++) values[i] = ((DenseMatrix)m).values[i] + addend; } else for (int i = m.numLocations()-1; i >= 0; i--) values[m.indexAtLocation(i)] = m.valueAtLocation(i) + addend; } public void setWithFactor (ConstantMatrix m, double factor) { if (m instanceof DenseMatrix) { assert (m.singleSize() == values.length); for (int i = 0; i < values.length; i++) values[i] = ((DenseMatrix)m).values[i] * factor; } else for (int i = m.numLocations()-1; i >= 0; i--) values[m.indexAtLocation(i)] = m.valueAtLocation(i) * factor; } public void plusEquals (double v) { for (int i = 0; i < values.length; i++) values[i] += v; } public void plusEquals (ConstantMatrix m) { if (m instanceof DenseMatrix) { assert (m.singleSize() == values.length); for (int i = 0; i < values.length; i++) { // added by Culotta - 12.10.0 to enforce INF - INF = 0 if(Double.isInfinite(values[i]) && Double.isInfinite(m.valueAtLocation(i))) { double newValue = m.valueAtLocation(i); // make sure they're opposite signed if((newValue * values[i]) < 0) { values[i] = 0.0; // inf - inf = 0 } else values[i] += newValue; } else values[i] += m.valueAtLocation(i); } } else for (int i = m.numLocations()-1; i >= 0; i--) { // added by Culotta - 12.10.02 to enforce INF - INF = 0 if(Double.isInfinite(values[m.indexAtLocation(i)]) && Double.isInfinite(((DenseMatrix)m).values[i])) { double newValue = m.valueAtLocation(i); // make sure they're oppisite signed if((newValue * values[m.indexAtLocation(i)]) < 0) { values[m.indexAtLocation(i)] = 0.0; } else values[m.indexAtLocation(i)] += newValue; } else values[m.indexAtLocation(i)] += m.valueAtLocation(i); } } public void plusEquals (ConstantMatrix m, double factor) { if (m instanceof DenseMatrix) { assert (m.singleSize() == values.length); for (int i = 0; i < values.length; i++) { // added by Culotta - 12.10.0 to enforce INF - INF = 0 if(Double.isInfinite(values[i]) && Double.isInfinite(m.valueAtLocation(i))) { double newValue = factor*(m.valueAtLocation(i)); // make sure they're opposite signed if((newValue * values[i]) < 0) { values[i] = 0.0; // inf - inf = 0 } else values[i] += newValue; } else values[i] += (m.valueAtLocation(i) * factor); } } else for (int i = m.numLocations()-1; i >= 0; i--){ // added by Culotta - 12.10.02 to enforce INF - INF = 0 if(Double.isInfinite(values[m.indexAtLocation(i)]) && Double.isInfinite(m.valueAtLocation(i))) { double newValue = factor*m.valueAtLocation(i); // make sure they're oppisite signed if((newValue * values[m.indexAtLocation(i)]) < 0) { values[m.indexAtLocation(i)] = 0.0; } else values[m.indexAtLocation(i)] += newValue; } else values[m.indexAtLocation(i)] += m.valueAtLocation(i) * factor; } } public void equalsPlus (double factor, ConstantMatrix m) { if (m instanceof DenseMatrix) { assert (m.singleSize() == values.length); for (int i = 0; i < values.length; i++) { // added by Culotta - 12.10.0 to enforce INF - INF = 0 if(Double.isInfinite(values[i]) && Double.isInfinite(((DenseMatrix)m).values[i])) { double lhs = factor*values[i]; double rhs = ((DenseMatrix)m).values[i]; // make sure they're opposite signed if((lhs * rhs) < 0) { values[i] = 0.0; // inf - inf = 0 } else values[i] = lhs + rhs; } else values[i] = factor*values[i] + ((DenseMatrix)m).values[i]; } } else for (int i = m.numLocations()-1; i >= 0; i--) { // added by Culotta - 12.10.02 to enforce INF - INF = 0 if(Double.isInfinite(values[m.indexAtLocation(i)]) && Double.isInfinite(((DenseMatrix)m).values[i])) { double lhs = factor * values[m.indexAtLocation(i)]; double rhs = m.valueAtLocation(i); // make sure they're oppisite signed if((lhs * rhs) < 0) { values[m.indexAtLocation(i)] = 0.0; } else values[m.indexAtLocation(i)] = lhs + rhs; } else values[m.indexAtLocation(i)] = factor * values[m.indexAtLocation(i)] + m.valueAtLocation(i); } } public void timesEquals (double factor) { for (int i = 0; i < values.length; i++) values[i] *= factor; } public void elementwiseTimesEquals (ConstantMatrix m) { if (m instanceof DenseMatrix) { assert (m.singleSize() == values.length); for (int i = 0; i < values.length; i++) values[i] *= ((DenseMatrix)m).values[i]; } else for (int i = m.numLocations()-1; i >= 0; i--) values[m.indexAtLocation(i)] *= m.valueAtLocation(i); } public void elementwiseTimesEquals (ConstantMatrix m, double factor) { if (m instanceof DenseMatrix) { assert (m.singleSize() == values.length); for (int i = 0; i < values.length; i++) values[i] *= ((DenseMatrix)m).values[i] * factor; } else for (int i = m.numLocations()-1; i >= 0; i--) values[m.indexAtLocation(i)] *= m.valueAtLocation(i) * factor; } public void divideEquals (double factor) { for (int i = 0; i < values.length; i++) values[i] /= factor; } public void elementwiseDivideEquals (ConstantMatrix m) { if (m instanceof DenseMatrix) { assert (m.singleSize() == values.length); for (int i = 0; i < values.length; i++) values[i] /= ((DenseMatrix)m).values[i]; } else for (int i = m.numLocations()-1; i >= 0; i--) values[m.indexAtLocation(i)] /= m.valueAtLocation(i); } public void elementwiseDivideEquals (ConstantMatrix m, double factor) { if (m instanceof DenseMatrix) { assert (m.singleSize() == values.length); for (int i = 0; i < values.length; i++) values[i] /= ((DenseMatrix)m).values[i] * factor; } else for (int i = m.numLocations()-1; i >= 0; i--) values[m.indexAtLocation(i)] /= m.valueAtLocation(i) * factor; } // xxx Perhaps make a special efficient case for binary vectors public double dotProduct (ConstantMatrix m) { double ret = 0; if (m instanceof DenseMatrix) { assert (m.singleSize() == values.length); for (int i = 0; i < values.length; i++) ret += values[i] * ((DenseMatrix)m).values[i]; } else { for (int i = m.numLocations()-1; i >= 0; i--) if(m.indexAtLocation(i) < values.length)//fix problem ret += values[m.indexAtLocation(i)] * m.valueAtLocation(i); else{ // System.out.println(m.indexAtLocation(i) + ":" + values.length); // throw new ArrayIndexOutOfBoundsException(m.indexAtLocation(i)); } } return ret; } public double absNorm() { double ret = 0; for (int i = 0; i < values.length; i++) ret += Math.abs(values[i]); return ret; } public double oneNorm () { double ret = 0; for (int i = 0; i < values.length; i++) ret += values[i]; return ret; } public double twoNorm () { double ret = 0; for (int i = 0; i < values.length; i++) ret += values[i] * values[i]; return Math.sqrt (ret); } public double infinityNorm () { double max = Double.NEGATIVE_INFINITY; for (int i = 0; i < values.length; i++) if (Math.abs(values[i]) > max) max = Math.abs(values[i]); return max; } public double oneNormalize () { double norm = oneNorm(); for (int i = 0; i < values.length; i++) values[i] /= norm; return norm; } public double twoNormalize () { double norm = twoNorm(); for (int i = 0; i < values.length; i++) values[i] /= norm; return norm; } public double absNormalize () { double norm = absNorm(); if (norm > 0) for (int i = 0; i < values.length; i++) values[i] /= norm; return norm; } public double infinityNormalize () { double norm = infinityNorm(); for (int i = 0; i < values.length; i++) values[i] /= norm; return norm; } public void print() { for (int i = 0; i < values.length; i++) System.out.println ("DenseMatrix["+i+"] = "+values[i]); } public boolean isNaN() { for (int i = 0; i < values.length; i++) if (Double.isNaN(values[i])) return true; return false; } public final void substitute (double oldValue, double newValue) { for (int i = values.length-1; i >= 0; i--) if (values[i] == oldValue) values[i] = newValue; } // Serialization private static final long serialVersionUID = 1; private static final int CURRENT_SERIAL_VERSION = 0; private static final int NULL_INTEGER = -1; private void writeObject (ObjectOutputStream out) throws IOException { int i, size; out.writeInt (CURRENT_SERIAL_VERSION); if (values != null) { size = values.length; out.writeInt(size); for (i=0; i<size; i++) { out.writeDouble(values[i]); } } else { out.writeInt(NULL_INTEGER); } } private void readObject (ObjectInputStream in) throws IOException, ClassNotFoundException { int i, size; this.hasInfinite = false; int version = in.readInt (); size = in.readInt(); if (size != NULL_INTEGER) { values = new double[size]; for (i = 0; i<size; i++) { values[i] = in.readDouble(); if (Double.isInfinite (values[i])) this.hasInfinite = true; } } else { values = null; } } public static void plusEquals (double[] accumulator, double[] addend) { assert (accumulator.length == addend.length); for (int i = 0; i < addend.length; i++) accumulator[i] += addend[i]; } public static void plusEquals (double[] accumulator, double[] addend, double factor) { assert (accumulator.length == addend.length); for (int i = 0; i < addend.length; i++) accumulator[i] += factor * addend[i]; } public static void timesEquals (double[] accumulator, double[] product) { assert (accumulator.length == product.length); for (int i = 0; i < product.length; i++) accumulator[i] *= product[i]; } public static double infinityNorm (double[] vector) { double max = Double.NEGATIVE_INFINITY; for (int i = 0; i < vector.length; i++) if (Math.abs(vector[i]) > max) max = Math.abs(vector[i]); return max; } // This should probably be generalized. public boolean almostEquals (ConstantMatrix m2) { if (getNumDimensions () != m2.getNumDimensions ()) { return false; } if (numLocations () != m2.numLocations ()) { return false; } int[] dims1 = new int [getNumDimensions ()]; int[] dims2 = new int [getNumDimensions ()]; getDimensions (dims1); m2.getDimensions (dims2); for (int i = 0; i < dims1.length; i++) { if (dims1 [i] != dims2 [i]) { return false; } } for (int i = 0; i < numLocations(); i++) { if (!Maths.almostEquals (valueAtLocation (i), m2.valueAtLocation (i))) { return false; } } return true; } }