/* * Copyright (C) 2014 tc * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */ package nars.lab.plugin.app.plan; import java.util.ArrayDeque; import java.util.List; import java.util.TreeSet; import nars.util.EventEmitter.EventObserver; import nars.util.Events.NewTaskExecution; import nars.util.Events.UnexecutableGoal; import nars.util.Events.UnexecutableOperation; import nars.NAR; import nars.config.Parameters; import nars.util.Plugin; import nars.control.DerivationContext; import nars.entity.Concept; import nars.entity.Task; import nars.lab.plugin.app.plan.MultipleExecutionManager; import nars.lab.plugin.app.plan.MultipleExecutionManager.Execution; import static nars.lab.plugin.app.plan.MultipleExecutionManager.isPlanTerm; import nars.lab.plugin.app.plan.GraphExecutive; import nars.inference.TemporalRules; import nars.inference.TruthFunctions; import nars.io.Symbols; import nars.language.Conjunction; import nars.language.Implication; import nars.language.Interval; import nars.language.Term; import nars.operator.Operation; /** * * @author tc */ public class TemporalParticlePlanner implements Plugin, EventObserver { /** * global plan search parameters */ public static boolean used=false; //cause decison making breaks if conjunction sequence is added when planner is not active float searchDepth; int planParticles; /** * inline search parameters */ float inlineSearchDepth; int inlineParticles; /** * max number of tasks that a plan can generate. chooses the N best */ int maxPlannedTasks = 1; MultipleExecutionManager executive; GraphExecutive graph; public TemporalParticlePlanner() { this(120, 64, 16); } public TemporalParticlePlanner(float searchDepth, int planParticles, int inlineParticles) { super(); this.searchDepth = this.inlineSearchDepth = searchDepth; this.planParticles = planParticles; this.inlineParticles = inlineParticles; } @Override public void event(Class event, Object[] a) { if (event == UnexecutableGoal.class) { Task t = (Task)a[0]; Concept c = (Concept)a[1]; DerivationContext n = (DerivationContext)a[2]; decisionPlanning(n, t, c); } else if (event == UnexecutableOperation.class) { Execution executing = (Execution)a[0]; Task task = executing.t; Term term = task.getTerm(); if (term instanceof Conjunction) { Conjunction c = (Conjunction) term; if (c.operator() == Symbols.NativeOperator.SEQUENCE) { executive.executeConjunctionSequence(executing, c); return; } } else if (term instanceof Implication) { Implication it = (Implication) term; if ((it.getTemporalOrder() == TemporalRules.ORDER_FORWARD) || (it.getTemporalOrder() == TemporalRules.ORDER_CONCURRENT)) { if (it.getSubject() instanceof Conjunction) { Conjunction c = (Conjunction) it.getSubject(); if (c.operator() == Symbols.NativeOperator.SEQUENCE) { executive.executeConjunctionSequence(executing, c); return; } } else if (it.getSubject() instanceof Operation) { executive.execute(executing, (Operation) it.getSubject(), task); //directly execute return; } } } } else if (event == NewTaskExecution.class) { Execution te = (Execution)a[0]; Task t = te.getTask(); Term term = t.getTerm(); if (term instanceof Implication) { Implication it = (Implication) term; if ((it.getTemporalOrder() == TemporalRules.ORDER_FORWARD) || (it.getTemporalOrder() == TemporalRules.ORDER_CONCURRENT)) { if (it.getSubject() instanceof Conjunction) { t = inlineConjunction(te, t, (Conjunction) it.getSubject()); } } } else if (term instanceof Conjunction) { t = inlineConjunction(te, t, (Conjunction) term); } te.setTask(t); } } public void decisionPlanning(final DerivationContext nal, final Task t, final Concept concept) { if (!concept.isDesired()) { return; } boolean plannable = graph.isPlannable(t.getTerm()); if (plannable) { graph.plan(nal, concept, t, t.getTerm(), planParticles, searchDepth, '!', maxPlannedTasks); } } //TODO support multiple inline replacements protected Task inlineConjunction(Execution te, Task t, final Conjunction c) { ArrayDeque<Term> inlined = new ArrayDeque(); boolean modified = false; if (c.operator() == Symbols.NativeOperator.SEQUENCE) { for (Term e : c.term) { if (!isPlanTerm(e)) { if (graph.isPlannable(e)) { TreeSet<GraphExecutive.ParticlePlan> plans = graph.particlePlan(e, inlineSearchDepth, inlineParticles); if (plans.size() > 0) { //use the first GraphExecutive.ParticlePlan pp = plans.first(); //if terms precede this one, remove a common prefix //scan from the end of the sequence backward until a term matches the previous, and splice it there //TODO more rigorous prefix compraison. compare sublist prefix List<Term> seq = pp.sequence; // if (prev!=null) { // int previousTermIndex = pp.sequence.lastIndexOf(prev); // // if (previousTermIndex!=-1) { // if (previousTermIndex == seq.size()-1) // seq = Collections.EMPTY_LIST; // else { // seq = seq.subList(previousTermIndex+1, seq.size()); // } // } // } //System.out.println("inline: " + seq + " -> " + e + " in " + c); //TODO adjust the truth value according to the ratio of term length, so that a small inlined sequence affects less than a larger one te.setDesire( TruthFunctions.deduction(te.getDesireValue(), pp.getTruth()) ); //System.out.println(t.sentence.truth + " <- " + pp.truth + " -> " + desire); inlined.addAll(seq); modified = true; } else { //no plan available, this wont be able to execute te.end(); } } else { //this won't be able to execute here te.end(); } } else { //executable term, add inlined.add(e); } } } //remove suffix intervals if (inlined.size() > 0) { while (inlined.peekLast() instanceof Interval) { inlined.removeLast(); modified = true; } } if (inlined.isEmpty()) { te.end(); } if (modified) { Term nc = c.clone(inlined.toArray(new Term[inlined.size()])); if (nc == null) { te.end(); } else { t = t.clone(t.sentence.clone(nc)); } } return t; } @Override public boolean setEnabled(NAR n, boolean enabled) { this.graph = executive.graph; n.memory.event.set(this, enabled, UnexecutableGoal.class, UnexecutableOperation.class); return true; } }