2
votes

I'm trying to use core.logic to figure out answer to the following equations:

x + y = W
x - y = V

W and V are both given, while x and y are the values I'm trying to compute.

I've tried approaches like (I substituted W with 60 and V with 10):

(logic/run* [q]
          (logic/fresh [x y]
                       (logic/== q [x y])
                       (logic/project [x y]
                                      ; x + y = 60
                                      ; x - y = 10
                                      (logic/== y (- 60 x))
                                      (logic/== x (+ 10 y)))))

But it returns (["10<lvar:y_6>" NaN]) (I would expect 35 and 25).

How do I approach that? I don't want to use clojure.core.logic.fd because I'm using ClojureScript - is that possible at all? Would it be possible with fd?


Note that those equations are an example only. In my real-world scenario I want to solve something more like that:

x + H + y = W
x / y * 100 = V

For now I simplified those to get the most basic example running, but the solution to the above is also welcome :)

1
Why not just use the inverse Matrix to solve this? If it's integers only then you can use the Hermite Normal form. - ClojureMostly
@Andre one of the reasons I'm evaluating core.logic is to be able to clearly express constraints in my code - for the readability/maintainability. So if, for a given problem, I would intuitively (using math notations) use couple of equations to describe my problem, I would like to be able to pass those equations to core.logic to get the unknowns. - kamituel
Gotcha, I read your last sentence as "the solution to the above (math) problem is also welcome". Sorry about that. - ClojureMostly

1 Answers

1
votes

The cljs version of core.async cannot solve this kind of problem yet, because the fd namespace has not been migrated from the clj version.

Using the clojure version, we can solve it this way:

(require '[clojure.core.logic :as logic]
         '[clojure.core.logic.fd :as fd])

(logic/run* [q]
  (logic/fresh [x y]
    (logic/== q [x y])
    (fd/in x y (fd/interval 0 100))
    (fd/eq (= 60 (+ x y)))
    (fd/eq (= 10 (- x y)))))

Result: ([35 25])

Instead of using logic/project we use fd/eq to express the relation between the LVars, and fd/interval to constrain their values into that interval.

In this answer @dnolen explains that "you cannot project finite domain vars that haven't been constrained to single value".