Fork me on GitHub
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?


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?


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]
                    (map (partial permuteo s)
         (== q input))
But still unsuccessful

Quentin Le Guennec22:12:00

I guess I'll try something else


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


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


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


input in your example is just kind of bogus


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


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)


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


and you have no kind of unique constraints


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


if X and Y are members of L


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


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


maybe, hard to tell from the code and description given


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


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


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


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


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


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


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)


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