distincto vs. fd/distinct in core.logic - clojure

What is the advantage of using fd/distinct in cases where the elements will be in a finite domain instead of distincto?
The following all return ([0 1] [1 0]).
;;; With distincto
(run* [q]
(fresh [x y]
(fd/in x y (fd/interval 1))
(distincto [x y])
(== q [x y])))
;;; With fd/distinct
(run* [q]
(fresh [x y]
(fd/in x y (fd/interval 1))
(fd/distinct [x y])
(== q [x y])))
;;; Without fd at all.
(let [interval [0 1]]
(run* [q]
(fresh [x y]
(membero x interval)
(membero y interval)
(distincto [x y])
(== q [x y]))))
Notably, although it appears you may use distincto in any place where you may use fd/distinct (but not the other way around), the same cannot be said for membero and fd/in.

fd/distinct is much more highly optimized than distincto which must receive any kind of value. fd/distinct under the hood deals with efficient representations of constrained variables all at once using sets, distincto uses the disequality operator != in a pretty simple manner.

Related

How to rewrite the core.logic snippet?

I'm trying to rewrite the below piece of core.logic code.
(run* [x y]
(fd/in x (fd/domain 1 2))
(fd/in y (fd/domain 1 2)))
o/p,
([1 1] [2 1] [1 2] [2 2])
I tried the below versions but none of them works,
(run* [x y]
(fresh [dom (fd/domain 1 2)])
(fd/in x dom)
(fd/in y dom)))
;; Error Unsupported binding form: (fd/domain 1 2)
(run* [x y]
(fresh [dom]
(== dom (fd/domain 1 2))
(fd/in x dom)
(fd/in y dom)))
O/P:
([1 1])
(run* [x y]
(let [dom (fd/domain 1 2)]
(fd/in x dom)
(fd/in y dom)))
O/P:
([_0 1] [_0 2])
What's the rationale for the 3 versions that I tried? Any help would be greatly appreciated.
fd/domain returns a concrete value that can be used with other goals/relations in the fd namespace — you can define it once and use it inside run* more than once:
(let [dom (fd/domain 1 2)]
(run* [x y]
(fd/in x dom)
(fd/in y dom)))
=> ([1 1] [2 1] [1 2] [2 2])
What's the rationale for the 3 versions that I tried?
The first refactoring doesn't work because fresh is being used like let, but it doesn't work like that; fresh simply allows you to give names to some fresh logic variables.
The second refactoring doesn't work because the domain value is being bound to a logic variable, and fd/in wants a concrete domain value as its second argument — not a (fresh) logic variable.
The third refactoring doesn't work (I assume) because let bindings aren't going to work like that inside the run* macro, which only wants a sequence of goals in its body.

How to write your own simple constraint function in core.logic?

I just read the primer for core.logic. It makes sense so far, but I'm not sure where to go to learn more.
Let's say I wanted to write my own constraint, sort of like the membero shown in the primer. This one is called vectoro and constrains things to be a vector.
(defn vectoro [s] ???)
(run* [q]
(conde
[(== q [1 2])]
[(== q :a)])
(vectoro q))
Now I want that to return [1 2]. How do you write vectoro? Is this documented anywhere?
There's a core.logic pred macro that makes this easy:
(run* [q]
(== q [1 2])
(pred q vector?))
=> ([1 2])
(run* [q]
(== q '(1 2))
(pred q vector?))
=> ()
Here's how you might define a vectoro function/contraint (but realize this is essentially the exact same thing pred is doing):
(defn vectoro [a]
(project [a]
(== true (vector? a))))
project is used to operate on the actual/concrete value of the logic variable (LVar). We can then use the plain old predicate vector? and require the result be true. This also works with your example program:
(run* [q]
(conde
[(== q [1 2])]
[(== q :a)])
(vectoro q))
=> ([1 2])
(run* [q]
(conde
[(== q '(1 2))]
[(== q :a)])
(vectoro q))
=> ()
To continue learning, I suggest looking for projects that use core.logic and seeing if their source code teaches you anything.
As for your specific question about vectoro, the "project" function (as in "projection") will probably accomplish what you want, something along the lines of
(defn vectoro [s v]
(core.logic/project [v]
(core.logic/== s (vector? v)))

Why does this implementation of sorto does not terminate?

I'm a beginner with logic programming.
I'm trying to implement a sorting relation like this:
(sorto [3 2 1][1 2 3]) -> #s
I'am using clojure and core.logic:
I don't understand why this can not terminate in most cases.
Any idea would be helpful, thank you.
(require '[clojure.core.logic :refer :all]
'[clojure.core.logic.fd :as fd])
First I define several little helpers:
A simple count relation: (counto [a b] 2) -> #s
(defne counto [list n]
([() 0])
([[fl . rl] _]
(fresh [nnxt]
(fd/- n 1 nnxt)
(counto rl nnxt))))
reduce and every? relational equivalents:
(defne reduceo [rel acc x y]
([_ _ () _] (== acc y))
([_ _ [fx . rx] _]
(fresh [nacc]
(rel acc fx nacc)
(reduceo rel nacc rx y))))
(defne everyo [g list]
([_ ()])
([_ [fl . rl]]
(g fl)
(everyo g rl)))
min relation: (mino 1 2 1) -> #s
(defn mino [x y z]
(conde
[(fd/<= x y) (== x z)]
[(fd/> x y) (== y z)]))
relation between a list and its minimum element: (mino* [1 2 3 0] 0) -> #s
(defne mino* [xs y]
([[fxs . rxs] _]
(reduceo mino fxs rxs y)))
The main relation: (sorto [2 3 1 4] [1 2 3 4]) -> #s
(defne sorto [x y]
([() ()])
([[fx . rx] [fy . ry]]
(fresh [x* c]
(counto rx c)
(counto ry c)
(mino* x fy)
(rembero fy x x*)
(sorto x* ry))))
The below runs doesn't terminate, I would like to understand why.
(run* [q]
(sorto q [1 2]))
; does not terminate
(run* [q]
(sorto [2 1] q))
; does not terminate
(run* [a b]
(everyo #(fd/in % (fd/interval 10)) a)
(everyo #(fd/in % (fd/interval 10)) b)
(sorto a b))
;neither
The high level answer is because conjunction are tried in order. Reordering them may sometimes make a program to terminate -- however in the general case there may not exist a "good" order.
Have a look at Chapter 5 in https://scholarworks.iu.edu/dspace/bitstream/handle/2022/8777/Byrd_indiana_0093A_10344.pdf

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.

Constraining two vectors to be in the same domain but not be member's of each other

I've used clojure for a while but just starting out with core.logic.
Given a domain like 1 2 3 4 I want to get a vector of two vectors back like ([[1 2] [3 4]]).
Note: This is just a simplified version of what I'm really trying to do. :) See: https://github.com/adamhoward/lineup
I found this definition for not-membero on the web:
(defne not-membero [x l]
([_ []])
([_ [?y . ?r]]
(!= x ?y)
(not-membero x ?r)))
And I'm trying to use it like this:
(run 1 [q]
(fresh [w x
y z]
(== q [[w x]
[y z]])
(infd w x y z (domain 1 2 3 4))
(everyg distinctfd [[w x] [y z]])
(everyg #(not-membero % [y z]) [w x])))
Running this in Emacs gives me an Evaluation aborted. message.
When I try switching out membero for not-membero I get back ([[1 2] [1 2]]) which makes sense to me. Every element in the first vector [w x] is a member of the second vector [y z].
But, when I call run 2 I get back ([[1 2] [1 2]] [[1 2] [1 3]]). I don't understand how [[1 2] [1 3]] can be correct for the rules above. Am I not understanding everyg correctly? Any guidance (including rtfmanual, rtfbook, rtfdissertation) will be appreciated.
Thanks.
Edit: May have solved this.
Still not sure about the strange results from membero but instead of the not-membero goal I found that I could do this:
(everyg #(distinctfd (conj [y z] %)) [w x])
Each element of [w x] conj'd to [y z] contains all distinct values. This may be less efficient than not-membero so I'm still open to any help.
Your example seems to be doing the same as this:
(run* [q]
(fresh [w x y z]
(fd/in w x y z (fd/domain 1 2 3 4))
(== q [[w x] [y z]])
(fd/distinct [w x y z])))
But seeing the soccer problem...
(ns test
(:refer-clojure :exclude [==])
(:use clojure.core.logic)
(require [clojure.core.logic.fd :as fd]))
(defn game [g] (fresh [a b c d e] (== g [a b c d e])))
(def players (range 1 11))
(defne not-membero [x l]
([_ []])
([_ [?y . ?r]]
(!= x ?y)
(not-membero x ?r)))
(defne plays [player games]
([_ []])
([_ [?f ?s . ?r]]
(membero player ?f) ; if you play this game
(not-membero player ?s) ; do not play next game
(plays player ?r))
([_ [?f ?s . ?r]]
(membero player ?s)
(not-membero player ?f)
(plays player ?r)))
(defne goalies [games]
([[[_ _ _ _ ?a]
[_ _ _ _ ?b]
[_ _ _ _ ?c]
[_ _ _ _ ?d]]]
(fd/in ?a ?b ?c ?d (apply fd/domain players))
(not-membero 1 [?a ?b ?c ?d]) ; star player != goalie
(fd/distinct [?a ?b ?c ?d]))) ; not goalie twice
(defn -main [& args]
(run 1 [q]
(fresh [a b c d]
(game a)
(game b)
(game c)
(game d)
(== q [a b c d])
(goalies q)
(everyg #(plays % q) players))))