// https://github.com/opennars/opennars/blob/master/nars_core/nars/entity/Concept.java#L233 /** * To accept a new judgment as belief, and check for revisions and solutions * * \param judg The judgment to be accepted * \param task The task to be processed * \return Whether to continue the processing of the task */ private void processJudgment(DerivationContext ctx, ClassicalConcept @this, ClassicalTask task) { ClassicalSentence judgement = task.sentence; ClassicalTask oldBeliefTask = selectCandidate(task, @this.beliefs, EnumForRevision.REVISION);// only revise with the strongest // QUESTION< how about projection? > ClassicalSentence oldBelief = null; if (oldBeliefTask != null) { oldBelief = oldBeliefTask.sentence; Stamp newStamp = judgement.stamp; Stamp oldStamp = oldBelief.stamp; // when table is full, the latter check is especially important, too if ( Stamp.checkEquals( newStamp, oldStamp, Stamp.EnumCompareCreationTime.NO, Stamp.EnumCompareOccurrenceTime.YES, Stamp.EnumCompareEvidentialBaseTime.YES) && task.sentence.truth == oldBelief.truth ) { memory.removeTask(task, "Duplicated"); return; } else if (LocalRules.revisible(judgement, oldBelief)) { // commented because we have to implement revision like in the legacy system // projection can occur either with the NARS default or the new exponential decay model // QUESTION< which one is better ? > ctx.setTheNewStamp(newStamp, oldStamp, memory.time); ClassicalSentence projectedBelief = oldBelief.projection(memory.time, newStamp.occurrenceTime); if (projectedBelief != null) { if (projectedBelief.stamp.occurrenceTime != oldBelief.stamp.occurrenceTime) { // nal.singlePremiseTask(projectedBelief, task.budget); } ctx.currentBelief = projectedBelief; LocalRules.revision(ctx, judgement, projectedBelief, false); } } } if (task.isAboveThreshold) { foreach (var iQuestion in @this.questions) { LocalRules.trySolution(judgement, iQuestion, ctx, true, memory); } TableMaintenance.addToTable(task, false, @this.beliefs, Parameters.CONCEPT_BELIEFS_MAX, null /*ConceptBeliefAdd.class*/, null /*ConceptBeliefRemove.class*/); // if taskLink predicts this concept then add to predictive // TODO } }
} // disable ctor public static void selectConceptForInference(Memory mem, CompoundAndTermContext compoundAndTermContext) { ClassicalConcept currentConcept = mem.workingCyclish.concepts.takeNext(); if (currentConcept == null) { return; } if (currentConcept.taskLinks.size == 0) // remove concepts without tasklinks and without termlinks { mem.workingCyclish.concepts.take(currentConcept.term); mem.conceptWasRemoved(currentConcept); return; } if (currentConcept.termLinks.size == 0) // remove concepts without tasklinks and without termlinks { mem.workingCyclish.concepts.take(currentConcept.term); mem.conceptWasRemoved(currentConcept); return; } DerivationContext ctx = new DerivationContext(mem, compoundAndTermContext); ctx.currentConcept = currentConcept; fireConcept(ctx, 1); }
// https://github.com/opennars/opennars/blob/master/nars_core/nars/entity/Concept.java#L193 public void directProcess(DerivationContext ctx, ClassicalConcept @this, ClassicalTask task) { var puctuation = task.sentence.punctation; /*final*/ switch (puctuation) { case ClassicalSentence.EnumPunctation.JUDGMENT: processJudgment(ctx, @this, task); break; case ClassicalSentence.EnumPunctation.GOAL: processGoal(ctx, @this, task); break; case ClassicalSentence.EnumPunctation.QUESTION: case ClassicalSentence.EnumPunctation.QUEST: processQuestion(ctx, @this, task); break; } maintainDisappointedAnticipations(); if (task.isAboveThreshold) // still need to be processed //memory.logic.LINK_TO_TASK.commit(); { linkToTask(ctx, @this, task); } }
/** * Link to a new task from all relevant concepts for continued processing in * the near future for unspecified time. * <p> * The only method that calls the TaskLink constructor. * * /param task The task to be linked * /param content The content of the task */ private static void linkToTask(DerivationContext ctx, ClassicalConcept @this, ClassicalTask task) { ClassicalBudgetValue taskBudget = task.budget; @this.insertTaskLink( new ClassicalTaskLink( task, null, taskBudget, Parameters.TERM_LINK_RECORD_LENGTH), ctx); // link type: SELF if (!TermUtilities.isTermCompoundTerm(@this.term)) { return; } if (@this.termLinkTemplates.isEmpty()) { return; } ClassicalBudgetValue subBudget = BudgetFunctions.distributeAmongLinks(taskBudget, @this.termLinkTemplates.Count); if (!subBudget.isAboveThreshold) { return; } // else here for (int t = 0; t < @this.termLinkTemplates.Count; t++) { ClassicalTermLink termLink = @this.termLinkTemplates[t]; if (termLink.type == ClassicalTermLink.EnumType.TEMPORAL) { continue; } TermOrCompoundTermOrVariableReferer componentTerm = termLink.target; ClassicalConcept componentConcept = @this.memory.conceptualize(subBudget, componentTerm); if (componentConcept != null) { componentConcept.insertTaskLink( new ClassicalTaskLink( task, termLink, subBudget, Parameters.TERM_LINK_RECORD_LENGTH), ctx); } } @this.buildTermLinks(taskBudget); // recursively insert TermLink }
// https://github.com/opennars/opennars/blob/4515f1d8e191a1f097859decc65153287d5979c5/nars_core/nars/entity/Concept.java#L648 /** * To answer a question by existing beliefs * * \param task The task to be processed * \return Whether to continue the processing of the task */ private void processQuestion(DerivationContext ctx, ClassicalConcept @this, ClassicalTask task) { ClassicalTask quesTask = task; bool newQuestion = true; foreach (ClassicalTask t in @this.questions) { if (t.sentence.equalsContent(quesTask.sentence)) { quesTask = t; newQuestion = false; break; } } if (newQuestion) { if (@this.questions.Count + 1 > Parameters.CONCEPT_QUESTIONS_MAX) { ClassicalTask removed = @this.questions[0]; @this.questions.RemoveAt(0); // FIFO //memory.event.emit(ConceptQuestionRemove.class, this, removed); } @this.questions.Add(task); // memory.event.emit(ConceptQuestionAdd.class, this, task); } ClassicalSentence ques = quesTask.sentence; ClassicalTask newAnswerT = (ques.isQuestion) ? selectCandidate(quesTask, @this.beliefs, EnumForRevision.NOREVISION) : selectCandidate(quesTask, @this.desires, EnumForRevision.NOREVISION); if (newAnswerT != null) { LocalRules.trySolution(newAnswerT.sentence, task, ctx, true, memory); } // commented because memory events are not implemented //else if(task.isInput() && !quesTask.getTerm().hasVarQuery() && quesTask.getBestSolution() != null) { //show previously found solution anyway in case of input //memory.emit(Events.Answer.class, quesTask, quesTask.getBestSolution()); //} }
// see https://github.com/opennars/opennars/blob/4515f1d8e191a1f097859decc65153287d5979c5/nars_core/nars/storage/Memory.java#L187 /** * Get the Concept associated to a Term, or create it. * * Doesn't take it from the bag and put it back to save some cycles and to allow better concurrency * Doesn't adjust budget * * if it fails with an soft error (can't take it from the bag etc) it returns null * * doesn't displace concepts * * @param term indicating the concept * @return an existing Concept, or a new one, or null */ public ClassicalConcept conceptualize(ClassicalBudgetValue budget, TermOrCompoundTermOrVariableReferer term) { ClassicalConcept concept = workingCyclish.concepts.referenceByKey(term); if (concept == null) { // CONCURRENCY< lock and put back > // create new concept, with the applied budget concept = new ClassicalConcept(compoundAndTermContext, term, bagBuilder, budget, this); workingCyclish.concepts.putIn(concept); // from java code base // TODO ASK< implement //emit(Events.ConceptNew.class, concept); } else { // legacy java code applies budget here, we don't } return(concept); }
// https://github.com/opennars/opennars/blob/62c814fb0f3e474a176515103394049b2887ec29/nars_core/nars/entity/Concept.java#L440 /** * To accept a new goal, and check for revisions and realization, then * decide whether to actively pursue it * * \param judg The judgment to be accepted * \param task The task to be processed * \return Whether to continue the processing of the task */ private bool processGoal(DerivationContext ctx, ClassicalConcept @this, ClassicalTask task) { ClassicalSentence goal = task.sentence; ClassicalTask oldGoalT = selectCandidate(task, @this.desires, EnumForRevision.REVISION); // revise with the existing desire values ClassicalSentence oldGoal = null; if (oldGoalT != null) { oldGoal = oldGoalT.sentence; Stamp newStamp = goal.stamp; Stamp oldStamp = oldGoal.stamp; bool isStampEqual = Stamp.checkEquals( newStamp, oldStamp, Stamp.EnumCompareCreationTime.NO, Stamp.EnumCompareOccurrenceTime.NO, Stamp.EnumCompareEvidentialBaseTime.YES); if (isStampEqual) { return(false); // duplicate } if (LocalRules.revisible(goal, oldGoal)) { ctx.setTheNewStamp(newStamp, oldStamp, memory.time); ClassicalSentence projectedGoal = oldGoal.projection(task.sentence.stamp.occurrenceTime, newStamp.occurrenceTime); if (projectedGoal != null) { // if (goal.after(oldGoal, nal.memory.param.duration.get())) { //no need to project the old goal, it will be projected if selected anyway now // nal.singlePremiseTask(projectedGoal, task.budget); //return; // } ctx.currentBelief = projectedGoal; if (true /* TODO< check if not operation > !(task.sentence.term instanceof Operation)*/) { bool successOfRevision = LocalRules.revision(ctx, task.sentence, projectedGoal, false); if (successOfRevision) // it is revised, so there is a new task for which this function will be called { return(false); // with higher/lower desire } // it is not allowed to go on directly due to decision making https://groups.google.com/forum/#!topic/open-nars/lQD0no2ovx4 } } } } Stamp s2 = goal.stamp.clone(); s2.occurrenceTime = memory.time; if (s2.after(task.sentence.stamp, ctx.memory.param.duration.value)) // this task is not up to date we have to project it first { ClassicalSentence projGoal = task.sentence.projection(memory.time, ctx.memory.param.duration.value); if (projGoal != null && projGoal.truth.expectation > ctx.memory.param.decisionThreshold) { ctx.singlePremiseTask(projGoal, task.budget.clone()); // keep goal updated // return false; //outcommented, allowing "roundtrips now", relevant for executing multiple steps of learned implication chains } } if (task.isAboveThreshold) { ClassicalTask beliefT = selectCandidate(task, @this.beliefs, EnumForRevision.NOREVISION); // check if the Goal is already satisfied double antiSatisfaction = 0.5; // we dont know anything about that goal yet, so we pursue it to remember it because its maximally unsatisfied if (beliefT != null) { ClassicalSentence belief = beliefT.sentence; ClassicalSentence projectedBelief = belief.projection(task.sentence.stamp.occurrenceTime, ctx.memory.param.duration.value); LocalRules.trySolution(projectedBelief, task, ctx, true, memory); // check if the Goal is already satisfied (manipulate budget) antiSatisfaction = task.sentence.truth.getExpDifAbs(belief.truth); } double satisfaction = 1.0 - antiSatisfaction; TruthValue t = goal.truth.clone(); t.frequency = (float)(t.frequency - satisfaction); // decrease frequency according to satisfaction value bool fullfilled = antiSatisfaction < Parameters.SATISFACTION_TRESHOLD; ClassicalSentence projectedGoal = goal.projection(ctx.memory.time, ctx.memory.time); // NOTE< this projection is fine > /* commented because we stil have to implement operations * if (projectedGoal != null && task.isAboveThreshold && !fullfilled && projectedGoal.truth.expectation > nal.memory.param.decisionThreshold.get()) { * * try { * Operation bestop = null; * float bestop_truthexp = 0.0f; * TruthValue bestop_truth = null; * Task executable_precond = null; * //long distance = -1; * long mintime = -1; * long maxtime = -1; * for (Task t: this.executable_preconditions) { * Term[] prec = ((Conjunction)((Implication)t.getTerm()).getSubject()).term; * Term[] newprec = new Term[prec.length - 3]; * for (int i = 0; i < prec.length - 3; i++) { //skip the last part: interval, operator, interval * newprec[i] = prec[i]; * } * * //distance = Interval.magnitudeToTime(((Interval)prec[prec.length-1]).magnitude, nal.memory.param.duration); * mintime = nal.memory.time() + Interval.magnitudeToTime(((Interval)prec[prec.length - 1]).magnitude - 1, nal.memory.param.duration); * maxtime = nal.memory.time() + Interval.magnitudeToTime(((Interval)prec[prec.length - 1]).magnitude + 2, nal.memory.param.duration); * * Operation op = (Operation)prec[prec.length - 2]; * Term precondition = Conjunction.make(newprec, TemporalRules.ORDER_FORWARD); * * Concept preconc = nal.memory.concept(precondition); * long newesttime = -1; * Task bestsofar = null; * if (preconc != null) { //ok we can look now how much it is fullfilled * * //check recent events in event bag * for (Task p : this.memory.sequenceTasks) { * if (p.sentence.term.equals(preconc.term) && p.sentence.isJudgment() && !p.sentence.isEternal() && p.sentence.getOccurenceTime() > newesttime && p.sentence.getOccurenceTime() <= memory.time()) { * newesttime = p.sentence.getOccurenceTime(); * bestsofar = p; //we use the newest for now * } * } * if (bestsofar == null) { * continue; * } * //ok now we can take the desire value: * TruthValue A = projectedGoal.getTruth(); * //and the truth of the hypothesis: * TruthValue Hyp = t.sentence.truth; * //and the truth of the precondition: * Sentence projectedPrecon = bestsofar.sentence.projection(memory.time() comment*- distance comment*, memory.time()); * * if (projectedPrecon.isEternal()) { * continue; //projection wasn't better than eternalization, too long in the past * } * //debug start * //long timeA = memory.time(); * //long timeOLD = bestsofar.sentence.stamp.getOccurrenceTime(); * //long timeNEW = projectedPrecon.stamp.getOccurrenceTime(); * //debug end * TruthValue precon = projectedPrecon.truth; * //and derive the conjunction of the left side: * TruthValue leftside = TruthFunctions.desireDed(A, Hyp); * //in order to derive the operator desire value: * TruthValue opdesire = TruthFunctions.desireDed(precon, leftside); * * float expecdesire = opdesire.getExpectation(); * if (expecdesire > bestop_truthexp) { * bestop = op; * bestop_truthexp = expecdesire; * bestop_truth = opdesire; * executable_precond = t; * } * } * } * * if (bestop != null && bestop_truthexp > memory.param.decisionThreshold.get()) { * Task t = new Task(new Sentence(bestop, Symbols.JUDGMENT_MARK, bestop_truth, projectedGoal.stamp), new BudgetValue(1.0f, 1.0f, 1.0f)); * //System.out.println("used " +t.getTerm().toString() + String.valueOf(memory.randomNumber.nextInt())); * if (!task.sentence.stamp.evidenceIsCyclic()) { * if (!executeDecision(t)) { //this task is just used as dummy * memory.emit(UnexecutableGoal.class, task, this, nal); * } else { * memory.decisionBlock = memory.time() + Parameters.AUTOMATIC_DECISION_USUAL_DECISION_BLOCK_CYCLES; * SyllogisticRules.generatePotentialNegConfirmation(nal, executable_precond.sentence, executable_precond.budget, mintime, maxtime, 2); * } * } * } * } * catch(Exception ex) { * System.out.println("Failure in operation choice rule, analyze!"); * } * * * * questionFromGoal(task, ctx); * * * addToTable(task, false, desires, Parameters.CONCEPT_GOALS_MAX, ConceptGoalAdd.class, ConceptGoalRemove.class); * * InternalExperience.InternalExperienceFromTask(memory, task,false); * * if(nal.memory.time >= memory.decisionBlock && !executeDecision(task)) { * // commented because we haven't implemented the observer until now memory.emit(UnexecutableGoal.class, task, this, nal); * return true; // it was made true by itself * } * return false; * } // big if */ return(fullfilled); } return(false); }
// function prototype and some of the methode is like https://github.com/opennars/opennars/blob/4515f1d8e191a1f097859decc65153287d5979c5/nars_core/nars/inference/RuleTables.java#L73 internal static void reason( ClassicalTaskLink taskLink, ClassicalTermLink beliefLink, DerivationContext ctx ) { { // debugging int taskId = taskLink.targetTask.name.term.getAtomicOrTerm; int beliefId = beliefLink.target.getAtomicOrTerm; if (taskId == 300002 && beliefId == 300004) { int breakpointHere2 = 1; } else if (taskId == 300004 && beliefId == 300002) { int breakpointHere2 = 1; } int breakpointHere1 = 1; } Memory memory = ctx.memory; memory.emotion.manageBusy(ctx); ClassicalTask task = ctx.currentTask; ClassicalSentence taskSentence = task.sentence; TermOrCompoundTermOrVariableReferer taskTerm = taskSentence.term; TermOrCompoundTermOrVariableReferer beliefTerm = beliefLink.target; // commented because not jet translated //if (equalSubTermsInRespectToImageAndProduct(taskTerm, beliefTerm)) // return; ClassicalConcept beliefConcept = memory.translateTermToConcept(beliefTerm); ClassicalSentence belief = (beliefConcept != null) ? beliefConcept.getBelief(ctx, task) : null; ctx.currentBelief = belief; if (belief != null) { beliefTerm = belief.term; //because interval handling that differs on conceptual level // too restrictive, its checked for non-deductive inference rules in derivedTask (also for single prem) if (Stamp.checkBaseOverlap(task.sentence.stamp, belief.stamp)) { ctx.evidentalOverlap = true; if (!task.sentence.stamp.isEternal || !belief.stamp.isEternal) { return; // only allow for eternal reasoning for now to prevent derived event floods } //return; // preparisons are made now to support this nicely } // comment out for recursive examples, this is for the future, it generates a lot of potentially useless tasks //ctx.emit(Events.BeliefReason.class, belief, beliefTerm, taskTerm, nal); if (LocalRules.match(task, belief, ctx)) // new tasks resulted from the match, so return { return; } } // current belief and task may have changed, so set again: ctx.currentBelief = belief; ctx.currentTask = task; // HACK< derivation must be made by combining compounds > if (!TermUtilities.isTermCompoundTerm(taskTerm) || !TermUtilities.isTermCompoundTerm(beliefTerm)) { return; } // derive and create new tasks for the results { IList <TemporaryDerivedCompoundWithDecorationAndTruth> derivedCompoundTermsWithDecorationAndTruth = new List <TemporaryDerivedCompoundWithDecorationAndTruth>(); bool insert = true; DeriverCaller.deriverCaller( ctx.compoundAndTermContext, ctx.compoundAndTermContext.translateToCompoundChecked(taskTerm), ctx.compoundAndTermContext.translateToCompoundChecked(beliefTerm), out derivedCompoundTermsWithDecorationAndTruth, insert); // translate derivedCompoundTermsWithDecorationAndTruth to tasks and add them // for this we have to call DerivationContext.doublePremiseTask() to generate the tasks foreach (var iDerivedWithDecorationAndTruth in derivedCompoundTermsWithDecorationAndTruth) { TermOrCompoundTermOrVariableReferer content = iDerivedWithDecorationAndTruth.derivedCompoundWithDecoration.termReferer; bool temporalInduction = false; // TODO< decide by rule? from the deriver? > bool overlapAllowed = false; // TODO< decide by rule? from the deriver? > TruthValue truth = null; truth = RuleTable.calcTruthDoublePremise(task.sentence.truth, belief.truth, iDerivedWithDecorationAndTruth.truthfunction); ClassicalBudgetValue budget = new ClassicalBudgetValue(0.5f, 0.5f, 0.5f); // TODO< calculate budget by table > ctx.doublePremiseTask(content, truth, budget, temporalInduction, overlapAllowed ); } } }
// see https://github.com/opennars/opennars/blob/4515f1d8e191a1f097859decc65153287d5979c5/nars_core/nars/storage/Memory.java#L365 public void conceptWasRemoved(ClassicalConcept concept) { // emit(Events.ConceptForget.class, c); }