I'm a beginner to the Expert System language called CLIPS. I need help writing a CLIPS script to decide, given three facts regarding properties A, B, and C (density, conductivity, etc), whether the object having these facts/properties is of a certain type, say TYPE1. I need to code in the rules necessary to make this decision. Thank you for your help.
KB
Elegance is subjective, but if you want code that is reusable and extensible, represent as much of the information as you can as data so that you can write generic rules.
CLIPS>
(deftemplate obj
(slot obj-name)
(slot print-name))
CLIPS>
(deftemplate opv
(slot obj-name)
(slot prop)
(slot val))
CLIPS>
(deftemplate type
(slot type-name)
(slot print-name))
CLIPS>
(deftemplate type-prop
(slot type-name)
(slot prop-name)
(slot prop-test)
(multislot values))
CLIPS>
(defrule is-type
?o <- (obj (obj-name ?obj-name))
?t <- (type (type-name ?type-name))
(forall (type-prop (type-name ?type-name)
(prop-name ?prop-name)
(prop-test ?prop-test)
(values $?values))
(opv (obj-name ?obj-name)
(prop ?prop-name)
(val ?val))
(test (funcall ?prop-test ?val (expand$ ?values))))
=>
(printout t (fact-slot-value ?o print-name)
" is "
(fact-slot-value ?t print-name)
crlf))
CLIPS>
(deffacts objects
(obj (obj-name thing1) (print-name "Thing 1"))
(opv (obj-name thing1) (prop color) (val red))
(opv (obj-name thing1) (prop weight) (val 5))
(obj (obj-name thing2) (print-name "Thing 2"))
(opv (obj-name thing2) (prop color) (val blue))
(opv (obj-name thing2) (prop weight) (val 20))
(obj (obj-name thing3) (print-name "Thing 3"))
(opv (obj-name thing3) (prop color) (val white))
(opv (obj-name thing3) (prop weight) (val 10)))
CLIPS>
(deffacts types
(type (type-name light) (print-name "light"))
(type-prop (type-name light) (prop-name weight) (prop-test <=) (values 5))
(type (type-name heavy) (print-name "heavy"))
(type-prop (type-name heavy) (prop-name weight) (prop-test >=) (values 20))
(type (type-name just-right) (print-name "just right"))
(type-prop (type-name just-right) (prop-name weight) (prop-test >=) (values 20))
(type-prop (type-name just-right) (prop-name color) (prop-test one-of) (values red green blue)))
CLIPS>
(deffunction one-of (?val $?rest)
(member$ ?val ?rest))
CLIPS> (reset)
CLIPS> (run)
Thing 2 is just right
Thing 2 is heavy
Thing 1 is light
CLIPS>
Related
I have the following two deftemplates:
(deftemplate effect (slot type) (slot value) (slot explanation))
(deftemplate result (slot type) (slot total_value) (multislot total_explanation))
and the following deffacts:
(effect (type A) (value 1) (explanation "A is 1"))
(effect (type A) (value 2) (explanation "A is 2"))
(effect (type B) (value 3) (explanation "B is 3"))
(effect (type B) (value 4) (explanation "B is 4"))
I want to sum up the total values for facts of the same type resulting in:
(result (type A) (total_value 3) (total_explanation "A is 1" "A is 2"))
(result (type B) (total_value 7) (total_explanation "B is 3" "B is 4"))
How would I accumulate the slots of facts? Here's what I tried:
(defrule accumulate_typeA
(exists (effect (type A)))
=>
(bind ?sum 0)
(do-for-all-facts ((?f effect) (bind ?sum (+ ?sum ?f:value))
(bind ?expl (create$))
(do-for-all-facts ((?f effect) (bind ?expl (inserts ?f:explanation))))
(assert (result (type A) (total_value ?sum) (total_explanation ?expl))
CLIPS (6.4 2/9/21)
CLIPS>
(deftemplate effect
(slot type)
(slot value)
(slot explanation))
CLIPS>
(deftemplate result
(slot type)
(slot total_value)
(multislot total_explanation))
CLIPS>
(deffacts initial
(effect (type A) (value 1) (explanation "A is 1"))
(effect (type A) (value 2) (explanation "A is 2"))
(effect (type B) (value 3) (explanation "B is 3"))
(effect (type B) (value 4) (explanation "B is 4")))
CLIPS>
(defrule accumulate_all_types
=>
(bind ?types (create$))
(do-for-all-facts ((?f effect)) TRUE
(if (not (member$ ?f:type ?types))
then
(bind ?types ?types ?f:type)))
(foreach ?t ?types
(bind ?sum 0)
(bind ?expl (create$))
(do-for-all-facts ((?f effect)) (eq ?f:type ?t)
(bind ?sum (+ ?sum ?f:value))
(bind ?expl ?expl ?f:explanation))
(assert (result (type ?t)
(total_value ?sum)
(total_explanation ?expl)))))
CLIPS> (reset)
CLIPS> (run)
CLIPS> (facts)
f-1 (effect (type A) (value 1) (explanation "A is 1"))
f-2 (effect (type A) (value 2) (explanation "A is 2"))
f-3 (effect (type B) (value 3) (explanation "B is 3"))
f-4 (effect (type B) (value 4) (explanation "B is 4"))
f-5 (result (type A) (total_value 3) (total_explanation "A is 1" "A is 2"))
f-6 (result (type B) (total_value 7) (total_explanation "B is 3" "B is 4"))
For a total of 6 facts.
CLIPS>
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>
I have a problem with my code that is to recommend a herbicide and an application rate for it as appropriate in a given field situation.
(deftemplate plant
(multislot weed)
(multislot crop))
(deftemplate Herbicide
(slot orgmatter)
(slot sencor)
(slot lasso)
(slot bicep))
(deffacts p
(plant (weed B) (crop C S))
(plant (weed B G) (crop C S))
(plant (weed B G) (crop C)))
(deffacts H
(Herbicide (orgmatter 1) (sencor 0.0) (lasso 2.0) (bicep 1.5))
(Herbicide (orgmatter 2) (sencor 0.75) (lasso 1.0) (bicep 2.5))
(Herbicide (orgmatter 3) (sencor 0.75) (lasso 0.5) (bicep 3.0)))
(defrule read-input
=>
(printout t "what is type of crop? (C:Corn , S:Soyabeans): ")
(assert (crop(read)))
(printout t "what is type of weed? (B:broadleaf , G:gress): ")
(assert (weed(read)))
(printout t "what is the organic matter? (1:<2% ,2: 2-4%, 3: >4%: ")
(assert (orgmatter(read))))
(defrule check-input
(crop ?crop)
(weed ?weed)
(orgmatter ? orgmatter)
(plant (weed $?weed1) (crop $?crop1))
(Herbicide (orgmatter ?orgmatter1) (sencor ?sencor1) (lasso ?lasso1)(bicep ?bicep1))
(test (member$ ?crop ?crop1))
(test (member$ ?weed ?weed1))
(test (= orgmatter ?orgmatter1))
=>
(printout t "you can use" ?sencor1 " pt/ac of sencor" crlf)
(printout t "you can use" ?lasso1 " pt/ac of lasso" crlf)
(printout t "you can use" ?bicep1 " pt/ac of bicep" crlf)))
The error is the following: Function = expected argument#1 to be of type integer or float
Your code has an extra ) at the end.
In defrule check-input, you have a test:
(test (= orgmatter ?orgmatter1))
Which is comparing a SYMBOL orgmatter with the variable ?orgmatter1. The = test works only with numerals. If you want to compare SYMBOLs or STRINGs, you need to use the eq function.
(test (eq orgmatter ?orgmatter1))
Nevertheless if you are not using ?orgmatter1 anywhere else, it is more effective to do a literal match rather than a test.
(Herbicide (orgmatter orgmatter)
(sencor ?sencor1)
(lasso ?lasso1)
(bicep ?bicep1))
I wrote a program which asserts the facts in the LHS of this rule:
(defrule check-open-better (declare (salience 50))
?f1 <- (newnode (ident ?id) (gcost ?g) (fcost ?f) (father ?anc))
(status (ident ?id) (subject ?subject) (data $?eqL))
?f2 <- (status (ident ?old) (subject ?subject) (data $?eqL))
?f3 <- (node (ident ?old) (gcost ?g-old) (open yes))
(test
(eq
(implode$
(find-all-facts ((?f status))
(and
(eq(str-compare ?f:ident ?id) 0)
(eq(str-compare ?f:subject ?subject) 0)
(eq(str-compare (implode$ ?f:data) (implode$ $?eqL)) 0)
)
)
)
(implode$
(find-all-facts ((?f status))
(and
(eq(str-compare ?f:ident ?old) 0)
(eq(str-compare ?f:subject ?subject) 0)
(eq(str-compare (implode$ ?f:data) (implode$ $?eqL)) 0)
)
)
)
0)
)
(test (< ?g ?g-old))
?f4 <- (open-better ?a)
=>
(assert (node (ident ?id) (gcost ?g) (fcost ?f) (father ?anc) (open yes)))
(assert (open-better (+ ?a 1)))
(retract ?f1 ?f2 ?f3 ?f4)
(pop-focus)
(pop-focus))
node, newnode and status are defined as deftemplate.
When this rule is in the agenda, CLIPS crash like it was typed the (exit) command.
I'm sure it's not fault of the rules that assert facts that allow this rule to be added in the agenda. Does anyone know why?
If CLIPS is crashing, it's a bug in CLIPS. I tried reproducing the problem by filling in the missing pieces and running in CLIPS 6.3, 6.31, and 6.4, but was unable to get a crash.
(deftemplate newnode
(slot ident)
(slot gcost (type INTEGER))
(slot fcost)
(slot father))
(deftemplate status
(slot ident)
(slot subject)
(multislot data))
(deftemplate node
(slot ident)
(slot gcost (type INTEGER))
(slot open))
(deffacts start
(node (ident "1") (gcost 10) (open yes))
(open-better 0)
(newnode (ident "2"))
(status (ident "1"))
(status (ident "2")))
Generally, it's a bad idea to use the query functions from the conditions of a rule because 1) you can use pattern matching and 2) the query contained within a test CE will not be reevaluated unless there's some changes to prior patterns.
It's not clear what you're trying to do with the find-all-facts calls. First, there's cruft in there that you don't need. The str-compare and implode$ function calls are unnecessary and the third argument of 0 to eq will cause the test CE to always fail since the return values of the find-all-facts calls will never be 0.
(test
(eq
(find-all-facts ((?f status))
(and
(eq ?f:ident ?id)
(eq ?f:subject ?subject)
(eq ?f:data $?eqL)
)
)
(find-all-facts ((?f status))
(and
(eq ?f:ident ?old)
(eq ?f:subject ?subject)
(eq ?f:data $?eqL)
)
)
)
)
Both find-all-fact calls must return the same facts in order for the test CE to be satisfied. That can only be true if there are no status facts or the ?id and ?old variables have the same value.
Try this one, it should work. :)
(defrule check-open-better (declare (salience 50))
?f1 <- (newnode (ident ?id) (gcost ?g) (fcost ?f) (father ?anc))
(status (ident ?id) (subject ?subject) (data $?eqL))
?f2 <- (status (ident ?old) (subject ?subject) (data $?eqL))
?f3 <- (node (ident ?old) (gcost ?g-old) (open yes))
(test (< ?g ?g-old))
?f4 <- (open-better ?a)
=>
(if (eq
(implode$
(find-all-facts ((?f status))
(and
(eq ?f:ident ?id)
(eq ?f:subject ?subject)
(eq (implode$ ?f:data) (implode$ $?eqL)))))
(implode$
(find-all-facts ((?f status))
(and
(eq ?f:ident ?old)
(eq ?f:subject ?subject)
(eq (implode$ ?f:data) (implode$ $?eqL)) 0))))
then
(assert (node (ident ?id) (gcost ?g) (fcost ?f) (father ?anc) (open yes)))
(assert (open-better (+ ?a 1)))
(retract ?f1 ?f2 ?f3 ?f4))
(pop-focus)
(pop-focus))
I am using CLIPS for a project.
I am using this template A which has an attribute model and another template B which has an attribute model as well.
So what I want to achieve is based on the attribute model, return those facts of template A which has the same attribute model value as of facts from template B.
I tried using this format
(find-all-facts((?a template_A)(?b template_B))
(and
//condition to be met
)
)
it does give me the results, but it is giving me both the results for A and B which are duplicates.. How do I make it in a way it returns non duplicate values, either A or B?
CLIPS>
(deftemplate template_A
(slot model))
CLIPS>
(deftemplate template_B
(slot model))
CLIPS>
(deffacts start
(template_A (model 1))
(template_A (model 2))
(template_A (model 3))
(template_B (model 2))
(template_B (model 3))
(template_B (model 4)))
CLIPS>
(deffunction extract-every-nth-value (?values ?start ?increment)
(bind ?rv (create$))
(while (<= ?start (length$ ?values))
(bind ?rv (create$ ?rv (nth$ ?start ?values)))
(bind ?start (+ ?start ?increment)))
(return ?rv))
CLIPS> (reset)
CLIPS> (facts)
f-0 (initial-fact)
f-1 (template_A (model 1))
f-2 (template_A (model 2))
f-3 (template_A (model 3))
f-4 (template_B (model 2))
f-5 (template_B (model 3))
f-6 (template_B (model 4))
For a total of 7 facts.
CLIPS>
(find-all-facts ((?a template_A)(?b template_B))
(eq ?a:model ?b:model))
(<Fact-2> <Fact-4> <Fact-3> <Fact-5>)
CLIPS>
(extract-every-nth-value
(find-all-facts ((?a template_A)(?b template_B))
(eq ?a:model ?b:model))
1 2)
(<Fact-2> <Fact-3>)
CLIPS>