class TermEntry { constructor(t:Term, p:string, a:number, time:number) { this.term = t; this.provenance = p; this.activation = a; this.time = time; } term:Term; provenance:string; activation:number; time:number; timeEnd:number; previousInTime:TermEntry; // if this sentence has been overwritten by another one, this points to the previous one } class TermContainer { addTerm(t:Term, provenance:string, activation:number, time:number) : TermEntry { let te:TermEntry = new TermEntry(t, provenance, activation, time); this.plainTermList.push(te); let l:TermEntry[] = this.termHash[t.functor.name]; if (l == null) { l = []; this.termHash[t.functor.name] = l; } l.push(te); return te; } static termReplacesPreviousStateTerm(t1:Term, t2:Term) : boolean { return t1.functor == t2.functor && (t1.attributes[0] instanceof ConstantTermAttribute) && (t2.attributes[0] instanceof ConstantTermAttribute) && ((t1.attributes[0])).value == ((t2.attributes[0])).value; } addStateTermIfNew(t:Term, provenance:string, activation:number, time:number) : boolean { // check if we need to replace some term: let l:TermEntry[] = this.termHash[t.functor.name]; let previous_t_l:TermEntry[] = []; if (l != null) { for(let te2 of l) { if (TermContainer.termReplacesPreviousStateTerm(t, te2.term)) previous_t_l.push(te2); } } if (previous_t_l.length == 0) { this.addTerm(t, provenance, activation, time); return true; } else { // check if it's different from the previous: if (previous_t_l.length == 1 && t.equalsNoBindings(previous_t_l[0].term) == 1) { if (previous_t_l[0].activation < activation) { previous_t_l[0].activation = activation; previous_t_l[0].provenance = provenance; // time is not updated } } else { // replace old with new, and store old: let previous_t_single:TermEntry = null; for(let previous_t of previous_t_l) { // even if it's a state term, if we have multiple of them in the same cycle, we assume they can coexist: if (previous_t.time != time) { previous_t_single = new TermEntry(previous_t.term, previous_t.provenance, previous_t.activation, previous_t.time) previous_t_single.timeEnd = time; previous_t_single.previousInTime = previous_t.previousInTime; this.plainPreviousTermList.push(previous_t_single); if (this.plainPreviousTermList.length > MAXIMUM_MEMORY_OF_PREVIOUS_STATES) this.plainPreviousTermList.splice(0,1); this.removeInternal(previous_t); } } let new_t:TermEntry = this.addTerm(t, provenance, activation, time); new_t.previousInTime = previous_t_single; return true; } } return false; } removeTerm(t:Term) { // console.log("removeTerm " + t.toString()); let l:TermEntry[] = this.termHash[t.functor.name]; if (l != null) { for(let idx:number = 0;idx0 && (tel[0].term.functor.is_a(t.functor) || t.functor.is_a(tel[0].term.functor))) { this.match_cache_l = this.match_cache_l.concat(tel); } } this.match_cache_idx = 0; return this.nextMatch(); } nextMatch() : [Term, Bindings] { if (this.match_cache_l==null) return null; while(this.match_cache_idx