I am trying to create a CLIPS program that will take any initial stack and rearrange it into any goal-stack. I am asserting this, but it doesn't seem to do anything.
(assert (stack A B C) (stack D E F) (goal-stack D C B) (goal-stack A) (goal-stack F E))
This is my code so far:
(defrule move-direct
;(declare (salience 10000))
?stack1 <- (stack ?block1 $?bottom1)
?stack2 <- (stack ?block2 $?bottom2)
(goal-stack ?block1 ?block2 $?goalbottom)
=>
(retract ?stack1 ?stack2)
(assert (stack ?block1 ?block2 ?bottom2))
(assert (stack $?bottom1))
(printout t ?block1 " moved on top of " ?block2 crlf))
(defrule move-on-floor
; (declare (salience 10000))
?stack1 <- (stack ?top $?blocks ?movethisblock $?bottom1)
;(goal-stack ?movethisblock $?bottom1)
(goal-stack $?blocks ?movethisblock $?bottom2)
=>
(retract ?stack1)
(assert (stack ?top))
(assert (stack $?blocks ?movethisblock $?bottom1))
(printout t ?top " moved on to the floor" crlf))
Debugging code usually involves questioning your expectations. You expect the move-direct and move-on-floor rules to do something, but why? For the move-direct rule and the assertions you've made, the only possible values for ?block1 and ?block2 in the first two patterns are either A or D. So the third pattern must match a goal-stack that starts with either A A, A D, D A, or D D. Such a goal-stack does not exist, so this rule is unmatched.
For the move-on-floor rule, look at each case. If (goal-stack A) matches the goal-stack pattern where ?move-this-block is A and $?blocks is (), then there must be stack that has a block on top of A (the variable ?top). Since A is at the top of the stack, the rule won't be matched for this goal-stack.
if (goal-stack F E) matches the goal-stack pattern, the sequence ($?blocks ?move-this-block) is either (F E) or F. There is no stack with either of these sequences where there's just a single block on top, so the rule won't be matched for this sequence.
If (goal-stack D C B) matches the goal-stack pattern the sequence from the goal-stack that must match the stack is either (D C B), (D C) or (D). Again there's no stack that contains this sequence with just a single block on top of the sequence.
In the logic for the move-direct rule, you only want to directly move the block when the existing stack matches the bottom portion of a goal-stack. For the move-on-floor rule you also want to insure that you're not moving blocks off a partially completed stack.
CLIPS (6.31 2/3/18)
CLIPS>
(defrule move-direct
(declare (salience 10))
?stack1 <- (stack ?block1 $?bottom)
?stack2 <- (stack ?block2 $?goalbottom)
(goal-stack $? ?block1 ?block2 $?goalbottom)
=>
(retract ?stack1 ?stack2)
(assert (stack ?block1 ?block2 ?goalbottom))
(assert (stack $?bottom))
(printout t ?block1 " moved on top of " ?block2 crlf))
CLIPS>
(defrule move-on-floor
(goal-stack $? ?next $?goalbottom)
(not (stack $? ?next $?goalbottom))
?stack <- (stack $?top ?bottom)
(test (member$ ?next ?top))
=>
(retract ?stack)
(assert (stack (nth$ 1 ?top)))
(assert (stack (rest$ ?top) ?bottom))
(printout t (nth$ 1 ?top) " moved on to the floor" crlf))
CLIPS>
(assert (stack A B C)
(stack D E F)
(goal-stack D C B)
(goal-stack A)
(goal-stack F E))
<Fact-5>
CLIPS> (run)
D moved on to the floor
E moved on to the floor
F moved on top of E
A moved on to the floor
B moved on to the floor
C moved on top of B
D moved on top of C
CLIPS> (facts)
f-0 (initial-fact)
f-3 (goal-stack D C B)
f-4 (goal-stack A)
f-5 (goal-stack F E)
f-10 (stack F E)
f-11 (stack)
f-12 (stack A)
f-17 (stack D C B)
For a total of 8 facts.
CLIPS> (reset)
CLIPS>
(assert (stack A B C)
(goal-stack A B)
(goal-stack C))
<Fact-3>
CLIPS> (run)
A moved on to the floor
B moved on to the floor
A moved on top of B
CLIPS> (facts)
f-0 (initial-fact)
f-2 (goal-stack A B)
f-3 (goal-stack C)
f-7 (stack C)
f-8 (stack A B)
f-9 (stack)
For a total of 6 facts.
CLIPS>
Related
modify is not working. I expected fact 1 to be (a x y z).
Further, if I want to change the second element c of the fact 1 to say g, i.e the new fact should be (a b g d) is there a way using modify ?
Snippet attached below.
CLIPS> (assert (a b c d))
<Fact-1>
CLIPS> (bind ?s x y z)
(x y z)
CLIPS> (facts)
f-1 (a b c d)
For a total of 1 fact.
CLIPS> ?s
(x y z)
CLIPS> (modify 1 (implied ?s))
FALSE
CLIPS> (facts)
f-1 (a b c d)
For a total of 1 fact.
CLIPS>
Modify only works with template facts. If you're using ordered facts, you need to do a retract and assert:
CLIPS> (assert (a b c d))
<Fact-1>
CLIPS> (bind ?s x y z)
(x y z)
CLIPS> (retract 1)
CLIPS> (assert (a ?s))
<Fact-2>
CLIPS> (facts)
f-2 (a x y z)
For a total of 1 fact.
CLIPS>
Use the replace$ function to replace values in a multifield value before asserting it as part of a fact:
CLIPS> (bind ?s (replace$ ?s 2 2 g))
(x g z)
CLIPS>
I'm trying to find the most common element across multiple multislot entry of type symbol and I don't seem to get a decent way to extracts the content of those multislot to single entry to iterate over.
==================================
(deftemplate chain ""
(multislot edge
(type SYMBOL))
)
(assert (chain (edge a b c d e f g)))
(assert (chain (edge d e f g h k l)))
(assert (chain (edge e o p q r s f)))
(deffunction find_most_common_edge ()
(bind ?edge (create$))
(bind ?counted_edge (create$))
(bind ?largest_count 0)
(do-for-all-facts ((?s chain)) TRUE
(loop-for-count (length$ ?s:edge) (?s1 (expand$ ?s:edge))
(if (not (member$ ?s1 ?counted_edge))
then
(bind ?counted_edge (create$ ?s1 ?counted_edge))
(bind ?count (length$ (find-all-facts ((?s2 chain)) (member$ ?s1 ?s2:edge))))
(if (= ?count ?largest_count)
then
(bind ?edge (create$ ?s1 ?edge))
else
(if (> ?count ?largest_count)
then
(bind ?largest_count ?count)
(bind ?edge (create$ ?s1)))))))
(return ?edge))
Using functions:
CLIPS (6.4 2/9/21)
CLIPS>
(deftemplate chain
(multislot edge (type SYMBOL)))
CLIPS>
(deffacts start
(chain (edge a b c d e f g))
(chain (edge d e f g h k l))
(chain (edge e o p q r s f)))
CLIPS>
(deffunction get-all-edges ()
(bind ?all-edges (create$))
(do-for-all-facts ((?f chain)) TRUE
(bind ?all-edges (create$ ?all-edges ?f:edge)))
(return ?all-edges))
CLIPS>
(deffunction count-edge (?e ?all-edges)
(bind ?all-length (length$ ?all-edges))
(return (- ?all-length (length$ (delete-member$ ?all-edges ?e)))))
CLIPS>
(deffunction remove-duplicates ($?mf)
(bind ?rv (create$))
(foreach ?v ?mf
(if (not (member$ ?v ?rv))
then
(bind ?rv (create$ ?rv ?v))))
(return ?rv))
CLIPS>
(deffunction find-most-common-edge ()
(bind ?all-edges (get-all-edges))
(bind ?unique-edges (remove-duplicates ?all-edges))
(bind ?largest-count 0)
(bind ?most-common (create$))
(foreach ?e ?unique-edges
(bind ?count (count-edge ?e ?all-edges))
(if (= ?count ?largest-count)
then
(bind ?most-common (create$ ?most-common ?e))
else
(if (> ?count ?largest-count)
then
(bind ?largest-count ?count)
(bind ?most-common (create$ ?e)))))
(return ?most-common))
CLIPS> (reset)
CLIPS> (find-most-common-edge)
(e f)
CLIPS>
Using rules:
CLIPS> (clear)
CLIPS>
(deftemplate chain
(slot id (default-dynamic (gensym*)))
(multislot edge (type SYMBOL)))
CLIPS>
(deftemplate count
(slot edge)
(multislot ids))
CLIPS>
(deffacts start
(chain (edge a b c d e f g))
(chain (edge d e f g h k l))
(chain (edge e o p q r s f))
(find-common-edge))
CLIPS>
(defrule create-count
(logical (find-common-edge))
(chain (id ?id) (edge $? ?e $?))
(not (count (edge ?e)))
=>
(assert (count (edge ?e) (ids ?id))))
CLIPS>
(defrule add-to-count
(logical (find-common-edge))
(chain (id ?id) (edge $? ?e $?))
?f <- (count (edge ?e) (ids $?ids))
(test (not (member$ ?id ?ids)))
=>
(modify ?f (ids ?ids ?id)))
CLIPS>
(defrule most-common-edge
(declare (salience -10))
?f <- (find-common-edge)
(count (edge ?e) (ids $?r1))
(not (and (count (edge ~?e) (ids $?r2))
(test (> (length$ ?r2) (length$ ?r1)))))
=>
(bind ?length (length$ ?r1))
(bind ?edges (create$))
(do-for-all-facts ((?c count))
(eq (length$ ?c:ids) ?length)
(bind ?edges (create$ ?edges ?c:edge)))
(assert (most-common-edges ?edges))
(retract ?f))
CLIPS> (reset)
CLIPS> (run)
CLIPS> (facts)
f-1 (chain (id gen4) (edge a b c d e f g))
f-2 (chain (id gen5) (edge d e f g h k l))
f-3 (chain (id gen6) (edge e o p q r s f))
f-20 (most-common-edges e f)
For a total of 4 facts.
CLIPS>
I need to make complement and difference operations between two sets. I've a example, to do union between two sets, I can reuse this code to make these two other operations.
Thanks
The union example, that I've is:
(deffacts datos-iniciales
(conjunto B C A D E E B C E)
(conjunto E E B F D E))
(defrule inicio
=>
(assert (union)))
(defrule union
?h <- (union $?u)
(conjunto ? $? ?e $?)
(not (union $? ?e $?))
=>
(retract ?h)
(assert (union ?e $?u)))
Specifically, which part of the program should be changed? Thx
Here's how you can compute all three leaving the set-1 and set-2 facts unmodified, ignoring duplicate members, and sorting the results.
CLIPS (6.31 6/12/19)
CLIPS>
(deffacts datos-iniciales
(set-1 B C A D E E B C E)
(set-2 E E B F D E))
CLIPS>
(deffacts universe
(universe A B C D E F G H I J K))
CLIPS>
(deffunction str-sort (?a ?b)
(> (str-compare (sym-cat ?a) (sym-cat ?b)) 0))
CLIPS>
(defrule calcula
=>
(assert (union)
(complement)
(difference)))
CLIPS>
(defrule add-to-union
?union <- (union $?u)
(or (set-1 $? ?v $?)
(set-2 $? ?v $?))
(test (not (member$ ?v ?u)))
=>
(retract ?union)
(assert (union ?u ?v)))
CLIPS>
(defrule add-to-complement
?complement <- (complement $?c)
(universe $?u1 ?v $?u2)
(set-1 $?s)
(test (and (not (member$ ?v ?c))
(not (member$ ?v ?s))))
=>
(retract ?complement)
(assert (complement ?c ?v)))
CLIPS>
(defrule add-to-difference
?difference <- (difference $?d)
(set-1 $? ?v $?)
(set-2 $?set2)
(test (and (not (member$ ?v ?d))
(not (member$ ?v ?set2))))
=>
(retract ?difference)
(assert (difference ?d ?v)))
CLIPS>
(defrule write-union
(declare (salience -10))
(union $?u)
=>
(printout t "The union is " (sort str-sort ?u) crlf))
CLIPS>
(defrule write-complement
(declare (salience -10))
(complement $?c)
=>
(printout t "The complement is " (sort str-sort ?c) crlf))
CLIPS>
(defrule write-difference
(declare (salience -10))
(difference $?d)
=>
(printout t "The difference is " (sort str-sort ?d) crlf))
CLIPS> (reset)
CLIPS> (run)
The union is (A B C D E F)
The complement is (F G H I J K)
The difference is (A C)
CLIPS>
I am trying to solve a problem, where I have to fill a 5x5 matrix with letters A, B, C, D, and E. Each letter cannot occur more than once in each row and in each column. With some initial letter positions given.
I created every position as separate facts eg. "M 1 1 X".
I am struggling how to loop a defrule in way to assert a fact with correct letter and check the conditions again.
(defrule solveA5
?a <-(M 5 ?c X)
(not (M ?x ?c A))
=>
(retract ?a)
(assert (M 5 ?c A))
)
Code above for example is only to check presence of A in every position of 5th row, but the problem is that conditions are checked at the beginning only and instead of asserting correct fact and checking again it asserts A in every position.
I've tried using deffunction to loop defrule.
(deffunction solve (?letter)
(loop-for-count (?x 1 5) do
(loop-for-count (?y 1 5) do
(build (str-cat"defrule costam
?a <-(M ?x ?y X)
(not (and(M ?x ?a ?letter) (M ?b ?y ?letter))
=>
(retract ?a)
(assert (M ?x ?y ?letter))")
)
)
)
)
Unfortunately running
(solve A)
returns "FALSE" and doesn't modify any facts.
To handle iteration within rules, you must assert the iteration information as facts to allow the rules to match and modify this information. In the placement, it's not essential to do this in any particular order, so you can just assert information containing the rows, columns, and letters to place and allow the rules fire arbitrarily:
CLIPS>
(deftemplate element
(slot row)
(slot column)
(slot value))
CLIPS>
(deftemplate print
(slot row)
(slot column)
(slot end-of-row))
CLIPS>
(deffacts initial
(rows 1 2 3 4 5)
(columns 1 2 3 4 5)
(letters A B C D E))
CLIPS>
(defrule place
(rows $? ?r1 $?)
(columns $? ?c1 $?)
(letters $? ?l $?)
(not (element (row ?r1) (column ?c1)))
(not (and (element (row ?r2)
(column ?c2)
(value ?l))
(test (or (= ?r1 ?r2) (= ?c1 ?c2)))))
=>
(assert (element (row ?r1) (column ?c1) (value ?l))))
CLIPS>
(defrule print-start
(declare (salience -10))
(rows ?r $?)
(columns ?c $?rest)
=>
(assert (print (row ?r)
(column ?c)
(end-of-row (= (length$ ?rest) 0)))))
CLIPS>
(defrule print-next-column
(declare (salience -10))
?f <- (print (column ?c))
(columns $? ?c ?nc $?rest)
=>
(modify ?f (column ?nc)
(end-of-row (= (length$ ?rest) 0))))
CLIPS>
(defrule print-next-row
(declare (salience -10))
?f <- (print (column ?c) (row ?r))
(columns $?first ?c)
(rows $? ?r ?nr $?)
=>
(if (= (length$ ?first) 0)
then
(bind ?eor TRUE)
(bind ?nc ?c)
else
(bind ?eor FALSE)
(bind ?nc (nth$ 1 ?first)))
(modify ?f (row ?nr)
(column ?nc)
(end-of-row ?eor)))
CLIPS>
(defrule print-placed
(print (row ?r) (column ?c) (end-of-row ?eor))
(element (row ?r) (column ?c) (value ?l))
=>
(if ?eor
then
(printout t ?l crlf)
else
(printout t ?l " ")))
CLIPS>
(defrule print-unplaced
(print (row ?r) (column ?c) (end-of-row ?eor))
(not (element (row ?r) (column ?c)))
=>
(if ?eor
then
(printout t "?" crlf)
else
(printout t "? ")))
CLIPS> (reset)
CLIPS> (run)
E D C B A
? C D A B
? B A D C
? A B C D
A ? ? ? E
CLIPS>
In this example, the print rules iterate over the rows and columns by storing the iteration information in facts. You can see how much more complicated this is than the place rule which assigns the elements in an arbitrary manner.
Whether you assign the values arbitrarily or in a specific order, it's possible to assign values that prevent a solution, so you must implement backtracking in order to guarantee finding the solution if one exists. In this example, the facts store information about the order of the value placements and the values that have been tried:
CLIPS> (clear)
CLIPS>
(deftemplate element
(slot row)
(slot column)
(slot value (default unset))
(multislot values)
(slot placement))
CLIPS>
(deffacts initial
(placement 0)
(rows 1 2 3 4 5)
(columns 1 2 3 4 5)
(letters A B C D E))
CLIPS>
(defrule prime
(placement ?p)
(rows $? ?r $?)
(columns $? ?c $?)
(letters $?l)
(not (element (placement ?p)))
(not (element (row ?r) (column ?c)))
=>
(assert (element (placement ?p) (values ?l) (row ?r) (column ?c))))
CLIPS>
(defrule place-good
?f1 <- (placement ?p)
?f2 <- (element (placement ?p)
(value unset)
(row ?r1)
(column ?c1)
(values ?v $?rest))
(not (and (element (row ?r2)
(column ?c2)
(value ?v))
(test (or (= ?r1 ?r2) (= ?c1 ?c2)))))
=>
(retract ?f1)
(assert (placement (+ ?p 1)))
(modify ?f2 (value ?v) (values ?rest)))
CLIPS>
(defrule place-bad
(placement ?p)
?f2 <- (element (placement ?p)
(value unset)
(row ?r1)
(column ?c1)
(values ?v $?rest))
(element (row ?r2)
(column ?c2)
(value ?v))
(test (or (= ?r1 ?r2) (= ?c1 ?c2)))
=>
(modify ?f2 (values ?rest)))
CLIPS>
(defrule backtrack
?f1 <- (placement ?p)
?f2 <- (element (placement ?p)
(value unset)
(values))
?f3 <- (element (placement =(- ?p 1))
(value ~unset))
=>
(retract ?f1)
(assert (placement (- ?p 1)))
(retract ?f2)
(modify ?f3 (value unset)))
CLIPS>
(defrule print
(declare (salience -10))
(rows $?rows)
(columns $?columns)
=>
(progn$ (?r ?rows)
(progn$ (?c ?columns)
(if (not (do-for-fact ((?f element))
(and (= ?r ?f:row) (= ?c ?f:column))
(printout t ?f:value " ")))
then
(printout t "? ")))
(printout t crlf)))
CLIPS> (reset)
CLIPS> (run)
B C D E A
A B C D E
C A E B D
D E A C B
E D B A C
CLIPS>
The print rules have been simplified into a single rule that iterates over the row and columns in the actions of the rule and uses the fact query functions to retrieve values that have been assigned.
The program also works if you preassign some of the values:
CLIPS> (reset)
CLIPS> (assert (element (row 1) (column 1) (value A)))
<Fact-5>
CLIPS> (assert (element (row 3) (column 3) (value C)))
<Fact-6>
CLIPS> (assert (element (row 5) (column 4) (value E)))
<Fact-7>
CLIPS> (run)
A C E D B
B A D C E
D E C B A
E D B A C
C B A E D
CLIPS>
I just want a function to print on item per line.
I am trying:
(deffunction myprint (?first $?rest)
(if (neq ?rest nil) then
(printout t ?first crlf)
(myprint ?rest)))
What is wrong?
Use the length function to determine if a list is empty (a return value of 0). Comparing a list to the symbol nil will always fail.
You want to print ?first even if ?rest is empty. Otherwise the last element will never be printed.
It is not necessary to use recursion.
CLIPS>
(deffunction myprint ($?rest)
(foreach ?r $?rest
(printout t ?r crlf)))
CLIPS> (myprint a b c)
a
b
c
CLIPS> (myprint (create$ a b) (create$ c d))
a
b
c
d
CLIPS>