Mercurial > hg > Members > kono > jpf-core
view src/main/gov/nasa/jpf/util/SparseIntVector.java @ 0:61d41facf527
initial v8 import (history reset)
author | Peter Mehlitz <Peter.C.Mehlitz@nasa.gov> |
---|---|
date | Fri, 23 Jan 2015 10:14:01 -0800 |
parents | |
children |
line wrap: on
line source
/* * Copyright (C) 2014, United States Government, as represented by the * Administrator of the National Aeronautics and Space Administration. * All rights reserved. * * The Java Pathfinder core (jpf-core) platform is licensed under the * Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package gov.nasa.jpf.util; import static java.lang.Integer.MIN_VALUE; import java.util.Arrays; /** * This has approximately the interface of IntVector but uses a hash table * instead of an array. Also, does not require allocation with each add. * Configurable default value. */ public class SparseIntVector implements Cloneable { private static final boolean DEBUG = false; static final double MAX_LOAD_WIPE = 0.6; static final double MAX_LOAD_REHASH = 0.4; static final int DEFAULT_POW = 10; static final int DEFAULT_VAL = 0; /** * a simplistic snapshot implementation that stores set indices/values in order to save space */ public static class Snapshot { private final int length; private final int pow, mask, nextWipe, nextRehash; private final int[] positions; private final int[] indices; private final int[] values; Snapshot (SparseIntVector v){ int len = v.idxTable.length; length = len; pow = v.pow; mask = v.mask; nextWipe = v.nextWipe; nextRehash = v.nextRehash; int size = v.count; positions = new int[size]; indices = new int[size]; values = new int[size]; int[] idxTable = v.idxTable; int[] valTable = v.valTable; int j=0; for (int i=0; i<len; i++) { if (idxTable[i] != MIN_VALUE) { positions[j] = i; indices[j] = idxTable[i]; values[j] = valTable[i]; j++; } } } void restore (SparseIntVector v) { int size = indices.length; v.count = size; v.pow = pow; v.mask = mask; v.nextWipe = nextWipe; v.nextRehash = nextRehash; int len = length; int[] idxTable = new int[len]; int[] valTable = new int[len]; Arrays.fill(idxTable, MIN_VALUE); for (int i=0; i<size; i++) { int j = positions[i]; idxTable[j] = indices[i]; valTable[j] = values[i]; } v.idxTable = idxTable; v.valTable = valTable; } } int[] idxTable; // MIN_VALUE => unoccupied int[] valTable; // can be bound to null int count; int pow; int mask; int nextWipe; int nextRehash; int defaultValue; /** * Creates a SimplePool that holds about 716 elements before first * rehash. */ public SparseIntVector() { this(DEFAULT_POW,DEFAULT_VAL); } /** * Creates a SimplePool that holds about 0.7 * 2**pow elements before * first rehash. */ public SparseIntVector(int pow, int defValue) { this.pow = pow; newTable(); count = 0; mask = valTable.length - 1; nextWipe = (int)(MAX_LOAD_WIPE * mask); nextRehash = (int)(MAX_LOAD_REHASH * mask); defaultValue = defValue; } // INTERNAL // @SuppressWarnings("unchecked") protected void newTable() { valTable = new int[1 << pow]; idxTable = new int[1 << pow]; if (defaultValue != 0) { Arrays.fill(valTable, defaultValue); } Arrays.fill(idxTable, MIN_VALUE); } protected int mix(int x) { int y = 0x9e3779b9; x ^= 0x510fb60d; y += (x >> 8) + (x << 3); x ^= (y >> 5) + (y << 2); return y - x; } // ********************* Public API ******************** // public Snapshot getSnapshot() { return new Snapshot(this); } public void restore (Snapshot snap) { snap.restore(this); } @Override public SparseIntVector clone() { try { SparseIntVector o = (SparseIntVector) super.clone(); o.idxTable = idxTable.clone(); o.valTable = valTable.clone(); return o; } catch (CloneNotSupportedException cnsx) { // can't happen return null; } } public int size() { return count; } public void clear() { Arrays.fill(valTable, defaultValue); Arrays.fill(idxTable, MIN_VALUE); count = 0; } public void clear(int idx) { int code = mix(idx); int pos = code & mask; int delta = (code >> (pow - 1)) | 1; // must be odd! int oidx = pos; for(;;) { int tidx = idxTable[pos]; if (tidx == MIN_VALUE) { return; // nothing to clear } if (tidx == idx) { count--; idxTable[pos] = MIN_VALUE; valTable[pos] = defaultValue; return; } pos = (pos + delta) & mask; assert (pos != oidx); // should never wrap around } } @SuppressWarnings("unchecked") public int get(int idx) { int code = mix(idx); int pos = code & mask; int delta = (code >> (pow - 1)) | 1; // must be odd! int oidx = pos; for(;;) { int tidx = idxTable[pos]; if (tidx == MIN_VALUE) { return defaultValue; } if (tidx == idx) { return valTable[pos]; } pos = (pos + delta) & mask; assert (pos != oidx); // should never wrap around } } // for debug only int count() { int count = 0; for (int i = 0; i < idxTable.length; i++) { if (idxTable[i] != MIN_VALUE /*&& valTable[i] != defaultValue*/) { count++; } } return count; } public void set(int idx, int val) { int code = mix(idx); int pos = code & mask; int delta = (code >> (pow - 1)) | 1; // must be odd! int oidx = pos; for(;;) { int tidx = idxTable[pos]; if (tidx == MIN_VALUE) { break; } if (tidx == idx) { valTable[pos] = val; // update return; // and we're done } pos = (pos + delta) & mask; assert (pos != oidx); // should never wrap around } // idx not in table; add it if ((count+1) >= nextWipe) { // too full if (count >= nextRehash) { pow++; } /** // determine if size needs to be increased or just wipe null blocks int oldCount = count; count = 0; for (int i = 0; i < idxTable.length; i++) { //if (idxTable[i] != MIN_VALUE && valTable[i] != defaultValue) { if (idxTable[i] != MIN_VALUE) { count++; } } if (count >= nextRehash) { pow++; // needs to be increased in size if (DEBUG) { System.out.println("Rehash to capacity: 2**" + pow); } } else { if (DEBUG) { System.out.println("Rehash reclaiming this many nulls: " + (oldCount - count)); } } **/ int[] oldValTable = valTable; int[] oldIdxTable = idxTable; newTable(); mask = idxTable.length - 1; nextWipe = (int)(MAX_LOAD_WIPE * mask); nextRehash = (int)(MAX_LOAD_REHASH * mask); int oldLen = oldIdxTable.length; for (int i = 0; i < oldLen; i++) { int tidx = oldIdxTable[i]; if (tidx == MIN_VALUE) continue; int o = oldValTable[i]; //if (o == defaultValue) continue; // otherwise: code = mix(tidx); pos = code & mask; delta = (code >> (pow - 1)) | 1; // must be odd! while (idxTable[pos] != MIN_VALUE) { // we know enough slots exist pos = (pos + delta) & mask; } idxTable[pos] = tidx; valTable[pos] = o; } // done with rehash; now get idx to empty slot code = mix(idx); pos = code & mask; delta = (code >> (pow - 1)) | 1; // must be odd! while (idxTable[pos] != MIN_VALUE) { // we know enough slots exist pos = (pos + delta) & mask; } } else { // pos already pointing to empty slot } count++; idxTable[pos] = idx; valTable[pos] = val; } public void setRange (int fromIndex, int toIndex, int val) { for (int i=fromIndex; i<toIndex; i++) { set(i, val); } } // ************************** Test main ************************ // public static void main(String[] args) { SparseIntVector vect = new SparseIntVector(3, MIN_VALUE); // add some for (int i = -4200; i < 4200; i += 10) { vect.set(i, i); } // check for added & non-added for (int i = -4200; i < 4200; i += 10) { int v = vect.get(i); if (v != i) { throw new IllegalStateException(); } } for (int i = -4205; i < 4200; i += 10) { int v = vect.get(i); if (v != MIN_VALUE) { throw new IllegalStateException(); } } // add some more for (int i = -4201; i < 4200; i += 10) { vect.set(i, i); } // check all added for (int i = -4200; i < 4200; i += 10) { int v = vect.get(i); if (v != i) { throw new IllegalStateException(); } } for (int i = -4201; i < 4200; i += 10) { int v = vect.get(i); if (v != i) { throw new IllegalStateException(); } } // "remove" some for (int i = -4200; i < 4200; i += 10) { vect.set(i,MIN_VALUE); } // check for added & non-added for (int i = -4201; i < 4200; i += 10) { int v = vect.get(i); if (v != i) { throw new IllegalStateException(); } } for (int i = -4200; i < 4200; i += 10) { int v = vect.get(i); if (v != MIN_VALUE) { throw new IllegalStateException(); } } // add even more for (int i = -4203; i < 4200; i += 10) { vect.set(i, i); } for (int i = -4204; i < 4200; i += 10) { vect.set(i, i); } } }