Tree search in Clojure core.logic - clojure

I've been puzzled by a modelisation problem for some time and I have to confess I have no idea how I could "properly" solve it in core.logic.
It is very easy to state: given a tree (acyclic unidirectional oriented graph) and a vertex in it, how do you use core.logic to define a goal which allow a lvar to be any reachable vertex from the given vertex?
I've started out with something as simple as possible:
(defrel vertex x)
(defrel child)
(def facts
(pldb/db
[vertex 'a]
[vertex 'b] [child 'a 'b]
[vertex 'c] [child 'b 'c]
[vertex 'd] [child 'c 'd]))
Given this configuration, I aim at defining a goal which allows a lvar to take values in ['a 'b 'c 'd]. It's straightforward to get reachable vertices with "1 hop":
(defn reachableo
[a]
(fresh [q]
(child a q)))
and you can add variables for 2 hops and so on but... can it be generalized? I've thought to define a list of lvar with something like
(let [vars (repeatedly lvar)]
(map #(child (nth vars %) (nth vars (inc %)))
(-> vars count dec range))
(all
...))
but several attempts later, I must confess I'm not sure it's the correct way to go.

(pldb/db-rel vertex x)
(pldb/db-rel child parent child)
(def facts
(pldb/db
[vertex 'a]
[vertex 'b] [child 'a 'b]
[vertex 'c] [child 'b 'c]
[vertex 'd] [child 'c 'd]))
The recursive goal:
(defn reachable° [from to]
(l/fresh [v]
(l/conde
[(child from to)]
[(child from v) (reachable° v to)])))
Testing
=> (pldb/with-db facts
(vec (l/run* [to] (reachable° 'a to))))
[b c d]

thanks for your help!
Actually I got
(defn order-relationo
"Abstract the general pattern of a order relation in a logic, relational way."
[relation x y]
(conde
[(relation x y)]
[(fresh [z]
(relation x z)
(order-relationo relation z y))]))
(def kino
"A goal where the two inputs x and y share kinship: x is an ancestor of y and
y a descandant of x."
(partial order-relationo child))
I asked this question because it was a long time I hadn't practiced logic programming but now I feel it's coming again ^^
Anyway, thanks a lot for your answer which gives me an additional viewpoint.

Related

Follow-up to 'how to add a child to a tree using clojure.zip'?

This question refers to and is a follow-up to question 37484870:
Consider the following code
(defn f [x]
(loop [a x v [(inc x)]]
(if (> a 0)
(recur (dec a) (conj [a] v))
v)))
(def v (z/vector-zip (f 10))
where z refers to clojure.zip. Note that 10 could have been a much larger number.
Now, how do I add a node to v using functions from the API for clojure.zip such that the result is equal to
((def v (z/vector-zip (f (inc 10)) ?
So a node is added to the left most node at the deepest level ( if that helps ).
The reason for asking this question is that the answer to question 37484870
implies a loop of 10
(z/down)
(z/right)
functions but perhaps zipper structures offer a more direct solution.
One of the possible solutions is
(-> v
(#(let [next (z/next %)]
(if (z/end? next)
%
(recur next))))
(#(z/insert-right % [(inc (z/node %))]))
(z/root))

Does projecting in two directions count as relational in core.logic?

I understand that project in core.logic is not relational.
However, it seems that I can get relational-like behaviour by projecting in both directions inside conda, e.g.:
(defn lifto-with-inverse
"Lifts a unary function and its inverse into a core.logic relation."
([f g]
(fn [& vs]
(let [[x y] vs]
(conda
[(pred x number?) (project [x] (== y (f x)))]
[(pred y number?) (project [y] (== x (g y)))])))))
(let [inco (lifto-with-inverse inc dec)]
(run* [q] (inco q 3)))
=> 2
Does this count as a relational operation? Or is there something else missing that makes this non-relational?
It still seems like in this case one of the arguments must be ground making it non-relational.

Refactoring with core.logic

I've started learning core.logic and I'm totally lost. I am trying to write a core.logic relation which refactors an expression, renaming symbols. I want a relation that returns for a given expression, list of symbols and a list of symbols to rename those symbols:
(defn rename [exp from to]...
the expression with all the symbols in from becoming the corresponding one in to:
e.g. (rename '(defn multiply [x y] (* x y)) [x y] [a b])
returns (defn multiply [a b] (* a b))
but it needs to be aware of scope,
so (rename '(defn q [x] ((fn [x] (* x 5)) x)) [x] [a])
would return (defn q [a] ((fn [x] (* x 5)) a))
I don't know where to start solving this - any hints would be greatly appreciated!
This problem is more suitable for FP as it is just a tree traversal and replace operation, where as LP is more about specifying constrains and asking all possible solution around those constrains for a specific input. But if you really want to do this logical way, I tried something that does try to do it LP way but it doesn't handle a lot of cases and is just a starting point.
(defrel replace-with a b)
(fact replace-with 'x 'a)
(fact replace-with 'y 'b)
(defn replace [a b]
(conde
[(replace-with a b)]
[(== a b)]))
(defn replace-list [from to]
(conde
[(== from []) (== to [])]
[(fresh [f t f-rest t-rest]
(resto from f-rest)
(resto to t-rest)
(firsto from f) (firsto to t)
(conda [(replace-list f t)]
[(replace f t)])
(replace-list f-rest t-rest))]))
(first (run 1 [q]
(fresh [from]
(== from '(defn multiply [x y] (* x y)))
(replace-list from q))))
==> (defn multiply (a b) (* a b))

Arithmetic and clojure functions on core.logic lvars

Two related questions in one:
Can Clojure's core.logic module perform arithmetic, logical comparison, etc, like ordinary Prolog? I am envisioning something like the following:
(defrel points person n)
(fact :bob 2)
(fact :charlie 3)
(run* [q] (fresh [x y]
(points :bob x)
(points :charlie y)
(< x y)
(== q (+ x y))))
=> (5)
In this example, neither the logical comparison (< x y) nor the attempted binding of q to (+ x y) works. I suppose that this is because I'm working with LVars, not integers at this point, and I can't make these comparisons because the symbols aren't yet bound. But it works in prolog:
points(bob, 2).
points(charlie, 3).
?- points(bob, X), points(charlie, Y), Result is X + Y.
=> Result = 5.
In a similar vein, can I somehow use Clojure functions (which return booleans or other "truthy" values) as logic predicates? In other words, to use functions to tell Minikanren which terms unify or not. Something along the lines of:
(defmagic startswithhi-o [v]
(.startsWith v "hi"))
(defrel person n)
(fact person "bob")
(fact person "hillary")
(run* [q]
(fresh [n]
(person n)
(startswithhi-o n)
(== q n)))
=> ("hillary")
If I try things like this I get errors also complaining that the LVars aren't bound. Is there a way to do this?
Lastly if anyone has read this far, I might as well ask: are there plans to incorporate probabilistic logic into core.logic, along the lines of:
http://dtai.cs.kuleuven.be/problog/ ?
I'm not holding my breath but it would be awesome!
Non-relational arithmetic is possible via project.
(run 1 [q]
(fresh [x y]
(== x 1)
(== y 2)
(project [x y]
(== q (+ x y)))))
(3)
I believe the Prolog example given is also non-relational.
The second half of your question can also be solved via project, but you must be careful that you always input a ground value.
(defn startwith [x]
(project [x]
(== true (.startsWith x "hi"))))
PS: Hold your breath for Constraint Logic Programming to come to core.logic!
I believe you have to "project" (nonrel/project) a logic variable to its binding before you can apply a function to it:
(defrel points person n)
(fact points :bob 2)
(fact points :charlie 3)
(run* [q]
(exist [x y]
(points :bob x)
(points :charlie y)
(project [x y]
(== true (< x y))
(== q (+ x y)))))
Note that exist substitutes for fresh in the original snippet and the additional argument for the fact declarations.

Grouping a sequence of bools in clojure?

I would like to transform the following sequence:
(def boollist [true false false false true false true])
Into the following:
[[true] [false false false true] [false true]]
My code leads to a Stackoverflow:
(defn sep [boollst]
(loop [lst boollst
separated [[]]
[left right] (take 2 lst)]
(if (nil? left) separated)
(recur (next lst)
(if (false? left)
(conj (last separated) left)
(conj separated [left]))
(take 2 (next lst)))))
Is there an elegant way of transforming this?
There's probably a much more elegant way, but this is what I came up with:
(defn f
([xs] (f xs [] []))
([[x & xs :as all] acc a]
(if (seq all)
(if x
(recur xs [] (conj a (conj acc x)))
(recur xs (conj acc x) a))
a)))
It just traverses the sequence keeping track of the current vector of falses, and a big accumulator of everything so far.
A short, "clever" solution would be:
(defn sep [lst]
(let [x (partition-by identity lst)]
(filter last (map concat (cons [] x) x))))
The "stack overflow" issue is due to the philosophy of Clojure regarding recursion and is easily avoided if approached correctly. You should always implement these types of functions* in a lazy way: If you can't find a trick for solving the problem using library functions, as I did above, you should use "lazy-seq" for the general solution (like pmjordan did) as explained here: http://clojure.org/lazy
* Functions that eat up a list and return a list as the result. (If something other than a list is returned, the idiomatic solution is to use "recur" and an accumulator, as shown by dfan's example, which I would not consider idiomatic in this case.)
Here's a version that uses lazy evaluation and is maybe a little more readable:
(defn f [bools]
(when-not (empty? bools)
(let
[[l & r] bools
[lr rr] (split-with false? r)]
(lazy-seq (cons
(cons l lr)
(f rr))))))
It doesn't return vectors though, so if that's a requirement you need to manually pass the result of concat and of the function itself to vec, thus negating the advantage of using lazy evaluation.
The stack overflow error is because your recur is outside of the if. You evaluate the if form for side effects, then unconditionally recur. (feel free to edit for format, I'm not at a real keyboard).