package nars.storage; import java.util.Iterator; import java.util.Set; import nars.config.Parameters; import nars.entity.Item; import nars.inference.BudgetFunctions; public abstract class Bag<E extends Item<K>,K> implements Iterable<E> { public static final int bin(final float x, final int bins) { int i = (int)Math.floor((x + 0.5f/bins) * bins); return i; } public abstract void clear(); /** * Check if an item is in the bag. both its key and its value must match the parameter * * @param it An item * @return Whether the Item is in the Bag */ public boolean contains(final E it) { E exist = get(it.name()); if (exist.equals(it)) return true; return false; } /** * Get an Item by key * * @param key The key of the Item * @return The Item with the given key */ abstract public E get(final K key); abstract public Set<K> keySet(); abstract public int getCapacity(); abstract public float getMass(); /** * Choose an Item according to distribution policy and take it out of the Bag * @return The selected Item, or null if this bag is empty */ abstract public E takeNext(); /** gets the next value without removing changing it or removing it from any index. however the bag is cycled so that subsequent elements are different. */ abstract public E peekNext(); /** * Insert an item into the itemTable, and return the overflow * * @param newItem The Item to put in * @return The overflow Item, or null if nothing displaced */ protected abstract E addItem(final E newItem); /** * Add a new Item into the Bag * * @param newItem The new Item * @return the item which was removed, which may be the input item if it could not be inserted; or null if nothing needed removed */ public E putIn(E newItem) { final K newKey = newItem.name(); final E existingItemWithSameKey = take(newKey); if (existingItemWithSameKey != null) { newItem = (E)existingItemWithSameKey.merge(newItem); } // put the (new or merged) item into itemTable final E overflowItem = addItem(newItem); if (overflowItem!=null) { return overflowItem; } else { return null; } } abstract public E take(final K key); public E take(E value) { return take(value.name()); } /** * The number of items in the bag * * @return The number of items */ public abstract int size(); public void printAll() { Iterator<E> d = iterator(); while (d.hasNext()) { System.out.println(" " + d.next() + "\n" ); } } abstract public Iterable<E> values(); public abstract float getAveragePriority(); public float getTotalPriority() { int size = size(); if (size == 0) return 0; return getAveragePriority() * size(); } /** iterates all items in (approximately) descending priority */ @Override public abstract Iterator<E> iterator(); /** allows adjusting forgetting rate in subclasses */ public float getForgetCycles(final float baseForgetCycles, final E item) { return baseForgetCycles; } /** * Put an item back into the itemTable * <p> * The only place where the forgetting rate is applied * * @param oldItem The Item to put back * @return the item which was removed, or null if none removed */ public E putBack(final E oldItem, final float forgetCycles, final Memory m) { float relativeThreshold = Parameters.FORGET_QUALITY_RELATIVE; BudgetFunctions.applyForgetting(oldItem.budget, getForgetCycles(forgetCycles, oldItem), relativeThreshold); return putIn(oldItem); } /** x = takeOut(), then putBack(x) * @forgetCycles forgetting time in cycles * @return the variable that was updated, or null if none was taken out */ public E processNext(final float forgetCycles, final Memory m) { final E x = takeNext(); if (x == null) return null; E r = putBack(x, forgetCycles, m); if (r!=null) { throw new RuntimeException("Bag.processNext should always be able to re-insert item: " + r); } return x; } public double[] getPriorityDistribution(double[] x) { int bins = x.length; double total = 0; for (E e : values()) { float p = e.budget.getPriority(); int b = bin(p, bins-1); x[b]++; total++; } if (total > 0) { for (int i = 0; i < bins; i++) x[i] /= total; } return x; } @Override public String toString() { return getClass().getSimpleName();// + "(" + size() + "/" + getCapacity() +")"; } /** slow, probably want to override in subclasses */ public float getMinPriority() { float min = 1.0f; for (Item e : this) { float p = e.getPriority(); if (p < min) min = p; } return min; } /** slow, probably want to override in subclasses */ public float getMaxPriority() { float max = 0.0f; for (Item e : this) { float p = e.getPriority(); if (p > max) max = p; } return max; } }