/*
* Here comes the text of your license
* Each line should be prefixed with *
*/
package nars.control;
import java.util.ArrayList;
import java.util.List;
import nars.util.Events;
import nars.storage.Memory;
import nars.NAR;
import nars.config.Parameters;
import nars.util.Plugin;
import nars.entity.BudgetValue;
import nars.entity.Concept;
import nars.entity.Sentence;
import nars.entity.Stamp;
import nars.entity.Task;
import nars.entity.TaskLink;
import nars.entity.TermLink;
import nars.entity.TruthValue;
import nars.inference.TruthFunctions;
import nars.language.CompoundTerm;
import nars.language.Interval;
import nars.language.Term;
import nars.language.Variable;
import nars.operator.Operation;
/**
* NAL Reasoner Process. Includes all reasoning process state.
*/
public class DerivationContext {
public interface DerivationFilter extends Plugin {
/** returns null if allowed to derive, or a String containing a short rejection reason for logging */
public String reject(DerivationContext nal, Task task, boolean revised, boolean single, Task parent, Sentence otherBelief);
@Override
public default boolean setEnabled(NAR n, boolean enabled) {
return true;
}
}
public boolean evidentalOverlap = false;
public final Memory memory;
protected Term currentTerm;
protected Concept currentConcept;
protected Task currentTask;
protected TermLink currentBeliefLink;
protected TaskLink currentTaskLink;
protected Sentence currentBelief;
protected Stamp newStamp;
public StampBuilder newStampBuilder;
protected List<DerivationFilter> derivationFilters = null;
public DerivationContext(Memory mem) {
super();
this.memory = mem;
this.derivationFilters = mem.param.getDerivationFilters();
}
public void setDerivationFilters(List<DerivationFilter> derivationFilters) {
this.derivationFilters = derivationFilters;
}
public void emit(final Class c, final Object... o) {
memory.emit(c, o);
}
/**
* Derived task comes from the inference rules.
*
* @param task the derived task
* @param overlapAllowed //https://groups.google.com/forum/#!topic/open-nars/FVbbKq5En-M
*/
public boolean derivedTask(final Task task, final boolean revised, final boolean single, Task parent,Sentence occurence2, boolean overlapAllowed) {
/*if(task.sentence.truth.getConfidence() > 0.98 && (task.getTerm() instanceof Implication) &&
(((Implication) task.getTerm()).getSubject() instanceof Conjunction) &&
((Conjunction) ((Implication) task.getTerm()).getSubject()).term.length == 4) {
int a = 3;
a = 0;
System.out.println(a);
}*/
/*if(task.sentence.term instanceof Implication) {
Implication imp = (Implication) task.sentence.term;
if(imp.getSubject() instanceof Conjunction) {
Conjunction conj = (Conjunction) imp.getSubject();
boolean lastWasIval = false;
for(Term t : conj.term) {
if(t instanceof Interval) {
if(lastWasIval) {
int a = 0;
System.out.println(a); //only decompose compound is allowed to do this!
} //this debug code helps identifying cases
lastWasIval = true;
} else {
lastWasIval = false;
}
}
}
}*/
if (derivationFilters!=null) {
for (int i = 0; i < derivationFilters.size(); i++) {
DerivationFilter d = derivationFilters.get(i);
String rejectionReason = d.reject(this, task, revised, single, parent, occurence2);
if (rejectionReason!=null) {
memory.removeTask(task, rejectionReason);
return false;
}
}
}
final Sentence occurence = parent!=null ? parent.sentence : null;
if (!task.budget.aboveThreshold()) {
memory.removeTask(task, "Insufficient Budget");
return false;
}
if (task.sentence != null && task.sentence.truth != null) {
float conf = task.sentence.truth.getConfidence();
if (conf == 0) {
//no confidence - we can delete the wrongs out that way.
memory.removeTask(task, "Ignored (zero confidence)");
return false;
}
}
if (task.sentence.term instanceof Operation) {
Operation op = (Operation) task.sentence.term;
if (op.getSubject() instanceof Variable || op.getPredicate() instanceof Variable) {
memory.removeTask(task, "Operation with variable as subject or predicate");
return false;
}
}
final Stamp stamp = task.sentence.stamp;
if (occurence != null && !occurence.isEternal()) {
stamp.setOccurrenceTime(occurence.getOccurenceTime());
}
if (occurence2 != null && !occurence2.isEternal()) {
stamp.setOccurrenceTime(occurence2.getOccurenceTime());
}
//its revision, of course its cyclic, apply evidental base policy
if(!overlapAllowed) { //todo reconsider
final int stampLength = stamp.baseLength;
for (int i = 0; i < stampLength; i++) {
final long baseI = stamp.evidentialBase[i];
for (int j = 0; j < stampLength; j++) {
if (this.evidentalOverlap || ((i != j) && (baseI == stamp.evidentialBase[j]))) {
memory.removeTask(task, "Overlapping Evidenctal Base");
//"(i=" + i + ",j=" + j +')' /* + " in " + stamp.toString()*/
return false;
}
}
}
}
//deactivated, new anticipation handling is attempted instead
/*if(task.sentence.getOccurenceTime()>memory.time() && ((this.getCurrentTask()!=null && (this.getCurrentTask().isInput() || this.getCurrentTask().sentence.producedByTemporalInduction)) || (this.getCurrentBelief()!=null && this.getCurrentBelief().producedByTemporalInduction))) {
Anticipate ret = ((Anticipate)memory.getOperator("^anticipate"));
if(ret!=null) {
ret.anticipate(task.sentence.term, memory, task.sentence.getOccurenceTime(),task);
}
}*/
task.setElemOfSequenceBuffer(false);
if(!revised) {
task.getBudget().setDurability(task.getBudget().getDurability()*Parameters.DERIVATION_DURABILITY_LEAK);
task.getBudget().setPriority(task.getBudget().getPriority()*Parameters.DERIVATION_PRIORITY_LEAK);
}
memory.event.emit(Events.TaskDerive.class, task, revised, single, occurence, occurence2);
//memory.logic.TASK_DERIVED.commit(task.budget.getPriority());
addTask(task, "Derived");
return true;
}
/* --------------- new task building --------------- */
/**
* Shared final operations by all double-premise rules, called from the
* rules except StructuralRules
*
* @param newContent The content of the sentence in task
* @param newTruth The truth value of the sentence in task
* @param newBudget The budget value in task
*/
public boolean doublePremiseTaskRevised(final Term newContent, final TruthValue newTruth, final BudgetValue newBudget) {
Sentence newSentence = new Sentence(newContent, getCurrentTask().sentence.punctuation, newTruth, getTheNewStamp());
Task newTask = new Task(newSentence, newBudget, getCurrentTask(), getCurrentBelief());
return derivedTask(newTask, true, false, null, null, true); //allows overlap since overlap was already checked on revisable( function
} //which is not the case for other single premise tasks
/**
* Shared final operations by all double-premise rules, called from the
* rules except StructuralRules
*
* @param newContent The content of the sentence in task
* @param newTruth The truth value of the sentence in task
* @param newBudget The budget value in task
* @param temporalInduction
* @param overlapAllowed // https://groups.google.com/forum/#!topic/open-nars/FVbbKq5En-M
*/
public List<Task> doublePremiseTask(final Term newContent, final TruthValue newTruth, final BudgetValue newBudget, boolean temporalInduction, boolean overlapAllowed) {
List<Task> ret = new ArrayList<Task>();
if(newContent == null) {
return null;
}
if (!newBudget.aboveThreshold()) {
return null;
}
if ((newContent != null) && (!(newContent instanceof Interval)) && (!(newContent instanceof Variable))) {
if(newContent.subjectOrPredicateIsIndependentVar()) {
return null;
}
try {
final Sentence newSentence = new Sentence(newContent, getCurrentTask().sentence.punctuation, newTruth, getTheNewStamp());
newSentence.producedByTemporalInduction=temporalInduction;
final Task newTask = Task.make(newSentence, newBudget, getCurrentTask(), getCurrentBelief());
if (newTask!=null) {
boolean added = derivedTask(newTask, false, false, null, null, overlapAllowed);
if(added) {
ret.add(newTask);
}
}
}
catch (CompoundTerm.UnableToCloneException e) {
return null;
}
//"Since in principle it is always valid to eternalize a tensed belief"
if(temporalInduction && Parameters.IMMEDIATE_ETERNALIZATION) { //temporal induction generated ones get eternalized directly
try {
TruthValue truthEt=TruthFunctions.eternalize(newTruth);
Stamp st=getTheNewStamp().clone();
st.setEternal();
final Sentence newSentence = new Sentence(newContent, getCurrentTask().sentence.punctuation, truthEt, st);
newSentence.producedByTemporalInduction=temporalInduction;
final Task newTask = Task.make(newSentence, newBudget, getCurrentTask(), getCurrentBelief());
if (newTask!=null) {
boolean added = derivedTask(newTask, false, false, null, null, overlapAllowed);
if(added) {
ret.add(newTask);
}
}
}
catch (CompoundTerm.UnableToCloneException e) {
return null;
}
}
return ret;
}
return null;
}
/**
* Shared final operations by all double-premise rules, called from the
* rules except StructuralRules
*
* @param newContent The content of the sentence in task
* @param newTruth The truth value of the sentence in task
* @param newBudget The budget value in task
* @param revisible Whether the sentence is revisible
*/
// public void doublePremiseTask(Term newContent, TruthValue newTruth, BudgetValue newBudget, boolean revisible) {
// if (newContent != null) {
// Sentence taskSentence = currentTask.getSentence();
// Sentence newSentence = new Sentence(newContent, taskSentence.getPunctuation(), newTruth, newStamp, revisible);
// Task newTask = new Task(newSentence, newBudget, currentTask, currentBelief);
// derivedTask(newTask, false, false);
// }
// }
/**
* Shared final operations by all single-premise rules, called in
* StructuralRules
*
* @param newContent The content of the sentence in task
* @param newTruth The truth value of the sentence in task
* @param newBudget The budget value in task
*/
public boolean singlePremiseTask(Term newContent, TruthValue newTruth, BudgetValue newBudget) {
return singlePremiseTask(newContent, getCurrentTask().sentence.punctuation, newTruth, newBudget);
}
/**
* Shared final operations by all single-premise rules, called in
* StructuralRules
*
* @param newContent The content of the sentence in task
* @param punctuation The punctuation of the sentence in task
* @param newTruth The truth value of the sentence in task
* @param newBudget The budget value in task
*/
public boolean singlePremiseTask(final Term newContent, final char punctuation, final TruthValue newTruth, final BudgetValue newBudget) {
if (!newBudget.aboveThreshold())
return false;
Task parentTask = getCurrentTask().getParentTask();
if (parentTask != null) {
if (parentTask.getTerm() == null) {
return false;
}
if (newContent == null) {
return false;
}
if (newContent.equals(parentTask.getTerm())) {
return false;
}
}
Sentence taskSentence = getCurrentTask().sentence;
if (taskSentence.isJudgment() || getCurrentBelief() == null) {
setTheNewStamp(new Stamp(taskSentence.stamp, getTime()));
} else {
// to answer a question with negation in NAL-5 --- move to activated task?
setTheNewStamp(new Stamp(getCurrentBelief().stamp, getTime()));
}
if(newContent.subjectOrPredicateIsIndependentVar()) {
return false;
}
if(newContent instanceof Interval) {
return false;
}
Sentence newSentence = new Sentence(newContent, punctuation, newTruth, getTheNewStamp());
Task newTask = Task.make(newSentence, newBudget, getCurrentTask());
if (newTask!=null) {
return derivedTask(newTask, false, true, null, null, false);
}
return false;
}
public boolean singlePremiseTask(Sentence newSentence, BudgetValue newBudget) {
if (!newBudget.aboveThreshold()) {
return false;
}
Task newTask = new Task(newSentence, newBudget, getCurrentTask());
return derivedTask(newTask, false, true, null, null, false);
}
public long getTime() {
return memory.time();
}
public Stamp getNewStamp() {
return newStamp;
}
public void setNewStamp(Stamp newStamp) {
this.newStamp = newStamp;
}
/**
* @return the currentTask
*/
public Task getCurrentTask() {
return currentTask;
}
/**
* @param currentTask the currentTask to set
*/
public void setCurrentTask(Task currentTask) {
this.currentTask = currentTask;
}
public void setCurrentConcept(Concept currentConcept) {
this.currentConcept = currentConcept;
}
/**
* @return the newStamp
*/
public Stamp getTheNewStamp() {
if (newStamp == null) {
//if newStamp==null then newStampBuilder must be available. cache it's return value as newStamp
newStamp = newStampBuilder.build();
newStampBuilder = null;
}
return newStamp;
}
/**
* @param newStamp the newStamp to set
*/
public Stamp setTheNewStamp(Stamp newStamp) {
this.newStamp = newStamp;
this.newStampBuilder = null;
return newStamp;
}
public interface StampBuilder {
Stamp build();
}
/** creates a lazy/deferred StampBuilder which only constructs the stamp if getTheNewStamp() is actually invoked */
public void setTheNewStamp(final Stamp first, final Stamp second, final long time) {
newStamp = null;
newStampBuilder = new StampBuilder() {
@Override
public Stamp build() {
return new Stamp(first, second, time);
}
};
}
/**
* @return the currentBelief
*/
public Sentence getCurrentBelief() {
return currentBelief;
}
/**
* @param currentBelief the currentBelief to set
*/
public void setCurrentBelief(Sentence currentBelief) {
this.currentBelief = currentBelief;
}
/**
* @return the currentBeliefLink
*/
public TermLink getCurrentBeliefLink() {
return currentBeliefLink;
}
/**
* @param currentBeliefLink the currentBeliefLink to set
*/
public void setCurrentBeliefLink(TermLink currentBeliefLink) {
this.currentBeliefLink = currentBeliefLink;
}
/**
* @return the currentTaskLink
*/
public TaskLink getCurrentTaskLink() {
return currentTaskLink;
}
/**
* @param currentTaskLink the currentTaskLink to set
*/
public void setCurrentTaskLink(TaskLink currentTaskLink) {
this.currentTaskLink = currentTaskLink;
}
/**
* @return the currentTerm
*/
public Term getCurrentTerm() {
return currentTerm;
}
/**
* @param currentTerm the currentTerm to set
*/
public void setCurrentTerm(Term currentTerm) {
this.currentTerm = currentTerm;
}
/**
* @return the currentConcept
*/
public Concept getCurrentConcept() {
return currentConcept;
}
public Memory mem() {
return memory;
}
/** tasks added with this method will be remembered by this NAL instance; useful for feedback */
public void addTask(Task t, String reason) {
if(t.sentence.term==null) {
return;
}
memory.addNewTask(t, reason);
}
/**
* Activated task called in MatchingRules.trySolution and
* Concept.processGoal
*
* @param budget The budget value of the new Task
* @param sentence The content of the new Task
* @param candidateBelief The belief to be used in future inference, for
* forward/backward correspondence
*/
public void addTask(final Task currentTask, final BudgetValue budget, final Sentence sentence, final Sentence candidateBelief) {
addTask(new Task(sentence, budget, currentTask, sentence, candidateBelief),
"Activated");
}
@Override
public String toString() {
return "DerivationContext[" + currentConcept + "," + currentTaskLink + "]";
}
}