break statement not working in function in clips - rules

the break statement is not working in my code.
error : The break function not valid in this context.
(deffunction slabFunction (?q0 ?q1 ?q2)
(if(and(>= ?q0 36)(>= ?q1 36)(>= ?q2 36)) then
(printout t "slab 3" crlf)
(break))
(if(and(>= ?q0 24)(>= ?q1 24)(>= ?q2 24))
then
(printout t "slab 2" crlf))
(if (and(>= ?q0 12)(>= ?q1 12)(>= ?q2 12))
then
(printout t "slab 1" crlf)
(break))
)
Please help!
If the slab 3 gets applied the other condition shouldnt get applied. If it doesnt, then slab 2 check is done, if statisfied it applies. then no further check is done. so on..

You use a break statement to terminate a loop (or in some languages a switch statement). If you want the function to terminate after a condition has been satisfied, use a return statement.
CLIPS (6.31 6/12/19)
CLIPS>
(deffunction slabFunction (?q0 ?q1 ?q2)
(if (and (>= ?q0 36) (>= ?q1 36) (>= ?q2 36))
then
(printout t "slab 3" crlf)
(return))
(if (and (>= ?q0 24) (>= ?q1 24) (>= ?q2 24))
then
(printout t "slab 2" crlf)
(return))
(if (and (>= ?q0 12) (>= ?q1 12) (>= ?q2 12))
then
(printout t "slab 1" crlf)
(return)))
CLIPS> (slabFunction 40 40 40)
slab 3
CLIPS> (slabFunction 26 26 45)
slab 2
CLIPS> (slabFunction 56 13 33)
slab 1
CLIPS> (slabFunction 10 3 2)
FALSE
CLIPS>

Related

Duplicated case statement in Common Lisp

there has to be a better way to do this here, right?
(format t "Enter your age: ~%")
(defun age-case (age)
(case age
(1 (format t "You belong in Kindergarden~%"))
(2 (format t "You belong in Kindergarden~%"))
(3 (format t "You belong in Kindergarden~%"))
(4 (format t "You belong in Kindergarden~%"))
(5 (format t "You belong in Preschool~%"))
(6 (format t "Elementary school ~%"))
(t (format t "Somewhere else"))))
(defvar *age* (read))
(age-case *age*)
In Python I would use a case 1..4 for this, in C++, Java and co. I would maybe use a falltrough switch case where I leave out the break for cases 1 to 3. Is there a neat little trick to do this in clisp w/o the code duplication?
Another option is to use type specifiers:
CL-USER > (let ((age 6))
(typecase age
((integer 1 4) 'one-to-four) ; integers from 1 to 4
((eql 5) 'five)
((eql 6) 'six)
(t 'something-else)))
SIX
A case clause can accept multiple keys:
(defun age-case (age)
(case age
((1 2 3 4) (format t "You belong in Kindergarden~%"))
(5 (format t "You belong in Preschool~%"))
(6 (format t "Elementary school ~%"))
(t (format t "Somewhere else"))))
Rainer's solution used ranges provided in the integer type with a typecase:
(typecase age
((integer 1 4) 'one-to-four)
((eql 5) 'five)
((eql 6) 'six)
(t 'something-else)))
Building on this, you can do type checking "for free":
(etypecase age
((integer 1 4) 'one-to-four)
((eql 5) 'five)
((eql 6) 'six)
((integer 7 *) 'something-else)))
Alternatively, you can also use cond:
(cond
((<= 1 age 100) 'one-to-ahundred)
;; ...and so on.
)
You can use cond and member like this:
(defun age-test ()
(format t "Enter your age: ~%")
(finish-output)
(let ((age (read)))
(format t (cond ((member age '(1 2 3 4)) "You belong in Kindergarden~%")
((= age 5) "You belong in Preschool~%")
((= age 6) "Elementary school ~%")
(t "Somewhere else")))))
(age-test)

asserting string in clips

I am trying to assert the value of name into a variable but when i assert it the value is coming in quotes and also with an extra space at the end.
(defrule discount_amt_group
(exists (Student (age 14)(marks ?q&:(> ?q 40))))
=>
(bind ?name "")
(do-for-all-facts ((?p Student))
(or (eq ?p:marks 80)
(eq ?p:marks 75)
(eq ?p:marks 90))
(bind ?name (str-cat ?name ?p:name " "))
(bind ?totalMarks (+ ?totalMarks ?p:marks)))
(assert (StudOut(names ?name)))
the expected value will be (name Harry Ron Ginger) but now its coming as (name "Harry Ron Ginger ")
please suggest.
Represent the names as a multifield value rather than a string. You can use the create$ function to initially create an empty multifield value and then again to append values to it.
CLIPS (6.31 6/12/19)
CLIPS>
(deftemplate Student
(slot name)
(slot age)
(slot marks))
CLIPS>
(deftemplate StudOut
(multislot names)
(slot totalMarks))
CLIPS>
(deffacts Students
(Student (name Harry) (age 14) (marks 80))
(Student (name Ron) (age 15) (marks 75))
(Student (name Ginger) (age 14) (marks 90))
(Student (name Sally) (age 12) (marks 95)))
CLIPS>
(defrule discount_amt_group
(exists (Student (age 14)(marks ?q&:(> ?q 40))))
=>
(bind ?name (create$))
(bind ?totalMarks 0)
(do-for-all-facts ((?p Student))
(or (eq ?p:marks 80)
(eq ?p:marks 75)
(eq ?p:marks 90))
(bind ?name (create$ ?name ?p:name))
(bind ?totalMarks (+ ?totalMarks ?p:marks)))
(assert (StudOut (names ?name)
(totalMarks ?totalMarks))))
CLIPS> (reset)
CLIPS> (run)
CLIPS> (facts)
f-0 (initial-fact)
f-1 (Student (name Harry) (age 14) (marks 80))
f-2 (Student (name Ron) (age 15) (marks 75))
f-3 (Student (name Ginger) (age 14) (marks 90))
f-4 (Student (name Sally) (age 12) (marks 95))
f-5 (StudOut (names Harry Ron Ginger) (totalMarks 245))
For a total of 6 facts.
CLIPS>

storing values in clips into variable

I am having a template of
(deftemplate Product
(slot productId (type INTEGER))
(slot uom (default EA))
(slot quantity (type INTEGER))
(slot amount))
I'm using the code for
(defrule sum_of_quantity
(exists (Product (productId 1 | 2 | 3)(amount ?amount)))
=>
(bind ?totalQuantity 0)
(do-for-all-facts ((?p Product))
(or (eq ?p:productNumber 1)
(eq ?p:productNumber 2)
(eq ?p:productNumber 3))
(bind ?totalQuantity (+ ?totalQuantity ?p:quantity)))
(if (>= ?amount 5000) then
(printout t "TotalQuantity is " ?totalQuantity crlf)))
Here i am getting an error saying that:
Undefined variable amount referenced in RHS of defrule.
I have to check if the amount of each product is greater than 5000. How do we do that.
A simple fact pattern that can be matched by several different facts can cause multiple activations of a rule:
CLIPS>
(deftemplate product
(slot id)
(slot amount))
CLIPS>
(deffacts products
(product (id 1) (amount 1000))
(product (id 2) (amount 3000))
(product (id 3) (amount 6000)))
CLIPS>
(defrule print-amount
(product (id ?id) (amount ?amount))
=>
(printout t ?id ": " ?amount crlf))
CLIPS> (reset)
CLIPS> (agenda)
0 print-amount: f-3
0 print-amount: f-2
0 print-amount: f-1
For a total of 3 activations.
CLIPS> (run)
3: 6000
2: 3000
1: 1000
CLIPS>
When each activation is allowed to executed, the variable amount is retrieved from the product fact associated with activation. So there are three rule firings where amount is 6000, 3000, and 1000 respectively.
An exists conditional element is matched just once regardless of the number of time the fact patterns it contains are matched:
CLIPS>
(defrule exists
(exists (product (id ?id) (amount ?amount)))
=>)
CLIPS> (agenda)
0 exists: *
For a total of 1 activation.
CLIPS>
When the agenda is listed, an * is displayed indicating that the pattern is matched, but not by a specific fact. If you tried accessing the variable amount in the actions of the rule, you'd get an error. This is because the variable amount has no meaning outside of the pattern because it has no specific value. You'd get unpredictable behavior if one of the facts matching the fact pattern was arbitrarily chosen to provide the value for amount.
The simplest way to rewrite your rule is to move the amount check from the actions of the rule to the exists pattern:
(defrule sum_of_quantity
(exists (Product (productId 1 | 2 | 3)
(amount ?amount&:(>= ?amount 5000))))
=>
(bind ?totalQuantity 0)
(do-for-all-facts ((?p Product))
(or (eq ?p:productId 1)
(eq ?p:productId 2)
(eq ?p:productId 3))
(bind ?totalQuantity (+ ?totalQuantity ?p:quantity)))
(printout t "TotalQuantity is " ?totalQuantity crlf))
Your do-for-all-facts query was also referencing productNumber rather than productId.

CLIPS Error: Illegal use of the module specifier when defrule

I want to define some module-rules to assert module-facts, and then batch get a group of facts list by get-fact-list, but an error occurred!
CLIPS (6.31 6/12/19)
CLIPS> (defmodule M)
CLIPS> (deftemplate M::T (slot k1))
CLIPS> (defrule M::T (testvalue 1) => (assert (M::T (k1 "v1"))))
[MODULDEF1] Illegal use of the module specifier.
ERROR:
(defrule M::T
(testvalue 1)
=>
(assert (M::T
CLIPS>
expected:
CLIPS> (defmodule M)
CLIPS> (deftemplate M::T (slot k1))
CLIPS> (defrule M::T (testvalue 1) => (assert (M::T (k1 "v1"))))
CLIPS> (assert (testvalue 1))
CLIPS> (get-fact-list M)
;; return the facts that M::rulexx assert
Why is the sytax error? How can I do it for the defrule of module?
Don't use M::T in your assert command. Since the defrule is contained in module M, all deftemplates visible to M can be referenced without using a module specifier.
CLIPS (6.31 6/12/19)
CLIPS> (defmodule M)
CLIPS> (deftemplate M::T (slot k1))
CLIPS> (defrule M::T (testvalue 1) => (assert (T (k1 "v1"))))
CLIPS> (assert (testvalue 1))
<Fact-1>
CLIPS> (get-fact-list M)
(<Fact-1>)
CLIPS>

Is there an equality operator for the test funcion in CLIPS? Also, how do nested or's work?

Good morning everyone!
As part of my thesis for my masters, I am trying to write some code in CLIPS for predicting the taste 37 subjects have perceived and compare it to the actual-known flavors that we had given them on the experiment. We have used an array of 122 EMG leads and recorded brain activity while they were experiencing each taste.
I used WEKA to create a hierarchical tree of the leads so that I'll keep only the most important ones which are related to brain areas for perceiving taste, leading down to 20.
Based on the tree from WEKA I'm trying to create this smart system for making predictions about what taste might a new subject experience, only with us "looking" in their EMG activity.
So...
I use the following rule to find among my facts, those which fulfill the following:
(test (or (or(eq ?L7 -5);Meaning that: test if L7 is either -5, -4, -4, -2, 2
(eq ?L7 -4)
(eq ?L7 -3)
(eq ?L7 -2)
(eq ?L7 2))
;OR
( (eq ?L7 -1);or test weather
(or(eq ?L120 -5) ;L7 is -1 AND L120 is -5 or
(eq ?L120 -4) ;L7 is -1 AND L120 is -4 or
(eq ?L120 -3) ;L7 is -1 AND L120 is -3 or
(eq ?L120 -1) ;L7 is -1 AND L120 is -1 or
(eq ?L120 1) ;L7 is -1 AND L120 is 1 or
(eq ?L120 2) ;L7 is -1 AND L120 is 2 or
(eq ?L120 3) ;L7 is -1 AND L120 is 3 or
(eq ?L120 4) ;L7 is -1 AND L120 is 4 or
(eq ?L120 5)) ;L7 is -1 AND L120 is 5
)
;OR
( (eq ?L7 0) ;OR weather
(eq ?L60 -4) ;L7 is 0 and L60 is -4
)
...etc...
What I get from this when I run it is a message saying:
[EXPRNPSR1] A function name must be a symbol
ERROR:
(defrule MAIN::rule1
(declare (salience 60))
(?f <- (facts (id ?id) (L7 ?L7) (L20 ?L20) (L23 ?L23) (L26 ?L26) ;other parameters follow ...
(test (or (or (eq ?L7 -5) (eq ?L7 -4) (eq ?L7 -3) (eq ?L7 -2) (eq ?L7 2)) ((
And there it stops, obviously implying that my syntax for nested or's in the test function are not correctly used.
Also I wonder about the "test weather equal function". I have used in the past
(test (<= ?L7 2))
and I know it works, but it didn't work for "==" (aka equal). The next best thing I found was "eq" function.
Still no luck.
I am sorry for my silly questions, but I'm new in CLIPS (and generally I'm a doctor not a programmer (yet!)), so any help would be appreciated.
So what am I doing wrong? How should the syntax be for what I'm stating in the ;comments of my code?
Thank you in advance!
Can you please help?
The error message shows the point at which the error occurred:
CLIPS (6.30 3/17/15)
CLIPS>
(deftemplate facts
(slot id)
(slot L7)
(slot L20)
(slot L23)
(slot L26))
CLIPS>
(defrule MAIN::rule1
(declare (salience 60))
?f <- (facts (id ?id) (L7 ?L7) (L20 ?L20) (L23 ?L23) (L26 ?L26))
(test (or (or (eq ?L7 -5)
(eq ?L7 -4)
(eq ?L7 -3)
(eq ?L7 -2)
(eq ?L7 2))
(())))
=>)
[EXPRNPSR1] A function name must be a symbol
ERROR:
(defrule MAIN::rule1
(declare (salience 60))
?f <- (facts (id ?id) (L7 ?L7) (L20 ?L20) (L23 ?L23) (L26 ?L26))
(test (or (or (eq ?L7 -5) (eq ?L7 -4) (eq ?L7 -3) (eq ?L7 -2) (eq ?L7 2)) ((
CLIPS>
In this case, the error occurs at the point where two left parentheses "((" are encountered. Unlike languages which allow infix operators and use parentheses to specify precedence, you can't use additional parentheses in CLIPS. So (+ 3 4) is valid syntax, but ((+ 3 4)) is not. Since the final ( is the last token parsed, the error message indicates that it was expecting that token to be a function name.
For numeric equality comparisons, use the = function.

Resources