/* * Here comes the text of your license * Each line should be prefixed with * */ package nars.lab.plugin.input; import java.util.ArrayList; import nars.util.EventEmitter; import nars.util.Events; import nars.NAR; import nars.config.Parameters; import nars.util.Plugin; import nars.control.DerivationContext; import nars.entity.BudgetValue; import nars.entity.Concept; import nars.entity.Sentence; import nars.entity.Stamp; import nars.entity.Task; import nars.entity.TruthValue; import nars.inference.BudgetFunctions; import static nars.inference.TemporalRules.ORDER_CONCURRENT; import static nars.inference.TemporalRules.ORDER_FORWARD; import nars.inference.TruthFunctions; import nars.inference.UtilityFunctions; import nars.io.Symbols; import nars.language.Conjunction; import nars.language.Interval; import nars.language.Term; /** * * @author tc */ public class PerceptionAccel implements Plugin, EventEmitter.EventObserver { @Override public boolean setEnabled(NAR n, boolean enabled) { //register listening to new events: n.memory.event.set(this, enabled, Events.InduceSucceedingEvent.class, Events.ConceptNew.class, Events.ConceptForget.class); return true; } double partConceptsPrioThreshold=0.1; public void setPartConceptsPrioThreshold(double value) { partConceptsPrioThreshold=value; } public double getPartConceptsPrioThreshold() { return partConceptsPrioThreshold; } ArrayList<Task> eventbuffer=new ArrayList<>(); int cur_maxlen=1; public void perceive(DerivationContext nal) { //implement Peis idea here now //we start with length 2 compounds, and search for patterns which are one longer than the longest observed one boolean longest_result_derived_already=false; for(int Len=cur_maxlen+1;Len>=2;Len--) { //ok, this is the length we have to collect, measured from the end of event buffer Term[] relterms=new Term[2*Len-1]; //there is a interval term for every event //measuring its distance to the next event, but for the last event this is obsolete //thus it are 2*Len-1] terms Task newEvent=eventbuffer.get(eventbuffer.size()-1); TruthValue truth=newEvent.sentence.truth; Stamp st=new Stamp(nal.memory); ArrayList<Long> evBase=new ArrayList<Long>(); int k=0; for(int i=0;i<Len;i++) { int j=eventbuffer.size()-1-(Len-1)+i; //we go till to the end of the event buffer if(j<0) { //event buffer is not filled up enough to support this one, happens at the beginning where event buffer has no elements //but the mechanism already looks for length 2 patterns on the occurence of the first event break; } Task current=eventbuffer.get(j); for(long l : current.sentence.stamp.evidentialBase) { evBase.add(l); } relterms[k]=current.sentence.term; if(i!=Len-1) { //if its not the last one, then there is a next one for which we have to put an interval truth=TruthFunctions.deduction(truth, current.sentence.truth); Task next=eventbuffer.get(j+1); relterms[k+1]=Interval.interval(next.sentence.getOccurenceTime()-current.sentence.getOccurenceTime(), nal.memory); } k+=2; } long[] evB=new long[evBase.size()]; int u=0; for(long l : evBase) { evB[u]=l; u++; } st.baseLength=evB.length; st.evidentialBase=evB; boolean eventBufferDidNotHaveSoMuchEvents=false; for(int i=0;i<relterms.length;i++) { if(relterms[i]==null) { eventBufferDidNotHaveSoMuchEvents=true; } } if(eventBufferDidNotHaveSoMuchEvents) { continue; } //decide on the tense of &/ by looking if the first event happens parallel with the last one //Todo refine in 1.6.3 if we want to allow input of difference occurence time boolean after=newEvent.sentence.after(eventbuffer.get(eventbuffer.size()-1-(Len-1)).sentence, nal.memory.param.duration.get()); //critical part: (not checked for correctness yet): //we now have to look at if the first half + the second half already exists as concept, before we add it Term[] firstHalf; Term[] secondHalf; if(relterms[Len-1] instanceof Interval) { //the middle can be a interval, for example in case of a,+1,b , in which case we dont use it firstHalf=new Term[Len-1]; //so we skip the middle here secondHalf=new Term[Len-1]; //as well as here int h=0; //make index mapping easier by counting for(int i=0;i<Len-1;i++) { firstHalf[i]=relterms[h]; h++; } h+=1; //we have to overjump the middle element this is why for(int i=0;i<Len-1;i++) { secondHalf[i]=relterms[h]; h++; } } else { //it is a event so its fine firstHalf=new Term[Len]; //2*Len-1 in total secondHalf=new Term[Len]; //but the middle is also used in the second one int h=0; //make index mapping easier by counting for(int i=0;i<Len;i++) { firstHalf[i]=relterms[h]; h++; } h--; //we have to use the middle twice this is why for(int i=0;i<Len;i++) { secondHalf[i]=relterms[h]; h++; } } Term firstC=Conjunction.make(firstHalf, after ? ORDER_FORWARD : ORDER_CONCURRENT); Term secondC=Conjunction.make(secondHalf, after ? ORDER_FORWARD : ORDER_CONCURRENT); Concept C1=nal.memory.concept(firstC); Concept C2=nal.memory.concept(secondC); if(C1==null || C2==null) { if(debugMechanism) { System.out.println("one didn't exist: "+firstC.toString()+" or "+secondC.toString()); } continue; //the components were not observed, so don't allow creating this compound } if(C1.getPriority()<partConceptsPrioThreshold || C2.getPriority()<partConceptsPrioThreshold) { continue; //too less priority } Conjunction C=(Conjunction) Conjunction.make(relterms, after ? ORDER_FORWARD : ORDER_CONCURRENT); Sentence S=new Sentence(C,Symbols.JUDGMENT_MARK,truth,st); //importance "summation" Task T=new Task(S,new BudgetValue(BudgetFunctions.or(C1.getPriority(), C2.getPriority()),Parameters.DEFAULT_JUDGMENT_DURABILITY,truth)); if(debugMechanism) { System.out.println("success: "+T.toString()); } if(longest_result_derived_already) { T.setElemOfSequenceBuffer(false); } longest_result_derived_already=true; nal.derivedTask(T, false, false, null, null, false); //lets make the new event the parent task, and derive it } } //keep track of how many conjunctions with related amount of component terms there are: int sz=100; int[] sv=new int[sz]; //use static array, should suffice for now boolean debugMechanism=false; public void handleConjunctionSequence(Term t, boolean Add) { if(!(t instanceof Conjunction)) { return; } Conjunction c=(Conjunction) t; if(debugMechanism) { System.out.println("handleConjunctionSequence with "+t.toString()+" "+String.valueOf(Add)); } if(Add) { //manage concept counter sv[c.term.length]++; } else { sv[c.term.length]--; } //determine cur_maxlen //by finding the first complexity which exists cur_maxlen=1; //minimum size is 1 (the events itself), in which case only chaining of two will happen for(int i=sz-1;i>=2;i--) { //>=2 because a conjunction with size=1 doesnt exist if(sv[i]>0) { cur_maxlen=i; //dont using the index 0 in sv makes it easier here break; } } if(debugMechanism) { System.out.println("determined max len is "+String.valueOf(cur_maxlen)); } } @Override public void event(Class event, Object[] args) { if (event == Events.InduceSucceedingEvent.class) { //todo misleading event name, it is for a new incoming event Task newEvent = (Task)args[0]; if(newEvent.sentence.punctuation==Symbols.JUDGMENT_MARK) { eventbuffer.add(newEvent); while(eventbuffer.size()>cur_maxlen+1) { eventbuffer.remove(0); } DerivationContext nal= (DerivationContext)args[1]; perceive(nal); } } if(event == Events.ConceptForget.class) { Concept forgot=(Concept) args[0]; handleConjunctionSequence(forgot.term,false); } if(event == Events.ConceptNew.class) { Concept newC=(Concept) args[0]; handleConjunctionSequence(newC.term,true); } } public static int PERCEPTION_DECISION_ACCEL_SAMPLES = 1; //new inference rule accelerating decision making: https://groups.google.com/forum/#!topic/open-nars/B8veE-WDd8Q //mostly only makes sense if perception plugin is loaded }