<< Back to previous view

[LOGIC-163] Namespace qualify pldb relations Created: 09/Nov/14  Updated: 12/Nov/14  Resolved: 12/Nov/14

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Reid McKenzie Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File 0001-Namespace-qualify-pldb-relations-in-ClojureScript.patch     Text File 0001-Namespace-qualify-pldb-relations.patch    
Patch: Code

 Description   

At present, pldb relations are globally named by munging together the name of the relation and the tuple size of the relation. This creates a potential pitfall in that when creating relations named say "name" or "text" in seperate namespaces inserting facts into the db will actually share the same backing fact collection leading to potentially unexpected query results.

This patch tweaks the rel-name generation operation so that pldb relation names include the namespace in which they are defined thus eliminating this conflict.



 Comments   
Comment by David Nolen [ 09/Nov/14 4:48 PM ]

fixed https://github.com/clojure/core.logic/commit/4f23f6b9631c4fe52f0bea39e6dcbc19314244a4

Comment by Tobias Kortkamp [ 12/Nov/14 8:43 AM ]

Not fixed in ClojureScript (-> patch).

Comment by David Nolen [ 12/Nov/14 8:50 AM ]

fixed https://github.com/clojure/core.logic/commit/375874803bbf4be95d33596dcfe5d1809bc6e042





[LOGIC-162] FD logic doesn't always return all solutions Created: 20/Oct/14  Updated: 09/Nov/14

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Viktar Basharymau Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: finite-domains
Environment:

org.clojure/core.logic 0.8.8



 Description   

Given the following code

(run* [x11 x12 x13 
       x21 x22     x24
       x31     x33 x34
           x42 x43 x44]
      (fd/in x11 x12 x13 x21 x22 x24 x31 x33 x34 x42 x43 x44 (fd/interval 1 9))
      (fd/eq (= (+ x11 (/ x12 x13))   5)
             (= (+ x21 (/ x22   2)) x24)
             (= (+ x31 (/   6 x33)) x34)
             (= (+   4 (/ x42 x43)) x44)
             (= (+ x11 (/ x21 x31))   4)
             (= (* x12 (/ x22   6)) x42)
             (= (+ x13 (-   2 x33)) x43)
             (= (+ (-  5 x24) x34)  x44)))

I have {{([1 4 1 3 6 6 1 1 7 4 2 6] [2 6 2 4 6 7 2 1 8 6 3 6])}} as a result.

However, as soon as I change (fd/interval 1 9) to (fd/interval 0 9), the result becomes an empty sequence. However, I expect it to include at least the two aforementioned solutions.



 Comments   
Comment by David Nolen [ 21/Oct/14 4:34 AM ]

It would help if you could confirm that the issue is present without using fd/eq - which is just macro sugar. Writing out the long form is tedious but it will help isolate the issue. Thanks.

Comment by Viktar Basharymau [ 21/Oct/14 8:08 AM ]

I actually suspect that the bug is in `fd/eq`. Here is a smaller test case:

(run* [q]
      (fd/in q (fd/interval 1 2))
      (fd/eq (= (/ q q) 1)))

It returns `(1 2)` as expected, but as soon as I change `fd/interval` to `0 2`, it returns an empty seq.

Comment by David Nolen [ 09/Nov/14 6:09 PM ]

Thanks for the minimal case, yeah looks like an issue with fd/eq as it works fine if you write it out long hand.





[LOGIC-161] fd/eq returns strange results Created: 13/Oct/14  Updated: 16/Oct/14  Resolved: 16/Oct/14

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Dustin Conrad Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None
Environment:

clojure.core.logic 0.8.8 on mac osx 10.9



 Description   
(logic/run* [q]
  (logic/fresh [a b]
    (fd/in a b (fd/interval 0 10))
    (fd/eq (= 4 (* (- a b) 2)))
    (logic/== q [a b])))

I am fairly new to logic programming, but it seems to me this should return a result. I believe it is equivalent to

(logic/run* [q]
  (logic/fresh [a b]
    (fd/in a b (fd/interval 0 10))
    (fd/eq (= 2 (- a b)))
    (logic/== q [a b])))

which does return 9 results



 Comments   
Comment by Dustin Conrad [ 13/Oct/14 10:37 PM ]

I apologize for the formatting, I am unable to edit the description after posting.

Comment by David Nolen [ 15/Oct/14 6:01 PM ]

This appears to be a problem with the sugar `fd/eq`. If you stick to the primitives you should see the results that you expect.

Comment by David Nolen [ 15/Oct/14 6:02 PM ]

My suspicion is that some of the implicitly constructed logic vars are not getting assigned FD intervals.

Comment by David Nolen [ 15/Oct/14 8:10 PM ]

I dug into this quite a bit. The specific issue with this code example is that the multiplication will set the domain of a logic var such that negative values leak into the domain calculation causing the spurious appearance of negative values where they should not exist. We should think quite a bit more about the appearance of negative values.

Comment by Dustin Conrad [ 15/Oct/14 10:35 PM ]

Thanks for looking at this David.

Comment by David Nolen [ 16/Oct/14 4:49 PM ]

fixed https://github.com/clojure/core.logic/commit/719c23f80280762ff20216a579d88efa32da2de7





[LOGIC-160] Disequality on pairs not respected Created: 06/Jul/14  Updated: 06/Jul/14  Resolved: 06/Jul/14

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Igor Wiedler Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

I've found some cases where disequality and equality on the same value both succeed:

(run* [q]
      (fresh [a d]
             (!= (lcons a d) '(2))
             (== (lcons a d) '(2))
             (== q [a d])))
;= ([2 ()])

Not sure if this is somehow intended, but it looks like a bug to me.



 Comments   
Comment by Igor Wiedler [ 06/Jul/14 11:25 AM ]

Here is another case that seems related (although it might be a separate issue):

(run* [q]
      (fresh [d]
             (!= q (lcons 5 d)))
      (== q '(5 6 7)))
;= ((5 6 7))
Comment by David Nolen [ 06/Jul/14 2:24 PM ]

fixed https://github.com/clojure/core.logic/commit/5221af81fcc6d391c7db5841807ac2daa14926d6





[LOGIC-159] Weird behavior with negative-number domains Created: 18/Jun/14  Updated: 06/Jul/14  Resolved: 06/Jul/14

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Alex Engelberg Assignee: David Nolen
Resolution: Declined Votes: 0
Labels: None
Environment:

Clojure 1.6.0



 Description   

These behave as normal:
=> (run* [q]
(fd/in q (fd/interval 1 10))
(fd/* q q 9))
(3)
=> (run* [q]
(fd/* q q 9)
(== q -3))
(-3)
=> (run* [q]
(fd/in q (fd/interval -10 -1)))
(-10 -9 -8 -7 -6 -5 -4 -3 -2 -1)

This is weird:
=> (run* [q]
(fd/in q (fd/interval -10 -1))
(fd/* q q 9))
()
I think it should return: (-3)

Also weird:
=> (run* [q]
(fd/in q (fd/interval -10 10))
(fd/* q q 9))
()
I think it should return: (-3 3)



 Comments   
Comment by David Nolen [ 19/Jun/14 10:17 AM ]

As with cKanren there isn't currently any support for negative domains.





[LOGIC-158] membero documentation does not describe arguments Created: 30/May/14  Updated: 15/Oct/14  Resolved: 15/Oct/14

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Phillip Lord Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File 0001-Change-defnm-to-add-arglists-metadata-to-defined-var.patch    

 Description   

(doc clojure.core.logic/membero)
-------------------------
clojure.core.logic/membero
A relation where l is a collection, such that l contains x.

Membero documentation is rather unhelpful because it doesn't
describe the order of the arguments (i.e. which is l and which
is x). appendo and permuteo are similarly affected, so it appears
to be a weakness in defne



 Comments   
Comment by Tobias Kortkamp [ 15/Aug/14 12:45 PM ]

defnm does not add :arglists to the var's metadata.

I've attached a patch that fixes this.

Comment by David Nolen [ 15/Oct/14 6:04 PM ]

fixed https://github.com/clojure/core.logic/commit/fa9451ed57ba9647399e1e6e1d5a723e422d7c6b





[LOGIC-157] A warning is thrown regarding the redefinition of record? in clojure 1.6.0 Created: 27/Mar/14  Updated: 15/May/14

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Task Priority: Trivial
Reporter: Justin Overfelt Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None
Environment:

Linux x64



 Description   

Clojure 1.6.0 adds a record? function that has the same implementation as the one in clojure.core.logic. As a result, a warning is shown when the code in the core.logic namespace is evaluated under clojure 1.6.0. Since the two functions have the same implementation, this is purely a cosmetic issue.



 Comments   
Comment by Justin Overfelt [ 15/May/14 7:17 PM ]

I saw that this is now fixed in master - thanks! This also breaks AOT compilation if used with clojure 1.6.0 as referenced in CLJ-1241. Is there a timeline for a 0.8.8 release?

Comment by David Nolen [ 15/May/14 7:22 PM ]

I will try to cut a release next week.

Comment by Justin Overfelt [ 15/May/14 7:25 PM ]

Awesome - thank you!





[LOGIC-156] Two consecutive calls to run* return different results Created: 22/Feb/14  Updated: 05/Mar/14

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Mauro Lopes Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: bug

Attachments: File core.clj     File core.clj    

 Description   

Calling run* twice with the same input may return different results for no apparent reason.
See attachment.



 Comments   
Comment by David Nolen [ 05/Mar/14 9:19 AM ]

The problematic code incorrectly uses finite domain operations on fresh variables that have not be assigned domains. Can we get an updated version of the problematic code that demonstrate the issue after the corrections?

Comment by Mauro Lopes [ 05/Mar/14 9:25 PM ]

Sure. I have just added a new code version with finite domains assigned to each variable that is involved in an fd operation. The problem persists.





[LOGIC-155] Dynamic variables are not seen inside a logic query Created: 28/Jan/14  Updated: 06/Jul/14  Resolved: 06/Jul/14

Status: Resolved
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Reinout Stevens Assignee: David Nolen
Resolution: Declined Votes: 0
Labels: binding, bug, dynamic
Environment:

core.logic version 0.8.6
clojure version 1.5.1



 Description   

core.logic does not work correctly with dynamic variables, as illustrated by the following code:

(def ^:dynamic dvar 'original)
(binding [*dvar* 'changed]
(logic/run* [?x] (logic/== ?x dvar)))

;;outputs (original), expected (changed)

To the best of my knowledge this used to work in older versions, although I do not know when the behaviour changed.



 Comments   
Comment by David Nolen [ 28/Jan/14 10:56 AM ]

This is because core.logic became lazy (been a year now? . There are now non lazy run variants or you can use doall yourself.





[LOGIC-154] walk* of an empty set overflows the stack Created: 31/Dec/13  Updated: 31/Dec/13

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Kevin Downey Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None


 Description   

I noticed this issue when asserting a relation with an empty set in it in the new pldb stuff, the minimal case I have is (walk* empty-s #{})






[LOGIC-153] deftest test-34-unify-with-metadata appears incorrect Created: 23/Dec/13  Updated: 01/Jan/14

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Andy Fingerhut Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None


 Description   
(deftest test-34-unify-with-metadata
  (is (run* [q]
            (== q (quote ^:haz-meta-daytuhs (form form form))))
      '((^:haz-meta-daytuhs (form form form)))))

I am not sure what was intended for this, but replacing it with the following causes the test to fail.

(deftest test-34-unify-with-metadata
  (is (= (run* [q]
               (== q (quote ^:haz-meta-daytuhs (form form form))))
         '((^:haz-meta-daytuhs (form form form))))))

I think the correct version is probably close to that, though.



 Comments   
Comment by David Nolen [ 30/Dec/13 7:20 PM ]

I'm pretty sure meta data on forms caused exceptions and that's what this test was for.

Comment by Andy Fingerhut [ 01/Jan/14 12:05 PM ]

As that test is written now, it is of the form:

(is (run* [q] (expr))
    '(expr2))

The second argument to the macro 'is' is optional, and if present should be a string, not something like '(expr2). The test passes if (run* [q] (expr)) returns true without throwing an exception, and '(expr2) is ignored completely. That is why the test appears to be written incorrectly.





[LOGIC-152] Correct several unit tests Created: 23/Dec/13  Updated: 30/Dec/13  Resolved: 30/Dec/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Andy Fingerhut Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: File logic-152-v1.diff    

 Description   

Found several unit tests of the form (is (= expr1) expr2) using a pre-release version of the Eastwood lint tool. They should be changed to (is (= expr1 expr2)).



 Comments   
Comment by Andy Fingerhut [ 23/Dec/13 1:07 AM ]

Patch logic-152-v1.diff corrects the issues mentioned, plus removes many unnecessary [] after test names in deftest forms.

Comment by David Nolen [ 30/Dec/13 7:22 PM ]

fixed, https://github.com/clojure/core.logic/commit/aa08c5f7775a3e2f3cc9c8eaa701d1f24753611a





[LOGIC-151] partitiono in c.c.logic.bench is emitting calls to 1-ary version of partition Created: 15/Dec/13  Updated: 20/Dec/13  Resolved: 20/Dec/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Nicola Mometto Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

Running clojure.tools.analyzer over core.logic raised an exception about an invocation of clojure.core/partition with a wrong arity.

It looks like it's partitiono's fault

(defne partitiono [a b c d]
  ([[x . l] _ [x . l1] _]
     (conda
       ((project [x b]
          (== (≤ x b) т))
        (partition l b l1 d))
       (partition l b c d))))

Here's the full macroexpansion:

(def partitiono (fn* ([a b c d] (fn* ([a7537] (fn* -inc ([] (clojure.core.logic.protocols/bind a7537 (fn* ([a__4345__auto__] (fn* -inc ([] (let* [x (clojure.core.logic/lvar (quote x)) l       
  (clojure.core.logic/lvar (quote l))] (clojure.core.logic.protocols/bind (clojure.core.logic.protocols/bind a__4345__auto__ (clojure.core.logic/== (clojure.core.logic/lcons x l) a)) (fn*       
  ([a__4345__auto__] (fn* -inc ([] (let* [l1 (clojure.core.logic/lvar (quote l1))] (clojure.core.logic.protocols/bind (clojure.core.logic.protocols/bind a__4345__auto__ (clojure.core.logic/==   
  (clojure.core.logic/lcons x l1) c)) (fn* ([a7544] (clojure.core.logic.protocols/ifa ((fn* ([a7546] (let* [x (clojure.core.logic/walk* a7546 x) b (clojure.core.logic/walk* a7546 b)] ((fn*      
  ([a__4345__auto__] (fn* -inc ([] (let* [] (clojure.core.logic.protocols/bind a__4345__auto__ (clojure.core.logic/== (clojure.lang.Numbers/lte x b) true))))))) a7546)))) a7544)                 
  [(clojure.core/partition l b l1 d)] (new clojure.lang.Delay (fn* ([] (clojure.core.logic.protocols/ifa (clojure.core/partition a7544) [l b c d] nil)))))))))))))))))))))))))))

Note the "(clojure.core/partition a7544)" near the end.

I am not familiar with core.logic so I don't know if this is simply a typo somewhere or a deeper bug so I set the priority to Major.



 Comments   
Comment by David Nolen [ 20/Dec/13 12:18 PM ]

fixed, https://github.com/clojure/core.logic/commit/dba36dd1219ee45812aaa3ffb558f176072e7d3a





[LOGIC-150] deftest test-root-1 in namespace clojure.core.logic.tests missing 'is'? Created: 15/Dec/13  Updated: 20/Dec/13  Resolved: 20/Dec/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Andy Fingerhut Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: File logic-150-v1.diff    

 Description   

The two = expressions in deftest test-root-1 should probably be wrapped in (is ...):

(deftest test-root-1 []
  (let [x (lvar 'x)
        s (ext-no-check empty-s x 1)]
    (= (root-var s x) x)
    (= (root-val s x) 1)))

Found while testing next version of Eastwood linter on a bunch of projects. It warned that the first (= ...) expression's return value was unused.



 Comments   
Comment by Andy Fingerhut [ 16/Dec/13 3:52 AM ]

Patch logic-150-v1.diff fixes the issue in the ticket description, and a few other minor ones also found by the Eastwood Clojure lint tool.

Comment by David Nolen [ 20/Dec/13 12:19 PM ]

fixed, https://github.com/clojure/core.logic/commit/5bf5147afdb0fe04da658c3573ca63a922975d05





[LOGIC-149] pair used in fd namespace Created: 12/Dec/13  Updated: 06/Jul/14  Resolved: 06/Jul/14

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

https://github.com/clojure/core.logic/blob/master/src/main/clojure/clojure/core/logic/fd.clj#L40, used without being included via the namespace.



 Comments   
Comment by David Nolen [ 06/Jul/14 2:27 PM ]

just made pair public in master





[LOGIC-148] -jonc protocol to support conjo Created: 03/Dec/13  Updated: 04/Dec/13  Resolved: 04/Dec/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

This would allow the operation to be reversible.



 Comments   
Comment by David Nolen [ 04/Dec/13 12:17 AM ]

fixed,
https://github.com/clojure/core.logic/commit/9f86dbab5c8edc41c22a7ecafcce3b5dfa58571f





[LOGIC-147] polymorphic conjo constraint Created: 03/Dec/13  Updated: 03/Dec/13  Resolved: 03/Dec/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

Would work like cons but when arguments ground would dispatch to conj.



 Comments   
Comment by David Nolen [ 03/Dec/13 11:46 PM ]

fixed, https://github.com/clojure/core.logic/commit/c0f69ab5f43567c5a9f8932b187c51a42ed2a5da





[LOGIC-146] run macro should take * in addition to n Created: 26/Nov/13  Updated: 16/Oct/14

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: David Nolen Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None





[LOGIC-145] partial-map bug Created: 26/Nov/13  Updated: 26/Nov/13  Resolved: 26/Nov/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   
(run* [x y]
  (== y {:baz "woz"})
  (== (partial-map {:foo x}) {:foo y}))

Fails with an exception about LVar not being castable to PMap.



 Comments   
Comment by David Nolen [ 26/Nov/13 1:18 AM ]

fixed,https://github.com/clojure/core.logic/commit/737452044d8feeebd908b6fb0cfb12f3370b58f3





[LOGIC-144] Extending cljs.core.logic with all of the functionality from clojure.core.logic Created: 19/Nov/13  Updated: 04/Dec/13

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Adrian Medina Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Repo I've been working from is here: https://github.com/aamedina/cljs.core.logic

I've followed the code layout in clojure.core.logic pretty much verbatim, compensating for ClojureScript necessities, moved macros into sister .clj files. I have no hard opinions about the best way to organize the macros for each file, the way I do it is just the way I've found easiest, because then you don't have to namespace qualify every syntax quoted form that references a function in the sister .cljs file.

Additionally I ported all of the clojure.core.logic tests with clojurescript.test.



 Comments   
Comment by Adrian Medina [ 27/Nov/13 10:43 PM ]

So I've updated the repo to reflect a more faithful adherence to the existing cljs.core.logic code conventions and organization. I'd appreciate any insight into how to potentially optimize the code to run more on par with the JVM.

Comment by David Nolen [ 04/Dec/13 1:09 AM ]

What kinds of performance problems are you observing? Do you have a particular benchmark that you're running?

Comment by Adrian Medina [ 04/Dec/13 12:18 PM ]

Appendo and membero are particularly slow.

(dotimes [i ie5] (run* [q] (== q true))) takes around ~4500ms, which is about 10x slower than the JVM.

After profiling, I've discovered the problem - pretty standard recursion optimizations are necessary, it's re-walking (by reunifying) lvars recursively as the code is executed. E.g.,
for appendo, (run 5 [q] (fresh [x y] (appendo x y q))) will expand into something like..

((_0) (_0 . _1) (_0 _1 . _2) ... ))

and it's slow because every new list is actually re-walking every previously unified lvar again.

I'll have more time to investigate this over the weekend, but I think it might be as simple as not generating unique lvars by default, since then the identical? for unification check should catch any attempted walk.





[LOGIC-143] bring pldb into core.logic Created: 06/Oct/13  Updated: 15/Oct/13  Resolved: 15/Oct/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Norman Richards Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File 0001-integrate-pldb.patch     Text File 0001-remove-old-defrel.patch    
Patch: Code and Test

 Description   

This patch integrates pldb into core.logic, using the technique suggested by David Nolen of adding the pldb db to the substitution metadata. This worked really well. I've tested this integration against the threatgrid codebase, and with the exception of a couple edge cases where we were using facts-for directly for testing, it is a drop in replacements for pldb, requiring only the namespace change of pldb -> clojure.core.logic.pldb.

I moved logic-dbs into the clojure.core.logic so that they could automatically be included in the various run macros and the existing pldb/with-db bindings. I've also added run-db macros that allow explicit declarations where that is desirable. This seems reasonable to me, but I'm open to suggestions.



 Comments   
Comment by Norman Richards [ 06/Oct/13 11:32 AM ]

My working branch: https://github.com/orb/core.logic/tree/pldb

Comment by Norman Richards [ 06/Oct/13 2:27 PM ]

This doesn't remove the old rel/fact code. I'm not sure what way you want to take that. Also, I need to add docs when we're happy with the look of things.

Comment by David Nolen [ 06/Oct/13 2:37 PM ]

Would prefer to just switcheroo if possible, and then ask people to give the new stuff a spin. If everyone is OK with then we can cut a release. Has anyone else contributed code to pldb besides yourself? Just need to make sure we have CAs for everyone. Might need to get a verbal something from them on clojure-dev as well.

Comment by Norman Richards [ 06/Oct/13 2:46 PM ]

Craig Brozefsky is the only other pldb contributor. He does have a CA.

Comment by Norman Richards [ 07/Oct/13 9:26 AM ]

Patch 2 removes all the old rel code/tests. I forgot to turn off emacs whitespace cleanup, so I trivially touched a lot of lines with trailing whitespace that didn't need to be. I usually go back and fix up the commits, but if it's ok, maybe we can just put in the whitespace cleanup too so it'll be easier to work with in the future.

I'll send a patch 3 with the doc updates later.

Comment by David Nolen [ 11/Oct/13 10:51 AM ]

Can we get a new Patch 2 updated to apply to HEAD? Thanks.

Comment by Norman Richards [ 13/Oct/13 9:57 AM ]

This patch (0001-remove-old-defrel.patch) is from the current master (335226f).

Comment by David Nolen [ 15/Oct/13 10:50 PM ]

fixed, http://github.com/clojure/core.logic/commit/1cdb5393aa9b5cac53de76e66d09b2555a1cd002





[LOGIC-142] Unified map values are returned as LVar rather than the unified value in ClojureScript Created: 29/Sep/13  Updated: 29/Sep/13

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Darrick Wiebe Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None
Environment:

ClojureScript



 Description   

This works correctly in core.logic for clojure:

(run 1 [q]
     (fresh [v]
            (== v 1)
            (== {:x v} q)))

In ClojureScript, I get this though:

({:x <lvar:v_4>})





[LOGIC-141] dcg: def--> ClassCastException Created: 23/Aug/13  Updated: 23/Aug/13

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Greg Chapman Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None


 Description   

I believe def--> needs to put its lsyms into a vector (as does -->). lsyms is passed to handle-clauses (as the env param), and there is used as a function. This causes an exception since a seq cannot be cast to a function.






[LOGIC-140] compile time occurs check for pattern matching Created: 25/Jun/13  Updated: 25/Jun/13

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Claire Alvis correctly pointed out that it's easy to make a mistake when you have many clauses and accidentally use parameter name in a match for that parameter - we could easily do a compile time occurs check for these cases.






[LOGIC-139] to-stream fails on constraints Created: 23/Jun/13  Updated: 28/Jul/13  Resolved: 03/Jul/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Norman Richards Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File 0001-fix-unification-on-relations.patch    

 Description   

an example:
(defrel foo n)
(fact foo 1)
(fact foo 2)

(run* [q] (fresh [x] (!= x 1) (foo x)))
=> ((_0 :- (Unable to render embedded object: File (- () not found.= (2 1))))

The problem is that to-stream uses unify, which doesn't consider constraints. Here's two alternate implementations of stream (not replacements for to-stream, but basically performing the same task). One uses unify and the other uses bind and == to unify. The bind version produces the correct results.

(defn my-stream-unify [s v vals]
(when (seq vals)
(mplus (unify s v (first vals))
(λ [] (my-stream-unify s v (rest vals))))))

(defn my-stream-bind [s v vals]
(when (seq vals)
(mplus (bind s (== v (first vals)))
(λ [] (my-stream-bind s v (rest vals))))))

(defn myval-unify [x]
(fn [s]
(my-stream-unify s x [10 20 30])))

(defn myval-bind [x]
(fn [s]
(my-stream-bind s x [10 20 30])))

(run* [q]
(fresh [x]
(!= x 80)
(myval-unify x)))

(run* [q]
(fresh [x]
(!= x 80)
(myval-bind x)))

I've fixed my use of to-stream in pldb 0.1.3 in https://github.com/threatgrid/pldb/commit/8e8036fa0fedca7bb6ccee4af41a2bf6a66ffc2b

(db-rel foo n)
(with-db (db [foo 1]
[foo 2])
(doall (run* [q]
(fresh [x]
(!= x 1)
(foo x)))))

=> (_0)

If I've analyzed and fixed the problem correctly, I'd be happy to fix this small in core.logic. (and maybe it's time to get cracking on moving pldb into core.logic?)



 Comments   
Comment by David Nolen [ 23/Jun/13 12:19 PM ]

The bind solution looks good to me. Please attach a patch, thanks!

And +1 to getting pldb into core.logic

Comment by Norman Richards [ 24/Jun/13 11:55 AM ]

https://github.com/orb/core.logic/commit/dd29620e792b55e6a114519f164de16c602a0d03.patch

Note - I could not test the change to the datomic use of to-stream, and there are no test cases covering it. If you don't have a way to verify that change (or would rather not touch that code) then we could not apply that part of the patch and leave the broken to-stream in for the datomic support.

Comment by David Nolen [ 24/Jun/13 11:59 AM ]

Can we actually get the patch attached to the ticket as a file upload? Thanks!

As far as fixing Datomic support it's not high priority, it's an experiment not a feature

Comment by Norman Richards [ 24/Jun/13 12:48 PM ]

The problem is that we either need to fix that code or leave in the broken method. I guess the best approach is to move to-stream to datomic.clj, so I did that with the attached patch.

Comment by Norman Richards [ 25/Jun/13 5:33 PM ]

Did some more testing with this. It seems that the use of mplus here eats the stack up for larger data sets. I'm working on an alternate implementation that won't blow the stack.

Comment by Norman Richards [ 25/Jun/13 7:41 PM ]

second version - doesn't blow the stack

Comment by Norman Richards [ 25/Jun/13 7:46 PM ]

Upon further reflection, to-stream really wasn't in error. It was the use of unify instead of ==. I didn't know how to apply the goal without mplus/bind. But, obviously, I can call the == goal directly to accomplish what bind was doing, and the existing choice in to-stream is sufficient to go what mplus was doing.

This second patch works on with the larger dbs I have and also passes the test case I added.

Comment by David Nolen [ 03/Jul/13 8:28 PM ]

fixed http://github.com/clojure/core.logic/commit/d00d58685764a68d4e7c6d8294ac200786c83a7e





[LOGIC-138] Allow tying multiple noms in one binder Created: 10/Jun/13  Updated: 10/Jun/13

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Tom Jack Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: nominal


 Description   

I think it may be useful to be able to tie multiple noms in one binder, with or without significant order.

A couple use cases I've thought of so far:

Lambdas in a non-currying language. Here order matters.

(== (list 'fn (ties [x y] (list '+ x y)))
    (list 'fn (ties [z w] (list '+ z w)))

My original use case, free/quantified variables in logical formulas. Order doesn't matter (note the second body has its noms swapped).

(== (list '∀ (ties #{x y} (list '= (list '+ x y) (list '+ y x))))
    (list '∀ (ties #{z w} (list '= (list '+ w z) (list '+ z w)))))

I have a draft implementation here: https://github.com/tomjack/core.logic/compare/ties

Possible issues with this implementation:

  • Is it OK to reextend IWalkTerm to IPersistentSet?
  • Should Tie and Ties present a uniform interface? (e.g. (tie? (ties #{x} x)))


 Comments   
Comment by David Nolen [ 10/Jun/13 3:37 PM ]

I really don't think the set bit is necessary, the vector syntax is fine. Also avoid needing to bring IWalkTerm back for sets. And yes, tie? should work in either case.

Comment by Tom Jack [ 10/Jun/13 3:55 PM ]

Hmm.. should:

(== (list 'fn (ties [x y] (list '- x y)))
    (list 'fn (ties [z w] (list '- w z)))

I'd think not.

Do you mean that order should always matter (take out the permutations stuff), or that it should never matter (don't use ties for cases like the above)?

Comment by David Nolen [ 10/Jun/13 4:07 PM ]

Ah hm, good point. Will think on it some more.





[LOGIC-137] OOM when setting (interval 1 2) for 20 logic vars Created: 11/May/13  Updated: 28/Jul/13  Resolved: 08/Jun/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Gary Fredericks Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None
Environment:

Clojure 1.5.1, both 0.8.3 and 0.8.4--994a7a3

Running on a 1GB VM.


Attachments: Text File LOGIC-137.patch    

 Description   

The following two programs (presumably equivalent) both give me OOM (heap space):

(let [vs (repeatedly 20 l/lvar)]
  (l/run 1 [q]
     (l/== q vs)
     (l/everyg (fn [v] (fd/in v (fd/interval 1 2))) vs)))
(l/run 1 [q]
         (l/fresh [x1 x2 x3 x4 x5 x6 x7 x8 x9
                   x10 x11 x12 x13 x14 x15
                   x16 x17 x18 x19 x20]
                  (l/== q [x1 x2 x3 x4 x5 x6 x7 x8 x9
                           x10 x11 x12 x13 x14 x15
                           x16 x17 x18 x19 x20])
                  (fd/in x1 x2 x3 x4 x5 x6 x7 x8 x9
                         x10 x11 x12 x13 x14 x15
                         x16 x17 x18 x19 x20
                         (fd/interval 1 2))))

I assume the expected value is something like ([1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]).



 Comments   
Comment by David Nolen [ 31/May/13 11:49 AM ]

We got another report about this issue. Consider:

(let [vs (into [] (take 17 (repeatedly lvar)))]
  (doall
    (run 1 [q]
      (== q vs)
      (everyg #(fd/in % (fd/interval 60 69)) vs))))

The behavior seems exponential in N, currently here at 17, but on my Macbook Air going to 20 results in hanging my REPL.

Comment by Gary Fredericks [ 05/Jun/13 7:51 PM ]

It looks like this has nothing to do with domains actually. I get the same effect with the following:

(let [vs (repeatedly 16 lvar)]
  (run 1 [q]
       (everyg #(conde [(== % 1)] [(== % 2)]) vs)
       (== q vs)))
Comment by David Nolen [ 05/Jun/13 8:09 PM ]

Thanks for the extra details!

Comment by Gary Fredericks [ 07/Jun/13 10:53 PM ]

In hindsight this seems obvious.

I think it must follow directly from the breadth-first-search approach ensured by conde's interleaving.

If the expression in my previous comment creates a binary tree of depth 16, and the single answer we want is in the leftmost leaf, we still can't get to that leaf before searching through the entire tree (breadth first), which means having the whole thing in memory in some sense, which means OOM whenever the tree isn't too small.

I assume this is a fundamentally difficult problem. Should this still be considered a bug?

Comment by David Nolen [ 08/Jun/13 1:51 PM ]

`conde` isn't bread-first, it's interleaving. I will need to think about it some more. I'm mostly concerned with the FD case because we rely on `map-sum` which uses `conde`, perhaps there's something clever we can do for domain enumeration?

Comment by Gary Fredericks [ 08/Jun/13 2:53 PM ]

One thing that seems to clear up the issue but which could easily have subtle performance issues I don't understand is removing the -inc from conde. This clears up all the test cases given here, and the test suite still passes.

I don't think the -inc is necessary in the cases where we know that the goals are simple ones (like unification) that don't diverge. So another approach is to have a special goal for disjunctively unifying with a bunch of concrete values:

(defn ==any
  "Like membero, but requires that vals be a ground sequence, and probably                                                                                                                     
   performs better."
  [x vals]
  (fn [s]
    (if-let [[v & vs] (seq vals)]
      (choice (unify s x v)
              (fn []
                ((==any x vs) s))))))

Using this (like you would membero) instead of conde seems to clear it up, and could presumably be used instead of conde in map-sum.

What do you think? Is there anything in particular that should be investigated regarding this approach?

Comment by Gary Fredericks [ 08/Jun/13 3:05 PM ]

I just looked at the code that uses map-sum closer and realized I don't understand everything that's going on, so am not totally sure if/how ==any would fit there.

Comment by Gary Fredericks [ 08/Jun/13 3:28 PM ]

In playing around with it I realized the definition of ==any should not use choice directly but rather mplus, which should still have the same performance gain.

Then I was able to use the same technique inlined with map-sum, which gives:

(defn map-sum [f]
  (fn loop [ls]
    (if (empty? ls)
      (fn [a] nil)
      (fn [a]
        (mplus
         ((f (first ls)) a)
         (fn []
           ((loop (rest ls)) a)))))))

The tests pass, and the FD examples are fast.

I started a branch here: https://github.com/fredericksgary/core.logic/compare/LOGIC-137

Comment by David Nolen [ 08/Jun/13 5:21 PM ]

Please attach a patch with the `map-sum` improvement. Thanks!

Comment by Gary Fredericks [ 08/Jun/13 6:03 PM ]

Attached patch with the altered map-sum.

Comment by David Nolen [ 08/Jun/13 8:30 PM ]

fixed http://github.com/clojure/core.logic/commit/5afeace2761eeb6731cf558bed354607e5401631





[LOGIC-136] Make benchmark suite as easy to run as `lein test` Created: 09/May/13  Updated: 09/May/13

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Austin Haas Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None


 Description   

`lein benchmark` (or some other non-lein-based incantation) prints a report listing the name of each benchmark and its timing.

Example:

$ lein benchmark
membero 2839
zebra 152738
$ lein benchmark comparison-report {:baseline "benchmark-5.9.2013-1"
                                    :runs 5
                                    :diffs-only true
                                    :threshold 25} ; only consider different if the delta is > 25 ms.                                     
membero +68ms
zebra -122ms
$ lein benchmark {:pretty true}
Thu May  9 11:21:41 PDT 2013

Linux mars 2.6.32-5-amd64 #1 SMP Fri Feb 15 15:39:52 UTC 2013 x86_64 GNU/Linux

java version "1.7.0_21"
Java(TM) SE Runtime Environment (build 1.7.0_21-b11)
Java HotSpot(TM) 64-Bit Server VM (build 23.21-b01, mixed mode)

membero     2839 ms
zebra     152738 ms

I haven't looked for any Clojure benchmarking libs, but ideally this would be a trivial script that automates the repetitive manual task of running benchmark tests. Unlike the test suite, we aren't looking for binary success or failure. Every run will generate unique results, so the script should accommodate a fuzzier comparison.

A "pretty" output that includes system info would be great for bug reports.



 Comments   
Comment by David Nolen [ 09/May/13 1:44 PM ]

Sounds like an excellent enhancement to me. Patch welcome for this.





[LOGIC-135] membero should be updated to use disequality constraints Created: 07/May/13  Updated: 28/Jul/13  Resolved: 07/May/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Austin Haas Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: File LOGIC-135-membero-using-disequality.diff    

 Description   

William Byrd considers the version of membero that appears in core.logic to be outdated and inferior to a version that uses disequality constraints. Full discussion here: http://youtu.be/MTAhbsWUUxM?t=1h20m00s

NEW version:

(defne membero
  "A relation where l is a collection, such that l contains x"
  [x l]
  ([_ [x . tail]])
  ([_ [head . tail]]
     (!= x head)       ;; The addition of this line is the only change.
     (membero x tail)))

(run* [q] (membero q [1 1 1])) 
;; => (1)
;; The current version returns (1 1 1).

Patch to follow.



 Comments   
Comment by Austin Haas [ 07/May/13 5:33 PM ]

This patch improves membero by adding a disequality constraint. Fix for LOGIC-135.

Note that this patch removes two tests that depended on assumptions that have nothing to do with the correctness of membero.

Comment by Austin Haas [ 07/May/13 5:41 PM ]

Regarding the tests, the first broke because it assumed reified fresh lvars wouldn't include disequality constraints.

For the 2nd one, test-116-constraint-store-migrate, I have not looked into it thoroughly, but I got the impression that the test needs to be rewritten. I'd argue that it is more important to fix membero before fixing that test (but I don't know what else that test is testing).

Comment by David Nolen [ 07/May/13 10:24 PM ]

fixed http://github.com/clojure/core.logic/commit/a35c8eebfff90515796ea734ba81e3f5db041b5c





[LOGIC-134] Historic artifacts in the implementation of Choice prevent take* from being generally usable. Created: 07/May/13  Updated: 28/Jul/13  Resolved: 07/May/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Austin Haas Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: File LOGIC-134-fix.diff    
Patch: Code

 Description   

The implementation of Choice is slightly broken, because in certain contexts it is assumed that the first value in the Choice stream will be wrapped in a list. I believe this is a historical artifact; maybe the list wrapper was used to differentiate two types of values, as in the case of distinguishing not-found from nil.

This defect prevents take* from being used generally, since the current implementation of take* for Choice assumes the first value is wrapped in a list, which is not the case for Choice streams during the search.

Patch to follow.



 Comments   
Comment by Austin Haas [ 07/May/13 3:23 PM ]

Never wrap first item to Choice in a list. Fixes LOGIC-134.

http://dev.clojure.org/jira/browse/LOGIC-134

Comment by David Nolen [ 07/May/13 10:27 PM ]

The attached patch does not work, many tests fail.

Comment by David Nolen [ 07/May/13 11:37 PM ]

fixed, http://github.com/clojure/core.logic/commit/0a8b619880c7cbea4cf8e9a280cbd5bdb413a12c





[LOGIC-133] Add label goal Created: 29/Apr/13  Updated: 11/Jan/14

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None


 Description   

This goal should enumerate any fd vars found in a fresh/ground var bound to a sequence. This would avoid some unintuitive behavior that came up on the mailing list:

(defne weighted-listo [l w]
  ([() _] (fd/== w 0))
  ([[h . t] _]
    (fresh [n]
      (fd/in n (fd/interval 0 java.lang.Integer/MAX_VALUE))
      (fd/in h (fd/interval 1 java.lang.Integer/MAX_VALUE))
      (fd/+ h n w)
      (weighted-listo t n))))


 Comments   
Comment by Austin Haas [ 11/Jan/14 10:23 PM ]

Here is a link to the discussion on the mailing list: https://groups.google.com/forum/#!topic/minikanren/MgcvtkA6_EI





[LOGIC-132] "PMap is non-storable" exception when using featurec with nested feature map. Created: 26/Apr/13  Updated: 28/Jul/13  Resolved: 05/May/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Martin Forsgren Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None
Environment:

core.locic 0.8.3



 Description   

This works as expected:

(run* [x y]
  (featurec x {:a {:b 1}})
  (== y {:b 1})
  (== x {:a y}))

;; => ([{:a {:b 1}} {:b 1}])

But with the last two goals swapped an exception is thrown:

(run* [x y]
  (featurec x {:a {:b 1}})
  (== x {:a y})
  (== y {:b 1}))

;; =>
Exception clojure.core.logic.PMap@3c6f0bed is non-storable
    clojure.core.logic.LVar (logic.clj:647)
    clojure.core.logic/unify (logic.clj:231)
    clojure.core.logic/unify-with-pmap* (logic.clj:2601)
    clojure.core.logic.PMap (logic.clj:2614)
    clojure.core.logic/unify (logic.clj:232)
    clojure.core.logic/==/fn--2819 (logic.clj:1135)
    clojure.core.logic/composeg/fn--2745 (logic.clj:1029)
    clojure.core.logic/-featurec/reify--3655 (logic.clj:2646)
    clojure.core.logic/composeg/fn--2745 (logic.clj:1029)
    clojure.core.logic/composeg/fn--2745 (logic.clj:1030)
    clojure.core.logic/run-constraint/fn--3431 (logic.clj:2184)
    clojure.core.logic/fix-constraints (logic.clj:2211)

The same exception is thrown when (== y {:b 1}) is left out:

(run* [x y]
  (featurec x {:a {:b 1}})
  (== x {:a y}))


 Comments   
Comment by David Nolen [ 05/May/13 7:34 PM ]

fixed, http://github.com/clojure/core.logic/commit/30fcd69dd4c9ca86b3a73c3f6b5866d6b943ddff





[LOGIC-131] Docstrings for lvaro and nonlvaro need improvement. Created: 22/Apr/13  Updated: 28/Jul/13  Resolved: 07/May/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Austin Haas Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: documentation

Attachments: File LOGIC-131-fix.diff    
Patch: Code

 Description   

Assuming the following definitions:

1. A term is ground if it does not contain unassociated logic variables.
2. Otherwise, it is non-ground.

My suggestions:

lvaro: A non-relational goal that succeeds if the supplied logic variable is fresh.

nonlvaro: A non-relational goal that succeeds if the supplied logic variable is not fresh.

In the case nonlvaro, it's important to recognize that the implementation only tests whether the supplied lvar is not fresh, and "not fresh" != grounded; the result could be partially instantiated. For example, nonlvaro succeeds here when its argument is neither fresh nor grounded:

(run* [q]
  (fresh [x]
    (== q [x])
    (nonlvaro q)))
;; => ([_0])


 Comments   
Comment by Austin Haas [ 22/Apr/13 12:26 PM ]

I added those initial definitions when I thought "groundedness" was the operative word, so they aren't directly relevant.

Comment by David Nolen [ 22/Apr/13 12:29 PM ]

Thanks, I'll happily accept docstring patches.

Comment by Austin Haas [ 07/May/13 2:11 PM ]

This patch changes the docstrings for lvaro and nonlvaro to be more accurate. This is a fix for LOGIC-131.

Comment by David Nolen [ 07/May/13 10:29 PM ]

fixed http://github.com/clojure/core.logic/commit/cc30fcb4f5690e928fa7103e5091b9de8aba0013





[LOGIC-130] StackOverFlowError when walking over set Created: 16/Apr/13  Updated: 16/Apr/13

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Coen De Roover Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None
Environment:

core.logic 0.8.3
Clojure 1.5



 Description   

Walking a Clojure set seems to cause a StackOverFlowError:

(run* [?s] (== ?s #{1 2 3}))

(let [s #{1 2 3}] (run* [?s] (== ?s s)))

(run* [?convertedseq ?seq] 
  (== ?seq #{1 2 3})
  (project [?seq]
    (== ?convertedseq (vector ?seq))))
StackOverflowError 
	clojure.core.logic/walk*/fn--2722 (logic.clj:216)
	clojure.core.logic/eval2927/fn--2928 (logic.clj:956)
	clojure.core.logic.protocols/eval1478/fn--1479/G--1469--1486 (protocols.clj:55)
	clojure.core.logic/walk* (logic.clj:214)
	clojure.core.logic/walk*/fn--2722 (logic.clj:218)
	clojure.core.logic/eval2927/fn--2928 (logic.clj:956)
	clojure.core.logic.protocols/eval1478/fn--1479/G--1469--1486 (protocols.clj:55)
	clojure.core.logic/walk* (logic.clj:214)
	clojure.core.logic/walk*/fn--2722 (logic.clj:218)
	clojure.core.logic/eval2927/fn--2928 (logic.clj:956)
	clojure.core.logic.protocols/eval1478/fn--1479/G--1469--1486 (protocols.clj:55)
	clojure.core.logic/walk* (logic.clj:214)


 Comments   
Comment by David Nolen [ 16/Apr/13 5:28 PM ]

core.logic no longer supports unification of sets so you're just seeing an error as result of a complete lack of support. I'm not against supporting basic unification of completely grounded sets, as then we only need to test for equality, but I'm inclined to make the system throw if any logic vars appear in the sets.





[LOGIC-129] matcha/matchu are not faithful to the semantics of conda/condu Created: 04/Apr/13  Updated: 09/Jun/13

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Austin Haas Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None


 Description   

The semantics of conda and condu give special importance to the head of each clause, but the pattern matching macros in core.logic that are built on top of them merge the body into the head. That means that every expression in a body position is considered when deciding which line is chosen, rather than just the expression in the head position. This is because the entire clause is wrapped in a fresh expression to bind the implicitly specified lvars that appear in the pattern.

To illustrate:

(matcha ['a]
    [['a] u#]
    [['a] s#])

;; expands to:

(conda
  [(fresh [] (== 'a 'a) u#)]
  [(fresh [] (== 'a 'a) s#)])

;; which has a different meaning than:

(conda
  [(== 'a 'a) u#]
  [(== 'a 'a) s#])

Ideally, we could devise a new system to marry the semantics of conda with pattern matching. At the very least, I think the offending macros should carry a warning in their docstring, stating this semantic difference.

I suspect this would also cause the "Third Commandment" warning to apply to the entire line, rather than just the head/question, but I have not investigated that issue.

Here's an example that demonstrates the difference in meaning:

;; This does not succeed, because we commit to the first line, 
;; since the question succeeds, but then fail in the body.

(run* [q]
  (conda
   [(== 'a 'a) u#]
   [(== 'a 'a) s#]))

;; => ()

;; This succeeds, because the whole line is used to determine which line to commit to, 
;; rather than just the pattern matching clause at the head. So when the first line fails,
;; the second line is tried.

(run* [q]
  (matcha ['a]
   [['a] u#]
   [['a] s#]))

;; => (_0)


 Comments   
Comment by Austin Haas [ 04/Apr/13 2:35 PM ]

For reference:

The Third Commandment

If prior to determining the question of a conda (or condu) line a variable is fresh, it must remain fresh in the question of that line.

From The Reasoned Schemer.

Comment by David Nolen [ 04/Apr/13 5:16 PM ]

Good catch I need to think about this one.

Comment by David Nolen [ 09/Jun/13 12:11 PM ]

The issue is that we rely on the `conde` macro which isn't very flexible. We should probably do something one step lower so can wrap each conde line in a `let` that constructs the logic vars and then ensure that all the head unifications are wrapped in one `fresh` so that the semantics of conda/u are preserved.





[LOGIC-128] add mod/rem/abs/min/max Created: 02/Apr/13  Updated: 15/Oct/14

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: David Nolen Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None


 Description   

SWI-Prolog's CLP(FD) module has this functionality http://www.swi-prolog.org/man/clpfd.html






[LOGIC-127] Swapping noms turns maps (and other collections) into seqs Created: 02/Apr/13  Updated: 28/Jul/13  Resolved: 10/Apr/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Jiří Maršík Assignee: Nada Amin
Resolution: Completed Votes: 0
Labels: bug, nominal

Attachments: Text File INomSwap-vectors-maps.patch     Text File INomSwap-vectors-maps-with-test.patch    
Approval: Accepted

 Description   

When I unify two binders, the swapping procedure turns all the maps inside the body into seqs of key/value pairs, which do not unify with maps, leading to the following trickiness:

(require '[clojure.core.logic :as l])
(require '[clojure.core.logic.nominal :as n])
(l/run* [q]
  (l/fresh [body]
    (n/fresh [a b]
      (l/== (n/tie a {:k a}) (n/tie b body))
      (l/== {:k q} body))))
;=> ()
; Expected (a_0)

For my purposes, fixing this by adding two new implementations of INomSwap for vectors and maps works well.



 Comments   
Comment by Jiří Maršík [ 02/Apr/13 11:14 AM ]

Oops, sorry for the malformatted code snippet. Here it is inside a code tag.

(require '[clojure.core.logic :as l])
(require '[clojure.core.logic.nominal :as n])
(l/run* [q]
        (l/fresh [body]
                 (n/fresh [a b]
                          (l/== (n/tie a {:k a}) (n/tie b body))
                          (l/== {:k q} body))))
;=> ()
; Expected (a_0)
Comment by David Nolen [ 02/Apr/13 11:22 AM ]

This seems like a easy one to fix, perhaps Nada can see quicker than I can. If not I can take a look.

Also your patch may very well solve the issue best, feel free to attach it to the ticket. We won't be able to apply it until you've submitted your Contributor Agreement - if you have a free moment please send it in. Thanks!

Comment by Jiří Maršík [ 02/Apr/13 11:48 AM ]

The patch that I use to fix the issue. I haven't signed the CA, but I would definitely like to. Might take a while to arrive though, since I'm in Europe and I'm lazy.

Comment by Nada Amin [ 03/Apr/13 2:36 AM ]

The patch LGTM. I would also add a test from the ticket example.

I guess we have to wait until the CA arrives, now.

Comment by Jiří Maršík [ 03/Apr/13 4:28 AM ]

I have also added the test case, the new patch INomSwap-vectors-maps-with-test.patch contains both the fix and the test case. I have just signed the CA and I plan to post it today.

Comment by Jiří Maršík [ 09/Apr/13 10:55 AM ]

OK, the CA has arrived and been processed.

http://clojure.org/contributing

  • Jiri Marsik (jirkamarsik)
Comment by Nada Amin [ 10/Apr/13 3:32 AM ]

Applied as https://github.com/clojure/core.logic/commit/d73c836c0d4bab2af12b4bdedb31daad4a661fb6

Thanks!





[LOGIC-126] fd/* and fd/+ interaction bug Created: 28/Mar/13  Updated: 28/Jul/13  Resolved: 28/Mar/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

Via this StackOverflow question http://stackoverflow.com/questions/15671823/unexpected-results-with-clojure-core-logic-using-clp-fd

(defn product-pluso [factor1 factor2 number sum]
  (fd/eq (= sum (+ number (* factor1 factor2)))))

(run* [x y]
  (fd/in x y (fd/interval 1 38))
  (product-pluso x y 2 40))

Returns too many answers. Even if we desugar into:

(run* [q]
  (fresh [x y p]
    (fd/in x y (fd/interval 1 38))
    (fd/* x y p)
    (fd/+ p 2 40)
    (== q [x y p])))

We see results which clearly violate the fd/+ constraint.



 Comments   
Comment by David Nolen [ 28/Mar/13 12:58 PM ]

It seems like we should be able to fix this at the level of update-var-dom by checking that the var doesn't already have a value in the substitution, but oddly by doing this we run into some strange non-termination behavior. I've experienced this before when trying to flip the order of checks in let-dom, but at the time I was too busy with bigger problems to look at the issue more closely.

Comment by David Nolen [ 28/Mar/13 1:01 PM ]

After digging into this some it looks like we have a fairly nice opportunity to refactor and make things considerably faster. In the Scheme version get-dom / walk are necessarily separate operations because of the implementation. This is not necessary in core.logic because of SubstValue. get-dom should always do the right thing - return the value in the substitution if present or domain otherwise. The constraint writers need not bother with walk at all.

Comment by David Nolen [ 28/Mar/13 1:27 PM ]

To be clear get-dom has different contract than walk - get-dom will return a not found value instead of a logic var. It would be nice to be able to return nil but we could image CLP(Set) and other cases where the possible values includes nil.

Comment by David Nolen [ 28/Mar/13 10:40 PM ]

fixed http://github.com/clojure/core.logic/commit/52eec3b04c2b785c84bed81671db80c2163c4967





[LOGIC-125] Using membero with a vector as an element Created: 25/Mar/13  Updated: 28/Jul/13  Resolved: 25/Mar/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Matthew O. Smith Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

Running this code gives an unexpected result of only one of the 2 members being present:

(defn solve1 [q]
  (symbol-macrolet   [_ (lvar)]
          (membero [_ _ 'blue-cheese 'Fortune] q) ;; 2
          (membero [:5:00 _ 'mozzarella _] q) ;; 11
          ))

(run 1 [q] (solve1 q))
=> (([:5:00 _0 mozzarella _1] . _2))

While adding an empty fresh seems to resolve the problem:

(defn solve2 [q]
  (symbol-macrolet   [_ (lvar)]
   (fresh []
          (membero [_ _ 'blue-cheese 'Fortune] q) ;; 2
          (membero [:5:00 _ 'mozzarella _] q) ;; 11
        )))

(run 1 [q] (solve2 q))
=> (([_0 _1 blue-cheese Fortune] [:5:00 _2 mozzarella _3] . _4))


 Comments   
Comment by David Nolen [ 25/Mar/13 10:52 AM ]

This is not a bug. You must always wrap a conjunction of goals in a run, fresh or an all or some other compound goal construct built from these primitives.

Comment by Matthew O. Smith [ 25/Mar/13 11:31 AM ]

Thanks, that is good to know.





[LOGIC-124] Order of args to fd/!= changes results (gives incorrect answer) Created: 24/Mar/13  Updated: 28/Jul/13  Resolved: 24/Mar/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Ryan Senior Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File arch-friends.patch    

 Description   

I have attached a failing test for the Arch Friends logic puzzle. Swapping the args to fd's != fixes the problem. So does moving the call to fd's != to after the fd's == or fd's + below it.

Tried this on 0.8.0-rc2, 0.8.0 and 0.8.1.



 Comments   
Comment by David Nolen [ 24/Mar/13 2:47 PM ]

fixed, http://github.com/clojure/core.logic/commit/ce323c9bb85e080211eddfb7203a34104c62dee3





[LOGIC-123] Allow unification with sequential in both directions Created: 23/Mar/13  Updated: 26/Mar/13

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Mike Anderson Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Currently I can't find a way to enable a custom data type to do unification with sequential objects in both direction. You can use IUnifyTerms to make it work in one direction, but it isn't possible to make it work in the other direction (i.e. when the sequential object is first).

The problem seemes to be in the following code:

(defn unify-with-sequential* [u v s]
  (cond
    (sequential? v)
    (if (and (counted? u) (counted? v)
          (not= (count u) (count v)))
      nil
      (loop [u u v v s s]
        (if (seq u)
          (if (seq v)
            (if-let [s (unify s (first u) (first v))]
              (recur (next u) (next v) s)
              nil)
            nil)
          (if (seq v) nil s))))
    
    (lcons? v) (unify-terms v u s)
    :else nil))

If the final nil could be replaced with a call to a protocol (IUnifyTermsReversed ???IUnifyWithSequential ???) then I believe it would make this extensible.



 Comments   
Comment by David Nolen [ 23/Mar/13 9:53 PM ]

I'm assume it's undesirable for your datatype to implement ISequential?

Comment by Mike Anderson [ 23/Mar/13 11:06 PM ]

It's undesirable because an expression can be a leaf node as well:

(+ 3 X) ;; OK as sequential
7 ;; definitely not sequential!

Hence making Expression implement ISequential would be problematic and break all kinds of contracts.....

Trying to unify the leaf node with a sequential object should fail of course, but that's logic I need to implement myself (I think??)

Comment by David Nolen [ 24/Mar/13 12:11 PM ]

I'm still not following as there's some context about your use case that I'm missing. Do you have a concrete core.logic example that you should think should work?

Comment by Mike Anderson [ 25/Mar/13 2:21 AM ]

Sure, here is my test case:

(let [ex1 (ex [+ 1 X])]  ;; an expression containing (+ 1 X) 
  (is (= [(ex X)] (run* [q] (fresh [op p] (== [op p q] ex1)))))  ;; fails
  (is (= [(ex X)] (run* [q] (fresh [op p] (== ex1 [op p q])))))  ;; OK
)

The first case fails (because of unify-with-sequential* returning nil as above). The second case is OK because it goes through my own implementation of IUnifyTerms. I may be wrong, but I don't think I can make it work without a change in core.logic itself.

Comment by David Nolen [ 25/Mar/13 7:39 AM ]

We used to support unifying in both directions but it made for a large number of protocols that had to be implemented. Recently I've been thinking it may be useful to provide coercion protocols, something like ICoerceToSequential.

Comment by Mike Anderson [ 25/Mar/13 7:37 PM ]

I think it is necessary to be able to support unifying in both directions somehow if custom data structures are ever going to be first-class citizens in core.logic?

I see how you could achieve this with ICoerceToSequential however so that might be a good solution. We do something a bit similar in core.matrix (to handle coercions between different back-end matrix implementations).

Comment by David Nolen [ 25/Mar/13 7:44 PM ]

custom data structures are already first class. Whether we should allow overloading unification of custom types with core Clojure interfaces/protocols/types is another matter entirely.

And sorry for the confusion. It's not clear to me why you want sequential to work, from your examples it appears that you have a proper expression type, what advantage is there for you to unify with sequential?

Comment by Mike Anderson [ 26/Mar/13 1:07 AM ]

I think it may be important if you have "sequence-like" data structures that aren't precisely sequential? but are conceptually equivalent to sequences. My custom Expression type is one example, and for interop reasons things like java.util.ArrayList spring to mind.

As it happens, I've switched back to using regular lists for the moment so the issue isn't a blocker for me. But it may still be worth thinking about.

Couple of advantages of doing this kind of unification would appear to be:
a) notational - you can use regular Clojure lists and vectors for unifying with something sequence-like
b) efficiency - avoid constructing a new custom object when it isn't needed (though the cost is probably too trivial to bother about in most cases....)

Of course, you may decide it is simpler and purer to avoid these complications, which is fine. But it seems a shame to have all the nice extensible protocols, and not quite be able to fully extend the functionality to custom types....





[LOGIC-122] Subpattern {?x (?y ?y)} fails to unify Created: 15/Mar/13  Updated: 28/Jul/13  Resolved: 17/Mar/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Jonas Enlund Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: File LOGIC-120-121-122-squashed.diff     File LOGIC-122.diff    

 Description   

This expression should unify but doesn't:

(unify {:as '{?x (?y ?y)}} '[[?y ?x] [1 (1 1)]])


 Comments   
Comment by Jonas Enlund [ 16/Mar/13 2:35 AM ]

The patch LOGIC-122.diff includes patches for LOGIC-120 and LOGIC-121

Comment by David Nolen [ 16/Mar/13 9:18 AM ]

So unless I'm mistaken I only need to apply this patch to address the three tickets correct?

Comment by Jonas Enlund [ 16/Mar/13 9:56 AM ]

Correct. This patch fixes LOGIC-120 121 and 122. The patch for LOGIC-118 is not included in these commits. Do you want tests in a seperate ticket/patch?

Comment by David Nolen [ 16/Mar/13 10:50 AM ]

I would actually prefer a squashed patch that includes the tests. Thanks. It makes sense to deal with LOGIC-118 separately, can we make sure we have tests there as well? Thanks!

Comment by Jonas Enlund [ 16/Mar/13 11:07 AM ]

Use LOGIC-120-121-122-squashed.diff. It includes the tests.

Comment by David Nolen [ 17/Mar/13 11:39 AM ]

fixed http://github.com/clojure/core.logic/commit/2bf23fd1ea64966bae094c9f634dfb21ddd386d1





[LOGIC-121] Unifier fails on some nested forms Created: 14/Mar/13  Updated: 28/Jul/13  Resolved: 17/Mar/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Jonas Enlund Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: File LOGIC-121.diff    

 Description   

The expression

(unifier '[((?x ?y)) ((1 2))])

returns the (invalid) result {?x 1}. Note that unify works as expected:

(unify '[((?x ?y)) ((1 2))])
=> ((1 2))


 Comments   
Comment by David Nolen [ 17/Mar/13 11:39 AM ]

patch applied from LOGIC-122

fixed, http://github.com/clojure/core.logic/commit/2bf23fd1ea64966bae094c9f634dfb21ddd386d1





[LOGIC-120] (unify '[?x 1]) throws IllegalArgumentException Created: 14/Mar/13  Updated: 28/Jul/13  Resolved: 17/Mar/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Jonas Enlund Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: File LOGIC-120.diff    

 Description   

The following two expressions throws IllegalArgumentException Don't know how to create ISeq from: java.lang.Long:

(unify '[?x 1])

(unifier '[?x 1])

The same thing happens for any non-sequential form.



 Comments   
Comment by Jonas Enlund [ 16/Mar/13 2:06 AM ]

The patch LOGIC-120.diff also incorporates the patch I submitted for LOGIC-121 as the approach taken doesn't work without that issue fixed.

Comment by David Nolen [ 17/Mar/13 11:40 AM ]

Patch applied from LOGIC-122

fixed,
http://github.com/clojure/core.logic/commit/2bf23fd1ea64966bae094c9f634dfb21ddd386d1





[LOGIC-119] tie disequality Created: 12/Mar/13  Updated: 12/Mar/13

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Nada Amin Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None


 Description   
(deftest test-tie-disequality
  (is (= (run* [q]
           (nom/fresh [a b]
             (!= (nom/tie a a) 'hello)))
        '(_0)))
  (is (= (run* [q]
           (nom/fresh [a b]
             (!= (nom/tie a a) (nom/tie b b))))
        ())))

Currently, the first causes an error, because IPersistentMap (which gets called because Tie is a record!) assumes that the the other term is also a record (that seems like a bug). If we revert the commit which makes Tie a record, this works.

The other one succeeds, when it should fail. This is regardless of whether Tie is a record or not.



 Comments   
Comment by Nada Amin [ 12/Mar/13 5:52 AM ]

quick fix in https://github.com/clojure/core.logic/commit/8af0f45f8d1cb515ec7a00e5acd751562a31bb37

for actually doing != modulo alpha equivalence requires the opposite of nom/hash.





[LOGIC-118] prep does not make lvar of ?x if ?x is in a vector Created: 11/Mar/13  Updated: 24/Nov/14  Resolved: 24/Nov/14

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Jonas Enlund Assignee: David Nolen
Resolution: Completed Votes: 1
Labels: None

Attachments: File LOGIC-118.diff     File LOGIC-118-version2.diff    

 Description   

In latest master:

user=> (use 'clojure.core.logic.unifier)
user=> (prep '([?x]))
([<lvar:?x>]) ;; ok. ?x turned into an lvar
user=> (prep '([?x] . ?xs))
([?x] . <lvar:?xs>) ;; fail. ?x is not an lvar

The last expression should return ([<lvar:?x>] . <lvar:?xs>)



 Comments   
Comment by Jonas Enlund [ 12/Mar/13 12:11 AM ]

patch LOGIC-118.diff fixes this issue. I'm not sure if it does so correctly.

Comment by David Nolen [ 17/Mar/13 11:42 AM ]

It's seem to me that this should be corrected in prep*? It looks like the issue is that prep* only handles seqs and not collections in general.

Comment by Jennifer Smith [ 09/Nov/14 11:29 PM ]

This should address the issue merely by swapping out (seq? ...) with (coll? ...) - passes the supplied test case.

Comment by David Nolen [ 24/Nov/14 1:24 PM ]

fixed https://github.com/clojure/core.logic/commit/dba7c697ca45a7fee7595cd18d057c420261d498





[LOGIC-117] one-shot constraints with multiple rands may run more than once Created: 11/Mar/13  Updated: 19/Mar/13

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Nada Amin Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Here are two examples using fixc:

(run* [q]
  (fresh [x y]
    (fixc [x y]
      (fn [[x y] a _] (!= x 1))
      (fn [[x y] a] (= (walk a x) (walk a y)))
      '...)
    (== x y)))

(run* [q]
  (fresh [x y c d]
    (fixc [x y]
      (fn [[x y] a _] (!= x y))
      (fn [[x y] a] (or (not (lvar? (walk a x))) (not (lvar? (walk a y)))))
      '...)
    (== [x y] [[c] [d]])))

The constraint != is reified twice in each example, showing that the fixc constraint indeed ran twice.



 Comments   
Comment by David Nolen [ 17/Mar/13 7:27 PM ]

For the first example I see the following as a result on master:

((_0 :- (!= (_1 1))))

Is this what you're seeing? As x isn't even part of the answer I wonder if we should show these constraints?

Comment by Nada Amin [ 19/Mar/13 1:36 AM ]

I changed the reifier by setifying the set of constraints, hence you get only one result now. So my illustration is now out-of-date but the problem remains. It's a separate issue to filter out irrelevant constraints, and I agree it should be done (I try to do it for the nominal constraints).





[LOGIC-116] ClassCastException in core.logic depending on ordering Created: 08/Mar/13  Updated: 28/Jul/13  Resolved: 17/Mar/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Matthew O. Smith Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: 0.8.0, bug

Attachments: File corefail.clj    

 Description   

I have two files:
1 -https://github.com/m0smith/LogicPuzzles/blob/master/src/logicpuzzles/coresucceed.clj
2 -https://github.com/m0smith/LogicPuzzles/blob/master/src/logicpuzzles/corefail.clj

The first one compiles and runs fine. The second throws a ClassCastException. The only difference is that rule-0 is moved in the second file.



 Comments   
Comment by David Nolen [ 11/Mar/13 7:40 AM ]

There's far too much context here. Do you have a minimal case? Thanks much!

Comment by Matthew O. Smith [ 11/Mar/13 9:15 AM ]

Here is the stack trace. I will try to narrow it down further.

java.lang.ClassCastException: clojure.lang.PersistentList cannot be cast to clojure.lang.IPersistentSet
at clojure.core$disj.invoke (core.clj:1420)
clojure.core.logic.ConstraintStore/fn (logic.clj:339)
clojure.lang.ArrayChunk.reduce (ArrayChunk.java:58)
clojure.core.protocols/fn (protocols.clj:94)
clojure.core.protocols$fn_5854$G5849_5863.invoke (protocols.clj:19)
clojure.core.protocols$seq_reduce.invoke (protocols.clj:31)
clojure.core.protocols/fn (protocols.clj:60)
clojure.core.protocols$fn_5828$G5823_5841.invoke (protocols.clj:13)
clojure.core$reduce.invoke (core.clj:6030)
clojure.core.logic.ConstraintStore.remc (logic.clj:338)
clojure.core.logic$remcg$fn__3272.invoke (logic.clj:2374)
clojure.core.logic$BANG$reify_3422.invoke (logic.clj:2719)
clojure.core.logic$composeg$fn__2569.invoke (logic.clj:1141)
clojure.core.logic$composeg$fn__2569.invoke (logic.clj:1142)
clojure.core.logic$run_constraint$fn__3285.invoke (logic.clj:2397)
clojure.core.logic$fix_constraints.invoke (logic.clj:2424)
clojure.core.logic$run_constraints$fn__3290.invoke (logic.clj:2434)
clojure.core.logic.Substitutions.bind (logic.clj:612)
clojure.core.logic$run_constraints_STAR_$fn__3296.invoke (logic.clj:2444)
clojure.core.logic.Substitutions.bind (logic.clj:612)
clojure.core.logic$run_constraints_STAR_$fn__3296.invoke (logic.clj:2446)
clojure.core.logic$EQEQ$fn__2647.invoke (logic.clj:1255)
clojure.core.logic.Substitutions.bind (logic.clj:612)
clojure.core.logic$rembero$fn_3465$_inc3466$fn3475$fn3476$_inc3477$fn3478$_inc_3479.invoke (logic.clj:2790)
clojure.core.logic$eval2628$fn_2633$_inc_2634.invoke (logic.clj:1223)
clojure.core.logic$eval2628$fn_2633$_inc_2634.invoke (logic.clj:1223)
clojure.core.logic$eval2628$fn_2637$_inc_2638.invoke (logic.clj:1220)
clojure.core.logic$eval2628$fn_2633$_inc_2634.invoke (logic.clj:1223)
clojure.core.logic$eval2628$fn_2633$_inc_2634.invoke (logic.clj:1223)
clojure.core.logic$eval2628$fn_2633$_inc_2634.invoke (logic.clj:1223)
clojure.core.logic$eval2628$fn_2637$_inc_2638.invoke (logic.clj:1220)
clojure.core.logic$eval2628$fn_2633$_inc_2634.invoke (logic.clj:1223)
clojure.core.logic$eval2628$fn_2637$_inc_2638.invoke (logic.clj:1220)
clojure.core.logic$eval2628$fn_2629$fn_2630.invoke (logic.clj:1225)
clojure.lang.LazySeq.sval (LazySeq.java:42)
clojure.lang.LazySeq.seq (LazySeq.java:67)
clojure.lang.RT.seq (RT.java:473)
clojure.core$seq.invoke (core.clj:133)
clojure.core$take$fn__4112.invoke (core.clj:2501)
clojure.lang.LazySeq.sval (LazySeq.java:42)
clojure.lang.LazySeq.seq (LazySeq.java:60)
clojure.lang.LazySeq.first (LazySeq.java:82)
clojure.lang.RT.first (RT.java:566)
clojure.core$first.invoke (core.clj:55)
clojure.pprint$pprint_reader_macro.invoke (dispatch.clj:50)
clojure.pprint$pprint_list.invoke (dispatch.clj:77)
clojure.lang.MultiFn.invoke (MultiFn.java:163)
clojure.pprint$write_out.invoke (pprint_base.clj:194)
clojure.pprint$pprint_vector$fn__7949.invoke (dispatch.clj:83)
clojure.pprint$pprint_vector.invoke (dispatch.clj:82)
clojure.lang.MultiFn.invoke (MultiFn.java:163)
clojure.pprint$write_out.invoke (pprint_base.clj:194)
clojure.pprint$pprint$fn__7359.invoke (pprint_base.clj:250)
clojure.pprint$pprint.invoke (pprint_base.clj:248)
clojure.pprint$pprint.invoke (pprint_base.clj:245)
logicpuzzles.corefail$show.invoke (corefail.clj:9)
logicpuzzles.corefail$eval3796.invoke (corefail.clj:153)
clojure.lang.Compiler.eval (Compiler.java:6511)
clojure.lang.Compiler.load (Compiler.java:6952)
user$eval971.invoke (NO_SOURCE_FILE:1)
clojure.lang.Compiler.eval (Compiler.java:6511)
clojure.lang.Compiler.eval (Compiler.java:6477)
clojure.core$eval.invoke (core.clj:2797)
clojure.main$repl$read_eval_print__6405.invoke (main.clj:245)
clojure.main$repl$fn__6410.invoke (main.clj:266)
clojure.main$repl.doInvoke (main.clj:266)
clojure.lang.RestFn.invoke (RestFn.java:1096)
clojure.tools.nrepl.middleware.interruptible_eval$evaluate$fn__544.invoke (interruptible_eval.clj:56)
clojure.lang.AFn.applyToHelper (AFn.java:159)
clojure.lang.AFn.applyTo (AFn.java:151)
clojure.core$apply.invoke (core.clj:601)
clojure.core$with_bindings_STAR_.doInvoke (core.clj:1771)
clojure.lang.RestFn.invoke (RestFn.java:425)
clojure.tools.nrepl.middleware.interruptible_eval$evaluate.invoke (interruptible_eval.clj:41)
clojure.tools.nrepl.middleware.interruptible_eval$interruptible_eval$fn_585$fn_587.invoke (interruptible_eval.clj:171)
clojure.core$comp$fn__4034.invoke (core.clj:2278)
clojure.tools.nrepl.middleware.interruptible_eval$run_next$fn__578.invoke (interruptible_eval.clj:138)
clojure.lang.AFn.run (AFn.java:24)
java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1145)
java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:615)
java.lang.Thread.run (Thread.java:722)

Comment by Matthew O. Smith [ 11/Mar/13 9:24 AM ]

I tightened up the fail case https://github.com/m0smith/LogicPuzzles/blob/master/src/logicpuzzles/corefail.clj . Is that enough?

Comment by David Nolen [ 11/Mar/13 10:17 AM ]

Thanks can you add the failing code to the ticket as an attachment? Thanks.

Comment by Matthew O. Smith [ 11/Mar/13 6:23 PM ]

corefail.clj exhibits the error

Comment by David Nolen [ 17/Mar/13 6:29 PM ]

fixed, http://github.com/clojure/core.logic/commit/7e4d0b6b71707e248fd4d0de3f6c090b50a18624





[LOGIC-115] fd/interval with (== lb ub) fails Created: 19/Feb/13  Updated: 28/Jul/13  Resolved: 19/Feb/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Herwig Hochleitner Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

Test case:

(run* [q] (fd/in q (fd/interval 3 3)))



 Comments   
Comment by David Nolen [ 19/Feb/13 7:38 PM ]

fixed, http://github.com/clojure/core.logic/commit/83e9cdb4247893ef0a8dbdefe61aebdca0163dbf





[LOGIC-114] stack overflow with conda/u Created: 14/Feb/13  Updated: 17/Mar/13

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Austin Haas Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None


 Description   
(ns test
  (:refer-clojure :exclude [==])
  (:require
   [clojure.core.logic :refer :all]))
 
(defn foo [in out]
  (matcha 
   [in out]
   ([('and a b . ()) ('and x y . ())] (foo a x) (foo b y))
   ([a ('bar ('baz a . ()) . ())])))
 
;; I get a stack overflow with the following, but if I remove one conjunct, then it will run.
 
(run 1 [q] (foo
            '(and p
                  (and p
                       (and p
                            (and p
                                 (and p
                                      (and p
                                           (and p
                                                (and p
                                                     (and p
                                                          (and p
                                                               (and p p)))))))))))
            q))


 Comments   
Comment by David Nolen [ 14/Feb/13 1:22 PM ]

It looks this issue still exists even if you swap the matcha with matche

Comment by Austin Haas [ 14/Feb/13 8:06 PM ]

I think the overflow is occurring during reification.

I was getting this error when returning a result from run, but now that I'm using the same value as the input to another goal there is no overflow.

If you replace q in the foo call with a fresh variable, it will not overflow.

Comment by David Nolen [ 17/Mar/13 7:30 PM ]

This works for me on master. Can you give me more specifics about your setup so I can try to recreate? I'm on OS X 10.8 running JDK 7 64bit.

Comment by Austin Haas [ 17/Mar/13 8:50 PM ]

I don't see the issue anymore, but I believe I was using Java 1.6 when I reported it and now I am using:

$ java -version
java version "1.7.0_15"
Java(TM) SE Runtime Environment (build 1.7.0_15-b03)
Java HotSpot(TM) 64-Bit Server VM (build 23.7-b01, mixed mode)

Comment by David Nolen [ 17/Mar/13 9:02 PM ]

OK, thanks for the quick response, I'll double check how things look under 1.6.





[LOGIC-113] A conde clause that beings with a fresh expression will initially fail Created: 13/Feb/13  Updated: 28/Jul/13  Resolved: 15/Feb/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Austin Haas Assignee: David Nolen
Resolution: Declined Votes: 0
Labels: None
Environment:

tested against HEAD (0.8.0-rc3-SNAPSHOT) and CLJ 1.5.0-RC15



 Description   
(ns test                                                                                                                                                                          
  (:refer-clojure :exclude [==])                                                                                                                                                  
  (:require                                                                                                                                                                       
   [clojure.core.logic :refer :all]))                                                                                                                                             

;; This expression should evaluate to true, but it does not, 
;; because the second run* returns (2 1) instead of (1 2).
                                                                                                                                                                                  
(= (run* [q]                                                                                                                                                                      
     (conde                                                                                                                                                                       
       [(== q 1)]                                                                                                                                                                 
       [(== q 2)]))                                                                                                                                                               
   (run* [q]                                                                                                                                                                      
     (conde                                                                                                                                                                       
       [(fresh [a] (== q 1))]                                                                                                                                                     
       [(== q 2)])))


 Comments   
Comment by David Nolen [ 14/Feb/13 12:13 AM ]

This is not an error. No promises are made about the order of results. If you want need to verify that two runs are the same it's best to put the results into a set - we actually do this in the tests now.

Comment by Austin Haas [ 14/Feb/13 1:14 AM ]

Shouldn't the programmer be able to reason about the order that the clauses will be tried? That's one way to direct the search and I know at least one example in TRS highlights that aspect--in Ch. 5, unwrapo is re-written to push the recursive call down, otherwise it diverges. How could you know that goal will terminate if you can't reason about the order of the clauses? I assume it is much more difficult to write exclusively non-overlapping clauses.

Likewise, shouldn't the programmer be able to design a logic program so that it produces a predictable first result?

This is all very new to me, so please forgive me if I'm way off.

Comment by David Nolen [ 14/Feb/13 8:57 AM ]

miniKanren makes no promises about order anymore, Will actually talks about this in his dissertation. It's part of the design and leaves the door wide open for concurrent search when we get there.

Even so, I do understand there are cases where the programmer might want more control than is provided by the default behavior. Customizable search is on the roadmap.

But the current default behavior is expected and unlikely to change.

Comment by David Nolen [ 15/Feb/13 12:49 PM ]

Not a bug.





[LOGIC-112] Incorrect results with tabled resolution Created: 05/Feb/13  Updated: 28/Jul/13  Resolved: 13/Mar/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Reinout Stevens Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None
Environment:

org.clojure/clojure "1.3.0"
org.clojure/core.logic "0.8.0-rc2"


Attachments: File tabling-test.clj    
Patch: Code

 Description   

We (authors of damp.qwal and damp.ekeko) are trying to track the cause of some indeterminism with respect to the solutions to a path query over a control flow graph. To this end, we wrote a small test case that mimics the qwal part of the query. This test case works under core.logic 0.7.5, but exhibits incorrect behavior in the latest release.

The test case illustrates two problems:
First, the solutions to two logically equivalent path queries return differ. The query that uses predicate test-2 returns the correct amount of solutions (4 nodes encountered on the single path through a graph).
The query that uses predicate test-1 returns just 2 nodes.

damp.tabling-test> (test-1)
(:baz :quux)
damp.tabling-test> (test-2)
(:foo :bar :baz :quux)

Both queries skip an arbitrary number of nodes (using patho), capture a node to obtain a solution (through unification), and skip an arbitrary number of nodes.
The predicates only differ in the last step: either this is achieved by including 'patho' as the last element in the last that is passed to solve-goals, or by calling 'patho' separately after the call to solve-goals. Logic-wise, both queries should be equivalent. Note that omitting 'tabled' from the definition of 'patho' causes the tests to behave as expected.

Second, we encountered a minor issue concerning the number of results returned by the faulty query. This sometimes changes when the file is recompiled.

damp.tabling-test> (test-1)
(:quux)
;;recompile
damp.tabling-test> (test-1)
(:baz :quux)

More comments can be found in the code for the test case that is attached.



 Comments   
Comment by David Nolen [ 13/Feb/13 3:10 PM ]

Ok, I've confirmed the issue. Will look into it.

Comment by David Nolen [ 11/Mar/13 8:37 AM ]

I believe I have found the issue as well as the source of the nondeterminism. When we switched to sets away from lists for the cache I didn't fully think through the implications. The nondeterminism arises from the use of sets. We actually want a hybrid cache datatype that works like a list but can efficiently check for the existence of a cached answer w/o scanning the list.

Comment by David Nolen [ 13/Mar/13 8:51 AM ]

fixed, http://github.com/clojure/core.logic/commit/53cbfca4b7062e09d7c7ff43fccec70e46d36ea1





[LOGIC-111] conda expression that no longer works in rc2 Created: 04/Feb/13  Updated: 28/Jul/13  Resolved: 13/Feb/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   
(run* [x]
  (conda 
    [succeed
      (project [x] succeed)
      (project [x] succeed)]))

This is issue was reported by the damp.ekeko developers.



 Comments   
Comment by David Nolen [ 13/Feb/13 2:56 PM ]

I'm surprised this one has gone unnoticed for so long, both conda and condu implementation were incorrect for the unit case. Fixed in master: http://github.com/clojure/core.logic/commit/1d1724bc66b344551619c32331393a811fe7714a





[LOGIC-110] Allow anonymous constraints Created: 04/Feb/13  Updated: 28/Jul/13  Resolved: 04/Feb/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Kevin Lynagh Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File 7ef6256a0e36888e0539b56d489a75dcf6072d70.patch     Text File anon-constraints.patch     Text File anon-constraints.patch    
Patch: Code and Test

 Description   

Add `fnc` macro that defines anonymous constraints.
Rename `defc` to `defnc` for consistency.



 Comments   
Comment by David Nolen [ 04/Feb/13 11:36 AM ]

Can we get a squashed patch please? Thanks!

Comment by Kevin Lynagh [ 04/Feb/13 11:57 AM ]

Update with squashed patch.

Comment by Kevin Lynagh [ 04/Feb/13 3:17 PM ]

Sorry about that---exported a bad squashed patch earlier. This latest one passes all tests.

Comment by David Nolen [ 04/Feb/13 4:03 PM ]

fixed, http://github.com/clojure/core.logic/commit/f015355c6cc375294c7b6a4b29565b62f0a68e27





[LOGIC-109] custom defc constraint does not run Created: 28/Jan/13  Updated: 28/Jul/13  Resolved: 29/Jan/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Kevin Downey Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

I have a custom constrain defined using defc, it looks like

(defc string-containsc [x y]
  (and (string? x)
       (.contains x y)))

I have a little core.logic program

(defn t []
  (logic/run* [q]
    (c/string-containsc q "foo")
    (logic/== q 1)))

the result of calling t is (1)

if I change the order of the goals:

(defn t []
  (logic/run* [q]
    (logic/== q 1)
    (c/string-containsc q "foo")))

the result of (t) is ()



 Comments   
Comment by David Nolen [ 28/Jan/13 10:50 PM ]

Possible fix in master, http://github.com/clojure/core.logic/commit/c0a5ea982624c9e9af869be0b653bf83f60de062

Does this work for you?

Comment by Kevin Downey [ 29/Jan/13 11:07 AM ]

yep, thanks

Comment by David Nolen [ 29/Jan/13 11:26 AM ]

fixed





[LOGIC-108] featurec or something similar to provide recursive partial partial map constraints Created: 24/Jan/13  Updated: 28/Jul/13  Resolved: 17/Mar/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Kevin Downey Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Comments   
Comment by David Nolen [ 24/Jan/13 3:58 PM ]

Basically, it should be ok for the `fs` argument to a be a nested map.

Comment by Kevin Downey [ 26/Jan/13 6:03 PM ]

the following seems to be pretty close:

    (defn rfeaturec [m f]
      (let [new-f (reduce (fn [m [k v]]
                            (assoc m k (logic/lvar (name k)))) {} (seq f))]
        (logic/fresh []
          (logic/featurec m new-f)
          (fn [s]
            (logic/to-stream
              (for [[k lvar] new-f]
                ((let [v (get f k)]
                   (if (map? v)
                     (logic/fresh [x]
                       (logic/featurec m {k lvar})
                       (rfeaturec lvar v))
                     (logic/== lvar v))) s)))))))
Comment by Kevin Downey [ 27/Jan/13 12:13 AM ]

the above falls apart quickly under use, the below works well so far:

(defn rfeaturec [m f]
  (let [new-f (reduce (fn [m [k v]] (assoc m k (logic/lvar (name k)))) {} (seq f))]
    (logic/fresh []
      (logic/featurec m new-f)
      (logic/everyg
       (fn [[k lvar]]
         (let [v (get f k)]
           (if (map? v)
             (logic/fresh []
               (logic/featurec m {k lvar})
               (rfeaturec lvar v))
             (logic/== lvar v))))
       new-f))))
Comment by David Nolen [ 27/Jan/13 6:43 PM ]

recursive featurec should work by recursively applying constraints like you've done but by using the lower level apis - we don't want to put the search language into a constraint.

Comment by David Nolen [ 17/Mar/13 7:50 PM ]

fixed, http://github.com/clojure/core.logic/commit/d5eda7d7f89443b449d7955a76e72828561082f6





[LOGIC-107] Less dependencies for non-dev environments? Created: 22/Jan/13  Updated: 28/Jul/13  Resolved: 22/Jan/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Jeroen van Dijk Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: feedback


 Description   

I am considering using core.logic, but after looking into its dependencies I am hesitating. Should I really pull in datomic and google closure if I just want to use core.logic in a normal Clojure project?



 Comments   
Comment by Jeroen van Dijk [ 22/Jan/13 10:28 AM ]

Sorry I think I spoke to soon. When I include core.logic in my project it doesn't pull in other dependencies, I have been misled by the project.clj of core.logic which declares Google closure and datomic as dependencies.

Apologies for the disturbance and thanks for a great library.

Comment by David Nolen [ 22/Jan/13 10:37 AM ]

Yes the project.clj is for development purposes only. It's not used to resolve dependencies.





[LOGIC-106] cannot use fresh/conde in the invoke of a constraint Created: 20/Jan/13  Updated: 28/Jul/13  Resolved: 21/Jan/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Nada Amin Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

This means that we cannot really emulate modes with constraints. The problem is related to -inc.

An easy way to try it out is to have a dummy fresh goal in predc and see the failing tests.

@@ -2932,7 +2932,7 @@
        (invoke [this a]
          (let [x (walk a x)]
            (when (p x)
-             ((remcg this) a))))
+             (bind* a (fresh [y] (== x x)) (remcg this)))))
        IConstraintOp
        (rator [_] (if (seq? pform)
                     `(predc ~pform)


 Comments   
Comment by David Nolen [ 20/Jan/13 7:55 PM ]

Sorry I didn't mean to suggest this approach. In general you cannot put search related operators into a constraint. In fact I think we should replace any instances of bind* and bind in constraint logic as they really are a part of the search infrastructure and I'd like them to become implementation details of a particular search approach.

Instead I meant to suggest that the disjunction expressed by your example

(run 1 [re]
  (forall [s o]
    (conde
      [(== s '(foo bar bar bar))
       (== o regex-BLANK)]
      [(!= s '(foo bar bar bar))
       (== o regex-NULL)])
    (regex-matcho re s o)))

Is perhaps best described as an explicit constraint something more like:

(defn regexc [s o]
  (reify
    IFn
    (invoke [c a]
      (let [s (walk* a)[
        (if (= s '(foo bar bar bar))
          ((== o regex-BLANK) a)
          ((== o regex-NULL) a)))))
    ...
    IRunnable
    (runnable? [c a]
      (ground-terms? x))
    ...))

Of course someone might want to write constraint like this quite often, then I think it's question of what the best way to support that might be.

Comment by David Nolen [ 21/Jan/13 11:56 AM ]

No plans to add support for search operators in constraints in the near future.





[LOGIC-105] java.lang.IllegalArgumentException: No single method: _id of interface: clojure.core.logic.IConstraintId found for function: -id of protocol: IConstraintId Created: 17/Jan/13  Updated: 28/Jul/13  Resolved: 18/Jan/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Timo Westkämper Assignee: David Nolen
Resolution: Declined Votes: 0
Labels: None
Environment:

java version "1.6.0_26"
Java(TM) SE Runtime Environment (build 1.6.0_26-b03)
Java HotSpot(TM) Server VM (build 20.1-b02, mixed mode)

Ubtunu 12.04 - 32 bit



 Description   

When compiling this project https://github.com/timowest/symbol with the master version of core.logic I run into the following stacktrace

Exception in thread "main" java.lang.IllegalArgumentException: No single method: _id of interface: clojure.core.logic.IConstraintId found for function: -id of protocol: IConstraintId, compiling:(clojure/core/logic.clj:177:5)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6566)
at clojure.lang.Compiler.analyze(Compiler.java:6360)
at clojure.lang.Compiler.analyze(Compiler.java:6321)
at clojure.lang.Compiler$IfExpr$Parser.parse(Compiler.java:2668)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6559)
at clojure.lang.Compiler.analyze(Compiler.java:6360)
at clojure.lang.Compiler.analyze(Compiler.java:6321)
at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5707)
at clojure.lang.Compiler$FnMethod.parse(Compiler.java:5138)
at clojure.lang.Compiler$FnExpr.parse(Compiler.java:3750)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6557)
at clojure.lang.Compiler.analyze(Compiler.java:6360)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6547)
at clojure.lang.Compiler.analyze(Compiler.java:6360)
at clojure.lang.Compiler.access$100(Compiler.java:37)
at clojure.lang.Compiler$DefExpr$Parser.parse(Compiler.java:528)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6559)
at clojure.lang.Compiler.analyze(Compiler.java:6360)
at clojure.lang.Compiler.analyze(Compiler.java:6321)
at clojure.lang.Compiler.eval(Compiler.java:6622)
at clojure.lang.Compiler.load(Compiler.java:7062)
at clojure.lang.RT.loadResourceScript(RT.java:361)
at clojure.lang.RT.loadResourceScript(RT.java:352)
at clojure.lang.RT.load(RT.java:431)
at clojure.lang.RT.load(RT.java:402)
at clojure.core$load$fn__5039.invoke(core.clj:5520)
at clojure.core$load.doInvoke(core.clj:5519)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5326)
at clojure.core$load_lib$fn__4988.invoke(core.clj:5365)
at clojure.core$load_lib.doInvoke(core.clj:5364)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invoke(core.clj:619)
at clojure.core$load_libs.doInvoke(core.clj:5403)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:621)
at clojure.core$use.doInvoke(core.clj:5497)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at symbol.types$eval75$loading_4931auto___76.invoke(types.clj:9)
at symbol.types$eval75.invoke(types.clj:9)
at clojure.lang.Compiler.eval(Compiler.java:6618)
at clojure.lang.Compiler.eval(Compiler.java:6607)
at clojure.lang.Compiler.load(Compiler.java:7062)
at clojure.lang.RT.loadResourceScript(RT.java:361)
at clojure.lang.RT.loadResourceScript(RT.java:352)
at clojure.lang.RT.load(RT.java:431)
at clojure.lang.RT.load(RT.java:402)
at clojure.core$load$fn__5039.invoke(core.clj:5520)
at clojure.core$load.doInvoke(core.clj:5519)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5326)
at clojure.core$load_lib$fn__4988.invoke(core.clj:5365)
at clojure.core$load_lib.doInvoke(core.clj:5364)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invoke(core.clj:619)
at clojure.core$load_libs.doInvoke(core.clj:5403)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:619)
at clojure.core$require.doInvoke(core.clj:5486)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at symbol.includes_test$eval69$loading_4931auto___70.invoke(includes_test.clj:9)
at symbol.includes_test$eval69.invoke(includes_test.clj:9)
at clojure.lang.Compiler.eval(Compiler.java:6618)
at clojure.lang.Compiler.eval(Compiler.java:6607)
at clojure.lang.Compiler.load(Compiler.java:7062)
at clojure.lang.RT.loadResourceScript(RT.java:361)
at clojure.lang.RT.loadResourceScript(RT.java:352)
at clojure.lang.RT.load(RT.java:431)
at clojure.lang.RT.load(RT.java:402)
at clojure.core$load$fn__5039.invoke(core.clj:5520)
at clojure.core$load.doInvoke(core.clj:5519)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5326)
at clojure.core$load_lib$fn__4988.invoke(core.clj:5365)
at clojure.core$load_lib.doInvoke(core.clj:5364)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invoke(core.clj:619)
at clojure.core$load_libs.doInvoke(core.clj:5403)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:619)
at clojure.core$require.doInvoke(core.clj:5486)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at user$eval29$fn__50.doInvoke(NO_SOURCE_FILE:1)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:617)
at user$eval29.invoke(NO_SOURCE_FILE:1)
at clojure.lang.Compiler.eval(Compiler.java:6618)
at clojure.lang.Compiler.eval(Compiler.java:6608)
at clojure.lang.Compiler.eval(Compiler.java:6581)
at clojure.core$eval.invoke(core.clj:2852)
at clojure.main$eval_opt.invoke(main.clj:300)
at clojure.main$initialize.invoke(main.clj:319)
at clojure.main$null_opt.invoke(main.clj:354)
at clojure.main$main$fn__6676.invoke(main.clj:432)
at clojure.main$main.doInvoke(main.clj:429)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at clojure.lang.Var.invoke(Var.java:419)
at clojure.lang.AFn.applyToHelper(AFn.java:163)
at clojure.lang.Var.applyTo(Var.java:532)
at clojure.main.main(main.java:37)
Caused by: java.lang.IllegalArgumentException: No single method: _id of interface: clojure.core.logic.IConstraintId found for function: -id of protocol: IConstraintId
at clojure.lang.Compiler$InvokeExpr.<init>(Compiler.java:3422)
at clojure.lang.Compiler$InvokeExpr.parse(Compiler.java:3629)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6561)
... 99 more
Subprocess failed



 Comments   
Comment by David Nolen [ 17/Jan/13 3:20 PM ]

Can you try again with master? What do you mean by "compiling" the project? Are you AOT'ing your project?

Comment by Timo Westkämper [ 17/Jan/13 3:23 PM ]

Still the same issue. I am running 'lein midje'.

Comment by David Nolen [ 17/Jan/13 3:30 PM ]

So you are testing with Midje? Is there anyway to confirm that this issue exists if you take Midje out of the picture? Can you run the tests manually via the REPL?

The error is very puzzling since I've tested the inclusion of core.logic 0.8.0-rc2 with some other projects.

Comment by Timo Westkämper [ 17/Jan/13 3:31 PM ]

Here is the new stacktrace

Exception in thread "main" java.lang.IllegalArgumentException: No single method: _id of interface: clojure.core.logic.IConstraintId found for function: -id of protocol: IConstraintId, compiling:(clojure/core/logic.clj:169:5)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6566)
at clojure.lang.Compiler.analyze(Compiler.java:6360)
at clojure.lang.Compiler.analyze(Compiler.java:6321)
at clojure.lang.Compiler$IfExpr$Parser.parse(Compiler.java:2668)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6559)
at clojure.lang.Compiler.analyze(Compiler.java:6360)
at clojure.lang.Compiler.analyze(Compiler.java:6321)
at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5707)
at clojure.lang.Compiler$FnMethod.parse(Compiler.java:5138)
at clojure.lang.Compiler$FnExpr.parse(Compiler.java:3750)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6557)
at clojure.lang.Compiler.analyze(Compiler.java:6360)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6547)
at clojure.lang.Compiler.analyze(Compiler.java:6360)
at clojure.lang.Compiler.access$100(Compiler.java:37)
at clojure.lang.Compiler$DefExpr$Parser.parse(Compiler.java:528)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6559)
at clojure.lang.Compiler.analyze(Compiler.java:6360)
at clojure.lang.Compiler.analyze(Compiler.java:6321)
at clojure.lang.Compiler.eval(Compiler.java:6622)
at clojure.lang.Compiler.load(Compiler.java:7062)
at clojure.lang.RT.loadResourceScript(RT.java:361)
at clojure.lang.RT.loadResourceScript(RT.java:352)
at clojure.lang.RT.load(RT.java:431)
at clojure.lang.RT.load(RT.java:402)
at clojure.core$load$fn__5039.invoke(core.clj:5520)
at clojure.core$load.doInvoke(core.clj:5519)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5326)
at clojure.core$load_lib$fn__4988.invoke(core.clj:5365)
at clojure.core$load_lib.doInvoke(core.clj:5364)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invoke(core.clj:619)
at clojure.core$load_libs.doInvoke(core.clj:5403)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:621)
at clojure.core$use.doInvoke(core.clj:5497)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at symbol.types$eval75$loading_4931auto___76.invoke(types.clj:9)
at symbol.types$eval75.invoke(types.clj:9)
at clojure.lang.Compiler.eval(Compiler.java:6618)
at clojure.lang.Compiler.eval(Compiler.java:6607)
at clojure.lang.Compiler.load(Compiler.java:7062)
at clojure.lang.RT.loadResourceScript(RT.java:361)
at clojure.lang.RT.loadResourceScript(RT.java:352)
at clojure.lang.RT.load(RT.java:431)
at clojure.lang.RT.load(RT.java:402)
at clojure.core$load$fn__5039.invoke(core.clj:5520)
at clojure.core$load.doInvoke(core.clj:5519)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5326)
at clojure.core$load_lib$fn__4988.invoke(core.clj:5365)
at clojure.core$load_lib.doInvoke(core.clj:5364)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invoke(core.clj:619)
at clojure.core$load_libs.doInvoke(core.clj:5403)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:619)
at clojure.core$require.doInvoke(core.clj:5486)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at symbol.includes_test$eval69$loading_4931auto___70.invoke(includes_test.clj:9)
at symbol.includes_test$eval69.invoke(includes_test.clj:9)
at clojure.lang.Compiler.eval(Compiler.java:6618)
at clojure.lang.Compiler.eval(Compiler.java:6607)
at clojure.lang.Compiler.load(Compiler.java:7062)
at clojure.lang.RT.loadResourceScript(RT.java:361)
at clojure.lang.RT.loadResourceScript(RT.java:352)
at clojure.lang.RT.load(RT.java:431)
at clojure.lang.RT.load(RT.java:402)
at clojure.core$load$fn__5039.invoke(core.clj:5520)
at clojure.core$load.doInvoke(core.clj:5519)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5326)
at clojure.core$load_lib$fn__4988.invoke(core.clj:5365)
at clojure.core$load_lib.doInvoke(core.clj:5364)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invoke(core.clj:619)
at clojure.core$load_libs.doInvoke(core.clj:5403)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:619)
at clojure.core$require.doInvoke(core.clj:5486)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at user$eval29$fn__50.doInvoke(NO_SOURCE_FILE:1)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:617)
at user$eval29.invoke(NO_SOURCE_FILE:1)
at clojure.lang.Compiler.eval(Compiler.java:6618)
at clojure.lang.Compiler.eval(Compiler.java:6608)
at clojure.lang.Compiler.eval(Compiler.java:6581)
at clojure.core$eval.invoke(core.clj:2852)
at clojure.main$eval_opt.invoke(main.clj:300)
at clojure.main$initialize.invoke(main.clj:319)
at clojure.main$null_opt.invoke(main.clj:354)
at clojure.main$main$fn__6676.invoke(main.clj:432)
at clojure.main$main.doInvoke(main.clj:429)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at clojure.lang.Var.invoke(Var.java:419)
at clojure.lang.AFn.applyToHelper(AFn.java:163)
at clojure.lang.Var.applyTo(Var.java:532)
at clojure.main.main(main.java:37)
Caused by: java.lang.IllegalArgumentException: No single method: _id of interface: clojure.core.logic.IConstraintId found for function: -id of protocol: IConstraintId
at clojure.lang.Compiler$InvokeExpr.<init>(Compiler.java:3422)
at clojure.lang.Compiler$InvokeExpr.parse(Compiler.java:3629)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6561)
... 99 more
Subprocess failed

Comment by Timo Westkämper [ 17/Jan/13 3:32 PM ]

Yes, same via repl

tiwe@tiwe:~/work/workspace/symbol$ lein repl
nREPL server started on port 55271
REPL-y 0.1.0-beta10
Clojure 1.5.0-RC2
Exit: Control+D or (exit) or (quit)
Commands: (user/help)
Docs: (doc function-name-here)
(find-doc "part-of-name-here")
Source: (source function-name-here)
(user/sourcery function-name-here)
Javadoc: (javadoc java-object-or-class-here)
Examples from clojuredocs.org: [clojuredocs or cdoc]
(user/clojuredocs name-here)
(user/clojuredocs "ns-here" "name-here")
CompilerException java.lang.IllegalArgumentException: No single method: _id of interface: clojure.core.logic.IConstraintId found for function: -id of protocol: IConstraintId, compiling:(clojure/core/logic.clj:169:5)
reply.eval-modes.nrepl=>

Comment by David Nolen [ 17/Jan/13 3:41 PM ]

OK, I just cloned your repo and switched the dependencies to Clojure 1.5.0-RC2 and core.logic 0.8.0-rc2. I can run lein repl without a hitch. While it's a bit obnoxious have you tried blowing away your maven cache and trying again? Perhaps there are other changes that aren't in your master branch on GitHub?

Comment by Timo Westkämper [ 17/Jan/13 3:51 PM ]

Yes, sorry, I forgot to push some changes. Could you pull and try again?

Comment by David Nolen [ 17/Jan/13 3:55 PM ]

I still cannot reproduce after pulling from master. I note that your repl prompt looks a bit different from mine however - "reply.eval-modes.nrepl=>", whereas I have "symbol.main=>"

Comment by Timo Westkämper [ 18/Jan/13 2:41 AM ]

It looks like this was caused by a too old version of clojure on my machine. I didn't realize lein uses the clojure version I have installed on Ubuntu for compilation instead of the version mentioned in project.clj.

Comment by David Nolen [ 18/Jan/13 9:53 AM ]

Thanks for the update, closing this one!





[LOGIC-104] -merge-doms for ::nom is not closed under composition Created: 11/Jan/13  Updated: 28/Jul/13  Resolved: 11/Jan/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Nada Amin Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: File logic-104.diff    

 Description   
(run* [q]
  (nom/fresh [a b c d]
    (fresh [x y z]
      (== (nom/tie a (nom/tie b y)) (nom/tie b (nom/tie a x)))
      (== (nom/tie c (nom/tie d x)) (nom/tie d (nom/tie c z)))
      (== x y)
      (== z x))))

The snippet above fails with a no implementation of method -merge-doms for LazySeq, because -merge-doms for ::nom is implemented for vectors but returns a lazy seq, not a vector.

The simplest fix is to change `concat` to `into` in the -merge-doms implementation of nominal.clj. However, while I am at it, I will replace the vector with a set, which makes more sense given how it's used anyways.

Patch will be attached shortly.



 Comments   
Comment by Nada Amin [ 11/Jan/13 7:59 AM ]

Patch logic-104.diff contains improved ::nom dom representation and test for this bug.

Comment by David Nolen [ 11/Jan/13 8:35 AM ]

fixed, http://github.com/clojure/core.logic/commit/9f0f0c70b9d02cabe7ac1dd0d10106d84e7c3870





[LOGIC-103] another non-termination case with CLP(FD) Created: 10/Jan/13  Updated: 28/Jul/13  Resolved: 10/Jan/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   
(run 2 [q]
  (fresh [a b s p]
    (infd a b (interval 2 99))
    (<=fd b a)
    (+fd a b s)
    (*fd a b p)
    (== q [a b s p])))

It's strange that we don't get the next possibility.



 Comments   
Comment by David Nolen [ 10/Jan/13 5:37 PM ]

fixed, http://github.com/clojure/core.logic/commit/e882be8dce190873431d61aefe89a025ab9c0cb6





[LOGIC-102] generalize the notion of hash for robustness Created: 07/Jan/13  Updated: 28/Jul/13  Resolved: 07/Jan/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Nada Amin Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: File logic-102.diff     File refactoring.diff    

 Description   

The second nom/hash throws an exception, because the nom/hash constraint is ran before the predc one.

(is (= (run* [q]
         (nom/fresh [x]
           (fresh [y]
             (predc y nom? `nom?)
             (nom/hash y x)
             (== y 'foo))))
      ()))

(is (= (run* [q]
         (nom/fresh [x]
           (fresh [y]
             (nom/hash y x)
             (predc y nom? `nom?)
             (== y 'foo))))
      ()))

Perhaps, we can generalize the notion of hash.



 Comments   
Comment by David Nolen [ 07/Jan/13 10:52 AM ]

Hmm but why throw in nom/hash like that instead of just failing?

Comment by David Nolen [ 07/Jan/13 10:59 AM ]

Closed wrong ticket

Comment by Nada Amin [ 07/Jan/13 11:11 AM ]

ok, seems reasonable to fail.

The fix to logic-101 is not entirely satisfactory, because we can now get constraints like _1#[_1]. so i think i also want to not use predc (but still use fixc), but have a custom constraint instead of the predc that takes the two rands into account.

implementing this now.

Comment by Nada Amin [ 07/Jan/13 12:39 PM ]

The patch logic-102.diff gives up on predc and fixc, and instead does a lot of ugly special-casing to cover the new TDD test cases.

Not too happy about this change...

Comment by David Nolen [ 07/Jan/13 1:23 PM ]

Is there something we could do to make it easier to rely on `fixc` and `predc`? Or is there some lacking feature of constraints?

Comment by David Nolen [ 07/Jan/13 1:52 PM ]

Also if you're OK w/ this patch, more than happy to move forward w/ this for now and it can be improved later.

Comment by Nada Amin [ 07/Jan/13 2:38 PM ]

OK, as discussed, please go ahead with the patch, and I'll think of some alternatives / refactoring soon.

Comment by David Nolen [ 07/Jan/13 7:06 PM ]

fixed, http://github.com/clojure/core.logic/commit/417246ad0d854f9f82ae3b5aeb566ea00249eb2c

Comment by Nada Amin [ 08/Jan/13 7:04 AM ]

refactoring.diff refactors the logic a bit. Hopefully it's more readable.

For now, it seems too much trouble for the gain to generalize hash or try to write it using more primitive constraints.

Comment by David Nolen [ 08/Jan/13 7:12 AM ]

Makes sense will apply later today.

Comment by Nada Amin [ 11/Mar/13 12:27 PM ]

I am going to apply the refactoring to master.

Comment by Nada Amin [ 11/Mar/13 12:30 PM ]

Applied in https://github.com/clojure/core.logic/commit/43d325bd8e3770f3483cc8be7d332adfae3a6a96





[LOGIC-101] nom/hash and variable noms Created: 07/Jan/13  Updated: 28/Jul/13  Resolved: 07/Jan/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Nada Amin Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: File logic-101.diff    

 Description   

It would be nice if nom/hash handled variable noms:

(run* [q]
  (nom/fresh [x]
    (fresh [y]
      (nomo y)
      (nom/hash y x)
      (== x y)))

This returns '(_0) instead of (). Fortunately, a work-around is to use != instead of nom/hash when comparing two noms. However, it's bad that this silently does something unexpected.



 Comments   
Comment by Nada Amin [ 07/Jan/13 8:05 AM ]

logic-101.diff has workaround + test.

Comment by David Nolen [ 07/Jan/13 8:34 AM ]

fixed, http://github.com/clojure/core.logic/commit/770e027858bde711121abb9267854966a4dd92ed





[LOGIC-100] pruning of unsatisfiable non-ground disequalities Created: 07/Jan/13  Updated: 28/Jul/13  Resolved: 07/Jan/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Nada Amin Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: File logic-100.diff     File logic-100-rebase.diff    

 Description   

Not sure whether we actually want to do anything about this.

When running this snippet,

(run* [q]
  (fresh [a b]
    (== q [a b])
    (!= a q)))

we get the result:

(([_0 _1] :- (!= (_0 [_0 _1]))))

The reified != constraint is arguably spurious, because of the occurs-check.

Even if we instantiate the a:

(run* [q]
  (fresh [a b]
    (== q [a b])
    (!= a q)
    (== a 1)))

we get the result:

(([1 _0] :- (!= (1 [1 _0]))))

while there is no way the != constraint can be satisfied.

Thoughts?



 Comments   
Comment by Nada Amin [ 07/Jan/13 7:25 AM ]

logic-100.diff contains a hackish fix: use unify instead of not= to deal with non-ground terms. Also, don't add the constraint if you know that some pairs cannot be unified upfront (this is needed b/c disunify and unify are not consistent wrt occurs-check).

Comment by David Nolen [ 07/Jan/13 8:37 AM ]

Well it is possible to disable occurs-check. Why can't we just use the existing occurs-check fn to do this work?

Comment by Nada Amin [ 07/Jan/13 9:35 AM ]

There are two issues. The first one is that it's too conservative to just prune != constraints by checking that ground term pairs are not=, because [1 w] and [2 z] should also be pruned. Here is an extra test case illustrating this:

(deftest test-logic-100-disequality-3
  (is (= (run* [q]
           (fresh [x y w z]
             (== x [1 w])
             (== y [2 z])
             (!= x y)))
        '(_0)))
  (is (= (run* [q]
           (fresh [x y w z]
             (!= x y)
             (== x [1 w])
             (== y [2 z])))
        '(_0))))

On master, the second one fails b/c it has the extra constraint

(!= ([1 _1] [2 _2]))

which we ought to prune.

The second issue is that disunify does not take the occurs-check into account, so it can create a !=c that is not considered runnable, but if run, would be rightly pruned by the new unify clause (if the occurs-check is enabled).

Comment by David Nolen [ 07/Jan/13 10:39 AM ]

Ok, makes sense. Can we get a new patch using master. This one doesn't apply anymore. Thanks!

Comment by Nada Amin [ 07/Jan/13 10:50 AM ]

logic-100-rebase.diff is a new patch against master. I also added the extra tests discussed above.

Comment by David Nolen [ 07/Jan/13 11:00 AM ]

fixed, http://github.com/clojure/core.logic/commit/770e027858bde711121abb9267854966a4dd92ed





[LOGIC-99] StackOverflow for large `appendo` Created: 05/Jan/13  Updated: 07/Jan/13

Status: In Progress
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None


 Description   
(def l (range 0 2000))
(run* [q] (appendo l l q))

Stacktrace

user=> (def l (range 0 2000))
#'user/l
user=> (run* [q] (appendo l l q))
StackOverflowError   clojure.core.logic.LVar (logic.clj:1307)
user=> (pst)
StackOverflowError 
    clojure.core.logic.LVar (logic.clj:1307)
    clojure.lang.KeywordLookupSite$1.get (KeywordLookupSite.java:45)
    clojure.core.logic.LVar (logic.clj:1325)
    clojure.lang.Util.equiv (Util.java:32)
    clojure.lang.PersistentHashMap$BitmapIndexedNode.find (PersistentHashMap.java:601)

    clojure.lang.PersistentHashMap$ArrayNode.find (PersistentHashMap.java:370)
    clojure.lang.PersistentHashMap$ArrayNode.find (PersistentHashMap.java:370)
    clojure.lang.PersistentHashMap.entryAt (PersistentHashMap.java:133)
    clojure.lang.RT.find (RT.java:720)
    clojure.core/find (core.clj:1432)
    clojure.core.logic.Substitutions (logic.clj:1134)
    clojure.core.logic/walk*/fn--2847 (logic.clj:1005)


 Comments   
Comment by David Nolen [ 05/Jan/13 2:44 PM ]

I cannot recreate on my machine but should try a large N & wait and see.





[LOGIC-98] nominal unification misses after-the-fact fd constraints Created: 05/Jan/13  Updated: 28/Jul/13  Resolved: 11/Jan/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Nada Amin Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: File logic-98.diff     File logic-98-nominal.diff    

 Description   

Related to http://dev.clojure.org/jira/browse/LOGIC-92, these two snippets both return (nom/tie 'a_0 1) instead of three results for 1, 2, 3.

(run* [q]
  (nom/fresh [a b c]
    (fresh [x y]
      (== (nom/tie b (nom/tie a x)) (nom/tie c q))
      (infd x (interval 1 3)))))

(run* [q]
  (nom/fresh [a b c]
    (fresh [x y]
      (infd y (interval 1 3))
      (== (nom/tie b (nom/tie a x)) (nom/tie c q))
      (== x y))))


 Comments   
Comment by Nada Amin [ 08/Jan/13 4:24 AM ]

logic-98.diff fixes this by forcing all nom-related vars at once.

Do you have any ideas for separating the concern, so that force-ans doesn't need to know about ::nom?

Comment by David Nolen [ 08/Jan/13 6:32 AM ]

Will need to think about this some more.

Comment by Nada Amin [ 08/Jan/13 2:33 PM ]

Ouch! Here is a snippet that doesn't do the right thing, even with the patch:

(run* [q]
  (nom/fresh [a b c d]
    (fresh [x y z]
      (== (nom/tie b (nom/tie a x)) (nom/tie c z))
      (infd x (interval 1 3))
      (== (nom/tie d q) z))))

It returns only (1) instead of (1 2 3).

Comment by Nada Amin [ 11/Jan/13 10:07 AM ]

logic-98-nominal.diff is a solution that works for all three test cases above by simply making core.logic.nominal aware of ::fd and updating the doms when appropriate.

Comment by David Nolen [ 11/Jan/13 10:49 AM ]

fixed, http://github.com/clojure/core.logic/commit/ef27fa3ed2381f3ad4685d4bc59a298646a4febb

It would be nice if nominal didn't need to know about fd, as there will be other "enumerable" domains in the future. But this works great for now.





[LOGIC-97] disequality pruning Created: 04/Jan/13  Updated: 28/Jul/13  Resolved: 04/Jan/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Nada Amin Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: File diseq-pruning.diff    

 Description   

Why we need disequality pruning in updatec:

(run* [q]
           (fresh [x y z]
             (!= x [y])
             (== x [z])
             (== y 'foo)
             (== z 'bar)))

Instead of returning just '(_0), this snippet returns '((_0 :- (!= ([bar] [foo])))).



 Comments   
Comment by Nada Amin [ 04/Jan/13 1:02 PM ]

Patch diseq-pruning.diff gives up on using updatec in favor of correctness. Test case incuded.

Comment by David Nolen [ 04/Jan/13 1:13 PM ]

fixed, http://github.com/clojure/core.logic/commit/0beb770dc0a072f0dcb888f0df2978a5632d92bf





[LOGIC-96] relevant-var? logic incorrectly discards a vars constraint set Created: 04/Jan/13  Updated: 17/Mar/13

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Trivial
Reporter: David Nolen Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Need a patch and a test showing that the vars constraint set is preserved.



 Comments   
Comment by David Nolen [ 07/Jan/13 7:04 PM ]

Currently dead code so this is not a blocker.





[LOGIC-95] disequality Created: 04/Jan/13  Updated: 28/Jul/13  Resolved: 04/Jan/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Blocker
Reporter: Nada Amin Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: File diseq.diff    

 Description   

This snippet wrongly succeeds with the result:

(([foo _0] :- (!= (foo _0))))

(run* [q]
      (nom/fresh [a b]
        (fresh [x y]
          (!= x y)
          (== (nom/tie a (nom/tie b [b y])) (nom/tie b (nom/tie a [a x])))
          (== x 'foo)
          (== [x y] q))))

Moving the disequality anywhere further down makes the snippet rightly fail.



 Comments   
Comment by Nada Amin [ 04/Jan/13 5:47 AM ]

An insight: if I remove the -relevant-var? protocol from !=c in core.logic, then this works and all other tests pass. Of course, this probably has performance applications, so thinking of alternatives.

Comment by Nada Amin [ 04/Jan/13 8:00 AM ]

The problem is not specific to nominal disequality. Here is the same bug with only core.logic:

(run* [q]
    (fresh [x y w z]
      (!= x y)
      (!= w z)
      (== z y)
      (== x 'foo)
      (== y 'foo)))

This should fail, because x == y == 'foo, but instead we get:

(_0 :- (!= (_1 foo)) (!= (foo foo))))
.

The problem is that var-rands takes the substitution map into account, while -relevant-var doesn't.

Comment by Nada Amin [ 04/Jan/13 8:31 AM ]

Another way disequality is broken:

(run* [q]
  (fresh [x y w z]
    (!= x [y])
    (== x ['foo])
    (== y 'foo)))

This snippet should fail, but instead returns '(_0). This is because y is not returned by recover-vars.

Comment by Nada Amin [ 04/Jan/13 11:18 AM ]

diseq.diff contains detailed commit message explaining the issues, fixes, and tests.

Comment by David Nolen [ 04/Jan/13 11:23 AM ]

fixed, http://github.com/clojure/core.logic/commit/fb489298417c643fdd03efbf6951e998e6821910





[LOGIC-94] nominal, spurious nil Created: 03/Jan/13  Updated: 28/Jul/13  Resolved: 03/Jan/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Nolen Assignee: Nada Amin
Resolution: Declined Votes: 0
Labels: None


 Description   
(nth
    (run 2 [q]
      (nom/fresh [a0 a1]
        (redo* q `((~'fn ~(nom/tie a0 a0)) (~'fn ~(nom/tie a1 a1))))))
    1) ; => ((fn  [a_0] (quote ((fn  [a_1] a_1) (fn  [a_2] a_2)))) nil)


 Comments   
Comment by Nada Amin [ 03/Jan/13 6:51 PM ]

Oh, this is actually correct.
nil is a value in our mini-language, so this applies the first function to nil, but then doesn't use it, and just returns the requested result quoted.

Comment by Nada Amin [ 03/Jan/13 6:51 PM ]

Not a bug





[LOGIC-93] eliminate FDConstraint, use a template instead of delegation Created: 03/Jan/13  Updated: 28/Jul/13  Resolved: 17/May/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

Currently the all different goals will exhibit entailment issues since they have implementations of `IRelevant` that just return `true`.



 Comments   
Comment by David Nolen [ 07/Jan/13 7:03 PM ]

FD constraints are always forced at the end so this is not a blocker.

Comment by David Nolen [ 17/May/13 12:57 AM ]

fixed





[LOGIC-92] nominal is missing a few constraints-related tweaks Created: 02/Jan/13  Updated: 28/Jul/13  Resolved: 02/Jan/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Nada Amin Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: File nominal-infd.diff    

 Description   

These tests fail. We get only the first result.

(is (= (run* [q]
           (fresh [x]
             (nom/fresh [a]
               (infd x (interval 1 3))
               (== q (nom/tie a x)))))
        [(nom/tie 'a_0 1) (nom/tie 'a_0 2) (nom/tie 'a_0 3)]))
  (is (= (run* [q]
           (nom/fresh [a b c]
             (fresh [x]
               (infd x (interval 1 3))
               (== (nom/tie b (nom/tie a x)) (nom/tie c q)))))
        [(nom/tie 'a_0 1) (nom/tie 'a_0 2) (nom/tie 'a_0 3)]))


 Comments   
Comment by Nada Amin [ 02/Jan/13 9:09 AM ]

nominal-infd.diff contains fix and tests.

Comment by David Nolen [ 02/Jan/13 9:17 AM ]

fixed, http://github.com/clojure/core.logic/commit/f973b36cb02b3b797852859f2cc2a09356157cc4





[LOGIC-91] nom/tie and spurious reification of predc constraint Created: 02/Jan/13  Updated: 28/Jul/13  Resolved: 02/Jan/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Blocker
Reporter: Nada Amin Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   
(is (= (run* [q]
           (nom/fresh [a]
             (fresh [x]
               (predc x number? `number?)
               (== x 1)
               (== (nom/tie a [a x]) q))))
        [(nom/tie 'a_0 '(a_0 1))]))
  (is (= (run* [q]
           (nom/fresh [a]
             (fresh [x]
               (== x 1)
               (predc x number? `number?)
               (== (nom/tie a [a x]) q))))
        [(nom/tie 'a_0 '(a_0 1))])) ;; false b/c of extra :- number? constraint


 Comments   
Comment by Nada Amin [ 02/Jan/13 5:07 AM ]

Implementing -force-ans in Tie

clojure.core.logic.IForceAnswerTerm
  (-force-ans [v x]
    (force-ans (:body v)))

resolves the test above, but not this one:

(is (= (run* [q]
           (nom/fresh [a b c]
             (fresh [x y]
               (== x 1)
               (predc x number? `number?)
               (== (nom/tie b (nom/tie a [a x])) (nom/tie c q)))))
        [(nom/tie 'a_0 '(a_0 1))])) ;; still false b/c of extra :- number? constraint
Comment by David Nolen [ 02/Jan/13 8:15 AM ]

This issue actually impacts any "single shot" constraint that implements `-relevant?` as simply returning `true`. The problem is that the `cgoal` constraint wrapper checks `runnable?`, runs the constraint, and then checks `relevant?` and if that's true adds the constraint even though it may very well may be entailed!

There are 6 constraints (1 of them the `defc` macro) which implement `-relevant?` as returning `true`. I think we should have more support (a protocol) for constraints which are essentially "single shot" and don't need to bother with implementing the `IRelevant` protocol.

For some background - the CLP(FD) constraints benefit most from the `IRelevant` protocol, where the constraints involve up to 3 terms and a considerable amount of propagation work may be avoided by doing some checking up front.

Comment by Nada Amin [ 02/Jan/13 8:19 AM ]

Hi David,

I have a fix proposed in pull request https://github.com/clojure/core.logic/pull/15

The idea there is that to honor single-shot constraints, we only need to honor the (remcg this) that they contain. This is only possible if they have proper ids. That's what I fix.

Let me know what you think.

Comment by David Nolen [ 02/Jan/13 8:46 AM ]

fixed, http://github.com/clojure/core.logic/commit/020f730429d71315f752ea51abad20dca896c8b0





[LOGIC-90] These three FD constraints seem to diverge with certain domains Created: 01/Jan/13  Updated: 28/Jul/13  Resolved: 01/Jan/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Blocker
Reporter: Gary Fredericks Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None
Environment:

clojure 1.5.0-beta1, core.logic 0.8.0-beta4



 Description   

This code:

(run 1 [a b c d]
     (infd a b c d (interval 0 3))
     (<fd a b)
     (<fd c d)
     (<fd d a))

returns

([2 3 0 1])
as expected. However, if we change the interval to (interval 0 4) it seems to diverge. The behavior is the same between (domain 0 1 2 3) and (domain 0 1 2 3 4).



 Comments   
Comment by David Nolen [ 01/Jan/13 1:45 PM ]

fixed, http://github.com/clojure/core.logic/commit/7ea49dffb057df6775a5b98d869bfef44ae83ec9





[LOGIC-89] Allow application again in pattern matches Created: 01/Jan/13  Updated: 15/Oct/14

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: David Nolen Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: 0.8.0


 Description   

Perhaps we can support simple function application in the following manner.

(defne substo [e new a out]
  (['(var ~a) _ _ new])
  (['(var ~y) _ _ '(var ~y)] (nom/hash a y))
  (['(app ~rator ~rand) _ _ '(app ~rator-res ~rand-res)]
     (substo rator new a rator-res)
     (substo rand new a rand-res))
  (['(lam ~(nom/tie c body)) _ _ '(lam ~(nom/tie c body-res))]
     (nom/hash c a) (nom/hash c new)
     (substo body new a body-res)))

If we have a seq in an unquote then we know we have an application. All function symbols are left alone, all arguments are considered to be fresh vars or locals.






[LOGIC-88] disequality reification is broken Created: 29/Dec/12  Updated: 28/Jul/13  Resolved: 02/Jan/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Blocker
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: 0.8.0


 Description   
(run* [q]
  (fresh [x y]
    (!= [1 x] [y 2])
    (== q [x y])))

Does not return the following expected reified value:

(([_0 _1] :- (!= [_0 2] [_1 1])))

Even more bizarre things happen with the following:

(run* [q]
  (fresh [x y z]
    (!= [1 x z] [y 2 3])
    (== q [x y])))

z leaks out in the reified value.

(run* [q]
  (fresh [x y z]
    (!= [1 x z] [y 2 3])
    (== q [x y z])))

We only see one var constraint in the reified value.



 Comments   
Comment by David Nolen [ 02/Jan/13 6:43 PM ]

fixed, http://github.com/clojure/core.logic/commit/5a0eb2754dc744e60ea1c4ea3460b5429685ef59





[LOGIC-87] Decomplect the narrowing of the constraint space from the search order Created: 27/Dec/12  Updated: 28/Dec/12

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Jamie Brandon Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File flexible_search.patch    
Patch: Code and Test

 Description   

From a high-level point of view a constraint solver takes a constraint space, generates a tree of narrowings of the space and runs some search algorithm on the tree. Core.logic complects the generation of this tree and the search algorithm by representing the search space as a lazy stream of the leaves of the tree. By explicitly representing the search tree we get new search algorithms, optional fair conjunction and parallel search via fork-join.

More detail: http://scattered-thoughts.net/blog/2012/12/19/search-trees-and-core-dot-logic/

Github fork: https://github.com/clojure/core.logic/pull/13

Attached is a cleaned-up patch against d68e3400472c5f745e4c13d64433459e11ba4871



 Comments   
Comment by David Nolen [ 28/Dec/12 12:41 AM ]

Thanks! Will try to find some time this weekend to do a thorough review.





[LOGIC-86] make `defc` more useful Created: 26/Dec/12  Updated: 17/Mar/13

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: David Nolen Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None


 Description   

As we start adding more constraints it's becoming clear we really want to have to specify less boiler plate. Instead of:

(defn -treec
  ([x fc cform] (-treec x fc cform nil))
  ([x fc cform _id]
     (reify
       clojure.lang.IFn
       (invoke [this a]
         (let [x (walk a x)]
           (if (tree-term? x)
             ((composeg
               (constrain-tree x
                 (fn [t a] ((treec t fc cform) a)))
               (remcg this)) a)
             ((composeg
               (fc x)
               (remcg this)) a))))
       IConstraintId
       (id [this] _id)
       IWithConstraintId
       (with-id [this _id]
         (-treec x fc cform _id))
       IConstraintOp
       (rator [_] `treec)
       (rands [_] [x])
       IReifiableConstraint
       (reifyc [_ v r a]
         (let [x (walk* r x)]
           `(treec ~x ~cform)))
       IRelevant
       (-relevant? [_ a] true)
       IRunnable
       (runnable? [_ a]
         (not (lvar? (walk a x))))
       IConstraintWatchedStores
       (watched-stores [this] #{::subst}))))

(defn treec [x fc cform]
  (cgoal (-treec x fc cform)))

We should be able to write just:

(defc treec [x fc cform]
  clojure.lang.IFn
  (invoke [this a]
    (let [x (walk a x)]
      (if (tree-term? x)
        ((composeg
          (constrain-tree x
            (fn [t a] ((treec t fc cform) a)))
          (remcg this)) a)
        ((composeg
          (fc x)
          (remcg this)) a))))
  IConstraintRands
  (rands [_] [x])
  IReifiableConstraint
  (reifyc [_ v r a]
    (let [x (walk* r x)]
      `(treec ~x ~cform))))

`defc` should intelligently fill in the details.






[LOGIC-85] another issue with predc constraint is not enforced when it could be Created: 24/Dec/12  Updated: 28/Jul/13  Resolved: 24/Dec/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Nada Amin Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

This returns ([1 1]) instead of ().

(run* [q]
  (fresh [x y]
    (predc y even? `even?)
    (predc x odd? `odd)
    (== x y)
    (== x 1)
    (== q [x y]))))


 Comments   
Comment by David Nolen [ 24/Dec/12 1:31 PM ]

This is actually related to the deeper problem also demonstrated by LOGIC-77. The problem is that cKanren checks constraints via "update-prefix" which calls "update" which calls "run-constraints*". "update" is called on the Substitution prior to unification. This creates all kinds of issues as it's during unification that we "migrate" constraints from one logic var to another.

I'm pondering eliminating "update" and moving "run-constraints*" lower into the system - perhaps at the level of "ext-no-check". A related change would be putting SubstValue smarts into "ext-no-check". For example a "ext-no-check" on a unbound constrained logic var would simply update its SubstValue. This is critical as SubstValue might contain constraint information that must be preserved.

Comment by David Nolen [ 24/Dec/12 6:14 PM ]

fixed, http://github.com/clojure/core.logic/commit/d4d4cd53edfd76c2f416bd699f4b4d914f880985





[LOGIC-84] make occurs-check a field Created: 24/Dec/12  Updated: 28/Jul/13  Resolved: 01/Jan/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

This way we can control occurs-check without worrying about laziness.



 Comments   
Comment by David Nolen [ 01/Jan/13 12:38 PM ]

fixed, http://github.com/clojure/core.logic/commit/3be00503588772c5ababd35f037a967fb00036e2





[LOGIC-83] test rel2-dup-retractions may need a fix Created: 23/Dec/12  Updated: 28/Jul/13  Resolved: 17/Mar/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Fanny Aenvie Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None
Environment:

all



 Description   

src/test/clojure/clojure/core/logic/tests.clj

function rel2-dup-retractions

parentheses may need a fix -> (== ...)

changing the expected expr from '() to '(:x) does
not make this test fail for me.

i like core.logic ... thanks for making it happen



 Comments   
Comment by David Nolen [ 17/Mar/13 7:08 PM ]

fixed, http://github.com/clojure/core.logic/commit/ae66b6fe7ff36b9fbb82edad7d227ecadd4e4af4





[LOGIC-82] conso and seq, when unifying tail later Created: 20/Dec/12  Updated: 28/Jul/13  Resolved: 20/Dec/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Nada Amin Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

These two snippets should both succeed, but the second one fails.

(run 1 [q]
  (fresh [a c]
    (conso a nil c)
    (== `(~a) c))) ;; '(_0)
(run 1 [q]
  (fresh [a b c]
    (conso a b c)
    (== b nil)
    (== `(~a) c))) ;; expected: '(_0), actual: '()


 Comments   
Comment by David Nolen [ 20/Dec/12 11:50 PM ]

It boggles the mind how this is just being discovered

Fixed, http://github.com/clojure/core.logic/commit/0c985df0236037907852f9b19c7df3ba6a607875





[LOGIC-81] predc constraint is not enforced when it could be Created: 19/Dec/12  Updated: 28/Jul/13  Resolved: 20/Dec/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Nada Amin Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: File logic-81.diff    

 Description   

The predc number constraint fails to be enforced here.

(is (= (run* [q]
           (fresh [x]
             (== q x)
             (predc q number? `number?)
             (== x "foo")))
        ())) ;; false -- actual is ((_0 :- number?))

Inverting the first two goals gives the expected result.

(is (= (run* [q]
           (fresh [x]
             (predc q number? `number?)
             (== q x)
             (== x "foo")))
        ())) ;; OK


 Comments   
Comment by Nada Amin [ 19/Dec/12 9:12 AM ]

Actually, the problem is not specific to predc. It's an issue that addcg can overwrite a precious binding. Here is another example without predc:

(is (= (run* [q]
           (fresh [x y z]
             (== q x)
             (distinctfd [q y])
             (== y x)
             (infd q x y (interval 1 3))))
        ()) ;; false -- actual is [1 2 3]

I have a fix that I'll submit shortly.

Comment by Nada Amin [ 19/Dec/12 9:20 AM ]

Let's discuss on GitHub first: https://github.com/namin/core.logic/compare/logic-81

Comment by Nada Amin [ 20/Dec/12 9:25 AM ]

logic-81.diff include fix and tests. Since the interface for the constraint store has been modified, some tests needed to be udpated.

discussion: https://github.com/clojure/core.logic/pull/14

rebase:
https://github.com/namin/core.logic/compare/logic-81-base

Comment by David Nolen [ 20/Dec/12 9:43 AM ]

fixed, http://github.com/clojure/core.logic/commit/0f7de6ed7125df65f4450d5507341a98b151001a





[LOGIC-80] add fne, anonymous version of defne Created: 18/Dec/12  Updated: 28/Jul/13  Resolved: 09/Jun/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File logic-80-3.patch    

 Comments   
Comment by Stanislas Nanchen [ 01/May/13 10:24 AM ]

The macros 'fnm' (and fn[eau]) use the optional argument :tabled after the argument list. Is it ok?

Comment by David Nolen [ 05/May/13 7:39 PM ]

tabling passed as an option is OK with me.

Also could we get tests? Thanks much!

Comment by Stanislas Nanchen [ 06/May/13 3:48 AM ]

I've used the existing pm tests to test the fne macro. you find it in the logic-80-2.patch. Is it what you had in mind?

It is not clear how I can test for tabled anonymous functions as the :tabled metadata is of the defn[x] vars.
Possibilities would be:

  • add meta-data to the function produced by the macro 'tabled';
  • let the function produced by tabled implement some interface/protocol.

what do you think?

Comment by David Nolen [ 07/May/13 10:31 PM ]

This looks good. Two things:

  • squashed patch
  • tabled anonymous goal patch
Comment by Stanislas Nanchen [ 09/May/13 1:38 AM ]

we're almost there

i do not understand what you mean. you prefer a separate patch for tabled anonymous goal?

Comment by David Nolen [ 09/May/13 8:11 AM ]

Sorry typo, I meant a test for the tabled anonymous goal. Thanks!

Comment by Stanislas Nanchen [ 10/May/13 10:51 AM ]

thanks, i'll do it asap.

Comment by Stanislas Nanchen [ 14/May/13 9:50 AM ]

Squashed Patch with tests for the fn[e] macros, normal and tabled.

Comment by Stanislas Nanchen [ 14/May/13 9:51 AM ]

so i finally got some time to look at it again. the patch is squashed and contains a test for the tabled anonymous goals; it just tests whether the macro code actually works.

Comment by David Nolen [ 17/May/13 12:53 AM ]

Thanks will take a look!

Comment by David Nolen [ 09/Jun/13 11:33 AM ]

fixed, http://github.com/clojure/core.logic/commit/a64ed2f3447bca78bb6f53244db5d5379ecd55f1





[LOGIC-79] Setting finite domain on more than two lvars using domain fn throws UnsupportedOperationException Created: 18/Dec/12  Updated: 28/Jul/13  Resolved: 20/Dec/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Frederik De Bleser Assignee: David Nolen
Resolution: Declined Votes: 0
Labels: None
Environment:

Clojure 1.4.0 , core.logic 0.8.0-beta3



 Description   

When specifying domains on more than two lvars core.logic 0.8.0-beta3 throws an UnsupportedOperationException. Here's an example:

(run* [q]
    (fresh [x y z]
        (infd x y z (domain 1 2 3))
  	    (<fd x y)
  	    (<fd y z)
        (== q [x y z])))
  • 0.8.0-beta2: nil.
  • 0.8.0-beta3: UnsupportedOperationException count not supported on this type: FiniteDomain clojure.lang.RT.countFrom (RT.java:545)
  • 0.8.0-beta4-SNAPSHOT (739ec7e): ([1 2 3]) (correct result)

I've checked and commit 07f2f6a introduced the fix, so this is possibly related to LOGIC-77.

When trying to isolate the bug I found that:

  • Using `(interval 1 3)` instead of `(domain 1 2 3)` works.
  • Using two fresh variables instead of three works:
(run* [q]
      (fresh [x y]
	      (infd x y (domain 1 2))
  	    (<fd x y)
        (== q [x y])))
;=> ([1 2])

Here's a test that checks the behavior. The test works in the latest version but fails in all commits before 07f2f6a.

(deftest test-domfd-three-lvars []
  (is (= (run* [q]
           (fresh [x y z]
           (infd x y z (domain 1 2 3))
           (<fd x y)
           (<fd y z)
           (== q [x y z])))
         '([1 2 3]))))


 Comments   
Comment by David Nolen [ 18/Dec/12 9:29 AM ]

So is there a bug in master or not? To keep tracking issues simpler, if the bug does not exist in master please don't open a ticket.

Comment by Frederik De Bleser [ 18/Dec/12 9:34 AM ]

The issue is fixed in master.

I still wanted to report it since it seems to somehow relate to LOGIC-77 – maybe I should just have added a comment there.

Sorry for the confusion.

Comment by David Nolen [ 20/Dec/12 11:51 PM ]

Not relevant to master.





[LOGIC-78] nominal unification inspired by alphaKanren Created: 16/Dec/12  Updated: 28/Jul/13  Resolved: 31/Dec/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Nada Amin Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: File nominal.diff    
Patch: Code and Test

 Description   

The new core.logic.nominal namespace implements the alphaKanren primitive fresh, tie and hash.
The tests also run the examples from the alphaKaren paper.

See https://github.com/clojure/core.logic/pull/12 for the patch in progress.

(Meta: Should I add the patch-in-progress now or wait until we finalize the review on GitHub?)



 Comments   
Comment by David Nolen [ 16/Dec/12 10:43 AM ]

We can continue discussing it on GitHub for now. Once we're both happy with it there, we can attach the patch here. Thanks.

Comment by Nada Amin [ 31/Dec/12 9:37 AM ]

nominal.diff patch with implementation + tests in own core.logic.nominal namespace.

Comment by David Nolen [ 31/Dec/12 10:14 AM ]

fixed, http://github.com/clojure/core.logic/commit/b46b8c077360095c72eaa00a6a4aa843dc9136ff





[LOGIC-77] Finite-domain vars inside a vector crash when constrained. Created: 15/Dec/12  Updated: 28/Jul/13  Resolved: 24/Dec/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Gary Fredericks Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None
Environment:

clojure 1.5.0-beta1 with core.logic 0.8.0-beta3



 Description   

I don't know a lot about the finite domain code, but it surprised me that this crashes:

(run 1 [r a b x]
  (== r [a b])
  (infd a b x (domain 1 2))
  (<fd a b)
  (firsto r x))

This was the most minimal example I could come up with.



 Comments   
Comment by David Nolen [ 15/Dec/12 7:43 PM ]

This commit http://github.com/clojure/core.logic/commit/07f2f6ac42ad13ed7476f70669b98e76a84f2455 fixes the exception. However I'm still not seeing the expected result which I believe is:

([[1 2] 1 2 1])
Comment by David Nolen [ 15/Dec/12 9:17 PM ]

This is bug results from the trickiness of aliasing of logic vars in the presence of constraints. Currently when two constrained vars are unified, we point one var to the other var and migrate the constraints. However this is not enough we also need to merge their domains - this is not currently being done.

Comment by David Nolen [ 24/Dec/12 6:14 PM ]

fixed, http://github.com/clojure/core.logic/commit/d4d4cd53edfd76c2f416bd699f4b4d914f880985





[LOGIC-76] partial-maps break the transitivity of unification Created: 14/Dec/12  Updated: 28/Jul/13  Resolved: 28/Dec/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

partial-map should never unify with fresh vars - this should be a hard error. This means partial-map functionality needs to be accessible by some other means - probably a constraint - `featurec` might be a good name for it. This way partial-maps never leak into an actual program, and users don't try to make the concrete data structure participate in unification. At the same time this does allow extracting features of interest via unification once the term (map) being checked actually becomes ground.



 Comments   
Comment by David Nolen [ 28/Dec/12 12:42 AM ]

resolved in master, functionality now available via `featurec`





[LOGIC-75] Combining maps and finite domains in core.logic returns only one result Created: 11/Dec/12  Updated: 28/Jul/13  Resolved: 12/Dec/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Frederik De Bleser Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: bug
Environment:

Clojure 1.4.0, core.logic 0.8.0-beta2



 Description   

I'm trying to combine maps with finite domains with some odd results.

A simple query using finite domains correctly returns all values:

(run* [q]
	  (fresh [x]
	    (infd x (interval 1 3))
	    (== q x)))
	
	;=> (1 2 3)

But putting this result in a map returns only the first value:

(run* [q]
	  (fresh [x]
	    (infd x (interval 1 3))
	    (== q {:foo x})))
	
	;=> ({:foo 1})

FYI this works with vectors:

(run* [q]
	  (fresh [x]
	    (infd x (interval 1 3))
	    (== q [x])))
	
	;=> ([1] [2] [3])

But lcons seems to fail as well:

(run* [q]
	  (fresh [x]
	    (infd x (interval 1 3))
	    (== q (lcons x 'foo))))
	
	;=> ((1 . foo))


 Comments   
Comment by David Nolen [ 12/Dec/12 11:53 AM ]

fixed, http://github.com/clojure/core.logic/commit/c96402f3e60b1118446b3e681d98e444e4ce417d





[LOGIC-74] Bug in conde (ClojureScript) Created: 26/Nov/12  Updated: 28/Jul/13  Resolved: 17/Mar/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Kevin De Valck Assignee: David Nolen
Resolution: Declined Votes: 0
Labels: bug
Environment:

[org.clojure/clojure "1.4.0"]
[org.clojure/core.logic "0.8.0-beta2"]



 Description   

While working on a project I found a somewhat strange behaviour. I reworked the problem in some simple predicate. Let's take this predicate foobad.

(defn foobad 
  [?bar]
  (l/project [?bar]
    (l/fresh [?var]
      (l/conde 
        [(l/== true (instance? js/Array ?bar))
          (membero ?var (seq ?bar))]))))

When running (l/run* [?f] (foobad 0)) it produces this error:

#<Error: No protocol method ISeqable.-seq defined for type number: 0>

Because 0 is not an instance of Array it should not be entering that conde clause where it tries (seq 0).

With this workaround we get a normal behaviour:

(defn foo 
  [?bar]
  (l/project [?bar]
    (l/fresh [?var]
      (l/conde 
        [(l/== true (instance? js/Array ?bar)) 
         (fresh [?s]
          (l/== ?s (seq ?bar))
          (membero ?var ?s))]))))

Running (l/run* [?f] (foo 0)) gives us (), which is what we expect.
While 0 is clearly not an instance of Array that conde clause is still executed resulting in previous error.



 Comments   
Comment by David Nolen [ 28/Dec/12 12:49 AM ]

I'm assuming this is referring the ClojureScript version of core.logic?

Comment by David Nolen [ 17/Mar/13 7:00 PM ]

This is not a bug. Goals do not delay evaluation in this way.





[LOGIC-73] Usage of c.c.l/prep can lead to a different result (compared to not using it) Created: 23/Nov/12  Updated: 28/Jul/13  Resolved: 23/Nov/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Hugo Duncan Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

Below are two expressions that differ only in the use of c.c.l/prep. When using prep there is an extra term returned, that includes a free ?a, which seems wrong, considering the second pattern should unify on the :a key.

(let [rules
      [{:pattern (partial-map (prep {:a :clojure.core.logic/not-found :x 1}))
        :production (prep {:a 1})}
       {:pattern (partial-map (prep {:a '?a :c :clojure.core.logic/not-found}))
        :production (prep {:c '(* ?a 2)})}]]
  (run* [q]
    (fresh [pattern production guards rule rule-name]
      (membero {:pattern pattern :production production} rules)
      (== {:x 1}  pattern)
      (== q production))))
  => ({:a 1} {:c (* _.0 2)})
(let [rules
      [{:pattern (partial-map {:a :clojure.core.logic/not-found :x 1})
        :production {:a 1}}
       {:pattern (partial-map {:a '?a :c :clojure.core.logic/not-found})
        :production {:c '(* ?a 2)}}]]
  (run* [q]
    (fresh [pattern production guards rule rule-name]
      (membero {:pattern pattern :production production} rules)
      (== {:x 1}  pattern)
      (== q production))))
  => ({:a 1})


 Comments   
Comment by David Nolen [ 23/Nov/12 4:34 PM ]

fixed, http://github.com/clojure/core.logic/commit/9a964d6c744433825332dd82370cb46eac7919da

Comment by Hugo Duncan [ 23/Nov/12 10:03 PM ]

The code in the prep case above contains a bug. Both the pattern and production should both be passed in a single call to prep, otherwise they end up with different logic vars. When corrected there is only one term returned when using prep.

I'm not sure what this means for the necessity or correctness of the fix.





[LOGIC-72] Unification with partial-map fails when a map contains a map value with extra keys Created: 22/Nov/12  Updated: 28/Jul/13  Resolved: 23/Nov/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Hugo Duncan Assignee: David Nolen
Resolution: Declined Votes: 0
Labels: None

Attachments: File recursive-partial-map.diff    
Patch: Code and Test

 Description   

Unification fails for partial-map when there is a partial match on a sub-map.

A failing test case:

(is (= '[#clojure.core.logic.PMap{:a {:b 2}}]
         (run* [q]
           (fresh [pm x]
             (== (partial-map {:a {:b x}}) pm)
             (== {:a {:b 2 :c 3}} pm)
             (== q pm)))))


 Comments   
Comment by Hugo Duncan [ 23/Nov/12 3:55 PM ]

As mentioned by Kevin Lynagh, this can be achieved using walk-term, and I agree the behaviour is better off being explicit.

(defn ->pmap [x]
  (if (map? x)
    (l/partial-map x)
    x))

(l/unifier target (->pmap (l/walk-term my-map ->pmap)))
Comment by David Nolen [ 23/Nov/12 3:58 PM ]

having partial-map implicitly recurse is undesirable. It's easy to achieve the desired behavior now that we have a reusable walk-term built into core.logic.





[LOGIC-71] set *reify-vars* to false for the user if the unifier is given more than 2 arguments Created: 20/Nov/12  Updated: 28/Jul/13  Resolved: 17/Mar/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   
(unifier '(?x) '(?x) '(1))

This will fail which is surprising.



 Comments   
Comment by David Nolen [ 17/Mar/13 6:47 PM ]

fixed, http://github.com/clojure/core.logic/commit/07292792bec2694dafd4bf62b1c96580d5d270d3





[LOGIC-70] support for defaults in the simple unifier Created: 19/Nov/12  Updated: 17/Mar/13

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: David Nolen Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None


 Description   

There should be a way to specify a logic var with default values. If it is not unified with something it should unify with the default provided value.






[LOGIC-69] prep does not properly recurse terms Created: 19/Nov/12  Updated: 28/Jul/13  Resolved: 21/Nov/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File logic69.patch     Text File logic69.patch    
Patch: Code and Test

 Description   
(prep {:a {:b ?c} :d ?d})

?c is not walked according to Kevin Lynagh. This should also handle complex map keys.



 Comments   
Comment by Kevin Lynagh [ 21/Nov/12 12:09 AM ]

Also available here: https://github.com/lynaghk/core.logic/tree/walk-recursive

Comment by Kevin Lynagh [ 21/Nov/12 12:13 AM ]

This patch adds prewalk recursion to IWalkTerm for map/record keys and values, seqs, and vectors.
Note that logic vars within map keys isn't going to unify in the current implementation, and probably isn't a sensible thing to do anyway. Prewalk of map keys is just so that people can use core.logic's walk implementation over clojure.walk to use the IUninitialized protocol.

Comment by Kevin Lynagh [ 21/Nov/12 12:17 AM ]

(Patch updated to walk map keys. I couldn't figure out how to remove old patch in JIRA.)

Comment by David Nolen [ 21/Nov/12 8:57 AM ]

fixed, http://github.com/clojure/core.logic/commit/bd65104ec3fda79790655d4be8a9be436f2c0d54





[LOGIC-68] add Prolog meta-logical predicates bagof, setof, findall Created: 16/Nov/12  Updated: 15/Oct/14

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: David Nolen Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File 0001-LOGIC-68-Add-run-a-run-a-logic-functions-to-support-.patch    

 Description   

This can be done by annotating logic variables and embedding a run within a run by passing in the current substitution, running on it, and extracting out the reified values and unifying it back into the current substitution.



 Comments   
Comment by Aaron Brooks [ 16/Nov/12 1:23 PM ]

I'm working on understanding the answers given for this StackOverflow question:

http://stackoverflow.com/questions/7647758/prolog-findall-implementation

Comment by Aaron Brooks [ 16/Nov/12 10:02 PM ]

For discussion — Initial working patch supporting nested version of 'run-a/'run-a*. Binding symbols must match existing lvars with which vectors of all returned values will be unified.

Comment by Aaron Brooks [ 17/Nov/12 4:07 PM ]

Should we provide wrappers that emulate each of bagof, setof and findall?

I'm still not sold on the current names run-a/run-a*. "a" is really an internal implementation detail. Expect a revised patch with better names when I think of them (any ideas?).

Comment by David Nolen [ 17/Nov/12 8:32 PM ]

Yes please. Yeah I don't think the names of run-a/etc are critical - implementation details for now until we really understand the implications and it gets some use.

Comment by Aaron Brooks [ 21/Nov/12 10:51 AM ]

I'm considering simply making run/run* conditionalized on the first argument, using the nesting form if we are being called with a substitution map as the first argument.

My current understanding of bagof and findall makes me think they're not worth implementing beyond the nesting run functionality.

I'm still thinking about setof which is quite useful and will want help from the infrastructure to be fully efficient.

I'll submit a new patch after Thanksgiving.

Comment by David Nolen [ 21/Nov/12 10:57 AM ]

Excellent, thanks much.

Comment by Aaron Brooks [ 06/Dec/12 12:30 AM ]

I have not forgotten, I've just gotten swamped.

There's a small chance I'll get to this before Christmas, otherwise, it's after the new year.

Comment by Aaron Brooks [ 04/Feb/13 5:50 PM ]

After a car accident, travel to London and Morocco, getting caught up at work and getting caught up on the apparently very busy stream of core.logic activity (great work!), I'm back on this.

I found some bugs in my implementation after porting the patch forwards and realized these issues highlighted my sloppy understanding of some of the semantics I had created.

I'm fairly convinced now that we don't want to name this after run or run*. It's too much of a strain to try to make it mean the same thing in a nested context.

The current mechanism is still not quite a match for findall/bagof/setof, however, so I'm seeing what a good fit would be. I'll post meaningful thoughts for review as I have them.

Comment by David Nolen [ 13/Feb/13 1:50 PM ]

Glad to hear you're OK! No worries, will take a patch whenever you get around to one.

Comment by Aaron Brooks [ 12/Jun/13 9:03 PM ]

Having switched to Datomic which has bagof/setof type aggregation and subqueries (though the switch wasn't for those specifically) I don't know if or when I'll get back to this. Sorry!

Comment by David Nolen [ 13/Jun/13 1:36 AM ]

No worries! Glad Datomic is working out for you





[LOGIC-67] match(e/a) in ClojureScript always creates free var Created: 14/Nov/12  Updated: 28/Jul/13  Resolved: 14/Nov/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Thomas Karolski Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None
Environment:

cljsbuild 0.2.8
core.logic 0.8.0-beta2



 Description   

The following code:

(defn map-geto* [m k v]
  (matche [m]
    ([[[k v] . _]])
    ([[_ . tail]] (map-geto* tail k v))))

(run* [q] (map-geto* (seq {:title "Blub" }) :title q))

works in Clojure as expected, returning ("Blub"). However in ClojureScript I get (_.0) instead. From what I can tell, this is because within the matche clause that matches [k v], both k and v are not being matched against the upper k and v, but rather create fresh variables instead.
I can work around the issue by writing the following:

(defn map-geto* [m k v]
  (matche [m]
    ([[[k' v'] . _]] (== k k') (== v v'))
    ([[_ . tail]] (map-geto* tail k v))))

(run* [q] (map-geto* (seq {:title "Blub" }) :title q))

Is this intended behavior?



 Comments   
Comment by David Nolen [ 14/Nov/12 5:52 PM ]

fixed, http://github.com/clojure/core.logic/commit/fff0033b288a2ff80ce3bc672e1daabfa16e555b





[LOGIC-66] Add test-paths to project.clj to be able to run tests with lein2 Created: 30/Oct/12  Updated: 28/Jul/13  Resolved: 30/Oct/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Trivial
Reporter: Jeff Dik Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File 0002-project.clj-update-src-test-paths-to-run-tests-with-.patch    
Patch: Code

 Description   

Add test-paths to project.clj to be able to run tests with lein2. Also remove "src/test/clojure" from :source-paths.



 Comments   
Comment by David Nolen [ 30/Oct/12 6:39 PM ]

fixed, http://github.com/clojure/core.logic/commit/d36af9f47bf194f253ba84d68973d6b7e9a53774





[LOGIC-65] fix for corrupted rel indexes if retracting duplicate tuples Created: 30/Oct/12  Updated: 28/Jul/13  Resolved: 30/Oct/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Jeff Dik Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File 0001-fix-for-corrupted-rel-indexes-if-retracting-duplicat.patch    
Patch: Code and Test

 Description   

If a duplicate tuple is retracted from a rel, the rel indexes get corrupted, resulting in a NullPointerException when the following query is run:

(defrel rel2 ^:index e ^:index a ^:index v)
(facts rel2 [[:e1 :a1 :v1]
             [:e1 :a2 :v2]])
(retractions rel2 [[:e1 :a1 :v1]
                   [:e1 :a1 :v1]
                   [:e1 :a2 :v2]])

(deftest rel2-dup-retractions
  (is (= (run* [out]
               (fresh [e a v]
                      (rel2 e :a1 :v1)
                      (rel2 e a v)
                      (== [e a v] out))))
      '()))


 Comments   
Comment by David Nolen [ 30/Oct/12 6:37 PM ]

fixed, http://github.com/clojure/core.logic/commit/715aebfbfc95f4332d98539583fd664b92e4810f





[LOGIC-64] Support inequalities in finite domain sugar Created: 26/Oct/12  Updated: 28/Jul/13  Resolved: 27/Oct/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Brandon Bloom Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: patch, patch,

Attachments: Text File LOGIC-64-v1.patch    
Patch: Code

 Description   

The attached patch enables the follow code:

(run* [x]
  (infd x (interval 0 9))
  (eqfd (!= 6 (* 2 x))))

You can also substitute != with <, >, >=, or <=



 Comments   
Comment by David Nolen [ 27/Oct/12 11:33 AM ]

fixed, http://github.com/clojure/core.logic/commit/423639c62584c0100f295cc87c1cf2f721e986e3





[LOGIC-63] Prep's use of metadata needs to be extended to other objects in ClojureScript Created: 26/Oct/12  Updated: 28/Jul/13  Resolved: 26/Oct/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Paul deGrandis Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

The simple unifier and binding-map work great in the simple cases, but fail with more complicated unification.
The root cause is prep's use of metadata banging up against JS Objects.

For the cases that fail, see the current failing tests:
https://github.com/clojure/core.logic/blob/master/src/test/cljs/cljs/core/logic/tests.cljs#L871



 Comments   
Comment by David Nolen [ 26/Oct/12 12:42 PM ]

I still don't understand. Is it failing because it's trying to add metadata to objects which don't support that? That doesn't really make sense given the unifications that are failing that you've highlighted.

Comment by Paul deGrandis [ 26/Oct/12 12:55 PM ]

That's correct - I couldn't determine what the Object was in the code. Whatever it is, it just needs the IWithMeta protocol extended to it.

I thought you might have more insight.

Comment by David Nolen [ 26/Oct/12 12:58 PM ]

Ok will look into it.

Comment by David Nolen [ 26/Oct/12 5:53 PM ]

fixed http://github.com/clojure/core.logic/commit/371c0355f51ee35c6e71616ec2923a8242d6e4b3





[LOGIC-62] distincto bug Created: 25/Oct/12  Updated: 28/Jul/13  Resolved: 26/Oct/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   
(run 16 [q] (distincto q) (everyo #(membero % (range 3)) q))
;; returns (() [0] [1] [2] (0 0) (0 1) (1 0) (0 2) (1 1) (2 0) (1 2) (2 1) (2 2) (0 0 0) (0 0 1) (0 1 0)), incorrect


 Comments   
Comment by David Nolen [ 26/Oct/12 12:39 AM ]

fixed, http://github.com/clojure/core.logic/commit/36cd3dfabd4848bce1c57fe5147b7f6c353de1b6





[LOGIC-61] partial-map in ClojureScript does not correctly unify map members Created: 25/Oct/12  Updated: 28/Jul/13  Resolved: 26/Oct/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Paul deGrandis Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

In the most recent changes to the core.logic's CLJS support (LOGIC-60), partial-map does not correctly unify the members within the map:

(m/run* [q]
  (m/fresh [pm x]
    (m/== pm (partial-map {:a x}))
    (m/== pm {:a 1 :b 2})
    (m/== x q))))
=> (1)

but,

(m/run* [q]
  (m/fresh [pm x]
    (m/== pm (partial-map {:a x}))
    (m/== pm {:a 1 :b 2})
    (m/== pm q))))
=> (#PMap{:a <lvar:x_3>})

The latter should unify to {:a 1}



 Comments   
Comment by David Nolen [ 26/Oct/12 6:04 PM ]

fixed, http://github.com/clojure/core.logic/commit/d39fd90ae096c1a940e79ea898a9f86d4b106362





[LOGIC-60] Simple unification and partial-map support for ClojureScript Created: 25/Oct/12  Updated: 28/Jul/13  Resolved: 26/Oct/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Paul deGrandis Assignee: Paul deGrandis
Resolution: Completed Votes: 0
Labels: None

Attachments: File logic-60-simple-unification-partmap-2.diff     File logic-60-simple-unification-partmap-3.diff     File logic-60-simple-unification-partmap.diff    

 Description   

This ports over the simple unifier (and prep and binding-map) as well as the partial-map support into ClojureScript. Additionally some deprecated protocol use was patched up.



 Comments   
Comment by David Nolen [ 25/Oct/12 11:11 AM ]

This looks great but could we copy over the related tests for simple unification and partial map unification? You can run these with script/test. Thanks.

Comment by Paul deGrandis [ 25/Oct/12 12:39 PM ]

I promise to write tests from now on

I patched up one bug, noted the failing unification for partial-map (I will open a new ticket for it).

Also, prep is failing on some JS Object because of a with-meta call. See the tests for the cases where that happens. I couldn't figure it out, but I haven't hit this in my project code (I'm doing extremely simple unification and binding-map stuff).
I'll open up a new ticket for that as well.

===
edit: take version 3 - removed print statements I left in the test file

Comment by David Nolen [ 26/Oct/12 12:40 AM ]

fixed, http://github.com/clojure/core.logic/commit/e33668ff0bd76aded94b7911e498c62473e47a6f





[LOGIC-59] tabled goals should have tables local to a particular run Created: 17/Oct/12  Updated: 28/Jul/13  Resolved: 28/Dec/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

Currently tabled goals cannot be used across multiple runs which is simply awful.



 Comments   
Comment by David Nolen [ 28/Dec/12 8:35 PM ]

fixed, http://github.com/clojure/core.logic/commit/ef437d676e72dd9a30e60b31d8ee4a1dccbfdcef





[LOGIC-58] make defrecord unification easier to adopt Created: 26/Sep/12  Updated: 28/Jul/13  Resolved: 15/Dec/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Comments   
Comment by David Nolen [ 04/Oct/12 7:29 PM ]

As pointed out on the mailing list calling empty on defrecord doesn't actually make sense. defrecords are never empty in the IPersistentCollection sense, they just have their keys initialized to nil. I'm open to suggestions here.

Comment by David Nolen [ 15/Dec/12 7:19 PM ]

This was resolved a while back with the addition of the IUninitialized protocol





[LOGIC-57] poor performance when using tabling Created: 26/Sep/12  Updated: 28/Jul/13  Resolved: 26/Oct/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: File tabling.clj    

 Comments   
Comment by David Nolen [ 05/Oct/12 6:49 PM ]

The following commit http://github.com/clojure/core.logic/commit/03ad0a425c5b3b91a00142ff91e5fcd378daa682, should give a very big performance boost. The table still ends up storing a lot of redundant information, we could probably get another large boost by figuring out some way to share information when goals are recursive.





[LOGIC-56] Unification of sets does not consider all possibilities Created: 21/Sep/12  Updated: 28/Jul/13  Resolved: 27/Sep/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Aaron Brooks Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

The current unify-with-set logic will unify the first lvars it comes across, preventing backtrack unification with other lvars in the sets. See examples:

user> (run* [out]
        (fresh [a b c d]
          (== out [a b c d])
          (== #{a b} #{c d})))
([_.0 _.1 _.0 _.1])

user> (run* [out]
        (fresh [a b c d]
          (== out [a b c d])
          (== [a c] [7 9])
          (== #{a b} #{c d})))
()

I'm still thinking of a way to efficiently handle this but wanted to post it when I came across it.



 Comments   
Comment by Aaron Brooks [ 21/Sep/12 3:18 PM ]

BTW, I should note that issue was noticed by Jim Duey.

Comment by David Nolen [ 21/Sep/12 3:28 PM ]

More evidence that I probably should not have attempted unification with sets. This is why there is no support for logic vars as keys in maps - we should probably even throw in that case.

Perhaps we can support backtracking by switching complex unification of sets to a conde? Though at that point you're probably better of using lists + distincto.

Comment by Aaron Brooks [ 21/Sep/12 3:34 PM ]

Yeah, I looked at map unification and decided to punt entirely. One thing at a time.

Now is a good time to thank you, again, for core.logic. This is better to have than not.

Comment by David Nolen [ 26/Sep/12 3:22 PM ]

After some discussion with William Byrd at StrangeLoop I'm inclined to remove set unification from core.logic entirely. It turns out this is an open research problem and I find it unlikely that I'll be able to figure this one out anytime soon. Will this cause too much trouble for you all?

Note that a related change would be to throw on any maps that have logic vars as keys during unification.

Comment by Aaron Brooks [ 26/Sep/12 8:58 PM ]

This seems entirely reasonable. The complexity explodes quickly and distincto judiciously applied is far more efficient. Kill it as you wish. (Though I might suggest leaving the protocol in with no implementation so experimenters can easily extend it.)

Thanks!

Comment by David Nolen [ 27/Sep/12 9:36 AM ]

Excellent. I'll leave the protocol in, along with some fair warning about attempting it Thanks for the quick feedback.

Comment by David Nolen [ 27/Sep/12 9:39 PM ]

fixed, http://github.com/clojure/core.logic/commit/cdc4bf8563e9f566cc6e3e0e4f8a7735cd92b88e





[LOGIC-55] Unification of sets allows for duplicate values leading to non-set-like behavior Created: 21/Sep/12  Updated: 28/Jul/13  Resolved: 27/Sep/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Aaron Brooks Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

Considering this behavior:

user> (run* [out] (== 3 out) (== #{3 out} #{3 out}))
(3)

There are other more convoluted cases involving multiple lvars but I think the above is enough for discussion. I think the above behavior is at least unexpected (desiring documentation) if not actually incorrect behavior.

A possible solution would be to apply distincto (or some equivalent) to the members of each incoming set before the body of unify-with-set (extending IUnifyWithSet to clojure.lang.IPersistentSet). Naturally this makes set unification even more expensive than it currently is but I'm currently inclined to think that this additional cost is unavoidable, at least with the current approach.



 Comments   
Comment by David Nolen [ 21/Sep/12 3:19 PM ]

I probably should held off on implementing unification with sets. Oh well. The distincto approach sounds reasonable to me - would gladly take a patch.

Comment by Aaron Brooks [ 21/Sep/12 3:22 PM ]

I'll look in to that. Would you be against declaring distincto so I can use it earlier in the file? I don't recall off the top of my head but I think distincto can't be moved that early in the file and probably wants to stay where it is anyways.

Comment by David Nolen [ 27/Sep/12 9:38 PM ]

fixed, http://github.com/clojure/core.logic/commit/cdc4bf8563e9f566cc6e3e0e4f8a7735cd92b88e





[LOGIC-54] Set unification does not operate symmetrically Created: 21/Sep/12  Updated: 28/Jul/13  Resolved: 27/Sep/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Aaron Brooks Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File 0001-Fix-unify-with-set-to-work-symmetrically.patch    
Patch: Code and Test

 Description   

A check is absent in unify-with-set that would check for missing values in addition to missing lvars. The incorrect behavior is shown below:

user> (run* [out] (== #{out} #{1}))
(1)
user> (run* [out] (== #{1} #{out}))
()

The attached patch includes a similar test to the above and was run against the HEAD as of this posting.



 Comments   
Comment by David Nolen [ 21/Sep/12 2:58 PM ]

Thanks for the report will look into it.

Comment by David Nolen [ 27/Sep/12 9:38 PM ]

fixed, http://github.com/clojure/core.logic/commit/cdc4bf8563e9f566cc6e3e0e4f8a7735cd92b88e





[LOGIC-53] core.logic converts defrecords to maps in it's query results Created: 18/Sep/12  Updated: 28/Jul/13  Resolved: 02/Jan/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Blocker
Reporter: Martin Trojer Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: 0.8.0
Environment:

0.7.5 or 0.8-alpha



 Description   
(defrecord Test [a b])

(run* [q]
  (== q (->Test 1 2 )))

;; ({:a 1, :b 2})
;; Where's my record?


 Comments   
Comment by David Nolen [ 19/Sep/12 12:02 PM ]

Records are IPersistentMaps. core.logic doesn't know anything about your custom type so it returns the type it knows how to unify.

If you want core.logic to work with your record you need to implement the unification protocols for you record. But of course that's a little tedious if you have many different records.

Open to better ideas. The relevant code where this unexpected behavior occurs is the implementation of IWalkTerm for the core Clojure data types.

Comment by David Nolen [ 02/Jan/13 7:18 PM ]

fixed, http://github.com/clojure/core.logic/commit/bd3f13a1cd3214e5e15e52383b49f0a54ec8a502





[LOGIC-52] Bug in finite domains (+fd, infd) Created: 10/Sep/12  Updated: 28/Jul/13  Resolved: 26/Oct/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: naeg Assignee: David Nolen
Resolution: Completed Votes: 1
Labels: +fd, bug, finite-domains, infd
Environment:

Clojure 1.4, core.logic 0.8-alpha3



 Description   

When running the code:

(run* [q]
(fresh [a b c d]
(infd a b c d (domain 1 3 4 5))
(+fd b 1 a)
(+fd c 1 b)
(+fd d 1 c)
(== q [a b c d])))

I get the ouput:

([5 4 3 1])

But I would expect:

()

Because [5 4 3 1] is no sequence where the next element is always one number higher than the one before.

It seems to me like +fd behaves as it would take the next element in the domain, instead of taking the next higher number (I hope I didn't misunderstand +fd or infd).



 Comments   
Comment by naeg [ 11/Sep/12 4:48 PM ]

There is workaround using membero:

(run* [q]
  (fresh [a b c d]
    (everyg #(membero % [1 3 4 5]) [a b c d])
    (+fd b 1 a)
    (+fd c 1 b)
    (+fd d 1 c)
    (== q [a b c d])))

=> ()

Note that this is quite a lot slower than it would be with infd.

Comment by David Nolen [ 26/Oct/12 1:03 AM ]

This is fixed try the latest 0.8.0 beta





[LOGIC-51] fd comparison relations behave strange when used with literals Created: 07/Sep/12  Updated: 28/Jul/13  Resolved: 26/Oct/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Tassilo Horn Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None
Environment:

java version "1.7.0_07"
OpenJDK Runtime Environment (IcedTea7 2.3.2) (Gentoo build 1.7.0_07-b30)
OpenJDK 64-Bit Server VM (build 23.2-b09, mixed mode)

org.clojure/clojure "1.5.0-alpha4"
org.clojure/core.logic "0.8-alpha3"



 Description   

The fd comparison relations always succeed when used with strings or a string and an integer:

user> (run* [q]
 (<=fd "foo" "bar"))
(_.0)
user> (run* [q]
 (<=fd "foo" 1))
(_.0)
user> (run* [q]
 (<=fd 1 "bar"))
(_.0)

IMHO, they should always fail if one argument is not a integer.

Furthermore, you get an exception when comparing integers and the larger integer is given first.

user> (run* [q]
 (<=fd 1 2))
(_.0)  ;; That's correct, but...
user> (run* [q]
 (<=fd 2 1))
IllegalArgumentException No implementation of method: :member? of protocol: #'clojure.core.logic/ISet found for class: nil  clojure.core/-cache-protocol-fn (core_deftype.clj:533)

I'd expect that comparisons of two integers should always work. You can circumvent this issue by unifying the numbers with some logic variables first, but is that really needed?

user> (run* [q]
 (fresh [a b]
  (== a 1)
  (== b 2)
  (<=fd a b)))
(_.0)
user> (run* [q]
 (fresh [a b]
  (== a 1)
  (== b 2)
  (<=fd b a)))
()

The first issue cannot be circumvented using this approach, though.

user> (run* [q]
 (fresh [a b]
  (== a "foo")
  (== b 2)
  (<=fd b a)))
(_.0)
user> (run* [q]
 (fresh [a b]
  (== a "foo")
  (== b 2)
  (<=fd a b)))
(_.0)
user> (run* [q]
 (fresh [a b]
  (== a "foo")
  (== b "bar")
  (<=fd a b)))
(_.0)
user> (run* [q]
 (fresh [a b]
  (== a "foo")
  (== b "bar")
  (<=fd b a)))
(_.0)


 Comments   
Comment by David Nolen [ 07/Sep/12 11:14 AM ]

Thanks for the report will look into it.

Comment by David Nolen [ 26/Oct/12 1:06 AM ]

I see no particular need to validate inputs. The other issues should be resolved in one of the latest betas.

Comment by Tassilo Horn [ 26/Oct/12 2:01 AM ]

> I see no particular need to validate inputs.

Well, the reported behavior ("every non-integer is both smaller and greater than anything") is likely to hide bugs in queries. But hey, even if you don't see a particular need, something you did fixed that problem anyhow.

This is with 0.8.0-beta1:

user> (run* [q] (<=fd 23 "1"))
IllegalArgumentException No implementation of method: :ub of protocol: #'clojure.core.logic/IInterval found for class: java.lang.String  clojure.core/-cache-protocol-fn (core_deftype.clj:562)
user> (run* [q] (<=fd "1" 23))
IllegalArgumentException No implementation of method: :lb of protocol: #'clojure.core.logic/IInterval found for class: java.lang.String  clojure.core/-cache-protocol-fn (core_deftype.clj:562)

IMO, both an exception and simply failing would be ok in those situations. Exception like now is probably even better.

> The other issues should be resolved in one of the latest betas.

Yes, it is. Thanks a lot, David! Feel free to close this issue.

Comment by David Nolen [ 26/Oct/12 7:04 AM ]

Thanks for the update!





[LOGIC-50] Rel relation PersistentHashSet becomes LazySeq after issuing a retraction Created: 01/Sep/12  Updated: 28/Jul/13  Resolved: 05/Sep/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Aaron Brooks Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: performance

Attachments: Text File core.logic-rel-001.patch     Text File core.logic-rel-002.patch    
Patch: Code

 Description   

The first retraction of facts from a relation transforms the internal PersistentHashSet -set var+atom, which guarantees uniqueness, into a LazySeq which allows duplicate facts to be added. Once the first retraction occurs, a LazySeq persists for the rest of the life of the relation. Only the value of the primary -set var+atom is affected, not the -index var+atom values.

This issue is not an external correctness issue but does affect performance of subsequent duplicate fact additions which grow the size relation.

Preparation:

user=> (defrel foo x y)
#<user$eval4287$fn__4288 user$eval4287$fn__4288@1a9d489b>
user=> (facts foo [[:joe :man][:jane :woman][:sue :boy]])
nil
user=> foo_2-set
#<Atom@52aaf223: #{[:joe :man] [:jane :woman] [:sue :boy]}>
user=> (class @foo_2-set)
clojure.lang.PersistentHashSet
user=> (retraction foo :jane :woman)
nil

Without patch applied:

user=> foo_2-set
#<Atom@52aaf223: ([:joe :man] [:sue :boy])>
user=> (class @foo_2-set)
clojure.lang.LazySeq
user=> (facts foo [[:joe :man][:jane :woman][:sue :boy]])
nil
user=> foo_2-set
#<Atom@52aaf223: ([:sue :boy] [:jane :woman] [:joe :man] [:joe :man] [:sue :boy])>
user=> (class @foo_2-set)
clojure.lang.LazySeq

With patch applied:

user=> foo_2-set
#<Atom@31eb9b15: #{[:joe :man] [:sue :boy]}>
user=> (class @foo_2-set)
clojure.lang.PersistentHashSet
user=> (facts foo [[:joe :man][:jane :woman][:sue :boy]])
nil
user=> foo_2-set
#<Atom@31eb9b15: #{[:joe :man] [:jane :woman] [:sue :boy]}>
user=> (class @foo_2-set)
clojure.lang.PersistentHashSet

I've filed this as a Minor issue as it does not affect core.logic correctness and degraded performance can be avoided by not re-asserting duplicate facts.

I will also issue a GitHub pull request which can be used or ignored at your convenience.



 Comments   
Comment by David Nolen [ 02/Sep/12 5:45 PM ]

Thanks! Is this meant to be applied to master?

Comment by Aaron Brooks [ 03/Sep/12 6:56 PM ]

(cf. here and GitHub I'll keep this thread on JIRA.) Yes, this is targeted for master. I don't know if this warrants a release unto itself.

Comment by Aaron Brooks [ 04/Sep/12 9:17 AM ]

I forgot to mention that I needed to add "src/test/clojure" to the project.clj :source-paths vector to get lein1/2's test command to run the tests. Is that expected? Is there another way to run the tests that I'm missing? I'm happy to file a separate ticket/patch to address this if project.clj needs to be modified.

Comment by David Nolen [ 04/Sep/12 9:25 AM ]

Thanks for the information. Will apply to master. I actually run tests with "mvn test", I've updated :source-paths so other people can run the tests with lein.

Comment by David Nolen [ 04/Sep/12 9:26 AM ]

I tried to apply the patch but I'm getting a "Patch format detection failed".

Comment by Aaron Brooks [ 04/Sep/12 4:16 PM ]

The attached patch should work fine with git-apply (in either "cat foo.patch |git apply" or "git apply foo.patch" form). I made the GitHub pull request as I figured that would be the easiest path to pull the changes in.

Comment by David Nolen [ 04/Sep/12 6:04 PM ]

Yes the patch is not properly formatted and we're not supposed to take pull requests. The patch is missing attribution info. I normally apply patches with "git am foo.patch". I used the following guide for figuring out how to generate patches that can be applied with "git am", http://ariejan.net/2009/10/26/how-to-create-and-apply-a-patch-with-git.

Comment by Aaron Brooks [ 05/Sep/12 9:25 AM ]

My apologies for the extra run-around here. I've attached an -002 version of the patch created with git-format-patch which should be amenable to git-am.

Comment by David Nolen [ 05/Sep/12 11:32 AM ]

fixed, http://github.com/clojure/core.logic/commit/9bc6eb42be28bfd2b493657344f6eea8f5ed657c. pushing out a 0.8.0-alpha3 release as well.





[LOGIC-49] minimal map type for unifying only part of a map Created: 31/Aug/12  Updated: 28/Jul/13  Resolved: 12/Oct/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: File 49-partial-map.diff     File 49-partial-map.diff     Text File 49-partial-map.patch    

 Description   

currently it's a bit obnoxious that map unification must be over the entire map. It would be useful to have a new datatype - partial-map this would allow us to only match part of a map instead of the whole thing. Is this unsound?



 Comments   
Comment by Kevin Lynagh [ 12/Oct/12 12:44 PM ]

How do you feel about letting partial map have a value meaning "don't unify with a map that has a key here". E.g.,

{:a ?x :b ?y} == {:a 1 :b 2 :c 3} => {:a 1 :b 2}

but

{:a ?x :b !_} == {:a 1 :b 2 :c 3} => nil

My use case is doing map matching + rewrites and in some cases I don't want a partial-map to match a map that already has some keys defined.

Comment by David Nolen [ 12/Oct/12 1:10 PM ]

Sure, but this is a separate ticket. Also it should be expressible via a normal goal - not-has-keyo or some such. Once that's done we can think about sugar.

Comment by Kevin Lynagh [ 12/Oct/12 1:16 PM ]

Also on the Github: https://github.com/lynaghk/core.logic/tree/partial-map

Comment by Kevin Lynagh [ 12/Oct/12 1:31 PM ]

Patch without !_ sugar.

Comment by Kevin Lynagh [ 12/Oct/12 1:47 PM ]

Add patch, not diff.

Comment by David Nolen [ 12/Oct/12 1:52 PM ]

fixed, http://github.com/clojure/core.logic/commit/9b340ea4fff2f4dad50b0f9631054e713b895fe8





[LOGIC-48] fd/in should provide a default domain if none specified Created: 30/Aug/12  Updated: 17/May/13

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: David Nolen Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None


 Description   

This domain should probably be (interval 0 Long/MAX_VALUE). In order for this to work this means we should probably accept passing in the vars to assigned domains as a seqable. It would be easy to accept the current way and this new way since if the first arg is not a symbol then the new behavior is being requested.

(fd/in [x y])
(fd/in [x y z] (interval 0 10))





[LOGIC-47] is macro needs to be improved Created: 30/Aug/12  Updated: 15/Oct/14

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: David Nolen Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None


 Description   

the is macro should work like the following:

(is x (- (+ a b) c))

All locals appearing in the right expression should be walked.






[LOGIC-46] Unification on Struct Maps Causes Error Created: 02/Aug/12  Updated: 28/Jul/13  Resolved: 04/Oct/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Daniel Gregoire Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

Unless two struct maps satisfy identical?, attempting to unify on them results in an error. Consider the following:

(defstruct element :tag :attrs :content)
(def an-element (struct element :div [] "bar"))

(run* [q]
  (membero an-element (all-elements))

Results in:

java.lang.RuntimeException: Can't remove struct key
 at clojure.lang.Util.runtimeException (Util.java:156)
    clojure.lang.PersistentStructMap.without (PersistentStructMap.java:178)
    clojure.lang.RT.dissoc (RT.java:736)
    clojure.core$dissoc.invoke (core.clj:1404)
    clojure.core.logic$eval4245$fn__4246.invoke (logic.clj:1430)
    clojure.core.logic$eval2230$fn__2231$G__2221__2240.invoke (logic.clj:36)
    clojure.core.logic$eval4139$fn__4140.invoke (logic.clj:1280)
    clojure.core.logic$eval2050$fn__2051$G__2041__2060.invoke (logic.clj:18)

During unification for IPersistentMap, the two map-like arguments have the just-compared entry removed with dissoc on recursion. For struct maps, this obviously throws the above error, whereas for Clojure records it "downgrades" them to regular maps (also sub-optimal).

(Aside: I've encountered the above using Christophe Grand's Enlive library, which still uses struct maps for modeling parsed HTML/XML documents.)



 Comments   
Comment by David Nolen [ 07/Aug/12 8:48 PM ]

There is no support for unifying struct maps. Patch welcome.

Comment by David Nolen [ 27/Sep/12 9:44 PM ]

I'm considering adding a IEmptyableCollection protocol to core.logic. If you implement then we can call it when unifying maps to preserve the original type. Does this sound satisfactory?

Comment by Daniel Gregoire [ 27/Sep/12 10:16 PM ]

Per our conversation at StrangeLoop, this sounds like a nice approach, and should solve current issues both with structmaps and records.

Comment by David Nolen [ 04/Oct/12 7:20 PM ]

Fixed, http://github.com/clojure/core.logic/commit/a62e7f11f02ade156043d309dc94166c9ec581b8. The record issue will be resolved in a separate ticket.

Comment by David Nolen [ 04/Oct/12 7:30 PM ]

I refined the ticket LOGIC-58 about issues around defrecord which is really an issue around reconstructing it during reification not unification specifically.





[LOGIC-45] add everyo (?) when we want to apply a goal to every element of a sequence. Created: 31/Jul/12  Updated: 28/Jul/13  Resolved: 15/Dec/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

It's a common pattern to do the following

(defn everyo [g xs]
  (if (seq xs)
    (all
      (g (first xs))
      (everyo g (next xs)))
    succeed))

We should add this to the standard library.



 Comments   
Comment by David Nolen [ 15/Dec/12 7:21 PM ]

We have everyg now - the naming and behavior should probably go through some more consideration.





[LOGIC-44] ex* could expand macros in patterns Created: 19/Jul/12  Updated: 17/Mar/13

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Joe Osborn Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: enhancement, patch, test

Attachments: Text File exstar-macros.patch    
Patch: Code and Test

 Description   

So, tagged data structures are probably interesting in a relational context. Say you have a relation with some default logic about dogs:

(defna friendlyo [Dog-Or-Breed]
    ([:Spot] succeed)
    ([:Spike] fail)
    ([Other-Dog] (fresh [Breed] (dog-breed Other-Dog Breed) (friendlyo Breed)))
    ([(breed :miniature-dachshund)] fail)
    ([(breed :golden-retriever)] succeed)
    ;. . .)

Assume there's a (defmacro breed [t] `[:breed ~t]).

That's nicer than having to drop [:breed :golden-retriever] in there or whatever, since it's compile-time-checkable, less error-prone, reduces duplication, etc.

This little patch makes ex* expand macros in patterns so it doesn't treat e.g. (breed :golden-retriever) as introducing a new LVar called "breed". Test also provided.



 Comments   
Comment by David Nolen [ 19/Jul/12 4:41 PM ]

I'm surprised that this doesn't already work. We have support for unifying expressions in the pattern already. Look at line 1230 in tests.clj in the master branch.

So this should just work, no need to explicitly support macros as far as I can tell. If it's not working, then there's a bug.

Comment by Joe Osborn [ 19/Jul/12 5:18 PM ]

At least on 0.7.5, matching against a macro gives a runtime error:

Exception in thread "main" java.lang.ClassCastException: clojure.core.logic.LVar cannot be cast to clojure.lang.IFn
	at rl.core$glyph_$fn__123$fn__144$fn__165$fn__166$_inc__167$fn__168.invoke(core.clj:61)
	at clojure.core.logic.Substitutions.bind(logic.clj:211)
	at rl.core$glyph_$fn__123$fn__144$fn__165$fn__166$_inc__167.invoke(core.clj:58)
	at clojure.core.logic$fn__1056$_inc__1057.invoke(logic.clj:1160)
	at clojure.core.logic$fn__1056$_inc__1057.invoke(logic.clj:1160)
	at clojure.core.logic$fn__898$_inc__899.invoke(logic.clj:823)
	at clojure.core.logic$fn__890$fn__891.invoke(logic.clj:828)

Using a fn instead of a macro gives the same:

Exception in thread "main" java.lang.ClassCastException: clojure.core.logic.LVar cannot be cast to clojure.lang.IFn
	at rl.core$drawable_$fn__235$fn__248$fn__249$_inc__250$fn__251.invoke(core.clj:67)
	at clojure.core.logic.Substitutions.bind(logic.clj:211)
	at rl.core$drawable_$fn__235$fn__248$fn__249$_inc__250.invoke(core.clj:65)
	at clojure.core.logic$fn__1056$_inc__1057.invoke(logic.clj:1160)
	at clojure.core.logic$fn__894$_inc__895.invoke(logic.clj:826)
	at clojure.core.logic$fn__1056$_inc__1057.invoke(logic.clj:1160)
	at clojure.core.logic$fn__898$_inc__899.invoke(logic.clj:823)
	at clojure.core.logic$fn__898$_inc__899.invoke(logic.clj:823)
	at clojure.core.logic$fn__898$_inc__899.invoke(logic.clj:823)
	at clojure.core.logic$fn__890$fn__891.invoke(logic.clj:828)

Here's (glyph-) for reference (don't mind all the extra [], I have a weird key/value thing because of some conveniences for maintaining fact identity in a temporal database):

(defna glyph- [Key Val]
	([[Thing] [Glyph]] (thing- [Thing]) (on-fire_ *turn* [Thing]) (== Glyph \δ))
	([[Thing] [Glyph]] (thing- [Thing]) (fresh [Type] (type- [Thing] [Type]) (glyph- [Type] [Glyph])))
	([[(type-enum :player)] [Glyph]] (== Glyph \@))
	([[(type-enum :dragon)] [Glyph]] (== Glyph \D))
	([[Type] [Glyph]] (== Glyph \?)))

and type-enum as a macro:

(defmacro type-enum [v] `[:enum :type ~v])

and as a fn:

(defn type-enum [v] [:enum :type ~v])

I'll mess around and see if my example works in HEAD.

Comment by Joe Osborn [ 19/Jul/12 5:37 PM ]

Same exception with this test case in HEAD (sorry for all the facts):

(defrel thing- [Thing])
(defrel type- [Thing] [Type])
(fact thing- [0])
(fact thing- [1])
(fact thing- [2])
(fact type- [0] [:player])
(fact type- [1] [:dragon])
(fact type- [2] [:pig])
(defn type-enum [t] [:type t])
(defna drawable- [Key]
  ([[Thing]] (thing- [Thing]) (fresh [Type] (type- [Thing] [Type]) (drawable- [Type])))
  ([[(type-enum :player)]] succeed)
  ([[(type-enum :dragon)]] succeed))

(deftest do-fns-work
	(is (= (run* [q] (drawable- [q])) '(0 1))))

Now that I look at it, I may be expecting a wrong-format return value, but the point is that I don't even get that far.

Using the REPL, I checked out how (defna drawable- . . .) expands (tidied up slightly):

(def drawable- (clojure.core/fn ([Key] 
  (clojure.core.logic/conda 
	  ((clojure.core.logic/fresh [Thing] (clojure.core.logic/== [Thing] Key) (thing- [Thing]) (fresh [Type] (type- [Thing] [Type]) (drawable- [Type])))) 
		((clojure.core.logic/fresh [type-enum] 
		  (clojure.core.logic/== [(type-enum :player)] Key) succeed))
		((clojure.core.logic/fresh [type-enum] 
		  (clojure.core.logic/== [(type-enum :dragon)] Key) succeed))))))

Note the (clojure.core.logic/fresh [type-enum] . . .) forms, which are exactly what I would not want to see in this case.

I'm not really sure why this doesn't work here yet works for the matche test case.

Comment by David Nolen [ 19/Jul/12 5:47 PM ]
[(type-enum :dragon)]

This pattern make it seem like you want to match:

[[:type :dragon]]

Note extra level of brackets here. Is this the case?

Even so I agree that the expansion doesn't look quite right. We should never descend into a seq form like that.

Comment by Joe Osborn [ 19/Jul/12 5:57 PM ]

Yes, that's exactly the desired outcome in this case--a tagged value in my naive interpretation. Is the reason it fails whereas the test on :1230 doesn't the fact that it's producing a vector and not a list? Changing the fn to return a list instead of a vector didn't seem to help.

My patch, fwiw, doesn't exhibit that behavior (at least for macros, haven't tested it with fns).

Comment by David Nolen [ 19/Jul/12 9:11 PM ]

What I mean is don't you want the following instead?

(defna drawable- [Key]
  ([[Thing]] (thing- [Thing]) (fresh [Type] (type- [Thing] [Type]) (drawable- [Type])))
  ([(type-enum :player)] succeed)
  ([(type-enum :dragon)] succeed))

Note that I removed a layer of square brackets.

Comment by Joe Osborn [ 20/Jul/12 10:28 AM ]

Nope! I actually want both. I'm doing some temporal logic stuff and I wanted some conveniences for "updating" a fluent, so I wanted to distinguish between the "key part" and the "value part" of the arguments. It looks silly for facts with no "value part", but it lets me write procedures and fns something like this:

(defrel heldo Time Fluent)
(defrel ¬heldo Time Fluent)
(declare fluent-obtainedo) ; most recent 'held' not terminated by a '¬held', or fail
(defn alter-fluent [Time Rel Key NewVal]
  ;todo: error check, ensure old != new, old obtains, new does not obtain
  (doseq [old-val (run* [old-val] (fluent-obtainedo Time [Rel Key old-val]))]
    (fact ¬heldo Time [Rel Key old-val]))
  (fact heldo Time [Rel Key NewVal]))
. . .
(fact heldo 0 ['pos [0] [0 0]])
. . .
(alter-fluent 1 'pos [0] [1 1])

And I write all the non-temporal fluents that way too for consistency and to help prevent mistakes.

Comment by David Nolen [ 20/Jul/12 2:58 PM ]

I'll try to give a closer look at this issue over the weekend.

Comment by David Nolen [ 17/Mar/13 7:05 PM ]

We're thinking about a more general solution here: http://github.com/clojure/core.logic/wiki/Better-syntax-support





[LOGIC-43] LVar should print readably Created: 05/Jul/12  Updated: 05/Jul/12

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Alan Malloy Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File 0001-Make-lvar-print-readably.patch    
Patch: Code

 Description   

Currently LVar objects print the same as symbols; they should either print as an unreadable form, or in a way that the reader can read them back in and get an LVar. Attached patch causes them to be read in as LVars.

However, (read-string (pr-str lv)) does not compare as equal to lv, because the implementation of .equals relies on their string :name objects being identical? - which they will not be, if one LVar was created by the lvar function, which uses str, and the other created by read-string, which uses String/intern.

It seems plausible to say that LVars can't be compared for equality after sending them through strings, but that's awkward and unpleasant. We could instead define LVars to compare their names with = rather than with identical?, but David expressed concern about the performance implications of that change.






[LOGIC-42] Generalize run to accept multiple logic vars Created: 13/Jun/12  Updated: 28/Jul/13  Resolved: 14/Jun/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Gary Fredericks Assignee: Gary Fredericks
Resolution: Completed Votes: 0
Labels: None

Attachments: File LOGIC-42.diff    

 Description   
(run 1 [x y z]
  ...goals...)

;; equivalent to

(run 1 [q]
  (fresh [x y z]
    (== q [x y z])
    ...goals...))


 Comments   
Comment by Gary Fredericks [ 13/Jun/12 7:36 PM ]

test and impl

Comment by David Nolen [ 14/Jun/12 9:19 AM ]

fixed, http://github.com/clojure/core.logic/commit/7b6d8f3c34e4feca18bb645282adee7aeef68ac7





[LOGIC-41] Unexpected behavior when using functions Created: 31/May/12  Updated: 28/Jul/13  Resolved: 31/May/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Jens Bendisposto Assignee: David Nolen
Resolution: Declined Votes: 0
Labels: None


 Description   

Not sure if this is a bug, but it seems a bit strange

=>(defn cp [a b c d] (== a b) (== c d))
=>(run* [q] (fresh [x y] (cp 1 x 2 y) (== q [x y])))
([_.0 2])

My expectation was that I get ([1 2)]



 Comments   
Comment by David Nolen [ 31/May/12 2:50 PM ]

This is not a bug. You can't just combine two unifications like that. They must be combined under fresh or all.





[LOGIC-40] Retractions with an empty collection produces a NullPointerException Created: 18/May/12  Updated: 28/Jul/13  Resolved: 18/May/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Michael Nygard Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None
Environment:

All.


Attachments: Text File allow_empty_collection_in_retraction.patch    
Patch: Code

 Description   

Example:

(defrel load-factor src snk lf)
(retractions load-factor [])

Results in NPE. Should do nothing without complaining.



 Comments   
Comment by David Nolen [ 18/May/12 7:24 PM ]

Fixed, http://github.com/clojure/core.logic/commit/d613316bbce889906b4ad2172970258bf0f16916





[LOGIC-39] core.logic is inconsistent in how it handles nil and false Created: 17/May/12  Updated: 28/Jul/13  Resolved: 26/Oct/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Task Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

Unification failure should always return nil. The fact that we sometimes return false and sometimes return nil creates problems when providing lower level data sources.



 Comments   
Comment by David Nolen [ 26/Oct/12 1:07 AM ]

This was resolved on the way to 0.8.0 alphas/beta





[LOGIC-38] Logic Threading Macro Created: 13/May/12  Updated: 15/Oct/14

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Jason Jackson Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File 0001-added-logic-threading-macro.patch     Text File 0001-added-logic-threading-macro.patch    

 Description   

This macro was somewhat useful when I was implementing static analysis for a compiler with core.logic.

(defmacro ==>> [expr-in & rel-forms]
"Thread the expr-in through rel-forms then unify with last rel-forms
(the 'out expression').

Example:
(==>> [[1]] (firsto) (firsto) x))
;; 'x' will become bound to value 1

This macro expands to:
(fresh [_A _B]
(firsto [[1]] _A)
(firsto _A _B)
(== _B q))

If you imagine that the 'return value' of firsto is its last parameter,
then it works just like clojure.core/-> as return value of each form is
first argument of the following form."



 Comments   
Comment by Jason Jackson [ 13/May/12 11:08 AM ]

There might be a better name, not sure.

Comment by Jason Jackson [ 13/May/12 11:18 AM ]

renamed ==>> to ==->





[LOGIC-37] The facts and retractions functions do not take the relation's namespace into account when resolving the index. Created: 03/May/12  Updated: 28/Jul/13  Resolved: 27/Sep/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Edgar Liebke Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File 0001-Fixed-issue-resolving-the-clojure.core.logic.Rel-ind.patch    
Patch: Code

 Description   

Inserting facts into a relation that is defined in another namespace, specifically a namespace that has been required but not referred (I don't see the bug if I :use the other namespace).

I've tracked the problem down to this line:

https://github.com/clojure/core.logic/blob/master/src/main/clojure/clojure/core/logic.clj#L1621

In the facts function, when the relation index gets resolved, the namespace is not taken into account,

index (var-get (resolve (index-sym (.name rel) arity o)))

as it is when resolving the relation set.

rel-set (var-get (ns-resolve rel-ns (set-sym (.name rel) arity)))

Using ns-resolve, with rel-ns, seems to fix the issue for me.

index (var-get (ns-resolve rel-ns (index-sym (.name rel) arity o)))



 Comments   
Comment by David Nolen [ 27/Sep/12 9:42 PM ]

Apologies for the slow response. Is this still a problem?

Comment by David Edgar Liebke [ 27/Sep/12 9:50 PM ]

Hi David,

Nope, the problem has been resolved, as I recall you applied the patch and cut a new release the same day I submitted the request; so thanks again for the quick fix!

David

Comment by David Nolen [ 27/Sep/12 9:52 PM ]

fixed





[LOGIC-36] Unification bug in binding-map Created: 09/Apr/12  Updated: 28/Jul/13  Resolved: 17/Mar/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: André Thieme Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: unify


 Description   

I tried some tests of core.unify against core.logics binding-map function and found some inconsistencies:
(binding-map '(?x ?y) '(?y ?x)) ==> {?y _.0, ?x _.0}
while core.unify returns ==> {?x ?y}



 Comments   
Comment by David Nolen [ 17/Mar/13 6:52 PM ]

fixed, http://github.com/clojure/core.logic/commit/c37212270688b1bdbbca7fb81c1fc52062b24139





[LOGIC-35] Core.logic equivalent of multimethods Created: 02/Apr/12  Updated: 28/Dec/12

Status: Open
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Gabriel Pickard Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: enhancement


 Description   

I need to define predicates to which I can later (and from other namespaces) attach further clauses (so not just facts). I couldn't find any such functionality in the source. Due to the extensive use of macros, hacking such a system onto core.logic from the outside is extremely difficult, if not impossible (to me at least).

I'd love to implement this myself too, if given an OK and rough direction.



 Comments   
Comment by Gabriel Pickard [ 03/Apr/12 6:27 PM ]

I actually did manage to tack on a prototype that covers the basic behavior I would like to see: https://github.com/werg/herpderp/blob/master/src/herpderp/multo.clj

I use a set stored in a ref in the defne's metadata to manage dynamic changes to the clauses. Upon changing that set using defclause I use eval to re-define the var using defne.

This might not be nice, but allows me to continue developing features against it.

Comment by David Nolen [ 28/Dec/12 12:48 AM ]

I don't think the current implementation can really support this and I don't think it's wise to try to hack around the current implementation. I'd be willing to consider a comprehensive solution if someone is willing to do the legwork.





[LOGIC-34] Unification should carry along metadata Created: 26/Mar/12  Updated: 28/Jul/13  Resolved: 28/Mar/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Kevin Lynagh Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File 34-unification-metadata.txt    
Patch: Code and Test

 Description   

Unification should not swallow metadata:

(run* [q]
(== q (quote ^:haz-meta-daytuhs (form form form))))

should yield

(^:haz-meta-daytuhs (form form form))



 Comments   
Comment by Kevin Lynagh [ 26/Mar/12 11:04 PM ]

Also available at

https://github.com/lynaghk/core.logic/tree/34-unification-metadata

Comment by David Nolen [ 26/Mar/12 11:10 PM ]

That doesn't seem right. Metadata should be available on the form but not present in the result of the query.

Comment by Kevin Lynagh [ 26/Mar/12 11:36 PM ]

I'm not sure what you mean; if you unify the query and a form with metadata, then the result should have that same form with the same metadata.

In that example I have (set! print-meta true); in the usual repl the result is just ((form form form)).

Comment by David Nolen [ 26/Mar/12 11:41 PM ]

Oh gotcha, sorry I didn't realize you had set the compiler flag. Will take a look at the patch.

Comment by David Nolen [ 28/Mar/12 10:48 AM ]

fixed, https://github.com/clojure/core.logic/commit/7f4ad132af7a825839a12ff3c33e375610e6f315

Comment by Kevin Lynagh [ 28/Mar/12 11:11 AM ]

Rad, thanks David!





[LOGIC-33] Added usage section to readme.md Created: 15/Mar/12  Updated: 28/Jul/13  Resolved: 17/Mar/13

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Trivial
Reporter: Linus Ericsson Assignee: David Nolen
Resolution: Declined Votes: 0
Labels: documentation

Attachments: Text File usage-added.patch    
Patch: Code

 Description   

added a short usage section in readme.md

the latest working repo was 0.6.7 for me, so that's what in the patch. (i have signed CA)



 Comments   
Comment by David Nolen [ 17/Mar/13 7:11 PM ]

Basic usage has since been added to README.md





[LOGIC-32] Unification bug Created: 15/Mar/12  Updated: 28/Jul/13  Resolved: 15/Mar/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   
(run* [q] (== q #{1}))

Results in the following exception:

IllegalArgumentException 
Don't know how to create ISeq from: 
java.lang.Long  clojure.lang.RT.seqFrom (RT.java:487)


 Comments   
Comment by David Nolen [ 15/Mar/12 6:17 PM ]

Fixed, https://github.com/clojure/core.logic/commit/a473226d0a9aeadace0a322d506c69f13c81970a





[LOGIC-31] unifier is not commutative Created: 14/Mar/12  Updated: 28/Jul/13  Resolved: 17/Mar/12

Status: Closed
Project: core.logic
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Jens Bendisposto Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None
Environment:

clojure 1.3.0, core.logic 0.6.7



 Description   

I am not sure if this is actually a bug

user=> (require '[clojure.core.logic :as logic])
nil
user=> (logic/unifier (logic/unifier '{:a ?x} '{:a ?y}) '{:a 5})
nil
user=> (logic/unifier (logic/unifier '{:a ?x} '{:a 5}) '{:a ?y})
{:a 5}

For comparison: here is the result of core.unify (and what I expected)

user=> (require '[clojure.core.unify :as unify])
nil
user=> (unify/unifier (unify/unifier '{:a ?x} '{:a ?y}) '{:a 5})
{:a 5}
user=> (unify/unifier (unify/unifier '{:a ?x} '{:a 5}) '{:a ?y})
{:a 5}



 Comments   
Comment by Jens Bendisposto [ 14/Mar/12 2:58 AM ]

Obviously i meant associative, not commutative.

Comment by David Nolen [ 14/Mar/12 12:30 PM ]

Thanks for pointing this out. Yes the unifier isn't doing the right thing here. Will look into a fix.