package nars.gui.graph; import java.util.Objects; import nars.storage.Memory; import nars.NAR; import nars.entity.Item; import nars.entity.Sentence; import nars.entity.Stamp; import nars.entity.TruthValue; import nars.lab.plugin.app.plan.MultipleExecutionManager; import nars.inference.TemporalRules; import nars.io.Symbols; import nars.io.Symbols.NativeOperator; import nars.language.CompoundTerm; import nars.language.Conjunction; import nars.language.Implication; import nars.language.Interval; import nars.language.Negation; import nars.language.Term; import nars.operator.Operation; import nars.gui.graph.ImplicationGraph.Cause; public class ImplicationGraph extends SentenceGraph<Cause> { float minConfidence = 0.25f; public static class Cause { public final Term cause; public final Term effect; public final Sentence parent; // /** strength below which an item will be removed */ // public final double minStrength = 0.01; private double activity = 0; private final int hash; public Cause(Term cause, Term effect, Sentence parent) { this.cause = cause; this.effect = effect; this.parent = parent; this.hash = Objects.hash(cause, effect, parent); } @Override public boolean equals(Object obj) { if (obj instanceof Cause) { Cause c = (Cause)obj; if (c.hash!=hash) return false; return (c.cause.equals(cause)) && (c.effect.equals(effect)) && (c.parent.equals(parent)); } return false; } @Override public int hashCode() { return hash; } public double getActivity() { return activity; } public double addActivity(double a) { activity += a; return activity; } public double multActivity(double m) { activity *= m; return activity; } public TruthValue getTruth() { return parent.truth; } public Stamp getStamp() { return parent.stamp; } public int getTemporalOrder() { return getImplication().getTemporalOrder(); } public Implication getImplication() { return (Implication)parent.term; } @Override public String toString() { return cause + " =/> " + effect /* + " [" + relevancy + "] in " + parent*/; } } public ImplicationGraph(NAR nar) { this(nar.memory); } public ImplicationGraph(Memory memory) { super(memory); } /** creates a clone, optionally with or without preconditions */ public ImplicationGraph(ImplicationGraph g, boolean includePrecondition, double minPriority) { super(null); if (includePrecondition) { throw new RuntimeException("Use .clone()"); } else { for (Term s : g.vertexSet()) { if ((s instanceof Interval) || (s instanceof Operation) || (s instanceof PostCondition)) super.addVertex(s); } for (Cause s : g.edgeSet()) { Term src = g.getEdgeSource(s); Term tgt = g.getEdgeTarget(s); boolean containsSrc = containsVertex(src); boolean containsTgt = containsVertex(tgt); //if both are precondition nodes, skip the edge if (!containsSrc && !containsTgt) continue; if (!containsSrc) super.addVertex(src); if (!containsTgt) super.addVertex(tgt); super.addEdge(src, tgt, s); } } //System.out.println(g.vertexSet().size() + ":" + vertexSet().size() + "," + g.edgeSet().size() + ":" + edgeSet().size()); } public static class UniqueOperation extends Operation { public final Implication parent; private final Term previous; private final int hash; public UniqueOperation(Implication parent, Operation o, Term previous) { super(o.term); this.previous = previous; this.parent = parent; this.hash = Objects.hash(previous, parent, o.term); init(o.term); } @Override public boolean equals(final Object that) { if (that == this) return true; if (hashCode()!=that.hashCode()) return false; if (that instanceof UniqueOperation) { UniqueOperation u = (UniqueOperation)that; if (!u.parent.equals(parent)) return false; if (!Objects.equals(u.previous, previous)) return false; return name().equals(u.name()); } return false; } @Override public int hashCode() { return hash; } } public static class UniqueInterval extends Interval { public final Implication parent; private final Term previous; private final int hash; public UniqueInterval(Implication parent, Term previous, Interval i) { super(i.magnitude, true); this.previous = previous; this.parent = parent; this.hash = Objects.hash(i, previous, parent); } @Override public int hashCode() { return hash; } @Override public boolean equals(final Object that) { if (that == this) return true; if (hashCode()!=that.hashCode()) return false; if (that instanceof UniqueInterval) { UniqueInterval u = (UniqueInterval)that; if (magnitude!=u.magnitude) return false; if (parent!=u.parent) return false; if (!Objects.equals(u.previous, previous)) return false; //handles null value return true; } return false; } } public static class PostCondition extends Negation { public PostCondition(final Term t) { super(t); init(term); } @Override protected CharSequence makeName() { return "~" + this.term[0].name(); } @Override public boolean equals(Object that) { if (!(that instanceof PostCondition)) return false; return super.equals(that); } } protected void meter(Term a) { /*if (a instanceof Interval) memory.logic.PLAN_GRAPH_IN_DELAY_MAGNITUDE.commit(((Interval)a).magnitude); else if (a instanceof Operation) memory.logic.PLAN_GRAPH_IN_OPERATION.commit(1); else memory.logic.PLAN_GRAPH_IN_OTHER.commit(1);*/ } protected static Term postcondition(Term t) { if ((t instanceof Operation) || (t instanceof Interval)) { return t; } return new PostCondition(t); } @Override public boolean add(final Sentence s, final CompoundTerm ct, final Item c) { if(s.truth!=null && s.truth.getExpectation()<0.5) { return false; } if (!(ct instanceof Implication)) { return false; } final Implication st = (Implication)ct; if ((st.getTemporalOrder() == TemporalRules.ORDER_NONE) || (st.operator() == NativeOperator.IMPLICATION_BEFORE) || (!s.isEternal())) return false; final Term subject, predicate; boolean reverse = false; if (reverse) { return false; //reverse temporal order //subject = st.getPredicate(); //predicate = st.getSubject(); } else { subject = st.getSubject(); predicate = st.getPredicate(); } if (s.term.hasVarIndep()) { return false; } final Term predicatePre = predicate; final Term predicatePost = postcondition(predicatePre); addVertex(predicatePre); addVertex(predicatePost); if (subject instanceof Conjunction) { Conjunction seq = (Conjunction)subject; if (seq.operator() == Symbols.NativeOperator.SEQUENCE) { Term prev = (predicatePre!=predicatePost) ? predicatePre : null; if (prev!=null) addVertex(prev); for (int i = 0; i < seq.term.length; i++) { Term a = seq.term[i]; meter(a); if (MultipleExecutionManager.isPlanTerm(a)) { //make a unique Term if an Interval or if an Operation in the middle of a sequence if (((i > 0) && (i < seq.term.length-1)) || (a instanceof Interval)) a = newExecutableVertex(st, a, prev); else { addVertex(a); } if (prev!=null) { newImplicationEdge(prev, a, c, s); } prev = a; } else { //separate the term into a disconnected pre and post condition Term aPre = a; Term aPost = postcondition(a); addVertex(aPre); addVertex(aPost); if (prev!=null) { addVertex(prev); newImplicationEdge(prev, aPre, c, s); //leading edge from previous only } prev = aPost; } } newImplicationEdge(prev, predicatePost, c, s); return true; } else if (seq.operator() == Symbols.NativeOperator.PARALLEL) { //TODO } } else { if (MultipleExecutionManager.isPlanTerm(subject)) { //newImplicationEdge(predicatePre, subject, c, s); //newImplicationEdge(subject, predicatePost, c, s); addVertex(subject); newImplicationEdge(subject, predicatePost, c, s); } else { //separate into pre/post PostCondition subjectPost = new PostCondition(subject); addVertex(predicatePre); addVertex(subject); addVertex(subjectPost); newImplicationEdge(predicatePre, subject, c, s); newImplicationEdge(subjectPost, predicatePost, c, s); } meter(subject); } return true; } @Override public Term getEdgeSource(final Cause e) { return e.cause; } @Override public Term getEdgeTarget(final Cause e) { return e.effect; } public Term newExecutableVertex(Implication st, Term t, Term prev) { Term r; if (t instanceof Operation) { r = new UniqueOperation(st, (Operation)t, prev); } else if (t instanceof Interval) { r = new UniqueInterval(st, prev, (Interval)t); } else throw new RuntimeException("Not executable vertex: " + t); addVertex(r); return r; } /** less costly subclass of Implication */ public static class LightweightImplication extends Implication { public LightweightImplication(Term subject, Term predicate, int order) { super(subject, predicate, order); } @Override protected void init(Term[] components) { } } public Cause newImplicationEdge(final Term source, final Term target, Item i, final Sentence parent) { if (source.equals(target)) return null; //System.out.println("cause: " + source + " -> " + target + " in " + parent); Cause c = new Cause(source, target, parent); try { addEdge(source, target, c); addComponents(parent, c); } catch (IllegalArgumentException wc) { //"no such vertex in graph" return null; } return c; } @Override public boolean allow(final Sentence s) { if(s.stamp.getOccurrenceTime()!=Stamp.ETERNAL) { return false; } float conf = s.truth.getConfidence(); if (conf > minConfidence) return true; return false; } @Override public boolean allow(final CompoundTerm st) { Symbols.NativeOperator o = st.operator(); if ((o == Symbols.NativeOperator.IMPLICATION_WHEN) || (o == Symbols.NativeOperator.IMPLICATION_BEFORE) || (o == Symbols.NativeOperator.IMPLICATION_AFTER)) { return true; } else { //System.err.println("ImplicationGraph disallow " + st); } return false; } @Override public String toString() { StringBuilder x = new StringBuilder(); x.append(getClass().toString()).append("\n"); x.append("Terms:\n"); for (Term v : vertexSet()) x.append(" ").append(v.toString()).append(","); x.append("\nImplications:\n"); for (Cause v : edgeSet()) x.append(" ").append(v.toString()).append(","); x.append("\n\n"); return x.toString(); } }