/* * BudgetValue.java * * Copyright (C) 2008 Pei Wang * * This file is part of Open-NARS. * * Open-NARS is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * Open-NARS 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Open-NARS. If not, see <http://www.gnu.org/licenses/>. */ package nars.entity; import nars.config.Parameters; import static nars.config.Parameters.TRUTH_EPSILON; import nars.inference.BudgetFunctions; import static nars.inference.UtilityFunctions.and; import static nars.inference.UtilityFunctions.aveGeo; import static nars.inference.UtilityFunctions.or; import nars.io.Symbols; import nars.io.Texts; import static nars.inference.UtilityFunctions.and; import static nars.inference.UtilityFunctions.aveGeo; import static nars.inference.UtilityFunctions.or; import static nars.inference.UtilityFunctions.and; import static nars.inference.UtilityFunctions.aveGeo; import static nars.inference.UtilityFunctions.or; import static nars.inference.UtilityFunctions.and; import static nars.inference.UtilityFunctions.aveGeo; import static nars.inference.UtilityFunctions.or; import static nars.inference.UtilityFunctions.and; import static nars.inference.UtilityFunctions.aveGeo; import static nars.inference.UtilityFunctions.or; import static nars.inference.UtilityFunctions.and; import static nars.inference.UtilityFunctions.aveGeo; import static nars.inference.UtilityFunctions.or; import static nars.inference.UtilityFunctions.and; import static nars.inference.UtilityFunctions.aveGeo; import static nars.inference.UtilityFunctions.or; import static nars.inference.UtilityFunctions.and; import static nars.inference.UtilityFunctions.aveGeo; import static nars.inference.UtilityFunctions.or; /** * A triple of priority (current), durability (decay), and quality (long-term average). */ public class BudgetValue implements Cloneable { /** The character that marks the two ends of a budget value */ private static final char MARK = Symbols.BUDGET_VALUE_MARK; /** The character that separates the factors in a budget value */ private static final char SEPARATOR = Symbols.VALUE_SEPARATOR; /** The relative share of time resource to be allocated */ private float priority; /** * The percent of priority to be kept in a constant period; All priority * values "decay" over time, though at different rates. Each item is given a * "durability" factor in (0, 1) to specify the percentage of priority level * left after each reevaluation */ private float durability; /** The overall (context-independent) evaluation */ private float quality; /** time at which this budget was last forgotten, for calculating accurate memory decay rates */ long lastForgetTime = -1; public BudgetValue(final float p, final float d, final TruthValue qualityFromTruth) { this(p, d, BudgetFunctions.truthToQuality(qualityFromTruth)); } /** * Constructor with initialization * @param p Initial priority * @param d Initial durability * @param q Initial quality */ public BudgetValue(final float p, final float d, final float q) { priority = p; durability = d; quality = q; if(d>=1.0) { durability=(float) (1.0-TRUTH_EPSILON); //throw new RuntimeException("durability value above or equal 1"); } if(p>1.0) { priority=1.0f; //throw new RuntimeException("priority value above 1"); } } /** * Cloning constructor * @param v Budget value to be cloned */ public BudgetValue(final BudgetValue v) { this(v.getPriority(), v.getDurability(), v.getQuality()); } /** * Cloning method */ @Override public BudgetValue clone() { return new BudgetValue(this.getPriority(), this.getDurability(), this.getQuality()); } /** * Get priority value * @return The current priority */ public float getPriority() { return priority; } /** * Change priority value * @param v The new priority */ public final void setPriority(float v) { if(v>1.0f) { throw new RuntimeException("Priority > 1.0: " + v); //v=1.0f; } priority = v; } /** * Increase priority value by a percentage of the remaining range * @param v The increasing percent */ public void incPriority(final float v) { setPriority( (float) Math.min(1.0, or(priority, v))); } /** AND's (multiplies) priority with another value */ public void andPriority(final float v) { setPriority( and(priority, v) ); } /** * Decrease priority value by a percentage of the remaining range * @param v The decreasing percent */ public void decPriority(final float v) { setPriority( and(priority, v) ); } /** * Get durability value * @return The current durability */ public float getDurability() { return durability; } /** * Change durability value * @param v The new durability */ public void setDurability(float d) { if(d>=1.0f) { d=1.0f-TRUTH_EPSILON; } durability = d; } /** * Increase durability value by a percentage of the remaining range * @param v The increasing percent */ public void incDurability(final float v) { float durability2 = or(durability, v); if(durability2>=1.0f) { durability2=1.0f-TRUTH_EPSILON; //put into allowed range } durability=durability2; } /** * Decrease durability value by a percentage of the remaining range * @param v The decreasing percent */ public void decDurability(final float v) { durability = and(durability, v); } /** * Get quality value * @return The current quality */ public float getQuality() { return quality; } /** * Change quality value * @param v The new quality */ public void setQuality(final float v) { quality = v; } /** * Increase quality value by a percentage of the remaining range * @param v The increasing percent */ public void incQuality(final float v) { quality = or(quality, v); } /** * Decrease quality value by a percentage of the remaining range * @param v The decreasing percent */ public void decQuality(final float v) { quality = and(quality, v); } /** * Merge one BudgetValue into another * @param that The other Budget */ public void merge(final BudgetValue that) { BudgetFunctions.merge(this, that); } /** * returns true if this budget is greater in all quantities than another budget, * used to prevent a merge that would have no consequence * @param other * @return */ public boolean greaterThan(final BudgetValue other) { return (getPriority() - other.getPriority() > Parameters.BUDGET_THRESHOLD) && (getDurability()- other.getDurability()> Parameters.BUDGET_THRESHOLD) && (getQuality() - other.getQuality() > Parameters.BUDGET_THRESHOLD); } /** * To summarize a BudgetValue into a single number in [0, 1] * @return The summary value */ public float summary() { return aveGeo(priority, durability, quality); } public boolean equalsByPrecision(final Object that) { if (that instanceof BudgetValue) { final BudgetValue t = ((BudgetValue) that); float dPrio = Math.abs(getPriority() - t.getPriority()); if (dPrio >= TRUTH_EPSILON) return false; float dDura = Math.abs(getDurability() - t.getDurability()); if (dDura >= TRUTH_EPSILON) return false; float dQual = Math.abs(getQuality() - t.getQuality()); if (dQual >= TRUTH_EPSILON) return false; return true; } return false; } /** * Whether the budget should get any processing at all * <p> * to be revised to depend on how busy the system is * @return The decision on whether to process the Item */ public boolean aboveThreshold() { return (summary() >= Parameters.BUDGET_THRESHOLD); } /** * Fully display the BudgetValue * @return String representation of the value */ @Override public String toString() { return MARK + Texts.n4(priority) + SEPARATOR + Texts.n4(durability) + SEPARATOR + Texts.n4(quality) + MARK; } /** * Briefly display the BudgetValue * @return String representation of the value with 2-digit accuracy */ public String toStringExternal() { //return MARK + priority.toStringBrief() + SEPARATOR + durability.toStringBrief() + SEPARATOR + quality.toStringBrief() + MARK; final CharSequence priorityString = Texts.n2(priority); final CharSequence durabilityString = Texts.n2(durability); final CharSequence qualityString = Texts.n2(quality); return new StringBuilder(1 + priorityString.length() + 1 + durabilityString.length() + 1 + qualityString.length() + 1) .append(MARK) .append(priorityString).append(SEPARATOR) .append(durabilityString).append(SEPARATOR) .append(qualityString) .append(MARK) .toString(); } /** * linear interpolate the priority value to another value * @see https://en.wikipedia.org/wiki/Linear_interpolation */ /*public void lerpPriority(final float targetValue, final float momentum) { if (momentum == 1.0) return; else if (momentum == 0) setPriority(targetValue); else setPriority( (getPriority() * momentum) + ((1f - momentum) * targetValue) ); }*/ /** returns the period in time: currentTime - lastForgetTime and sets the lastForgetTime to currentTime */ public long setLastForgetTime(final long currentTime) { long period; if (this.lastForgetTime == -1) period = 0; else period = currentTime - lastForgetTime; lastForgetTime = currentTime; return period; } public long getLastForgetTime() { return lastForgetTime; } }