All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gov.sandia.cognition.math.matrix.custom.DenseVector Maven / Gradle / Ivy

There is a newer version: 4.0.1
Show newest version
/*
 * 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);
    }
    
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy