I need help comparing numbers in defrule with multislot objects in CLIPS - clips

I have the following code
(deftemplate choice-evaluation
(slot x_front)
(slot y_left)
(deftemplate es_result
(slot classp)
(slot classr)
(slot nr) )
(defrule MAIN::one
(x_front ?val)
(bind ?temp 1)
(choice-evaluation(y_left -1) (test (<= ?val ?temp ))(class ?x))
?c<-(choice-evaluation(y_left -1) (test(<= ?val ?temp ))(class ?x))
=>
(assert (es_result (classp 0) (classr ?x) (nr 1)))
(retract ?c))
and I get the error : ERROR:
(defrule MAIN::one
(x_front ?val)
(choice-evaluation (y_left -1) (test
I have tried a lot of things but I will always either get the error above or syntax error for defrules . I do not understand how I can have a comparison in defrules with multislot objects.
I tried creating a rule like the examples here :https://www.csie.ntu.edu.tw/~sylee/courses/clips/advpattern.htm and they do work but it doesnt work for my particular case.

There are several errors in your code which are easier to see if you ident the code:
(defrule MAIN::one
(x_front ?val)
(bind ?temp 1)
(choice-evaluation (y_left -1)
(test (<= ?val ?temp))
(class ?x))
?c <- (choice-evaluation (y_left -1)
(test (<= ?val ?temp))
(class ?x))
=>
(assert (es_result (classp 0) (classr ?x) (nr 1)))
(retract ?c))
You've placed test conditional elements inside choice-evaluation conditional elements so the parser treats the test symbols as slot names and since the choice-evaluation deftemplate has no slot named test you get an error. You'll also get an error for using class as a slot name since this slot is also not defined in the choice-evaluation deftemplate.
Also, (bind ?temp 1) will be treated as a fact pattern, not a function call. If you want to retrieve a value in the conditions of a rule, assert a fact containing that value and assign it to a variable using a pattern like the x_front pattern in your rule. Duplication of the choice-evaluation pattern serves no purpose--Just keep the 2nd one since it binds ?c to the fact-address matching the pattern which is need by the retract command in the actions of the rule.

#Gary Riley thanks for your input it helped a lot!
(choice-evaluation (x_front ?val) (y_left -1) (class ?x))
(test (<= ?val 1 ))
?c <- (choice-evaluation (x_front ?val) (y_left -1) (class ?x))
=>
(assert (es_result (classp 0) (classr ?x) (nr 1)))
(retract ?c))
So turns out this is how it is supposed to be used. Leaving it here in case someone else in the future has a similar problem
credits : I. Xatziligeroudis

Related

Suggestions for grammar for auditing system

I was wondering if you can point me in the right direction. I would like to write a rules-based system to audit a set of machines -- for example
Check configuration parameters to see if they were set correctly
Check state of machines to see if they are at acceptable ranges
The thing that I am struggling with is coming up with a grammar for the auditing rules so that I don't have to code defrules. I created some simple auditing rules but I am struggling with coming up with a generic form.
Here is my current attempt.
First, I am currently representing configuration parameters and running state with a single template (for a lack of imagination, I called it audit-fact) so that my auditing language can work for both configuration and state. I use the domain slot to specify configuration vs. state.
(deftemplate audit-fact
(slot domain (allowed-values config state)) ;; config vs. state
(slot machine) ;; machine to audit
(slot name) ;; parameter or state to check/audit
(slot value) ;; parameter value
(slot already-checked (default FALSE))
)
Next, I wrote a program to read in and assert the machines configuration and state as audit-facts. The following are sample configuration and state audit-facts
(assert (audit-fact
(domain config)
(machine drl-a-15_0)
(name os-version) (value 5.5))
)
(assert (audit-fact
(domain state)
(machine drl-a-15_0)
(name rpm) (value 5023))
)
Here is my current attempt at an auditing grammar/language ---
(deftemplate rule
(slot domain)
(slot name)
(slot constraint (default ?NONE) (allowed-values should-remain-at-default should-equal should-be-between ignore-if-ends-with))
(multislot values)
(multislot reasons)
(multislot references)
(slot criticality (allowed-values critical info suggestion warning))
(slot already-checked (default FALSE))
)
The following rule is used to check if a state or parameter is within a certain range
(assert (rule
(domain state)
(name rpm)
(constraint should-be-between)
(values 5000 5500)
(criticality critical)
(reasons "Low values could cause engine to stall. Prolonged high value could cause engine to heat up") )
)
Next, I used the following rule to check that a state or parameter is equal to a specific value
(assert (rule
(domain config)
(name os-version)
(constraint should-equal)
(values 5.5)
(criticality critical)
(reasons "OS version must be at 5.5 – no other levels are currently certified.") )
)
The following rules implements the equal and between checks
(defrule rule-should-eq
(rule (domain ?d) (name ?n) (constraint should-equal) (values ?cv) (reasons ?r))
?p <- (audit-fact (domain ?d) (name ?n) (value ?v) (already-checked FALSE))
=>
(if (eq ?v ?cv)
then
(printout t "checking " ?d ": " ?n ". Passed " crlf)
else
(printout t "checking " ?d “: “ ?n " should be set to " ?cv ". " ?r ". Warning" crlf)
)
(modify ?p (already-checked TRUE))
)
(defrule rule-should-be-between
(rule (domain ?d) (name ?n) (constraint should-be-between) (values ?cv-low ?cv-high) (reasons ?r))
?p <- (audit-fact (domain ?d) (name ?n) (value ?v) (already-checked FALSE))
=>
(if (and (>= ?v ?cv-low) (<= ?v ?cv-high))
then
(printout t "checking " ?n ". Passed " crlf)
else
(printout t "checking " ?n " should be between " ?cv-low " and " ?cv-high ". " ?r ". Warning" crlf)
)
(modify ?p (already-checked TRUE))
)
Using the above, I can implement simple checks -- e.g., must-be-set-to, must-be-between, must-not-equal, must-remain-at-default-value, must-be-higher-than, must-be-lower-than, etc.
But I can't think of an easy way to make the grammar handle multiple conditions with ands or ors, etc.
Question ---
is there a paper that describes a design pattern for auditing rules like above. I am currently studying the wine.clp in examples (CLIPS).
should I give up and just use the simple grammar for simple auditing rules and just use defrules for anything complicated -- e.g., if config-A is set to X, then check five other configs to make sure they are also set correctly, and then assert a check of the state. Once asserted, then check the state to be within a certain range.
Thanks in advance.
Bernie
Here's a method to evaluate arbitrary expressions from a generic rule:
CLIPS>
(deffunction str-replace (?str ?rpl ?fnd)
(if (eq ?fnd "") then (return ?str))
(bind ?rv "")
(bind ?i (str-index ?fnd ?str))
(while ?i
(bind ?rv (str-cat ?rv (sub-string 1 (- ?i 1) ?str) ?rpl))
(bind ?str (sub-string (+ ?i (str-length ?fnd)) (str-length ?str) ?str))
(bind ?i (str-index ?fnd ?str)))
(bind ?rv (str-cat ?rv ?str)))
CLIPS>
(deftemplate audit-fact
(slot domain)
(slot machine)
(slot name)
(slot value))
CLIPS>
(deftemplate rule
(slot domain)
(slot name)
(slot constraint)
(multislot reasons)
(multislot references)
(slot criticality))
CLIPS>
(deffacts initial
(audit-fact
(domain config)
(machine drl-a-15_0)
(name os-version)
(value 5.4))
(audit-fact
(domain state)
(machine drl-a-15_0)
(name rpm)
(value 5023))
(rule
(domain state)
(name rpm)
(constraint "(and (>= ?v 5000) (<= ?v 5500))")
(criticality critical)
(reasons "Low values could cause engine to stall. Prolonged high value could cause engine to heat up."))
(rule
(domain config)
(name os-version)
(constraint "(eq ?v 5.5)")
(criticality critical)
(reasons "OS version must be at 5.5 – no other levels are currently certified.")))
CLIPS>
(defrule rule-check
(rule (domain ?d) (name ?n) (constraint ?constraint) (reasons ?r))
?p <- (audit-fact (domain ?d) (name ?n) (value ?v))
=>
(bind ?constraint (str-replace ?constraint ?v "?v"))
(if (eval ?constraint)
then
(printout t "checking " ?d ": " ?n " Passed" crlf)
else
(printout t "checking " ?d ": " ?n " Warning : " ?r crlf)))
CLIPS> (reset)
CLIPS> (run)
checking config: os-version Warning : OS version must be at 5.5 – no other levels are currently certified.
checking state: rpm Passed
CLIPS>
1) If statements on the RHS are a code smell: don't!
2) You don't need the already-checked flag since you aren't modifying these facts.
Rewriting the check against one machine attribute:
?p <- (Configuration (machine ?m)(param ?p)(value ?v))
(ConfigCheckRange (param ?p){?v < loBound || $v > hiBound})
(You may need another variants, e.g., ConfigCheckEnum is permitted values aren't in one interval.)
Checking parameter value combinations is more difficult since you have chosen to represent every parameter value by a separate fact. You'll have to
?p1 <- (Configuration (machine ?m)(param ?p1)(value ?v1))
?p2 <- (Configuration (machine ?m)(param ?p2)(value ?v2)
{?p2 != ?p1))
(ConfigCheckCombi (param1 ?p1)(param2 ?p2)
{lowBound1 <= ?v1 && ?v2 <= lowBound2}
{?v2 < loBound2 || $v2 > hiBound2})
The right hand sides should merely register a violation in a (new) fact, let's call it Findings. One Findings contains the id to the machine and a list of (violated) ConfigCheck facts.
At the end (with a low-salience rule) you locate Findings facts and call the report method on it. (It may be more convenient to use some proper Java beans as facts.)

Compare symbol variable to many values

I'd like to compare a variable that holds a symbol to many values, so that if any of them matches the variable, the CE is satisfied. Here is a minimal example:
(defrule compare-students
?x <- (Student (FirstName ?n))
(or (eq ?n John) (eq ?n Beter) (eq ?n Sarah))
=>
(modify ?x (SecondName ?n)))
When I compile the constructs file to c code, I got something like this:
Defining defrule: compare-students +j+j+j
=j=j+j+j
=j=j+j+j
Is this the right way to do that?
Thanks
Preferably use this:
(defrule compare-students
?x <- (Student (FirstName ?n&John | Beter | Sarah)
(SecondName ~?n))
=>
(modify ?x (SecondName ?n)))
Or alternately this:
(defrule compare-students
?x <- (Student (FirstName ?n)
(SecondName ~?n))
(test (or (eq ?n John) (eq ?n Beter) (eq ?n Sarah)))
=>
(modify ?x (SecondName ?n)))
The first uses pattern matching constraints for brevity and the second uses the test conditional element (CE) to indicate that the following syntax is a function call to be evaluated, not a pattern to be matched. In your original rule, you don't use the test CE, so the "or" in that rule is an "or" conditional element. It will attempt to match eq facts rather than make a function call.

List manipulation in CLIPS (expert system)

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>

How do I assert a fact in a CLIPS deffunction?

I originally attempted using the modify function but it doesn't do anything and just prints false, I don't know what I am doing wrong.
I used
(modify ?tv (v ?x))
it didn't work.
I then used
(retract ?tv)
(assert (v ?x))
instead, which worked.
But I don't want to type that out every time I want to modify a fact, so I made a deffunction to do it for me, but
(deffunction modfact(?index ?factname ?factvalue)
(retract ?index)
(assert (?factname ?factvalue))
)
in this it gives a syntax error of:
[PRNTUTIL2] Syntax Error: Check appropriate syntax for first field of a RHS pattern.
ERROR:
(deffunction MAIN::modfact
(?index ?factname ?factvalue)
(retract ?index)
(assert (?factname
Which seems to me that its saying that I can't actually make this function because I can't assert a fact with the value of the variable. How can I get this to work?
Modify only works with facts that have an associated deftemplate defined with slots:
CLIPS>
(deftemplate task
(slot id)
(slot completed))
CLIPS> (watch facts)
CLIPS> (assert (task (id x) (completed no)))
==> f-1 (task (id x) (completed no))
<Fact-1>
CLIPS>
(defrule modit
?f <- (task (completed ~yes))
=>
(modify ?f (completed yes)))
CLIPS> (run)
<== f-1 (task (id x) (completed no))
==> f-2 (task (id x) (completed yes))
CLIPS>
When using the assert command, the first field of the fact must be a symbol. If you must get around this restriction you can use the str-assert function.
CLIPS>
(deffunction modfact (?index ?factname ?factvalue)
(retract ?index)
(str-assert (str-cat "(" ?factname " " ?factvalue ")")))
CLIPS> (assert (v 3))
==> f-3 (v 3)
<Fact-3>
CLIPS> (modfact 3 v 4)
<== f-3 (v 3)
==> f-4 (v 4)
<Fact-4>
CLIPS>

How can I run the clips with out reset the fact when using CLIPS

Here is my situation:
I want to run the CLIPS periodically and the system can record how many times it runs.
for example: I type in the terminal "run" many times to call the system periodically. then the system can record how many the system runs and show it on the screen. Here is my .clp file
(defglobal ?*lock* = 0)
(deftemplate counter
(slot number))
(deffacts initial_data
(counter (number 0))
)
(defrule set_counter
?f<-(counter (number ?x))
(test (= ?*lock* 0))
=>
(bind ?*lock* 1)
(printout t "plus 1" crlf)
(modify ?f (number (+ ?x 1)))
)
(defrule show_result
?f<-(counter (number ?x))
(test (= ?*lock* 1))
=>
(printout t "the counter value has been changed:" crlf)
(ppfact (fact-index ?f) t)
(bind ?*lock* 0)
)
I use a global value as a lock to control the rules and store the running times in the fact named counter. Now is my problem: Once the system finishes running for the first time. There are no rules in the agenda any more. I want the system can run again with out resetting the facts and the system can process the facts saved form the first running process. How can I refresh the agenda or rematch the rule without reset the facts?
I have find some commands like (refresh rule-name) and (refresh-agenda) but they can not solve my problem. I just type in "(refresh set_counter)" and "(refresh-agenda)" after "(run)". However, no rules are added into agenda.
I don't know if there are solution to my problem or clips can not work like this?
Another question is I try (refresh rule-name) with
(defglobal ?*lock* = 0)
(deftemplate counter
(slot number))
(deftemplate set
(slot number))
(deffacts initial_data
(counter (number 0))
)
(defrule set_counter
(initial-fact)
=>
(bind ?*lock* (+ ?*lock* 1))
(printout t ?*lock* crlf)
)
It works fine. I don't know why it doesn't work in the first example?
really thanks for any advice.
Global variables don't trigger pattern matching so you shouldn't use them in the condition of a rule unless the value is never changed. If you use a fact to represent the lock, the rules will execute for as many cycles as you specify:
(deftemplate lock
(slot value))
(deftemplate counter
(slot number))
(deffacts initial_data
(counter (number 0))
(lock (value 0))
)
(defrule set_counter
?f <- (counter (number ?x))
?l <- (lock (value 0))
=>
(modify ?l (value 1))
(printout t "plus 1" crlf)
(modify ?f (number (+ ?x 1)))
)
(defrule show_result
?f <- (counter (number ?x))
?l <- (lock (value 1))
=>
(printout t "the counter value has been changed:" crlf)
(ppfact (fact-index ?f) t)
(modify ?l (value 0))
)

Resources