If you’re shopping around for ideas as to how to define data manipulation API, 
it may be worth taking some time looking at Specter too.

Have you considered encoding your port graph into a normal graph? That would 
require you to define a mapping, but would then allow you to fairly easily 
reuse theorems, algorithms and libraries by having them operate on the encoded 
graph, with a hopefully thin layer of translation.

One possible encoding based on what you’ve described could be to turn nodes and 
edges in the port graph into nodes in the encoded graph, and ports in the port 
graph into edges in the encoded graph. It’s hard to say how well that specific 
transform would work in your case without more details about your type of graph 
and somewhat more considerate thinking than I’ve given this, but I have seen 
this approach of encoding graphs into other graphs work out pretty well in 
other contexts.

> On 2 Jan 2018, at 20:11, Christopher Small <metasoar...@gmail.com> wrote:
> 
> > ...noticed that the attribute names in the datoms are a lot like the port 
> > labels in port graphs. A port label is essentially an attribute key whose 
> > value is the edges incident to it. And when you chain data patterns in 
> > Datalog queries, that's a lot like navigating through a graph.
> 
> That's very much in line with what I was thinking you might want to do in 
> this setting.
> 
> You should also take a look at the entity api. It let's you traverse the 
> graph via these entity objects which behave more or less like a dictionary of 
> the av pairs associated with a particular entity in the database. Importantly 
> though, when an attribute points to another entity (a reference attribute), 
> it is returned as yet another of these entity objects, letting you traverse 
> the graph using get, in a pretty similar fashion to what you're describing.
> 
> http://docs.datomic.com/entities.html
> 
> You may also check out the pull api. It let's you pull facts out of the graph 
> as regular old maps by specifying what attributes & paths you wish to pull 
> out of the graph. The result is that you can read from the underlying graph 
> database as though it was a document store, but where the documents are 
> dynamically computed/queried from the graph based on the pull expression you 
> provide. You can also use pull expressions inside the `:find` clause of 
> either a DataScript of Datomic datalog query, which is often a convenient way 
> of specifying both a set of entities (via a datalog query) and statement of 
> facts to pull about them.
> 
> http://docs.datomic.com/pull.html
> 
> Collectively, these three interfaces give you quite a lot of expressiveness 
> and flexibility in how you query/traverse your data.
> 
> 
> 
>> On Tue, Jan 2, 2018 at 12:31 PM, Ben Kovitz <bkov...@gmail.com> wrote:
>> Christopher Small,
>> 
>> Your suggestion to look into Datomic definitely turned up a new idea. I went 
>> through the Datalog tutorial at http://www.learndatalogtoday.org (which is 
>> excellent, by the way), and noticed that the attribute names in the datoms 
>> are a lot like the port labels in port graphs. A port label is essentially 
>> an attribute key whose value is the edges incident to it. And when you chain 
>> data patterns in Datalog queries, that's a lot like navigating through a 
>> graph.
>> 
>> The new, hopefully simple, easy-to-use, and not error-prone idea is to use 
>> the clojure.lang.IPersistentMap  interface to query and update graphs. 
>> Nodes, edge, attribute names, port labels, and a few "reserved keywords" 
>> like :adj-nodes and :edge, could navigate the graph as if it were an 
>> ordinary nested map with get-in, assoc-in, and the like, without ever 
>> needing to wrap anything inside a record to tell what it is. Here are some 
>> sample queries and what they could return:
>> 
>> (get-in g [node port-label :adj-nodes])
>>   a coll of all the nodes with an edge to [node port-label]
>> (get-in g [node port-label :adj-node])
>>   one node with an edge to [node port-label], or nil
>> (get-in g [node port-label])
>>   true or false, according to whether node has a port named port-label
>> (get-in g [node k])
>>   value of node's attr k
>> (get-in g [edge k])
>>   value of edge's attr k
>> (get g node-or-edge)
>>   the entire map of attrs associated with node-or-edge, or nil if it does 
>> not exist
>> (get-in g [node k1 k2 k3])
>>   treat node's attrs as a nested map
>> (get-in [node port-label :edges])
>>   a coll of all the edges that link to [node port-label]
>> (get-in [node port-label :edge])
>>   a single edge that links to port-label, or nil
>> (get-in [node port-label1 port-label2])
>>   coll of all nodes that link to [node port-label1] from a port named 
>> port-label2
>> 
>> And here are some function calls that would return a modified graph:
>> 
>> (assoc-in g [node k] v)
>>   sets node attr k to v
>> (assoc-in g [edge k] v)
>>   sets edge attr k to v  (and similarly for multiple keys)
>> (assoc-in g [node1 port-label1 port-label2 node2] :edge)
>>   makes an edge between [node1 port-label1] and [node2 port-label2]
>> (assoc-in g [node1 port-label1 port-label2 :edge k] v)
>>   sets value of edge attr k to v
>> 
>> I haven't yet thought this through completely, and I suspect that some parts 
>> are still error-prone. For example, notice in the last function call that 
>> it's not clear whether you should include node2. The approach might be "too 
>> cute"—that is, brittle because it tries to impose one kind of structure 
>> (nested maps) onto one that isn't fully isomorphic (graphs).
>> 
>> But I like the basic idea of having a "little language" for designating 
>> whatever you want, and the little language is nothing but a sequence that 
>> tells how to navigate through the graph to find (or make) what you're 
>> interested in. 
>> 
>> This would solve the fundamental problem of how to designate an edge without 
>> imposing type restrictions. For each connection point, you just have a 
>> sequence that describes a path to that point. If the sequence ends on a port 
>> label, the connection point is a port. If it ends on :edge, the connection 
>> point is an edge. So, instead of type restrictions, there are just a few 
>> reserved words in the tiny DSL for navigating the graph.
>> 
>> This hopefully makes simple editing and querying of port graphs easy, but it 
>> does not even try to solve the problem of conveniently entering a graph. I 
>> figure that a "shorthand", i.e. a separate tiny DSL, is the solution for 
>> that. I found with my current implementation of port graphs that it really 
>> helped to use a custom shorthand for each specific type of graph. For 
>> example, there's a obvious and very nice shorthand for specifying graphs 
>> that represent mathematical expressions, but it's terrible for graphs of 
>> social networks. Graphs of social networks, though, can be conveniently 
>> described by their own custom sexprs.
>> 
>> I figure that implementing it will force me to think this idea through the 
>> rest of the way. Here goes…
>> 
>> --
>> Ben Kovitz
>> http://pages.iu.edu/~bkovitz/
>> 
>> 
>> -- 
>> You received this message because you are subscribed to the Google
>> Groups "Clojure" group.
>> To post to this group, send email to clojure@googlegroups.com
>> Note that posts from new members are moderated - please be patient with your 
>> first post.
>> To unsubscribe from this group, send email to
>> clojure+unsubscr...@googlegroups.com
>> For more options, visit this group at
>> http://groups.google.com/group/clojure?hl=en
>> --- 
>> You received this message because you are subscribed to a topic in the 
>> Google Groups "Clojure" group.
>> To unsubscribe from this topic, visit 
>> https://groups.google.com/d/topic/clojure/uSwY475pbGA/unsubscribe.
>> To unsubscribe from this group and all its topics, send an email to 
>> clojure+unsubscr...@googlegroups.com.
>> For more options, visit https://groups.google.com/d/optout.
> 
> -- 
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with your 
> first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
> --- 
> You received this message because you are subscribed to the Google Groups 
> "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to clojure+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to