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

gov.sandia.cognition.math.matrix.DefaultInfiniteVector Maven / Gradle / Ivy

There is a newer version: 4.0.1
Show newest version
/*
 * File:                DefaultInfiniteVector.java
 * Authors:             Kevin R. Dixon
 * Company:             Sandia National Laboratories
 * Project:             Cognitive Foundry
 * 
 * Copyright Apr 26, 2011, 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;

import gov.sandia.cognition.collection.AbstractMutableDoubleMap;
import gov.sandia.cognition.collection.ScalarMap;
import gov.sandia.cognition.math.MutableDouble;
import gov.sandia.cognition.math.matrix.InfiniteVector.Entry;
import gov.sandia.cognition.util.ArgumentChecker;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;



/**
 * An implementation of an {@code InfiniteVector} backed by a
 * {@code LinkedHashMap}.
 *
 * @param   
 *      The type of the keys (indices) into the infinite dimensional vector.
 * @author  Justin Basilico
 * @author  Kevin R. Dixon
 * @since   3.2.1
 */
public class DefaultInfiniteVector
    extends AbstractMutableDoubleMap
    implements InfiniteVector
{
    
    /** The default capacity is {@value}. */
    public static final int DEFAULT_INITIAL_CAPACITY = 16;

    /** 
     * Creates a new, empty instance of {@code DefaultInfiniteVector}.
     */
    public DefaultInfiniteVector()
    {
        this(DEFAULT_INITIAL_CAPACITY);
    }

    /**
     * Creates a new, empty instance of {@code DefaultInfiniteVector} with the
     * given initial capacity.
     *
     * @param   initialCapacity
     *      The initial capacity of the data structure. Must be positive.
     */
    public DefaultInfiniteVector(
        final int initialCapacity)
    {
        this(new LinkedHashMap(initialCapacity));
    }


    /**
     * Creates a new {@code AbstractMapInfiniteVector} with the given backing
     * map.
     *
     * @param   map
     *      The backing map that the data is stored in.
     */
    protected DefaultInfiniteVector(
        final LinkedHashMap map)
    {
        super( map );
    }

    @Override
    public DefaultInfiniteVector clone()
    {
        return (DefaultInfiniteVector) super.clone();
    }

    @Override
    @SuppressWarnings("unchecked")
    public boolean equals(
        final Object other)
    {
        return (other == this)
            || (other instanceof InfiniteVector
                && this.equals((InfiniteVector) other, 0.0));
    }

    @Override
    public boolean equals(
        final InfiniteVector other,
        final double effectiveZero)
    {
        return (other != null) && this.euclideanDistance(other) <= effectiveZero;
    }

    @Override
    public int hashCode()
    {
        return this.map.hashCode();
    }

    @Override
    public double sum()
    {
        double sum = 0.0;
        for( ScalarMap.Entry entry : this.entrySet() )
        {
            sum += entry.getValue();
        }
        return sum;
    }

    @Override
    public double norm1()
    {
        double result = 0.0;
        for (ScalarMap.Entry entry : this.entrySet())
        {
            result += Math.abs(entry.getValue());
        }
        return result;
    }

    @Override
    public double norm2()
    {
        return Math.sqrt(this.norm2Squared());
    }

    @Override
    public double norm2Squared()
    {
        double result = 0.0;
        for (ScalarMap.Entry entry : this.entrySet())
        {
            final double value = entry.getValue();
            result += value * value;
        }
        return result;
    }

    @Override
    public double normInfinity()
    {
        double max = 0.0;
        for (ScalarMap.Entry entry : this.entrySet())
        {
            final double value = Math.abs(entry.getValue());
            if (value > max)
            {
                max = value;
            }

        }
        return max;
    }

    @Override
    public double norm(
        final double power)
    {
        ArgumentChecker.assertIsPositive("power", power);
        if( Double.isNaN(power) )
        {
            throw new ArithmeticException( "Power cannot be NaN" );
        }

        if( Double.isInfinite(power) )
        {
            return this.normInfinity();
        }

        double sum = 0.0;
        for( VectorSpace.Entry entry : this )
        {
            final double value = Math.abs(entry.getValue());
            sum += Math.pow(value,power);
        }
        return Math.pow(sum,1.0/power);
    }

    @Override
    public double cosine(
        final InfiniteVector other)
    {
        final double dotProduct = this.dotProduct(other);
        if (dotProduct == 0.0)
        {
            return 0.0;
        }
        else
        {
            final double thisNorm = this.norm2Squared();
            final double otherNorm = other.norm2Squared();
            return dotProduct / Math.sqrt(thisNorm * otherNorm);
        }
    }

    @Override
    public double angle(
        final InfiniteVector other)
    {
        return Math.acos(this.cosine(other));
    }

    @Override
    public double euclideanDistance(
        final InfiniteVector other)
    {
        return Math.sqrt(this.euclideanDistanceSquared(other));
    }

    @Override
    public double euclideanDistanceSquared(
        final InfiniteVector other)
    {
        return this.minus(other).norm2Squared();
    }

    @Override
    public InfiniteVector unitVector()
    {
        final InfiniteVector result = this.clone();
        result.unitVectorEquals();
        return result;
    }

    @Override
    public void unitVectorEquals()
    {
        final double length = this.norm2();

        if (length != 0.0)
        {
            this.scaleEquals(1.0 / length);
        }
    }

    @Override
    public boolean isUnitVector()
    {
        return this.isUnitVector(0.0);
    }

    @Override
    public boolean isUnitVector(
        final double tolerance)
    {
        return Math.abs(1.0 - this.norm2()) <= tolerance;
    }

    @Override
    public double dot(
        final InfiniteVector other)
    {
        return this.dotProduct(other);
    }
    
    @Override
    public double dotProduct(
        final InfiniteVector other)
    {
        double result = 0.0;
        for (Map.Entry entry : this.map.entrySet())
        {
            final KeyType key = entry.getKey();
            final double thisValue = entry.getValue().value;
            final double otherValue = other.get(key);
            result += thisValue * otherValue;
        }
        return result;
    }

    @Override
    public InfiniteVector plus(
        final InfiniteVector other)
    {
        final InfiniteVector result = this.clone();
        result.plusEquals(other);
        return result;
    }

    @Override
    public void plusEquals(
        final InfiniteVector other)
    {
        for (ScalarMap.Entry entry : other.entrySet())
        {
            this.increment(entry.getKey(), entry.getValue());
        }
    }

    @Override
    public InfiniteVector minus(
        final InfiniteVector other)
    {
        final InfiniteVector result = this.clone();
        result.minusEquals(other);
        return result;
    }
    
    @Override
    public void minusEquals(
        final InfiniteVector other)
    {
        if (this == other)
        {
            // If we are subtracting from self, avoid modification errors.
            this.zero();
        }
        else
        {
            for (ScalarMap.Entry entry : other.entrySet())
            {
                this.decrement(entry.getKey(), entry.getValue());
            }
        }
    }

    @Override
    public InfiniteVector dotTimes(
        final InfiniteVector other)
    {
        final InfiniteVector result = this.clone();
        result.dotTimesEquals(other);
        return result;
    }

    @Override
    public void dotTimesEquals(
        final InfiniteVector other)
    {
        for (Map.Entry entry : this.map.entrySet())
        {
            final KeyType key = entry.getKey();
            final MutableDouble value = entry.getValue();
            final double thisValue = value.value;
            final double otherValue = other.get(key);
            value.value = thisValue * otherValue;
        }
    }

    @Override
    public InfiniteVector scale(
        final double scaleFactor)
    {
        final InfiniteVector result = this.clone();
        result.scaleEquals(scaleFactor);
        return result;
    }
    
    @Override
    public void scaleEquals(
        final double scaleFactor)
    {
        for (Map.Entry entry : this.map.entrySet())
        {
            final MutableDouble value = entry.getValue();
            value.value *= scaleFactor;
        }
    }

    @Override
    public InfiniteVector scaledPlus(
        final double scaleFactor,
        final InfiniteVector other)
    {
        final InfiniteVector result = this.clone();
        result.scaledPlusEquals(scaleFactor, other);
        return result;
    }

    @Override
    public void scaledPlusEquals(
        final double scaleFactor,
        final InfiniteVector other)
    {
        for (ScalarMap.Entry entry : other.entrySet())
        {
            this.increment(entry.getKey(), scaleFactor * entry.getValue());
        }
    }

    @Override
    public InfiniteVector scaledMinus(
        final double scaleFactor,
        final InfiniteVector other)
    {
        final InfiniteVector result = this.clone();
        result.scaledMinusEquals(scaleFactor, other);
        return result;
    }

    @Override
    public void scaledMinusEquals(
        final double scaleFactor,
        final InfiniteVector other)
    {
        for (ScalarMap.Entry entry : other.entrySet())
        {
            this.decrement(entry.getKey(), scaleFactor * entry.getValue());
        }
    }

    @Override
    public void zero()
    {
        this.clear();
    }

    @Override
    public boolean isZero()
    {
        return this.isZero(0.0);
    }

    @Override
    public boolean isZero(
        final double effectiveZero)
    {
        for (Map.Entry entry : this.map.entrySet())
        {
            final double v1 = entry.getValue().value;
            if (Math.abs(v1) > effectiveZero)
            {
                return false;
            }
        }
        return true;
    }

    @Override
    public void compact()
    {
        // We can't use entrySet to remove null/zero elements because it throws
        // a ConcurrentModificationException
        // We can't use the keySet either because that throws an Exception,
        // so we need to clone it first
        LinkedList removeKeys = new LinkedList();
        for (Map.Entry entry : this.map.entrySet())
        {
            final MutableDouble value = entry.getValue();
            if( value.value == 0.0 )
            {
                removeKeys.add( entry.getKey() );
            }
        }
        for( KeyType key : removeKeys )
        {
            this.map.remove(key);
        }
    }

    @Override
    public String toString()
    {
        return this.map.toString();
    }

    @Override
    public Iterator> iterator()
    {
        return new SimpleIterator();
    }

    @Override
    public InfiniteVector negative()
    {
        final InfiniteVector result = this.clone();
        result.negativeEquals();
        return result;
    }

    @Override
    public void negativeEquals()
    {
        this.scaleEquals(-1.0);
    }

    /**
     * Simple iterator for DefaultInfiniteVector
     */
    protected class SimpleIterator
        implements Iterator>
    {

        /**
         * Iterator that does all the work
         */
        private Iterator> delegate;

        /**
         * Default constructor
         */
        public SimpleIterator()
        {
            this.delegate = map.entrySet().iterator();
        }

        @Override
        public boolean hasNext()
        {
            return this.delegate.hasNext();
        }

        @Override
        public AbstractMutableDoubleMap.SimpleEntry next()
        {
            Map.Entry entry = this.delegate.next();
            return new AbstractMutableDoubleMap.SimpleEntry(
                entry.getKey(), entry.getValue() );
        }

        @Override
        public void remove()
        {
            this.delegate.remove();
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy