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 `:a`to `: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