/* * Copyright (C) 2003-2006 Bjørn-Ove Heimsund * * This file is part of MTJ. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation; either version 2.1 of the License, or (at your * option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package tk.amberide.engine.data.sparse; import tk.amberide.ide.os.OS; import java.util.Iterator; /** * Sparse vector */ public class SparseVector<T> implements Iterable<T>, Cloneable { Object[] data; int[] index; int used; int size; /** * Constructor for SparseVector. * * @param size Size of the vector * @param nz Initial number of non-nulls */ public SparseVector(int size, int nz) { this.size = size; data = new Object[nz]; index = new int[nz]; } @Override public SparseVector<T> clone() { SparseVector<T> clone = new SparseVector<T>(size, data.length); clone.data = OS.deepcopy(data); clone.index = index.clone(); clone.used = used; return clone; } /** * Constructor for SparseVector. Zero initial pre-allocation * * @param size Size of the vector */ public SparseVector(int size) { this(size, 0); } public SparseVector() { this(Integer.MAX_VALUE); } public void set(int index, T value) { check(index); int i = getIndex(index); data[i] = value; } public T get(int index) { check(index); int in = binarySearch(this.index, index, 0, used); if (in >= 0) { return (T) data[in]; } return null; } /** * Tries to find the index. If it is not found, a reallocation is done, and * a new index is returned. */ protected int getIndex(int ind) { // Try to find column index int i = binarySearchInterval(index, ind, 0, used, true); // Found if (i < used && index[i] == ind) { return i; } int[] newIndex = index; Object[] newData = data; // Check available memory if (++used > data.length) { // If zero-length, use new length of 1, else double the bandwidth int newLength = data.length != 0 ? data.length << 1 : 1; // Copy existing data into new arrays newIndex = new int[newLength]; newData = new Object[newLength]; System.arraycopy(index, 0, newIndex, 0, i); System.arraycopy(data, 0, newData, 0, i); } // All ok, make room for insertion System.arraycopy(index, i, newIndex, i + 1, used - i - 1); System.arraycopy(data, i, newData, i + 1, used - i - 1); // Put in new structure newIndex[i] = ind; newData[i] = 0.; // Update pointers index = newIndex; data = newData; // Return insertion index return i; } /** * Returns the internal data */ public Object[] getData() { return data; } /** * Returns the indices */ public int[] getIndex() { if (used == index.length) { return index; } // could run compact, or return subarray // compact(); int[] indices = new int[used]; for (int i = 0; i < used; i++) { indices[i] = index[i]; } return indices; } /** * Number of entries used in the sparse structure */ public int getUsed() { return used; } public int nonZeroEntries() { int nz = 0; for (Object e : data) { if (e != null) { nz++; } } return nz; } protected void check(int index) { if (index < 0) { throw new IndexOutOfBoundsException("index is negative (" + index + ")"); } if (index >= size) { throw new IndexOutOfBoundsException("index >= size (" + index + " >= " + size + ")"); } } /** * Compacts the vector */ public void compact() { int nz = nonZeroEntries(); // catches zero entries if (nz < data.length) { int[] newIndex = new int[nz]; Object[] newData = new Object[nz]; // Copy only non-zero entries for (int i = 0, j = 0; i < data.length; ++i) { if (data[i] != null) { newIndex[j] = index[i]; newData[j] = data[i]; j++; } } data = newData; index = newIndex; used = data.length; } } protected int binarySearchInterval(int[] index, int key, int begin, int end, boolean greater) { // Zero length array? if (begin == end) { if (greater) { return end; } else { return begin - 1; } } end--; // Last index int mid = (end + begin) >> 1; // The usual binary search while (begin <= end) { mid = (end + begin) >> 1; if (index[mid] < key) { begin = mid + 1; } else if (index[mid] > key) { end = mid - 1; } else { return mid; } } // No direct match, but an inf/sup was found if ((greater && index[mid] >= key) || (!greater && index[mid] <= key)) { return mid; } // No inf/sup, return at the end of the array else if (greater) { return mid + 1; // One past end } else { return mid - 1; // One before start } } protected int binarySearch(int[] index, int key, int begin, int end) { end--; while (begin <= end) { int mid = (end + begin) >> 1; if (index[mid] < key) { begin = mid + 1; } else if (index[mid] > key) { end = mid - 1; } else { return mid; } } return -1; } public SparseVectorIterator<T> iterator() { return new SparseVectorIterator<T>(); } public class SparseVectorIterator<T> implements Iterator<T> { private int pointer; public boolean hasNext() { return pointer < used; } public T next() { return (T) data[pointer++]; } public void remove() { data[pointer] = null; } public int realIndex() { return pointer == 0 ? 0 : index[pointer - 1]; } } }