package nars.gui.util; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; import javax.xml.transform.TransformerConfigurationException; import nars.NAR; import nars.entity.BudgetValue; import nars.entity.Concept; import nars.entity.TaskLink; import nars.entity.TermLink; import nars.language.Term; import org.jgrapht.Graph; import org.jgrapht.ext.GmlExporter; import org.jgrapht.ext.GraphMLExporter; import org.jgrapht.ext.IntegerEdgeNameProvider; import org.jgrapht.ext.IntegerNameProvider; import org.jgrapht.ext.StringEdgeNameProvider; import org.jgrapht.ext.StringNameProvider; import org.jgrapht.graph.DefaultEdge; import org.jgrapht.graph.DirectedMultigraph; import org.xml.sax.SAXException; /** * Stores the contents of some, all, or of multiple NAR memory snapshots. * * @author me */ public class NARGraph extends DirectedMultigraph { public <X> Set<X> vertices(Class<? extends X> type) { Set<X> s = new HashSet(); for (Object o : vertexSet()) { if (type.isInstance(o)) s.add((X)o); } return s; } /** * determines which NARS term can result in added graph features */ public static interface Filter { boolean includePriority(float l); boolean includeConcept(Concept c); } public final static Filter IncludeEverything = new Filter() { @Override public boolean includePriority(float l) { return true; } @Override public boolean includeConcept(Concept c) { return true; } }; public final static class ExcludeBelowPriority implements Filter { final float thresh; public ExcludeBelowPriority(float l) { this.thresh = l; } @Override public boolean includePriority(float l) { return l >= thresh; } @Override public boolean includeConcept(Concept c) { return true; } } /** * creates graph features from NARS term */ public static interface Graphize { /** * called at beginning of operation * * @param g * @param time */ void onTime(NARGraph g, long time); /** * called per concept * * @param g * @param c */ void onConcept(NARGraph g, Concept c); /** * called at end of operation * * @param g */ void onFinish(NARGraph g); } abstract public static class NAREdge<X> extends DefaultEdge { private final X object; private int hash; public NAREdge(X x) { this.object = x; this.hash = getHash(); } public NAREdge() { this.object = (X) getClass(); this.hash = getHash(); } private int getHash() { return Objects.hash(object.hashCode(), getSource(), getTarget()); } @Override public int hashCode() { return hash; } public X getObject() { return object; } @Override public boolean equals(final Object obj) { if (obj == object) { return true; } if (obj instanceof NAREdge) { NAREdge e = (NAREdge) obj; return ((getSource() == e.getSource()) && //need .equals? (getTarget() == e.getTarget()) && //need .equals? (object.equals(((NAREdge) obj).object))); } return false; } @Override public Object getSource() { return super.getSource(); } @Override public Object getTarget() { return super.getTarget(); } @Override public Object clone() { return super.clone(); } } public static class TermBelief extends NAREdge { @Override public String toString() { return "belief"; } @Override public Object clone() { return super.clone(); } } public static class TermLinkEdge extends NAREdge<TermLink> { public TermLinkEdge(TermLink t) { super(t); } @Override public String toString() { return "termlink"; } @Override public Object clone() { return super.clone(); } public BudgetValue getBudget() { return this.getObject().getBudget(); } public Term getTerm() { return this.getObject().getTerm(); } } public static class TaskLinkEdge extends NAREdge<TaskLink> { public TaskLinkEdge(TaskLink t) { super(t); } @Override public String toString() { return "tasklink"; } @Override public Object clone() { return super.clone(); } public BudgetValue getBudget() { return this.getObject().getBudget(); } public Term getTerm() { return this.getObject().getTerm(); } } public static class TermQuestion extends NAREdge { @Override public String toString() { return "question"; } @Override public Object clone() { return super.clone(); } } public static class TermDerivation extends NAREdge { @Override public String toString() { return "derives"; } @Override public Object clone() { return super.clone(); } } public static class TermContent extends NAREdge { @Override public String toString() { return "has"; } @Override public Object clone() { return super.clone(); } } public static class TermType extends NAREdge { @Override public String toString() { return "type"; } @Override public Object clone() { return super.clone(); } } public static class SentenceContent extends NAREdge { @Override public String toString() { return "sentence"; } @Override public Object clone() { return super.clone(); } } public NARGraph() { super(DefaultEdge.class); } public List<Concept> currentLevel = new ArrayList(); public NARGraph add(NAR n, Filter filter, Graphize graphize) { graphize.onTime(this, n.time()); //TODO support AbstractBag for (Concept c : n.memory) { //TODO use more efficient iterator so that the entire list does not need to be traversed when excluding ranges float p = c.getPriority(); if (!filter.includePriority(p)) { continue; } //graphize.preLevel(this, p); if (!filter.includeConcept(c)) { continue; } graphize.onConcept(this, c); //graphize.postLevel(this, level); } graphize.onFinish(this); return this; } public boolean addEdge(Object sourceVertex, Object targetVertex, NAREdge e) { return addEdge(sourceVertex, targetVertex, e, false); } public boolean addEdge(Object sourceVertex, Object targetVertex, NAREdge e, boolean allowMultiple) { if (!allowMultiple) { Set existing = getAllEdges(sourceVertex, targetVertex); if (existing != null) { for (Object o : existing) { if (o.getClass() == e.getClass()) { return false; } } } } return super.addEdge(sourceVertex, targetVertex, e); } public void toGraphML(Writer writer) throws SAXException, TransformerConfigurationException { GraphMLExporter gme = new GraphMLExporter(new IntegerNameProvider(), new StringNameProvider(), new IntegerEdgeNameProvider(), new StringEdgeNameProvider()); gme.export(writer, this); } public void toGraphML(String outputFile) throws SAXException, TransformerConfigurationException, IOException { toGraphML(new FileWriter(outputFile, false)); } public void toGML(Writer writer) { GmlExporter gme = new GmlExporter(new IntegerNameProvider(), new StringNameProvider(), new IntegerEdgeNameProvider(), new StringEdgeNameProvider()); gme.setPrintLabels(GmlExporter.PRINT_EDGE_VERTEX_LABELS); gme.export(writer, this); } public void toGML(String outputFile) throws IOException { toGML(new FileWriter(outputFile, false)); } @Override public Graph clone() { return (Graph) super.clone(); } public void graphMLWrite(String filename) throws Exception { new GraphMLExporter(new IntegerNameProvider(), new StringNameProvider(), new IntegerEdgeNameProvider(), new StringEdgeNameProvider()).export(new FileWriter(filename), this); } public static class TimeNode { private final long time; public TimeNode(long t) { this.time = t; } @Override public int hashCode() { return (int) time; } @Override public boolean equals(Object obj) { if (!(obj instanceof TimeNode)) { return false; } return ((TimeNode) obj).time == time; } @Override public String toString() { return "t" + time; } } public static class UniqueEdge { private final String label; public UniqueEdge(String label) { this.label = label; } @Override public String toString() { return label; } } public void at(Object x, long t) { at(x, t, "c"); //c=creation time } public void at(Object x, long t, String edgeLabel) { at(x, t, new UniqueEdge(edgeLabel)); } public void at(Object x, long t, Object edge) { TimeNode timeNode = new TimeNode(t); addVertex(timeNode); addEdge(timeNode, x, edge); } }