gov.sandia.cognition.math.matrix.custom.DenseVector Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cognitive-foundry Show documentation
Show all versions of cognitive-foundry Show documentation
A single jar with all the Cognitive Foundry components.
/*
* File: DenseVector.java
* Authors: Jeremy D. Wendt
* Company: Sandia National Laboratories
* Project: Cognitive Foundry
*
* Copyright 2015, Sandia Corporation. Under the terms of Contract
* DE-AC04-94AL85000, there is a non-exclusive license for use of this work by
* or on behalf of the U.S. Government. Export of this program may require a
* license from the United States Government. See CopyrightHistory.txt for
* complete details.
*/
package gov.sandia.cognition.math.matrix.custom;
import gov.sandia.cognition.collection.ArrayUtil;
import gov.sandia.cognition.math.matrix.Matrix;
import gov.sandia.cognition.math.matrix.Vector;
import gov.sandia.cognition.math.matrix.VectorEntry;
import gov.sandia.cognition.math.matrix.VectorFactory;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
/**
* Our dense vector implementation. Rather straightforward: stores all of the
* data in an in-order array.
*
* @author Jeremy D. Wendt
* @since 3.4.3
*/
public class DenseVector
extends BaseVector
{
/**
* The data is stored in this vector.
*/
double[] values;
/**
* This should never be called by anything or anyone other than Java's
* serialization code.
*/
protected DenseVector()
{
super();
// NOTE: This doesn't initialize anything
}
/**
* Creates a dense vector of length n. Initializes the vector to all zeroes.
*
* @param n The length the vector should be
*/
public DenseVector(
final int n)
{
super();
this.values = new double[n];
}
/**
* Initializes the vector to length n with all values initialized to
* defaultVal.
*
* @param n The length the vector should be
* @param defaultVal The initial value for all elements of the vector
*/
public DenseVector(
final int n,
final double defaultVal)
{
super();
this.values = new double[n];
Arrays.fill(this.values, defaultVal);
}
/**
* Copy constructor copies the input dense vector into this
*
* @param v The vector to copy
*/
public DenseVector(
final DenseVector v)
{
this(v.values);
}
/**
* Helper constructor that copies the data from the array into this
*
* @param arr An array of doubles to put in this dense vector
*/
public DenseVector(
final double[] arr)
{
super();
this.values = Arrays.copyOf(arr, arr.length);
}
/**
* Helper constructor that copies the data from the list into this
*
* @param arr A list of doubles to put into this dense vector
*/
public DenseVector(
final List arr)
{
super();
final int d = arr.size();
values = new double[d];
for (int i = 0; i < d; ++i)
{
values[i] = arr.get(i);
}
}
@Override
final public DenseVector clone()
{
final DenseVector result = (DenseVector) super.clone();
result.values = ArrayUtil.copy(this.values);
return result;
}
@Override
public void scaledPlusEquals(
final DenseVector other,
final double scaleFactor)
{
this.assertSameDimensionality(other);
for (int i = 0; i < values.length; ++i)
{
values[i] += other.values[i] * scaleFactor;
}
}
@Override
public void scaledPlusEquals(
final SparseVector other,
final double scaleFactor)
{
this.assertSameDimensionality(other);
other.compress();
int[] locs = other.getIndices();
double[] vals = other.getValues();
for (int i = 0; i < locs.length; ++i)
{
values[locs[i]] += vals[i] * scaleFactor;
}
}
@Override
public final void plusEquals(
final DenseVector other)
{
this.assertSameDimensionality(other);
for (int i = 0; i < values.length; ++i)
{
values[i] += other.values[i];
}
}
@Override
public final void plusEquals(
final SparseVector other)
{
this.assertSameDimensionality(other);
other.compress();
int[] locs = other.getIndices();
double[] vals = other.getValues();
for (int i = 0; i < locs.length; ++i)
{
values[locs[i]] += vals[i];
}
}
@Override
public final void minusEquals(
final DenseVector other)
{
this.assertSameDimensionality(other);
for (int i = 0; i < values.length; ++i)
{
values[i] -= other.values[i];
}
}
@Override
public final void minusEquals(
final SparseVector other)
{
this.assertSameDimensionality(other);
other.compress();
int[] locs = other.getIndices();
double[] vals = other.getValues();
for (int i = 0; i < locs.length; ++i)
{
values[locs[i]] -= vals[i];
}
}
@Override
public final void dotTimesEquals(
final DenseVector other)
{
this.assertSameDimensionality(other);
for (int i = 0; i < values.length; ++i)
{
values[i] *= other.values[i];
}
}
@Override
public final void dotTimesEquals(
final SparseVector other)
{
this.assertSameDimensionality(other);
other.compress();
int[] locs = other.getIndices();
double[] vals = other.getValues();
int idx = 0;
for (int i = 0; i < values.length; ++i)
{
if ((idx < locs.length) && (locs[idx] == i))
{
values[i] *= vals[idx];
++idx;
}
else
{
values[i] = 0;
}
}
}
@Override
public final double euclideanDistanceSquared(
final DenseVector other)
{
this.assertSameDimensionality(other);
double dist = 0.0;
double tmp;
for (int i = 0; i < values.length; ++i)
{
tmp = (values[i] - other.values[i]);
dist += tmp * tmp;
}
return dist;
}
@Override
public final double euclideanDistanceSquared(
final SparseVector other)
{
return other.euclideanDistanceSquared(this);
}
@Override
public final Matrix outerProduct(
final DenseVector other)
{
int numRows = getDimensionality();
int numCols = other.getDimensionality();
final DenseVector[] rows = new DenseVector[numRows];
for (int i = 0; i < numRows; ++i)
{
DenseVector row = new DenseVector(numCols);
for (int j = 0; j < numCols; ++j)
{
row.values[j] = values[i] * other.values[j];
}
rows[i] = row;
}
return new DenseMatrix(rows);
}
@Override
public final Matrix outerProduct(
final SparseVector other)
{
int numRows = getDimensionality();
int numCols = other.getDimensionality();
SparseMatrix result = new SparseMatrix(numRows, numCols, true);
other.compress();
int[] locs = other.getIndices();
double[] vals = other.getValues();
for (int i = 0; i < numRows; ++i)
{
SparseVector row = new SparseVector(numCols);
for (int j = 0; j < locs.length; ++j)
{
row.setElement(locs[j], values[i] * vals[j]);
}
result.setRowInternal(i, row);
}
return result;
}
@Override
public final Vector stack(
final DenseVector other)
{
DenseVector result = new DenseVector(values.length + other.values.length);
for (int i = 0; i < values.length; ++i)
{
result.values[i] = values[i];
}
for (int i = 0; i < other.values.length; ++i)
{
result.values[values.length + i] = other.values[i];
}
return result;
}
@Override
public final Vector stack(
final SparseVector other)
{
Vector result;
int len = values.length + other.getDimensionality();
int nnz = countNonZeros() + other.countNonZeros();
if (nnz > SparseVector.SPARSE_TO_DENSE_THRESHOLD * len)
{
result = new DenseVector(len);
}
else
{
result = new SparseVector(len);
}
for (int i = 0; i < values.length; ++i)
{
result.setElement(i, values[i]);
}
// NOTE: The below could be faster (and I could get rid of all of the
// "setElement"s if I wanted to write two versions of this method. As
// it's likely to be infrequently called, I don't want to increase code
// complexity for a minimal gain.
//
// The way to do this would be to move the below into the above if/elses.
// Then, you would only need to set the 0s in the dense vector class
// (as 0s are implicitly stored in sparse vectors). Moreover, you
// could call the package-private methods to get direct access to the
// entries of the sparse or dense vector instead of calling setElement.
other.compress();
int[] locs = other.getIndices();
double[] vals = other.getValues();
int idx = 0;
final int otherDimensionality = other.getDimensionality();
for (int i = 0; i < otherDimensionality; ++i)
{
if ((idx < locs.length) && (locs[idx] == i))
{
result.setElement(values.length + i, vals[idx]);
++idx;
}
else
{
result.setElement(values.length + i, 0);
}
}
return result;
}
@Override
public final double dotProduct(
final DenseVector other)
{
this.assertSameDimensionality(other);
double result = 0;
for (int i = 0; i < values.length; ++i)
{
result += values[i] * other.values[i];
}
return result;
}
@Override
public final double dotProduct(
final SparseVector other)
{
return other.dotProduct(this);
}
@Override
final public Iterator iterator()
{
return new VectorIterator(this);
}
@Override
final public int getDimensionality()
{
return values.length;
}
@Override
public double get(
final int index)
{
return values[index];
}
@Override
final public double getElement(
final int index)
{
return values[index];
}
@Override
public void set(
final int index,
final double value)
{
values[index] = value;
}
@Override
final public void setElement(
final int index,
final double value)
{
values[index] = value;
}
/**
* Package-private method that allows peers direct access to the elements
* contained herein.
*
* @return the array of elements stored herein.
*/
final double[] getValues()
{
return this.values;
}
@Override
final public Vector subVector(
final int minIndex,
final int maxIndex)
{
if (minIndex > maxIndex)
{
throw new NegativeArraySizeException("Input bounds [" + minIndex
+ ", " + maxIndex + "] goes backwards!");
}
if ((minIndex < 0) || (maxIndex >= values.length))
{
throw new ArrayIndexOutOfBoundsException("Input subvector from "
+ minIndex + " to " + maxIndex + " (inclusive) exceeds the "
+ "bounds of this vector [0, " + values.length + ").");
}
int len = maxIndex - minIndex + 1;
DenseVector result = new DenseVector(len);
for (int i = minIndex; i <= maxIndex; ++i)
{
result.values[i - minIndex] = values[i];
}
return result;
}
@Override
final public Vector scale(
final double d)
{
DenseVector result = new DenseVector(values.length);
for (int i = 0; i < values.length; ++i)
{
result.values[i] = values[i] * d;
}
return result;
}
@Override
final public Vector dotTimes(
final Vector v)
{
// By switch from this.dotTimes(v) to v.dotTimes(this), we get sparse
// vectors dotted with dense still being sparse and dense w/ dense is
// still dense. The way this was originally implemented in the Foundry
// (this.clone().dotTimesEquals(v)), if v is sparse, it returns a
// dense vector type storing sparse data.
Vector result = v.clone();
result.dotTimesEquals(this);
return result;
}
/**
* Computes the number of non-zero entries in this
*
* @return The number of non-zero entries in this
*/
final public int countNonZeros()
{
int nnz = 0;
for (final double d : values)
{
nnz += (d == 0) ? 0 : 1;
}
return nnz;
}
@Override
public boolean isSparse()
{
return false;
}
@Override
public VectorFactory> getVectorFactory()
{
return CustomDenseVectorFactory.INSTANCE;
}
@Override
public double sum()
{
double result = 0.0;
for (final double value : this.values)
{
result += value;
}
return result;
}
@Override
public double getMinValue()
{
double min = Double.POSITIVE_INFINITY;
for (final double value : this.values)
{
if (value < min)
{
min = value;
}
}
return min;
}
@Override
public double getMaxValue()
{
double max = Double.NEGATIVE_INFINITY;
for (final double value : this.values)
{
if (value > max)
{
max = value;
}
}
return max;
}
@Override
public int getEntryCount()
{
return this.values.length;
}
@Override
public void zero()
{
Arrays.fill(this.values, 0.0);
}
}