Fork me on GitHub
#core-logic
<
2021-12-13
>
Quentin Le Guennec20:12:55

I'm getting unexpected results from a core.logic expression:

(let [input  (mapv (partial mapv #(lvar % false))
                   '((0 1)
                     (0 1 2 3 4 5 6)
                     (0 1 2 3 4 5)
                     (0 1 2 3 4 5)
                     (0 1 2 3)
                     (0 1 2 3 4)
                     (0 1 2 3 4 5)
                     (0 1 2 3 4)
                     (0 1 2 3 4)
                     (0 1 2)))
      model [[:a :b :c :e :f :g]
             [:c :f]
             [:a :c :d :e :g]
             [:a :c :d :f :g]
             [:b :c :d :f]
             [:a :b :d :f :g]
             [:a :b :d :e :f :g]
             [:a :c :f]
             [:a :b :c :d :e :f :g]
             [:a :b :c :d :f :g]]]
  (->> (run* [q]
         (everyg (fn [s] (membero s model)) input)
         (== q input)) ))
I would like to solve: "For all values from 0 to 9 in input , what is the corresponding value from :ato :f ?" (e.g: (0 1) can only map to [:c :f] because it is the only length 2 collection.) Is that what I'm expressing as goals in run*? Or am I expressing something else?

hiredman21:12:23

its not a great problem for logic/relational programming, things defined in terms of counting are tricky

Quentin Le Guennec21:12:24

Are you sure? I think I'm pretty much using logic programming when I'm trying to solve it myself

Quentin Le Guennec21:12:53

what do you mean by counting exactly though?

hiredman22:12:44

you are defining the correspondence relation based on the count (the size, the length) of collections

Quentin Le Guennec22:12:40

Isn't it supposed to work with permuteo though? I updated it:

(run* [q]
         (everyg (fn [s]
                   (or*
                    (map (partial permuteo s)
                         model)))
                 input)
         (== q input))
But still unsuccessful

Quentin Le Guennec22:12:00

I guess I'll try something else

hiredman21:12:25

if you define it in some way that isn't based on counting it will go much better

hiredman21:12:56

like say, all rows are the same length, but have some pattern of true, false

hiredman22:12:45

so if you replace all you vectors of letters with things like [false false true false false true false] which would correspond to [:c :f] because those positions are true

hiredman22:12:34

input in your example is just kind of bogus

hiredman22:12:52

I am not sure even what you are trying to do with it

hiredman22:12:16

there are reasons to call the lvar constructor with arguments, but basically you never need to

Quentin Le Guennec22:12:42

Well [0 1] => [:c :f], [0 1 2 3] => [:b :c :d :f] (permutable), because they uniquely got the same length. The rest should follow with the the numbers mapped to the letters.

Quentin Le Guennec22:12:09

Because 0 should be the same across all the input

Quentin Le Guennec22:12:41

0 in the first element of input should be the same than in the second

Quentin Le Guennec22:12:52

So from [0 1] => `[:c :f]` , we can deduce that (or (and 0 => c, 1=> f) (and 0 => f, 1 => c)

hiredman22:12:58

thats not how it works though, like, you are saying the vars are members of the lists, 2 vars can be members of 3 element list just as easy as they can be members of a 2 element list

hiredman22:12:08

and you have no kind of unique constraints

hiredman22:12:09

so 2 vars can be members of a 1 element list easily as well

Quentin Le Guennec22:12:32

I'm not sure I understand

hiredman22:12:46

if X and Y are members of L

hiredman22:12:05

if L is just (1) then X a and Y, absent other constraints, are both 1

Quentin Le Guennec22:12:35

Oh, that makes sense.

Quentin Le Guennec22:12:42

I think that's why I'm getting some kind of factorial of all possibilities as a result

hiredman22:12:23

but even then, if you can, it is best to avoid membero, because membero is at best a linear search in a list, so combinatorial is bad

Quentin Le Guennec22:12:54

I think that linear search is pretty much required by the problem itself

hiredman22:12:57

maybe, hard to tell from the code and description given

hiredman22:12:50

there is search through the space of all possibilities, then there is search through data structures for the right things to unify

hiredman22:12:41

like, the code you shared has no branching of the search tree, other then the recursive cases for membero

hiredman22:12:34

so outside the is this lvar the first, the second, the third, ..., etc member of this list, there are no branches

hiredman22:12:02

so its not like it is considering all the model or inputs as different searches or something

Quentin Le Guennec22:12:18

Do you think I should give up on core.logic? It's an advent of code exercise and I thought it was a nice way to learn core.logic

hiredman22:12:47

I dunno, there is definitely a significant hump to get over

hiredman22:12:36

core.logic is kind of a bare bones logic programming environment, so figuring out how to represent problems in a way that works can be tricky

hiredman22:12:04

and because core.logic is a dsl embedded in clojure, often the way to do things is with clojure as a meta/macro language for constructing core.logic programs, which is also tricky to get the hang of sometimes (see all the troubles people get into learning macros)

hiredman22:12:10

my understanding of logic programming comes in large part from sitting down with the minikanren paper and implementing it in go, and then writing solvers for a bunch of logic riddles in it as tests, not from working with core.logic a lot