package nars.gui.graph; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import nars.util.EventEmitter; import nars.util.EventEmitter.EventObserver; import nars.util.Events; import nars.storage.Memory; import nars.entity.Concept; import nars.entity.Item; import nars.entity.Sentence; import nars.entity.Task; import nars.language.CompoundTerm; import nars.language.Statement; import nars.language.Term; import org.jgrapht.EdgeFactory; import org.jgrapht.graph.DirectedMultigraph; abstract public class SentenceGraph<E> extends DirectedMultigraph<Term, E> implements EventObserver { public final Memory memory; public static class GraphChange { } private boolean needInitialConcepts; private boolean started; public final Map<Sentence, List<E>> components = new HashMap(); public final EventEmitter event = new EventEmitter( GraphChange.class ); public SentenceGraph(Memory memory) { super(/*null*/new EdgeFactory() { @Override public Object createEdge(Object v, Object v1) { return null; } }); this.memory = memory; reset(); start(); } private void setEvents(boolean n) { if (memory!=null) { memory.event.set(this, n, Events.FrameEnd.class, Events.ConceptForget.class, Events.ConceptBeliefAdd.class, Events.ConceptBeliefRemove.class, Events.ConceptGoalAdd.class, Events.ConceptGoalRemove.class, Events.ResetEnd.class ); } } public void start() { if (started) return; started = true; setEvents(true); } public void stop() { if (!started) return; started = false; setEvents(false); } @Override public void event(final Class event, final Object[] a) { // if (event!=FrameEnd.class) // System.out.println(event + " " + Arrays.toString(a)); if (event == Events.ConceptForget.class) { //remove all associated beliefs Concept c = (Concept)a[0]; //create a clone of the list for thread safety for (Task b : new ArrayList<Task>(c.beliefs)) { remove(b.sentence); } } else if (event == Events.ConceptBeliefAdd.class) { Concept c = (Concept)a[0]; Sentence s = ((Task)a[1]).sentence; add(s, c); } else if (event == Events.ConceptBeliefRemove.class) { Concept c = (Concept)a[0]; Sentence s = (Sentence)a[1]; remove(s); } else if (event == Events.ConceptGoalAdd.class) { Concept c = (Concept)a[0]; Sentence s = ((Task)a[1]).sentence; add(s, c); } else if (event == Events.ConceptGoalRemove.class) { Concept c = (Concept)a[0]; Sentence s = (Sentence)a[1]; remove(s); } else if (event == Events.FrameEnd.class) { if (needInitialConcepts) getInitialConcepts(); } else if (event == Events.ResetEnd.class) { reset(); } } protected boolean remove(Sentence s) { List<E> componentList = components.get(s); if (componentList!=null) { for (E e : componentList) { if (!containsEdge(e)) continue; Term source = getEdgeSource(e); Term target = getEdgeTarget(e); removeEdge(e); ensureTermConnected(source); ensureTermConnected(target); } componentList.clear(); components.remove(s); return true; } return false; } public void reset() { try { this.removeAllEdges( new ArrayList(edgeSet()) ); } catch (Exception e) { System.err.println(e); } try { this.removeAllVertices( new ArrayList(vertexSet()) ); } catch (Exception e) { System.err.println(e); } if (!edgeSet().isEmpty()) { System.err.println(this + " edges not empty after reset()"); System.exit(1); } if (!vertexSet().isEmpty()) { System.err.println(this + " vertices not empty after reset()"); System.exit(1); } needInitialConcepts = true; } private void getInitialConcepts() { needInitialConcepts = false; try { for (final Concept c : memory) { for (final Task ts : c.beliefs) { add(ts.sentence, c); } } } catch (NoSuchElementException e) { } } protected final void ensureTermConnected(final Term t) { if (inDegreeOf(t)+outDegreeOf(t) == 0) removeVertex(t); } abstract public boolean allow(Sentence s); abstract public boolean allow(CompoundTerm st); public boolean remove(final E s) { if (!containsEdge(s)) return false; Term from = getEdgeSource(s); Term to = getEdgeTarget(s); boolean r = removeEdge(s); ensureTermConnected(from); ensureTermConnected(to); if (r) event.emit(GraphChange.class, null, s); return true; } protected void addComponents(final Sentence parentSentence, final E edge) { List<E> componentList = components.get(parentSentence); if (componentList == null) { componentList = new ArrayList(1); components.put(parentSentence, componentList); } componentList.add(edge); } public boolean add(final Sentence s, final Item c) { if (!allow(s)) return false; if (s.term instanceof CompoundTerm) { CompoundTerm cs = (CompoundTerm)s.term; if (cs instanceof Statement) { Statement st = (Statement)cs; if (allow(st)) { if (add(s, st, c)) { event.emit(GraphChange.class, st, null); return true; } } } } return false; } /** default behavior, may override in subclass */ abstract public boolean add(final Sentence s, final CompoundTerm ct, final Item c); }