Your SlideShare is downloading. ×
Relational Logic Programming for ClojureCORE.LOGIChttp://www.slideshare.net/normanrichards/corelogic-introductiongit clone...
Why core.logic?http://xkcd.com/292/
core.logic in the real worldThreatGRID uses core.logic toprocess observations of malwareexecution looking for behavioralin...
run*core.logic(run* [q])This is the simplest possiblecore.logic program. q is thequery. run* says “give me all theresults”...
unificationcore.logic(run* [q](== q :hello-world))The most fundamental operationon a logic variable is to unify it.unificat...
unificationcore.logic(run* [q](== q [:hello :world]))Logic variables can also beunified over sequences.There is still only ...
unificationcore.logic(run* [q](== q [:hello :world])(== q [:hello :world]))A logic variable can be unifiedwith the same val...
unificationcore.logic(run* [q](== q :hello)(== q :world))A logic variable cannot unify withtwo different values at the same...
condecore.logic(run* [q](conde[(== q :hello)][(== q :world)]))You can introduce alternativevalues with conde. Every condel...
Disunificationcore.logic(run* [q](conde[(== q :hello)][(== q :world)])(!= q :hello))!= introduces a constraint thattwo val...
FRESHcore.logic(run* [q](fresh [x y](== x :something)(== y :something-else)))fresh introduces new logicvariables.x and y a...
FRESHcore.logic(run* [q](fresh [x y](== x :something)(== x :something-else)))The query fails since no value ofq can make x...
FRESHcore.logic(run* [q](fresh [x y](== q [x :and y])(== x :something)(== :something-else y)))Order does not matter foruni...
memberocore.logiccore.logic(run* [q](fresh [smurf](membero smurf[:papa :brainy :lazy :handy])(== q [smurf smurf])))membero...
memberocore.logiccore.logic(run* [q](fresh [smurf1 smurf2](membero smurf1[:papa :brainy :lazy :handy])(membero smurf2[:pap...
distinctocore.logiccore.logic(run* [q](fresh [smurf1 smurf2 smurf3](membero smurf1[:papa :brainy :lazy :handy])(membero sm...
everygcore.logiccore.logic(run* [q](fresh [smurf1 smurf2 smurf3](== q [smurf1 smurf2 smurf3])(everyg #(membero % [:papa :b...
lvarcore.logiccore.logic(run* [q](== q [(lvar) (lvar) (lvar)])(everyg #(membero % [:papa :brainy :lazy :handy])q)(distinct...
Map coloringcore.logiccore.logichttp://pragprog.com/book/btlang/seven-languages-in-seven-weeks(run 1 [q](fresh [tn ms al g...
rock paper scissorscore.logiccore.logic(defn beatso [player1 player2](conde[(== player1 :rock) (== player2 :scissors)][(==...
rock paper scissorscore.logiccore.logic(run* [q](beatso :rock :paper))beatso fails because :rock doesnot beat paper. No va...
rock paper scissorscore.logiccore.logic(run* [q](beatso :paper :rock))beatso succeeds because :paperbeats rock. q remains ...
rock paper scissorscore.logiccore.logic(run* [q](beatso :rock q))beatso can answer in eitherdirection.(:scissors)(run* [q]...
rock paper scissorscore.logiccore.logic(run* [q](fresh [x y](beatso x y)(== q [x y])))This query asks for all the pairswhe...
FACTS and RELATIONScore.logiccore.logicrpsls is a relation of one term.Five facts are asserted about therelation.(defrel r...
FACTS and RELATIONScore.logiccore.logic(run* [q](rpsls q))defrel relations answer queries inthe same way as the otherrelat...
FACTS and RELATIONScore.logiccore.logicbeats is a relation of two terms,indicating the first gesture beatsthe second one.(d...
FACTS and RELATIONScore.logiccore.logic(run* [q](fresh [x y](beats :spock x)(beats x y)(beats y :spock)(== q [:spock x y :...
FACTS and RELATIONScore.logiccore.logic(defn win-chaino [x](fresh [a d](rpsls a)(conso a d x)(conde[(emptyo d)][(fresh [b]...
FACTS and RELATIONScore.logiccore.logic(count(run* [q](== q (concat [:spock](repeatedly 10 lvar)[:lizard]))(win-chaino q))...
USEless logic puzzlecore.logiccore.logic‣ petey pig did not hand out the popcorn‣ pippin pig does not live in the wood hou...
USEless logic puzzlecore.logiccore.logic(defn pigso [q](fresh [h1 h2 h3 t1 t2 t3](== q [[:petey h1 t1][:pippin h2 t2][:pet...
USEless logic puzzlecore.logiccore.logic(fresh [notpopcorn _](membero notpopcorn [:chocolate :apple])(membero [:petey _ no...
FACTS and RELATIONScore.logiccore.logic(run* [q](pigso q))pigso finds the only solution.([[:petey :wood :chocolate][:pippin...
FINITE DOMAINScore.logiccore.logicfd/interval declares a finiteinteger interval and fd/incontrains logic variables to adoma...
FINITE DOMAINScore.logiccore.logicfd/eq translates simple math toconstraints over finite domainlogic variables.(fd/eq (= TW...
FINITE DOMAINScore.logiccore.logicThere are 7 unique solutions tothe problem.(run* [q](two-plus-two-is-four q))T W O+ T W ...
sudoku made easiercore.logiccore.logicAfter setting up the logicvariables and initializing state,the solution simply requi...
sudoku made easiercore.logiccore.logicmatche is pattern matchingsyntax for conde. To unify theinitial logic variables with...
sudokucore.logiccore.logic(def puzzle1[0 0 0 0 0 9 0 6 00 3 8 0 0 5 0 0 40 2 0 0 6 0 0 7 00 0 0 0 0 0 3 9 00 0 0 9 2 6 0 0...
Norman richardsorb@nostacktrace.com@maximoburrito
core.logic introduction
core.logic introduction
core.logic introduction
core.logic introduction
core.logic introduction
Upcoming SlideShare
Loading in...5
×

core.logic introduction

2,944

Published on

core.logic introduction for Austin Clojure Meetup 4/8/13
updated for DFW Clojure Meetup 5/15/13
updated for Houston Clojure Meetup 6/27/13

0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
2,944
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
1
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

Transcript of "core.logic introduction"

  1. 1. Relational Logic Programming for ClojureCORE.LOGIChttp://www.slideshare.net/normanrichards/corelogic-introductiongit clone https://github.com/orb/logicdemo.git
  2. 2. Why core.logic?http://xkcd.com/292/
  3. 3. core.logic in the real worldThreatGRID uses core.logic toprocess observations of malwareexecution looking for behavioralindicators of compromise.Observations are simple factual statements that map intocore.logic relations and SQL tables. The mapping allowsthe same data model to be used for core.logic programs inmemory, as well as persistance in a database and lateranalysis and querying via SQL.A persistent core.logic database. pldb provides an in-memory persistent fact database making it easier to usecore.logic in multi-threaded environments like webapplications.github.com/threatgrid/observationsgithub.com/threatgrid/pldb
  4. 4. run*core.logic(run* [q])This is the simplest possiblecore.logic program. q is thequery. run* says “give me all theresults”.run* returns a seq of all possibleresults. The symbol _0represents a fresh (unbound)logic variable.(_0)
  5. 5. unificationcore.logic(run* [q](== q :hello-world))The most fundamental operationon a logic variable is to unify it.unification is ==.There is only one value of q thatsatisfies the relation. (:hello-world)
  6. 6. unificationcore.logic(run* [q](== q [:hello :world]))Logic variables can also beunified over sequences.There is still only one value of qthat satisfies the relation.([:hello :world])
  7. 7. unificationcore.logic(run* [q](== q [:hello :world])(== q [:hello :world]))A logic variable can be unifiedwith the same value multipletimes.([:hello :world])
  8. 8. unificationcore.logic(run* [q](== q :hello)(== q :world))A logic variable cannot unify withtwo different values at the sametime.There are no values of q thatsatisfy the relation. ()
  9. 9. condecore.logic(run* [q](conde[(== q :hello)][(== q :world)]))You can introduce alternativevalues with conde. Every condeline that succeeds producespossible alternative values.There are 2 values of q thatsatisfy the relation. (:hello :world)
  10. 10. Disunificationcore.logic(run* [q](conde[(== q :hello)][(== q :world)])(!= q :hello))!= introduces a constraint thattwo values never unify.There are 2 values of q thatsatisfy the conde goal, but !=eliminates one of them. (:world)
  11. 11. FRESHcore.logic(run* [q](fresh [x y](== x :something)(== y :something-else)))fresh introduces new logicvariables.x and y are bound, but the queryremains unbound.(_0)
  12. 12. FRESHcore.logic(run* [q](fresh [x y](== x :something)(== x :something-else)))The query fails since no value ofq can make x unify with twodifferent values.()
  13. 13. FRESHcore.logic(run* [q](fresh [x y](== q [x :and y])(== x :something)(== :something-else y)))Order does not matter forunification.([:something :and :something-else])
  14. 14. memberocore.logiccore.logic(run* [q](fresh [smurf](membero smurf[:papa :brainy :lazy :handy])(== q [smurf smurf])))membero is relation thatsucceeds when the firstargument is a member of thesecond argument. It cansucceed multiple times.q produces each success ([:papa :papa][:brainy :brainy][:lazy :lazy][:handy :handy])
  15. 15. memberocore.logiccore.logic(run* [q](fresh [smurf1 smurf2](membero smurf1[:papa :brainy :lazy :handy])(membero smurf2[:papa :brainy :lazy :handy])(== q [smurf1 smurf2])))Both membero relations succeedmultiple times. q is unified witheach pair.([:papa :papa][:papa :brainy][:brainy :papa]...[:handy :lazy][:handy :handy])
  16. 16. distinctocore.logiccore.logic(run* [q](fresh [smurf1 smurf2 smurf3](membero smurf1[:papa :brainy :lazy :handy])(membero smurf2[:papa :brainy :lazy :handy])(membero smurf3[:papa :brainy :lazy :handy])(distincto [smurf1 smurf2 smurf3])(== q [smurf1 smurf2 smurf3])))distincto ensures that no twoitems in the relation unify witheach other. smurf1 will neverunify with smurf2, and neither willunify with smurf3.([:papa :brainy :lazy][:papa :brainy :handy][:brainy :papa :lazy][:brainy :papa :handy]...[:handy :lazy :brainy])
  17. 17. everygcore.logiccore.logic(run* [q](fresh [smurf1 smurf2 smurf3](== q [smurf1 smurf2 smurf3])(everyg #(membero % [:papa :brainy :lazy :handy])q)(distincto q)))everyg ensures that everyelement in a collection satisfies agoal. It is not a proper relation, inthat it requires the collection toalready be a seq.([:papa :brainy :lazy][:papa :brainy :handy][:brainy :papa :lazy][:brainy :papa :handy]...[:handy :lazy :brainy])
  18. 18. lvarcore.logiccore.logic(run* [q](== q [(lvar) (lvar) (lvar)])(everyg #(membero % [:papa :brainy :lazy :handy])q)(distincto q))lvar creates a new a logicvariable. Since we don’t need torefer to the items individually, wecan just say that the([:papa :brainy :lazy][:papa :brainy :handy][:brainy :papa :lazy][:brainy :papa :handy]...[:handy :lazy :brainy])
  19. 19. Map coloringcore.logiccore.logichttp://pragprog.com/book/btlang/seven-languages-in-seven-weeks(run 1 [q](fresh [tn ms al ga fl](everyg #(membero % [:red :blue :green])[tn ms al ga fl])(!= ms tn) (!= ms al) (!= al tn)(!= al ga) (!= al fl) (!= ga fl) (!= ga tn) (== q {:tennesse tn:mississipi ms:alabama al:georgia ga:florida fl})))({:tennesse :blue,:mississipi :red,:alabama :green,:georgia :red,:florida :blue})
  20. 20. rock paper scissorscore.logiccore.logic(defn beatso [player1 player2](conde[(== player1 :rock) (== player2 :scissors)][(== player1 :scissors) (== player2 :paper)][(== player1 :paper) (== player2 :rock)]))beatso is a custom relationbetween two terms. It succeedswhen the first players movebeats the second players move
  21. 21. rock paper scissorscore.logiccore.logic(run* [q](beatso :rock :paper))beatso fails because :rock doesnot beat paper. No value of qmakes this succeed.()
  22. 22. rock paper scissorscore.logiccore.logic(run* [q](beatso :paper :rock))beatso succeeds because :paperbeats rock. q remains freshbecause no questions wereasked of it.(_0)
  23. 23. rock paper scissorscore.logiccore.logic(run* [q](beatso :rock q))beatso can answer in eitherdirection.(:scissors)(run* [q](beatso q :scissors))(:rock)
  24. 24. rock paper scissorscore.logiccore.logic(run* [q](fresh [x y](beatso x y)(== q [x y])))This query asks for all the pairswhere x beats y.([:rock :scissors][:scissors :paper][:paper :rock])
  25. 25. FACTS and RELATIONScore.logiccore.logicrpsls is a relation of one term.Five facts are asserted about therelation.(defrel rpsls gesture)(fact rpsls :rock)(fact rpsls :paper)(fact rpsls :scissors)(fact rpsls :lizard)(fact rpsls :spock)
  26. 26. FACTS and RELATIONScore.logiccore.logic(run* [q](rpsls q))defrel relations answer queries inthe same way as the otherrelations we’ve seen.(:rock :paper :scissors :lizard :spock)
  27. 27. FACTS and RELATIONScore.logiccore.logicbeats is a relation of two terms,indicating the first gesture beatsthe second one.(defrel beats gesture1 gesture2)(fact beats :scissors :paper)(fact beats :paper :rock)(fact beats :rock :lizard)(fact beats :lizard :spock)(fact beats :spock :scissors)(fact beats :scissors :lizard)(fact beats :lizard :paper)(fact beats :paper :spock)(fact beats :spock :rock)(fact beats :rock :scissors)
  28. 28. FACTS and RELATIONScore.logiccore.logic(run* [q](fresh [x y](beats :spock x)(beats x y)(beats y :spock)(== q [:spock x y :spock])))We can ask questions like: giveme a 4-chain of dominatedmoves starting and endingwith :spock. There are threesolutions.([:spock :scissors :lizard :spock][:spock :scissors :paper :spock][:spock :rock :lizard :spock])
  29. 29. FACTS and RELATIONScore.logiccore.logic(defn win-chaino [x](fresh [a d](rpsls a)(conso a d x)(conde[(emptyo d)][(fresh [b](beats a b)(firsto d b))(win-chaino d)])))A winning chain is a single rpslsmove either by itself or followedby a winning chain whose firstmove is beaten by the originalmove.conso, emptyo and firsto arerelations over cons lists.
  30. 30. FACTS and RELATIONScore.logiccore.logic(count(run* [q](== q (concat [:spock](repeatedly 10 lvar)[:lizard]))(win-chaino q)))How many winning chains arethere from :spock to :lizard with10 steps?385
  31. 31. USEless logic puzzlecore.logiccore.logic‣ petey pig did not hand out the popcorn‣ pippin pig does not live in the wood house‣ the pig that lives in the straw house handed out popcorn‣ Petunia pig handed out apples‣ The pig who handed out chocolate does not live in the brick house.Three little pigs, who eachlived in a different type ofhouse, handed out treats forHalloween. Use the clues tofigure out which pig lived ineach house, and what type oftreat each pig handed out.http://holidays.hobbyloco.com/halloween/logic1.html
  32. 32. USEless logic puzzlecore.logiccore.logic(defn pigso [q](fresh [h1 h2 h3 t1 t2 t3](== q [[:petey h1 t1][:pippin h2 t2][:petunia h3 t3]])(permuteo [t1 t2 t3][:chocolate :popcorn :apple])(permuteo [h1 h2 h3][:wood :straw :brick]) ... ))pigso starts by defining thesolution space.permuteo succeeds when thefirst list is permutation of thesecond.
  33. 33. USEless logic puzzlecore.logiccore.logic(fresh [notpopcorn _](membero notpopcorn [:chocolate :apple])(membero [:petey _ notpopcorn] q))(fresh [notwood _](membero notwood [:straw :brick])(membero [:pippin notwood _] q))(fresh [_](membero [_ :straw :popcorn] q))(fresh [_](membero [:petunia _ :apple] q))(fresh [notbrick _](membero notbrick [:straw :wood])(membero [_ notbrick :chocolate] q))The clues translate cleanly togoals constraining the solutionspace.membero has a solution whenthe first item is a member of thesecond.
  34. 34. FACTS and RELATIONScore.logiccore.logic(run* [q](pigso q))pigso finds the only solution.([[:petey :wood :chocolate][:pippin :straw :popcorn][:petunia :brick :apple]])
  35. 35. FINITE DOMAINScore.logiccore.logicfd/interval declares a finiteinteger interval and fd/incontrains logic variables to adomain.(defn two-plus-two-is-four [q](fresh [t w o f u r TWO FOUR](fd/in t w o f u r (fd/interval 0 9))(fd/distinct [t w o f u r])(fd/in TWO (fd/interval 100 999))(fd/in FOUR (fd/interval 1000 9999)) ...(== q [TWO TWO FOUR])))T W O+ T W O-------F O U Rhttp://www.amazon.com/Crypt-arithmetic-Puzzles-in-PROLOG-ebook/dp/B006X9LY8O
  36. 36. FINITE DOMAINScore.logiccore.logicfd/eq translates simple math toconstraints over finite domainlogic variables.(fd/eq (= TWO(+ (* 100 t)(* 10 w)o)))(fd/eq (= FOUR(+ (* 1000 f)(* 100 o)(* 10 u)r))) (fd/eq (= (+ TWO TWO) FOUR))T W O+ T W O-------F O U R
  37. 37. FINITE DOMAINScore.logiccore.logicThere are 7 unique solutions tothe problem.(run* [q](two-plus-two-is-four q))T W O+ T W O-------F O U R([734 734 1468][765 765 1530][836 836 1672][846 846 1692][867 867 1734][928 928 1856][938 938 1876])
  38. 38. sudoku made easiercore.logiccore.logicAfter setting up the logicvariables and initializing state,the solution simply requires everyrow, column and square on theboard to have distinct values.(defn solve [puzzle](let [sd-num (fd/domain 1 2 3 4 5 6 7 8 9)board (repeatedly 81 lvar)rows (into [] (map vec (partition 9 board)))cols (apply map vector rows)squares (for [x (range 0 9 3)y (range 0 9 3)](get-square rows x y))] (run* [q](== q board)(everyg #(fd/in % sd-num) board)(init-board board puzzle)(everyg fd/distinct rows)(everyg fd/distinct cols)(everyg fd/distinct squares))))https://gist.github.com/swannodette/3217582
  39. 39. sudoku made easiercore.logiccore.logicmatche is pattern matchingsyntax for conde. To unify theinitial logic variables with aboard, we require either theboard have a 0 or that the logicvariable unifies with the value ofthe board.(defn init-board [vars puzzle](matche [vars puzzle]([[] []]succeed)([[_ . vs] [0 . ps]](init-board vs ps))([[num . vs] [num . ps]](init-board vs ps))))
  40. 40. sudokucore.logiccore.logic(def puzzle1[0 0 0 0 0 9 0 6 00 3 8 0 0 5 0 0 40 2 0 0 6 0 0 7 00 0 0 0 0 0 3 9 00 0 0 9 2 6 0 0 00 9 7 0 0 0 0 0 00 4 0 0 7 0 0 3 05 0 0 4 0 0 2 1 00 7 0 8 0 0 0 0 0])(partition 9 (first (solve puzzle1)))((7 1 4 2 8 9 5 6 3)(6 3 8 7 1 5 9 2 4)(9 2 5 3 6 4 1 7 8)(8 6 1 5 4 7 3 9 2)(4 5 3 9 2 6 7 8 1)(2 9 7 1 3 8 4 5 6)(1 4 9 6 7 2 8 3 5)(5 8 6 4 9 3 2 1 7)(3 7 2 8 5 1 6 4 9))
  41. 41. Norman richardsorb@nostacktrace.com@maximoburrito

×