How to Reset the fact-index when assert new fact? - clips

I have embedded CLIPS into C Language.
I have situation like this:
in a .clp file, I have fact list
(deftemplate sensor
(slot name)
(slot status))
(deffacts FRONTSENSOR
(sensor (name 1) (status 1))
(sensor (name 2) (status 1))
(sensor (name 3) (status 0))
(sensor (name 4) (status 0))
(sensor (name 5) (status 1))
(sensor (name 6) (status 0))
(sensor (name 7) (status 0))
(sensor (name 8) (status 0)))
now I want to cancel these facts and assert new facts in to the list.
I use Retract(factPtr); to cancel facts and use AssertString("(sensor (name 1) (status 0))"); to assert fact.
And I print the fact list, result is
f-0 (initial-fact)
f-11 (sensor (name 1) (status 0))
f-12 (sensor (name 2) (status 0))
f-13 (sensor (name 3) (status 1))
f-14 (sensor (name 4) (status 0))
f-15 (sensor (name 5) (status 0))
f-16 (sensor (name 6) (status 0))
f-17 (sensor (name 7) (status 1))
f-18 (sensor (name 8) (status 1))
For a total of 9 facts.
the fact-index is start from 11 instead of 1, I wonder if there is function or solution that the new asserted fact can start from f-1.
Ps:Clear()function can reset the fact-index, but the rules will also be cleaned. It seems not helpful.
Thank for answers or any ideas.

The Reset() function will remove all the facts and reset the fact-indices without removing any of the rules.

Related

Clips range find between 2 json inputs

I want to implemen a rule ;
Lets assume that ı have one input.json it consist a name value pair.Example;
{
"quality":"300"
}
I have another constant json ,Example
[{
"up":"100",
"down":"0",
"data":"xx"
},
{
"up":"200",
"down":"100",
"data":"yy"
},
,
{
"up":"300",
"down":"200",
"data":"zz"
}
]
I am trying to find propert value for data for which up and down range.
for this one ı, have to get zz because "quality":"300" is between 200-300.
how can ı success this one in clips rule.
CLIPS (6.31 6/12/19)
CLIPS>
(deftemplate pair
(slot name)
(slot value))
CLIPS>
(deffacts pairs
(pair (name "quality") (value 300)))
CLIPS>
(deftemplate data
(slot name)
(slot up)
(slot down))
CLIPS>
(deffacts data-values
(data (name "xx") (up 100) (down 0))
(data (name "yy") (up 200) (down 100))
(data (name "zz") (up 300) (down 200)))
CLIPS>
(defrule in-range
(pair (name "quality")
(value ?value))
(data (name ?name)
(up ?up)
(down ?down))
(test (and (> ?value ?down) (<= ?value ?up)))
=>
(printout t ?name " is in range." crlf))
CLIPS> (reset)
CLIPS> (facts)
f-0 (initial-fact)
f-1 (pair (name "quality") (value 300))
f-2 (data (name "xx") (up 100) (down 0))
f-3 (data (name "yy") (up 200) (down 100))
f-4 (data (name "zz") (up 300) (down 200))
For a total of 5 facts.
CLIPS> (agenda)
0 in-range: f-1,f-4
For a total of 1 activation.
CLIPS> (run)
zz is in range.
CLIPS>

How to printout all matches facts in a rule

I have a rule like below and I want to print all facts(here objct) that are compatible to this rule. I have a fact objct and there are some of these "objct"s that follow the rule. how I can do it? The printout below just prints the latest objct that player got. However I want to printout all of them. Any idea?
(defrule have_objcts
?input <- (input have|possession)
(objct (name ?n) (location player) (used 0))
=>
;WHAT SHOULD I WRITE HERE TO PRINTOUT those OBJCT's BELONG TO
PALYER???????????
(printout t crlf ?n)
(retract ?input))
Use the matches command:
CLIPS>
(deftemplate objct
(slot name)
(slot location)
(slot used))
CLIPS>
(deffacts initial
(objct (name x) (location player) (used 0))
(objct (name y) (location elsewhere) (used 1))
(objct (name z) (location player) (used 0))
(input have)
(input want)
(input possession)
(input thing))
CLIPS>
(defrule have_objcts
?input <- (input have|possession)
(objct (name ?n) (location player) (used 0))
=>
(retract ?input))
CLIPS> (reset)
CLIPS> (matches have_objcts)
Matches for Pattern 1
f-4
f-6
Matches for Pattern 2
f-1
f-3
Partial matches for CEs 1 - 2
f-6,f-3
f-6,f-1
f-4,f-3
f-4,f-1
Activations
f-6,f-3
f-6,f-1
f-4,f-3
f-4,f-1
(4 4 4)
CLIPS> (run)
CLIPS> (matches have_objcts)
Matches for Pattern 1
None
Matches for Pattern 2
f-1
f-3
Partial matches for CEs 1 - 2
None
Activations
None
(2 0 0)
CLIPS>

CLIPS defrule checking if multiple sides of a box are taken

I am working on a program that will tell me which moves to make in a dots-and-boxes game. I am trying to implement a defrule that will check to see if a box already has 2 of the possible 4 sides taken. If this is the case then I don't want to take one of the remaining two lines, as that will give the opponent a free point.
(defrule Player_Move_No_Box_1_1
(next_turn p)
(turn_num ?t_num)
(test(> ?t_num 3))
(line ?l1&~1)
(not(line 1))
=>
(if
(not(or(and(any-factp ((?l line)) (member$ (+ ?l1 3) ?l:implied))(any-factp ((?l line)) (member$ (+ ?l1 4) ?l:implied)))
(and(any-factp ((?l line)) (member$ (+ ?l1 3) ?l:implied))(any-factp ((?l line)) (member$ (+ ?l1 7) ?l:implied)))
(and(any-factp ((?l line)) (member$ (+ ?l1 4) ?l:implied))(any-factp ((?l line)) (member$ (+ ?l1 7) ?l:implied)))))
then
(printout t "Take line #1" crlf)
(assert(line 1))
(assert(next_turn c))))
I've been trying a lot of different things, but this is the last code I tried to use, but with no success. For this piece of code I'm looking at line 1 (clockwise starting from the top of a box the boxes are numbered: x, x+4, x+7, x+3). Is there a simpler way of making this check, or will this way work and I've just messed the code up somewhere?
I would suggest explicitly representing each possible line as a fact and denote in the fact whether the line has been taken. Also do the pattern matching in the conditions of the rules rather than the actions.
CLIPS>
(deftemplate line
(slot id)
(slot taken (default no)))
CLIPS>
(defrule Player_Move_Top_Line
?take <- (line (id ?l1) (taken no))
(line (id =(+ ?l1 3)) (taken ?t3))
(line (id =(+ ?l1 4)) (taken ?t4))
(line (id =(+ ?l1 7)) (taken ?t7))
(test (not (or (and (eq ?t3 yes) (eq ?t4 yes) (eq ?t7 no))
(and (eq ?t3 yes) (eq ?t4 no) (eq ?t7 yes))
(and (eq ?t3 no) (eq ?t4 yes) (eq ?t7 yes)))))
=>
(printout t "Take line #" ?l1 crlf)
(modify ?take (taken yes)))
CLIPS>
I've stripped out the turn information from your original rule just to make it easier to test it.
CLIPS> (assert (line (id 0)) (line (id 3)) (line (id 4)) (line (id 7)))
<Fact-4>
CLIPS> (agenda)
0 Player_Move_Top_Line: f-1,f-2,f-3,f-4
For a total of 1 activation.
CLIPS> (reset)
CLIPS> (assert (line (id 0)) (line (id 3)) (line (id 4)) (line (id 7) (taken yes)))
<Fact-4>
CLIPS> (agenda)
0 Player_Move_Top_Line: f-1,f-2,f-3,f-4
For a total of 1 activation.
CLIPS> (reset)
CLIPS> (assert (line (id 0)) (line (id 3)) (line (id 4) (taken yes)) (line (id 7)))
<Fact-4>
CLIPS> (agenda)
0 Player_Move_Top_Line: f-1,f-2,f-3,f-4
For a total of 1 activation.
CLIPS> (reset)
CLIPS> (assert (line (id 0)) (line (id 3) (taken yes)) (line (id 4)) (line (id 7)))
<Fact-4>
CLIPS> (agenda)
0 Player_Move_Top_Line: f-1,f-2,f-3,f-4
For a total of 1 activation.
CLIPS> (reset)
CLIPS> (assert (line (id 0)) (line (id 3) (taken yes)) (line (id 4) (taken yes)) (line (id 7)))
<Fact-4>
CLIPS> (agenda)
CLIPS> (reset)
CLIPS> (assert (line (id 0)) (line (id 3) (taken yes)) (line (id 4)) (line (id 7) (taken yes)))
<Fact-4>
CLIPS> (agenda)
CLIPS> (reset)
CLIPS> (assert (line (id 0)) (line (id 3)) (line (id 4) (taken yes)) (line (id 7) (taken yes)))
<Fact-4>
CLIPS> (agenda)
CLIPS> (reset)
CLIPS> (assert (line (id 0)) (line (id 3) (taken yes)) (line (id 4) (taken yes)) (line (id 7) (taken yes)))
<Fact-4>
CLIPS> (agenda)
0 Player_Move_Top_Line: f-1,f-2,f-3,f-4
For a total of 1 activation.
CLIPS>

Calling a function disrupts the rules

I'm trying to change the design of an expert system to work carried out by my rules.
Topic - processing of different parts on different machines. Naturally, each kind of items processed at different times on different machines.
The system consists of three rules. The first rule - load machines work. The second rule - unloads machines. The third rule - performs the movement of time.
I added in the first rule of a function call, which seeks item with maximum processing time. However, the expert system stopped working. Simply displays "1". That's all.
(defglobal ?*time* = 0)
(deftemplate details
(field det (type SYMBOL))
(field oper (type INTEGER))
(field count (type INTEGER))
)
(deftemplate route
(field det (type SYMBOL))
(field oper (type INTEGER))
(field machine (type INTEGER))
(field time (type INTEGER))
)
(deftemplate machine
(field num (type INTEGER))
(field count (type INTEGER)(default 0))
(field det (type SYMBOL)(default A))
(field oper (type INTEGER)(default 0))
(field time (type INTEGER)(default 0))
)
(deffacts details
(details (det A) (oper 0) (count 100))
(details (det B) (oper 0) (count 150))
(details (det C) (oper 0) (count 200))
(details (det D) (oper 0) (count 300))
(details (det E) (oper 0) (count 200))
(details (det A) (oper 1) (count 0))
(details (det B) (oper 1) (count 0))
(details (det C) (oper 1) (count 0))
(details (det D) (oper 1) (count 0))
(details (det E) (oper 1) (count 0))
....
)
(deffacts route
(route (det A) (oper 1) (machine 1) (time 10))
(route (det A) (oper 2) (machine 2) (time 5))
(route (det A) (oper 2) (machine 2) (time 2))
(route (det A) (oper 3) (machine 3) (time 4))
(route (det A) (oper 3) (machine 4) (time 3))
(route (det A) (oper 4) (machine 4) (time 8))
(route (det A) (oper 4) (machine 1) (time 8))
(route (det B) (oper 1) (machine 1) (time 8))
(route (det B) (oper 2) (machine 5) (time 4))
(route (det B) (oper 2) (machine 2) (time 6))
(route (det B) (oper 3) (machine 6) (time 3))
(route (det B) (oper 3) (machine 5) (time 2))
(route (det B) (oper 4) (machine 7) (time 2))
(route (det B) (oper 4) (machine 2) (time 3))
...
)
(deffacts machines
(machine (num 1))
(machine (num 2))
(machine (num 3))
(machine (num 4))
(machine (num 5))
(machine (num 6))
(machine (num 7))
(machine (num 8))
)
(deffunction my-predicate (?fact1 ?fact2)
(< (fact-slot-value ?fact1 time) (fact-slot-value ?fact2 time)))
(deffunction find-max2 (?template1 ?predicate1 ?operation ?template2 ?max)
(bind ?max FALSE)
(do-for-all-facts ((?f2 ?template2)) (eq (fact-slot-value ?f2 count) 0)
(do-for-all-facts ((?f1 ?template1)) (eq (fact-slot-value ?f1 oper) ?operation) (eq (fact-slot-value ?f1 oper)(fact-slot-value ?f2 oper))
(if (or (not ?max) (funcall ?predicate1 ?f1 ?max))
then
(bind ?max ?f1)))
)
)
;--------------------------------------------------------------------------------------------------
(defrule work_on_1
(declare (salience 10000))
(machine (num ?num1)(count ?count1) (time ?time1))
(test (eq ?count1 0))
(test (eq ?time1 0))
?node1 <- (machine (num ?num1)(count ?count1) (time ?time1))
(details (det ?detail) (oper ?operation1) (count ?count2))
(test (not (eq ?count2 0)))
?node2 <- (details (det ?detail) (oper ?operation1) (count ?count2))
; add this code
(funcall find-max2 route my-predicate ?operation1 details ?max)
(test (eq ?operation1(fact-slot-value ?max oper )))
(route (machine ?num1) (det ?detail) (oper ?operation2) (time ?time2))
(test (eq ?operation2 (+ ?operation1 1)))
=>
(if (> ?count2 30)
then
(modify ?node1 (count 30) (time ?time2) (oper ?operation2) (det ?detail))
(modify ?node2 (count (- ?count2 30)))
(printout t ?*time*" ," ?num1 " 30 деталей типа "?detail " , " ?operation2 " , " ?time2 crlf)
else
(modify ?node1 (count ?count2) (time ?time2) (oper ?operation2) (det ?detail))
(modify ?node2 (count (- ?count2 ?count2)))
(printout t ?*time*" , " ?num1 " " ?count2 " , "?detail " , " ?operation2 " , " ?time2 crlf)
)
)
There are numerous issues with the code. First it's unclear why there’s redundant pattern matching for the machine and details facts:
(machine (num ?num1)(count ?count1) (time ?time1))
(test (eq ?count1 0))
(test (eq ?time1 0))
?node1 <- (machine (num ?num1)(count ?count1) (time ?time1))
(details (det ?detail) (oper ?operation1) (count ?count2))
(test (not (eq ?count2 0)))
?node2 <- (details (det ?detail) (oper ?operation1) (count ?count2))
The following code is sufficient to achieve the same task:
?node1 <- (machine (num ?num1) (count ?count1&0) (time ?time1&0))
?node2 <- (details (det ?detail) (oper ?operation1) (count ?count2&~0))
Second, it looks like you're expecting the funcall pattern to invoke a function call and place the result of that function call in the variable ?max:
(funcall find-max2 route my-predicate ?operation1 details ?max)
There is no funcall conditional element that has this type of behavior. In this case, you've just created a pattern conditional element that's looking for an ordered fact with the relation name funcall. If you wanted to invoke funcall from the conditions of a rule you'd use the test conditional element:
(test (funcall find-max2 route my-predicate ?operation1 details))
Since the function being invoked is a literal, find-max2, there's really no point in using funcall since you can just call the function directly:
(test (find-max2 route my-predicate ?operation1 details))
Third, there's not much point to using the query functions within the conditions of a rule since you can directly pattern match on the facts instead. In addition, the placement of the query function you've used within the conditions will cause it to be executed once there are matching machine/details facts, but possibly before there are any route facts, so it will likely not even return the correct results.
The following rule shows how to find the maximum values without using query functions:
(defrule find-max
(route (oper ?oper1) (time ?time1))
(exists (details (count 0) (oper ?oper1)))
(not (and (route (oper ?oper2) (time ?time2&:(> ?time2 ?time1)))
(exists (details (count 0) (oper ?oper2)))))
=>
(printout t "Maximum time is " ?time1 crlf))
(defrule work_on_1
(declare (salience 10000))
?node1 <- (machinegun (num ?num1) (count ?count1&0) (time ?time1&0))
?node2 <- (store (det ?detail) (oper ?operation1) (count ?count2&~0))
(tex_route (oper ?oper1) (time ?time2))
(exists (store (count 0) (oper ?oper1)))
(not (and (tex_route (oper ?oper2) (time ?time3&:(> ?time3 ?time2)))
(exists (store (count 0) (oper ?oper2)))))
(test (eq ?time1 ?time2))
(route (machine ?num1) (det ?detail) (oper ?operation2) (time ?time2))
(test (eq ?operation2 (+ ?operation1 1)))
=>
(if (> ?count2 30)
then
(modify ?node1 (count 30) (time ?time2) (oper ?operation2) (det ?detail))
(modify ?node2 (count (- ?count2 30)))
(printout t ?*time*" ," ?num1 " 30 деталей типа "?detail " , " ?operation2 " , " ?time2 crlf)
else
(modify ?node1 (count ?count2) (time ?time2) (oper ?operation2) (det ?detail))
(modify ?node2 (count (- ?count2 ?count2)))
(printout t ?*time*" , " ?num1 " " ?count2 " , "?detail " , " ?operation2 " , " ?time2 crlf)
)
)
It is new rule, but when the expert system stopped working - simply displays "1".

Clips- small routine program

I have 10 sensor that watch an environment. The sensor is 1 if OK and 0 if not.
I need to create a functional that will print out a Warning message to the terminal if there are at least 3 sensor that are on 0, and the message warning to be showed only once. This I need to do in clips.
Thank you.
(deffacts listaSenzor
(sensor L1 0)
(sensor L2 0)
(sensor L3 1)
(sensor L4 1)
(sensor L5 1)
(sensor L6 1)
(sensor L7 0)
(sensor L8 1)
(sensor L9 0)
)
(defrule rr
(sensor ?a 0 )
(sensor ?b 0 )
(sensor ?c 0 )
=>
printout t ?a ?b ?c "==>WARNING" crlf)
)
There are two issues you need to deal with. The first is that the patterns you defined can match the same fact multiple times (e.g., sensor L1 will be bound to a, b, and c). To get around this, you need to ensure that a, b, and c are unique. One way to do this is as follows (note that I also added a missing "(" in front of your printout statement):
(deffacts listaSenzor
(sensor L1 0)
(sensor L2 0)
(sensor L3 1)
(sensor L4 1)
(sensor L5 1)
(sensor L6 1)
(sensor L7 0)
(sensor L8 1)
(sensor L9 0))
(defrule rr
(sensor ?a 0)
(sensor ?b 0)
(sensor ?c 0)
(test (neq ?a ?b))
(test (neq ?a ?c))
(test (neq ?b ?c))
=>
(printout t ?a ?b ?c "==>WARNING" crlf))
Running this rule against your facts gives:
CLIPS> (reset)
CLIPS> (run)
L9L7L2==>WARNING
L9L7L1==>WARNING
L9L2L7==>WARNING
...
L1L2L7==>WARNING
L2L1L7==>WARNING
The warning is now only generated when there are three or more not-OK sensors; however, the output presents the second issue, which is that your warning is being generated multiple times (once for every unique combination of three not-OK sensors). To get around this, you probably want a control fact to prevent the rule from firing multiple times. To achieve this, you could modify the rule with the following:
(defrule rr
(not (sensor-warning))
(sensor ?a 0)
(sensor ?b 0)
(sensor ?c 0)
(test (neq ?a ?b))
(test (neq ?a ?c))
(test (neq ?b ?c))
=>
(assert (sensor-warning))
(printout t ?a ?b ?c "==>WARNING" crlf))
This ensures that the rule will only fire once (unless you retract the sensor-warning fact). Running with the updated rule:
CLIPS> (reset)
CLIPS> (run)
L9L7L2==>WARNING
CLIPS>
This is a simple solution to your problem. If you are likely to change the number of not-OK sensors that should trigger the rule, then you should probably replace the "hardwired" sensor name comparisons with more general logic (e.g., you could compute the total number of not-OK sensors and compare that to your threshold).
Here's another way to do it:
(deftemplate sensor
(slot id)
(slot value))
(deffacts listaSenzor
(sensor (id L1) (value 0))
(sensor (id L2) (value 0))
(sensor (id L3) (value 1))
(sensor (id L4) (value 1))
(sensor (id L5) (value 1))
(sensor (id L6) (value 1))
(sensor (id L7) (value 0))
(sensor (id L8) (value 1))
(sensor (id L9) (value 0)))
(defrule rr
(exists
(sensor (id ?id1) (value 0))
(sensor (id ?id2&~?id1) (value 0))
(sensor (id ?id3&~?id2&~?id1) (value 0)))
=>
(bind ?sensors (create$))
(do-for-all-facts ((?f sensor)) (eq ?f:value 0)
(bind ?sensors (create$ ?sensors ?f:id)))
(printout t (str-implode ?sensors) " ==> WARNING" crlf))
This will print all of the sensors if there are more than 3 that have a value of 0.
CLIPS> (reset)
CLIPS> (run)
L1 L2 L7 L9 ==> WARNING
CLIPS>

Resources