/*
* Task.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 com.google.common.base.Strings;
import java.lang.ref.WeakReference;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import nars.storage.Memory;
import nars.language.Term;
import nars.operator.Operation;
import nars.plugin.mental.InternalExperience;
/**
* A task to be processed, consists of a Sentence and a BudgetValue.
* A task references its parent and an optional causal factor (usually an Operation instance). These are implemented as WeakReference to allow forgetting via the
* garbage collection process. Otherwise, Task ancestry would grow unbounded,
* violating the assumption of insufficient resources (AIKR).
*/
public class Task<T extends Term> extends Item<Sentence<T>> {
/** placeholder for a forgotten task */
public static final Task Forgotten = new Task();
/* The sentence of the Task*/
public final Sentence<T> sentence;
/* Task from which the Task is derived, or null if input*/
final WeakReference<Task> parentTask;
/* Belief from which the Task is derived, or null if derived from a theorem*/
public final WeakReference<Sentence> parentBelief;
/* For Question and Goal: best solution found so far*/
private Sentence bestSolution;
/** causal factor; usually an instance of Operation */
private WeakReference<Term> cause;
/**
* Constructor for input task
*
* @param s The sentence
* @param b The budget
*/
public Task(final Sentence<T> s, final BudgetValue b) {
this(s, b, (WeakReference)null, null, null);
}
public Task(final Sentence<T> s, final BudgetValue b, final Task parentTask) {
this(s, b, parentTask, null);
}
protected Task() {
this(null, null);
}
private boolean partOfSequenceBuffer = false;
private boolean observablePrediction = false;
/**
* Constructor for a derived task
*
* @param s The sentence
* @param b The budget
* @param parentTask The task from which this new task is derived
* @param parentBelief The belief from which this new task is derived
*/
public Task(final Sentence<T> s, final BudgetValue b, final Task parentTask, final Sentence parentBelief) {
this(s, b, new WeakReference(parentTask), new WeakReference(parentBelief), null);
}
public Task(final Sentence<T> s, final BudgetValue b, final WeakReference<Task> parentTask, final WeakReference<Sentence> parentBelief, Sentence solution) {
super(b);
this.sentence = s;
this.parentTask = parentTask;
this.parentBelief = parentBelief;
this.bestSolution = solution;
}
/**
* Constructor for an activated task
*
* @param s The sentence
* @param b The budget
* @param parentTask The task from which this new task is derived
* @param parentBelief The belief from which this new task is derived
* @param solution The belief to be used in future inference
*/
public Task(final Sentence<T> s, final BudgetValue b, final Task parentTask, final Sentence parentBelief, final Sentence solution) {
this(s, b, new WeakReference(parentTask), new WeakReference(parentBelief), solution);
}
public Task clone() {
return new Task(sentence, budget, parentTask, parentBelief, bestSolution);
}
public Task clone(final Sentence replacedSentence) {
return new Task(replacedSentence, budget, parentTask, parentBelief, bestSolution);
}
@Override public Sentence name() {
return sentence;
}
@Override
public boolean equals(final Object obj) {
if (obj == this) return true;
if (obj instanceof Task) {
Task t = (Task)obj;
return t.sentence.equals(sentence);
}
return false;
}
@Override
public int hashCode() {
return sentence.hashCode();
}
//public static boolean isValidTerm(Term t) {
// return t instanceof CompoundTerm;
// }
public static Task make(Sentence s, BudgetValue b, Task parent) {
return make(s, b, parent, null);
}
public static Task make(Sentence s, BudgetValue b, Task parent, Sentence belief) {
Term t = s.term;
//if (isValidTerm(t)) { sentence wouldnt exist if it wouldnt be valid..
return new Task(s, b, parent, belief);
//}
//return null;
}
/**
* Directly get the creation time of the sentence
*
* @return The creation time of the sentence
*/
public long getCreationTime() {
return sentence.stamp.getCreationTime();
}
/**
* Check if a Task is a direct input
*
* @return Whether the Task is derived from another task
*/
public boolean isInput() {
return parentTask == null;
}
public boolean aboveThreshold() {
return budget.aboveThreshold();
}
/**
* Check if a Task is derived by a StructuralRule
*
* @return Whether the Task is derived by a StructuralRule
*/
// public boolean isStructural() {
// return (parentBelief == null) && (parentTask != null);
// }
/**
* Merge one Task into another
*
* @param that The other Task
*/
@Override
public Item merge(final Item that) {
if (getCreationTime() >= ((Task) that).getCreationTime()) {
return super.merge(that);
} else {
return that.merge(this);
}
}
/**
* Get the best-so-far solution for a Question or Goal
*
* @return The stored Sentence or null
*/
public Sentence getBestSolution() {
return bestSolution;
}
/**
* Set the best-so-far solution for a Question or Goal, and report answer
* for input question
*
* @param judg The solution to be remembered
*/
public void setBestSolution(final Memory memory,final Sentence judg) {
InternalExperience.InternalExperienceFromBelief(memory, this, judg);
bestSolution = judg;
}
/**
* Get the parent belief of a task
*
* @return The belief from which the task is derived
*/
public Sentence getParentBelief() {
if (parentBelief == null) return null;
return parentBelief.get();
}
/**
* Get the parent task of a task
*
* @return The task from which the task is derived
*/
public Task getParentTask() {
if (parentTask == null) return null;
return parentTask.get();
}
/**
* Get a String representation of the Task
*
* @return The Task as a String
*/
@Override
public String toStringLong() {
final StringBuilder s = new StringBuilder();
s.append(super.toString()).append(' ').append(sentence.stamp.name());
Task pt = getParentTask();
if (pt != null) {
s.append(" \n from task: ").append(pt.toStringExternal());
if (parentBelief != null) {
s.append(" \n from belief: ").append(parentBelief.toString());
}
}
if (bestSolution != null) {
s.append(" \n solution: ").append(bestSolution.toString());
}
return s.toString();
}
public boolean hasParent(Task t) {
if (getParentTask() == null)
return false;
Task p=getParentTask();
do {
Task n = p.getParentTask();
if (n!=null) {
if (n.equals(t))
return true;
p = n;
}
else
break;
} while (p!=null);
return false;
}
public Task getRootTask() {
if (getParentTask() == null) {
return null;
}
Task p=getParentTask();
do {
Task n = p.getParentTask();
if (n!=null)
p = n;
else
break;
} while (p!=null);
return p;
}
public String getExplanation() {
String x = toString() + "\n";
if (bestSolution!=null) {
if (!getTerm().equals(bestSolution.term))
x += " solution=" + bestSolution + "\n";
}
if (parentBelief!=null)
x += " parentBelief=" + parentBelief + " @ " + parentBelief.get().getCreationTime() + "\n";
Task pt = getParentTask();
if (pt!=null) {
x += " parentTask=" + pt + " @ " + pt.getCreationTime() + "\n";
int indentLevel = 1;
Task p=getParentTask();
do {
indentLevel++;
Task n = p.getParentTask();
if (n!=null) {
x += Strings.repeat(" ",indentLevel) + n.toString();
p = n;
}
else
break;
} while (p!=null);
}
return x;
}
public TruthValue getDesire() { return sentence.truth; }
// /** returns the goal term for this task, which may be either the predicate of a forward implication,
// * an operation. if neither, returns null */
// public Term getGoalTerm() {
// Term t = getContent();
// if (t instanceof Implication) {
// Implication i = (Implication)t;
// if (i.getTemporalOrder() == TemporalRules.ORDER_FORWARD)
// return i.getPredicate();
// else if (i.getTemporalOrder() == TemporalRules.ORDER_BACKWARD) {
// throw new RuntimeException("Term getGoal reversed");
// }
// }
// else if (t instanceof Operation)
// return t;
// else if (Executive.isSequenceConjunction(t))
// return t;
//
// return null;
// }
//
/** flag to indicate whether this Event Task participates in tempporal induction */
public void setElemOfSequenceBuffer(boolean b) {
this.partOfSequenceBuffer = b;
}
public boolean isElemOfSequenceBuffer() {
return !this.sentence.isEternal() && (this.isInput() || partOfSequenceBuffer);
}
public void setObservablePrediction(boolean b) {
this.observablePrediction = b;
}
public boolean isObservablePrediction() {
return this.observablePrediction;
}
public static Set<Task> getTasks(Collection<Task> tasks) {
Set<Task> tl = new HashSet();
for (Task t : tasks)
tl.add(t);
return tl;
}
public T getTerm() {
return sentence.getTerm();
}
public boolean isInputOrOperation() {
return this.isInput() || (this.sentence.term instanceof Operation);
}
}