Mark <markaddle...@gmail.com> writes:

Hi Mark,

> Let's take a specific example: Suppose I have a Person table with id,
> name and gender columns.  Then, I have a Parent-Child table that
> contains two id columns, both of which are foreign keys back into the
> Person table.  I'd could use the logic system to define a set of rules
> about family relationships.  I could express a query in logic terms
> which would then be translated into a series of SQL calls to obtain
> the results (forget any optimization concerns for the moment).

I'm pretty much experimenting in the same direction, but not with
databases but with graphs.  Currently, my approach is to translate the
graph's schema (type graph) to a set of relations.  For example, if the
schema defines a node type Person, I generate a

  (defrel +Person x)

which succeeds if x is a Person vertex.

If the schema defines an edge type Knows between Person, I generate a
relation

  (defrel +Knows e a o)

which succeeds if e is a Knows edge starting at a node a and ending at a
node e.  (There are also relations for the attributes of nodes and
edges.)

Those relations are then populated with facts about the graph.

Then I can use core.logic to query the graph in terms of a fact base.
For example, here's a query on a graph representing a route map that
finds for any County the City being its capital.  (with-fresh is only a
convenience macro that expands into a `fresh' declaring fresh logic vars
for all the ?variables.)

  (run* [q]
    (with-fresh
      (+Locality ?loc)
      (+ContainsLocality _ ?county ?loc)
      (+HasCapital _ ?county ?capital)
      (!= ?capital ?loc)
      (+name ?capital ?cname)
      (+name ?loc ?lname)
      (== q [?cname ?lname])))

Basically, that works pretty well, but there are some issues, which are
probably because I take the wrong approach.

First, it's very memory intensive.  I have the graph in memory anyway,
and basically I duplicate it into the relations.  That doesn't feel
correct.

Second, with my simply translation approach, when I'd change the graph,
the relations would be out of sync...

Basically, I'd like to be able to define the relations that I have right
now, at least interface-wise.  But instead of duplicating the graph in
facts, I'd like to give an own implementation directly on the graph.  I
mean, for all these relations I can easily tell when they succeed.  For
examle, for (+ContainsLocality e a b), if b is given, I can tell the
valid bindings for e and a in O(degree(b)).

Third, it quickly becomes very slow when I define some recursive
relations like that:

--8<---------------cut here---------------start------------->8---
  (defn connected
    "Succeeds, if the junctions j1 and j2 are connected by connections (Ways,
    Streets, AirRoutes)."
    [j1 j2]
    (with-fresh
      (conde
       ((+Connection _ j1 j2))
       ((+Connection _ j2 j1))
       ((connected j1 ?middle)
        (connected ?middle j2)))))

  (defn connected-locs
    "Succeeds, if the localities l1 and l2 are connected.
    Localities are connected, if they contain crossroads that are connected by
    connections (Ways, Streets, AirRoutes)."
    [l1 l2]
    (with-fresh
      (conde
       ((+Airport! l1) (+Airport! l2) (connected l1 l2))
       ((+ContainsCrossroad _ l1 ?c1)
        (connected ?c1 ?c2)
        (+ContainsCrossroad _ l2 ?c2)))))

  ;; What locality is connected with what other locality?
  (run 250 [q]
    (with-fresh
      (+Locality ?l1) (+Locality ?l2)
      (!= ?l1 ?l2)    (connected-locs ?l1 ?l2)
      (== q [?l1 ?l2])))
--8<---------------cut here---------------end--------------->8---

Running that last query takes several minutes on a graph that contains
less than thousand nodes and edges, whereas our usual graphs contain
millions.  Even worse, the 250 results are in fact only 3 when removing
duplicates.  That's probably because I get a result tuple [A B] for any
possibly street connection between A and B, even if it contains cycles,
etc.  Is there something to restrict the search by expressing that any
route between A and B makes no sense if the same node is visited twice?

Bye,
Tassilo
-- 
(What the world needs (I think) is not
      (a Lisp (with fewer parentheses))
      but (an English (with more.)))
Brian Hayes, http://tinyurl.com/3y9l2kf

-- 
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

Reply via email to