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

edu.ucla.sspace.util.IntegerMap Maven / Gradle / Ivy

Go to download

The S-Space Package is a collection of algorithms for building Semantic Spaces as well as a highly-scalable library for designing new distributional semantics algorithms. Distributional algorithms process text corpora and represent the semantic for words as high dimensional feature vectors. This package also includes matrices, vectors, and numerous clustering algorithms. These approaches are known by many names, such as word spaces, semantic spaces, or distributed semantics and rest upon the Distributional Hypothesis: words that appear in similar contexts have similar meanings.

The newest version!
/*
 * Copyright 2009 David Jurgens
 *
 * This file is part of the S-Space package and is covered under the terms and
 * conditions therein.
 *
 * The S-Space package is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as published
 * by the Free Software Foundation and distributed hereunder to you.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND NO REPRESENTATIONS OR WARRANTIES,
 * EXPRESS OR IMPLIED ARE MADE.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, WE MAKE
 * NO REPRESENTATIONS OR WARRANTIES OF MERCHANT- ABILITY OR FITNESS FOR ANY
 * PARTICULAR PURPOSE OR THAT THE USE OF THE LICENSED SOFTWARE OR DOCUMENTATION
 * WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER
 * RIGHTS.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see .
 */

package edu.ucla.sspace.util;

import java.util.AbstractCollection;
import java.util.AbstractSet;
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Set;

/**
 * A space-optimized map for associating integer keys with values, which also
 * doubles as a sparse object array.

* * When used as a {@link SparseArray} this class allows negative valued indices, * as well as the index of {@link Integer#MAX_VALUE}. This affects the behavior * of two methods. First {@code size} will return {@code Integer.MAX_VALUE}, * but the true maximum size is 232, which is larger than an {@code * int} can represent. Second, the {@code toArray} method will only return * those elements that fall within the range of the provided array. This * limitation entails that the values at negative-valued indices will not * be stored. In this case it is best to use the {@link #entrySet()} method to * access all of the indices and associated values in order.

* * This class makes a trade off for reduced space usage at the cost of decreased * performace. The {@code put}, {@code get}, {@code containsKey} and {@code * get} operations are all logarithmic when the map is unmodified. If a new * mapping is added, or one is removed, the operation is linear in the number of * mappings. Both {@code size} and {@code isEmpty} are still constant time.

* * The {@code get} operation runs in logarithmic time. The {@code set} * operation runs in consant time if setting an existing non-zero value to a * non-zero value. However, if the {@code set} invocation sets a zero value to * non-zero, the operation is linear with the size of the array.

* * This map does not allow {@code null} keys, but does allow {@code null * values}.

* * Implementation Note: the {@code Iterator.remove()} method is currently * unsupported and will throw an exception when called. However, a future * implementation will fix this.

* * @see TrieMap * @see Map * @see SparseArray * * @author David Jurgens */ public class IntegerMap extends AbstractMap implements SparseArray { private static final long serialVersionUID = 1L; /** * The keys stored in this map, in sorted order. The index at which a key * is found corresponds to the index at which its value is found. */ int[] keyIndices; /** * The values stored in this map. */ Object[] values; /** * Creates a new map. */ public IntegerMap() { keyIndices = new int[0]; values = new Object[0]; } /** * Creates a new map with the mappings contained in {@code m}. */ public IntegerMap(Map m) { // Pre-allocate the arrays for all the mappings needed instead of just // one at time keyIndices = new int[m.size()]; values = new Object[m.size()]; // Get all of the integer keys and sort them to their correct position // in the key array Iterator it = m.keySet().iterator(); for (int i = 0; i < m.size(); ++i) { keyIndices[i] = it.next().intValue(); } Arrays.sort(keyIndices); // Then map the values to their respective positions for (int i = 0; i < keyIndices.length; ++i) { Integer key = keyIndices[i]; values[i] = m.get(key); } } /** * Creates a sparse copy of the provided object array, retaining only those * non-{@code null} values and their associated indices. */ public IntegerMap(V[] array) { // Find how many non-null elements there are int nonNull = 0; for (int i = 0; i < array.length; ++i) { if (array[i] != null) nonNull++; } keyIndices = new int[nonNull]; values = new Object[nonNull]; int keyIndex = 0; for (int i = 0; i < array.length; ++i) { if (array[i] != null) { keyIndices[keyIndex] = i; values[keyIndex++] = array[i]; } } } /** * {@inheritDoc} */ public int cardinality() { return keyIndices.length; } /** * Checks that the key is non-{@code null} and is an {@code Integer} object, * and then returns its {@code int} value. */ private int checkKey(Object key) { if (key == null) { throw new NullPointerException("key cannot be null"); } else if (!(key instanceof Integer)) { throw new IllegalArgumentException("key must be an Integer"); } else { return ((Integer)key).intValue(); } } /** * Removes all of the mappings from this map. */ public void clear() { keyIndices = new int[0]; values = new Object[0]; } /** * Returns {@code true} if this map contains a mapping for the specified key. */ public boolean containsKey(Object key) { int k = checkKey(key); int index = Arrays.binarySearch(keyIndices, k); return index >= 0; } public boolean containsValue(Object value) { for (Object o : values) { if (o == value || (o != null && o.equals(value))) { return true; } } return false; } /** * Returns a {@link Set} view of the mappings contained in this map. */ public Set> entrySet() { return new EntrySet(); } /** * Returns the value to which the specified key is mapped, or {@code null} * if this map contains no mapping for the key. */ public V get(Object key) { int k = checkKey(key); return get(k); } /** * {@inheritDoc} Note that this implementation accepts negative valued * indices. */ @SuppressWarnings("unchecked") public V get(int index) { int pos = Arrays.binarySearch(keyIndices, index); return (pos >= 0) ? (V)(values[pos]) : null; } /** * {@inheritDoc} */ public int[] getElementIndices() { return keyIndices; } /** * Returns a {@link Set} view of the keys contained in this map. */ public Set keySet() { return new KeySet(); } public int length() { return Integer.MAX_VALUE; } /** * Adds the mapping from the provided key to the value. * * @param key * @param value * * @throws NullPointerException if the key is {@code null} * @throws IllegalArgumentException if the key is not an instance of {@link * Integer} */ @SuppressWarnings("unchecked") public V put(Integer key, V value) { int k = checkKey(key); int index = Arrays.binarySearch(keyIndices, k); if (index >= 0) { V old = (V)(values[index]); values[index] = value; return old; } else { int newIndex = 0 - (index + 1); Object[] newValues = Arrays.copyOf(values, values.length + 1); int[] newIndices = Arrays.copyOf(keyIndices, values.length + 1); // shift the elements down to make room for the new value for (int i = newIndex; i < values.length; ++i) { newValues[i+1] = values[i]; newIndices[i+1] = keyIndices[i]; } // insert the new value newValues[newIndex] = value; newIndices[newIndex] = k; // switch the arrays with the lengthed versions values = newValues; keyIndices = newIndices; return null; } } /** * Removes the mapping for a key from this map if it is present and returns * the value to which this map previously associated the key, or {@code * null} if the map contained no mapping for the key. * * @param key key whose mapping is to be removed from the map * * @return the previous value associated with key, or {@code null} if there * was no mapping for key. */ @SuppressWarnings("unchecked") public V remove(Object key) { int k = checkKey(key); int index = Arrays.binarySearch(keyIndices, k); if (index >= 0) { V old = (V)(values[index]); Object[] newValues = Arrays.copyOf(values, values.length - 1); int[] newIndices = Arrays.copyOf(keyIndices, keyIndices.length - 1); // shift the elements up to remove the values for (int i = index; i < values.length - 1; ++i) { newValues[i] = values[i+1]; newIndices[i] = keyIndices[i+1]; } // update the arrays with the shorted versions values = newValues; keyIndices = newIndices; return old; } return null; } /** * {@inheritDoc} */ public void set(int index, V obj) { put(Integer.valueOf(index), obj); } /** * Returns the number of key-value mappings in this trie. */ public int size() { return keyIndices.length; } /** * {@inheritDoc} */ @SuppressWarnings("unchecked") public E[] toArray(E[] array) { for (int i = 0; i < keyIndices.length; ++i) { int index = keyIndices[i]; if (index < 0) continue; else if (index >= array.length) break; array[keyIndices[i]] = (E)(values[i]); } return array; } /** * Returns a {@link Collection} view of the values contained in this map. */ public Collection values() { return new Values(); } private class EntryIterator extends IntMapIterator> { public Map.Entry next() { return nextEntry(); } } private class KeyIterator extends IntMapIterator { public Integer next() { return nextEntry().getKey(); } } private class ValueIterator extends IntMapIterator { public V next() { return nextEntry().getValue(); } } abstract class IntMapIterator implements Iterator { private int next; public IntMapIterator() { next = 0; } public boolean hasNext() { return next < size(); } @SuppressWarnings("unchecked") public Entry nextEntry() { if (next >= size()) { throw new NoSuchElementException("no further elements"); } int key = keyIndices[next]; V value = (V)(values[next]); next++; return new IntEntry(key, value); } // REMINDER: this class needs to work with the actual indices for the // key and value to avoid the logrithmic lookup public void remove() { throw new UnsupportedOperationException(); } } // REMINDER: this class needs to work with the actual indices for the key // and value to avoid the logrithmic lookup class IntEntry extends SimpleEntry { private static final long serialVersionUID = 1L; public IntEntry(int key, V value) { super(key, value); } public V setValue(V newValue) { return IntegerMap.this.put(getKey(), newValue); } } class EntrySet extends AbstractSet> { private static final long serialVersionUID = 1L; public void clear() { IntegerMap.this.clear(); } public boolean contains(Object o) { if (o instanceof Map.Entry) { Map.Entry e = (Map.Entry)o; Object key = e.getKey(); Object val = e.getValue(); Object mapVal = IntegerMap.this.get(key); return mapVal == val || (val != null && val.equals(mapVal)); } return false; } public Iterator> iterator() { return new EntryIterator(); } public int size() { return IntegerMap.this.size(); } } class KeySet extends AbstractSet { private static final long serialVersionUID = 1L; public KeySet() { } public void clear() { IntegerMap.this.clear(); } public boolean contains(Object o) { return containsKey(o); } public Iterator iterator() { return new KeyIterator(); } public boolean remove(Object o) { return IntegerMap.this.remove(o) != null; } public int size() { return IntegerMap.this.size(); } } /** * A {@link Collection} view of the values contained in this trie. */ private class Values extends AbstractCollection { private static final long serialVersionUID = 1L; public void clear() { IntegerMap.this.clear(); } public boolean contains(Object o) { return containsValue(o); } public Iterator iterator() { return new ValueIterator(); } public int size() { return IntegerMap.this.size(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy