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

gov.sandia.cognition.collection.AbstractMutableDoubleMap Maven / Gradle / Ivy

There is a newer version: 4.0.1
Show newest version
/*
 * File:                AbstractScalarMap.java
 * Authors:             Kevin R. Dixon
 * Company:             Sandia National Laboratories
 * Project:             Incremental Learning Core
 *
 * Copyright June 15, 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.
 *
 */
package gov.sandia.cognition.collection;

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



/**
 * A partial implementation of a ScalarMap with a MutableDouble value
 * @param 
 * Type of key in the Map
 * @author Kevin R. Dixon
 * @since 3.2.1
 */
public class AbstractMutableDoubleMap
    extends AbstractScalarMap
{

    /**
     * Map backing that performs the storage.
     */
    protected Map map;

    /** 
     * Creates a new instance of AbstractMutableDoubleMap 
     * @param   map
     *      The backing map that the data is stored in.
     */
    public AbstractMutableDoubleMap(
        final Map map )
    {
        super();
        this.map = map;
    }


    @Override
    public AbstractMutableDoubleMap clone()
    {
        @SuppressWarnings("unchecked")
        AbstractMutableDoubleMap clone =
            (AbstractMutableDoubleMap) super.clone();
        // NOTE: there is the potential for a problem if this.map isn't a
        // LinkedHashMap!
        clone.map = new LinkedHashMap( this.size() );
        clone.incrementAll(this);
        return clone;
    }

    @Override
    public Map asMap()
    {
        return this.map;
    }

    /**
     * Removes entries from the map with value of 0.0
     */
    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 double get(
        final KeyType key)
    {
        final MutableDouble entry = this.map.get(key);
        if (entry == null)
        {
            return 0.0;
        }
        else
        {
            return entry.value;
        }
    }

    @Override
    public void set(
        final KeyType key,
        final double value)
    {

        final MutableDouble entry = this.map.get(key);
        if( entry == null )
        {
            // Only need to allocate if it's not null
            if( value != 0.0 )
            {
                this.map.put( key, new MutableDouble( value ) );
            }
        }

        // I've commented this out, because I think there's the potential for
        // memory thrashing if this is left in... call compact() method instead?
        //  -- krdixon, 2011-06-27
//        else if( value == 0.0 )
//        {
//            this.map.remove(key);
//        }
        else
        {
            entry.value = value;
        }
    }

    @Override
    public double increment(
        final KeyType key,
        final double value)
    {
        final MutableDouble entry = this.map.get(key);
        double newValue;
        if( entry == null )
        {
            if( value != 0.0 )
            {
                // It's best to avoid this.set() here as it could mess up
                // our total tracker in some subclasses...
                // Also it's more efficient this way (avoid another get)
                this.map.put( key, new MutableDouble(value) );
            }
            newValue = value;
        }
        else
        {
            entry.value += value;
            newValue = entry.value;
        }
        return newValue;
    }


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

    @Override
    public SimpleEntrySet entrySet()
    {
        return new SimpleEntrySet( this.map );
    }

    @Override
    public Set keySet()
    {
        return this.map.keySet();
    }

    @Override
    public boolean containsKey(
        final KeyType key)
    {
        return this.map.containsKey(key);
    }

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

    /**
     * Simple Entry Set for DefaultInfiniteVector
     * @param 
     *      The type of the key in the map.
     */
    protected static class SimpleEntrySet
        extends AbstractSet>
    {

        /**
         * Backing map
         */
        protected Map map;

        /**
         * Creates a new instance of SimpleEntrySet
         * @param map
         * Backing map
         */
        public SimpleEntrySet(
            Map map)
        {
            this.map = map;
        }

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

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

    }

    /**
     * Simple iterator for DefaultInfiniteVector
     * @param 
     *      The type of the key in the map.
     */
    protected static class SimpleIterator
        implements Iterator>
    {

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

        /**
         * Default constructor
         * @param delegate
         * Iterator that does all the work
         */
        public SimpleIterator(
            Iterator> delegate )
        {
            this.delegate = delegate;
        }

        @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();
        }

    }


    /**
     * Entry for the AbstractScalarMap
     * @param 
     *      The type of the key in the map.
     */
    protected static class SimpleEntry
        implements ScalarMap.Entry,
        InfiniteVector.Entry
    {

        /**
         * Key associated with this entry
         */
        protected KeyType key;

        /**
         * Value associated with the entry
         */
        protected MutableDouble value;

        /**
         * Creates a new instance of SimpleEntry
         * @param key
         * Key represented by the Entry
         * @param value
         * Value associated with the Entry
         */
        public SimpleEntry(
            final KeyType key,
            final MutableDouble value )
        {
            this.key = key;
            this.value = value;
        }

        @Override
        public KeyType getKey()
        {
            return this.key;
        }

        @Override
        public double getValue()
        {
            return value.value;
        }

        @Override
        public void setValue(
            double value)
        {
            this.value.value = value;
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy