I'm new in Clips. I'd like to know if it is a way to read an array (chain of numeric or characters with an index, sorry if it's the wrong name) on LHS. I have rules to ask for a value (s,cs,cn,n) then it assert the value to next asking rule, to finally read all the values in an answering rule to get a diagnostic, but in my small example I have 4 questions and 4 options for each one so mixing all the answers would give me 64 rules, and I have so at least 30 questions in my program so I think that would be too much rules (I'm doing my first Expert System an maybe this is normal). In any case I think I could get the values from questions into an array an read it in answering rules, but my questions are:
*How can I bind the values from my function into an array?
*Is it possible to verify that array in LHS?
*Do you have any other idea to verify the answer-rules? Hope you can help me.
(deffunction funcionPregunta (?pregunta $?valoresAceptados) ;;ask-question function
(printout t ?pregunta)
(bind ?respuesta (read))
(if (lexemep ?respuesta)
then (bind ?respuesta (lowcase ?respuesta)))
(while (not (member$ ?respuesta ?valoresAceptados)) do
(printout t ?pregunta)
(bind ?respuesta (read))
(if (lexemep ?respuesta)
then (bind ?respuesta (lowcase ?respuesta))))
?respuesta)
;;===============================================================
;; QUESTION RULES
;;===============================================================
(defrule pregunta1T5 "AGORAFOBIA"
(not (diagnostico ?))
=>
(assert (Pregunta2T5
(funcionPregunta "1.Siente miedo o ansiedad marcada. (always/frecuently/rare/never)? "
s cs cn n))))
(defrule Pregunta2T5 "AGORAPUBLICO"
(not (diagnostico ?))
(Pregunta2T5 ?Pregunta2T5)
=>
(assert (Pregunta3T5
(funcionPregunta "2.Siente miedo en una multitud. (always/frecuently/rare/never)? "
s cs cn n)))
)
(defrule Pregunta3T5 "AGORAMIEDO"
(not (diagnostico ?))
(Pregunta3T5 ?Pregunta3T5)
=>
(assert (Pregunta4T5
(funcionPregunta "3.Miedo de estar en una situacion. (always/frecuently/rare/never)? "
s cs cn n)))
)
(defrule Pregunta4T5 "AGORAANSIEDAD"
... ;; similar rules
;;===============================================================
;; ANSWERS RULES
;;===============================================================
(defrule Respuesta1T6 "RESULTADO 1 TAS"
(not (diagnostico ?))
(Pregunta2T6 s)(Pregunta3T6 s)(Pregunta4T6 s)(Pregunta5T6 s)
=>
(assert (diagnostico "TRASTORNO DE ANSIEDAD SOCIAL"))
)
(defrule Respuesta2T6 "RESULTADO 2 TAS"
(not (diagnostico ?))
(Pregunta2T6 cs)(Pregunta3T6 s)(Pregunta4T6 s)(Pregunta5T6 s)
=>
(assert (diagnostico "TRASTORNO DE ANSIEDAD SOCIAL"))
)
In the case of the two answer rules you've already got, the simplest way to reduce the number of rules is just to combine them:
(defrule Respuesta1T6-2T6
(not (diagnostico ?))
(Pregunta2T6 s | cs) ; s or cs is allowed
(Pregunta3T6 s)
(Pregunta4T6 s)
(Pregunta5T6 s)
=>
(assert (diagnostico "TRASTORNO DE ANSIEDAD SOCIAL")))
If you're creating lots of rules that differ only in the constants matched in the patterns, you should consider representing the rules as a combination of facts containing these constants and generic rules to process that data. For example, you could rewrite your question rules like this:
(deftemplate Pregunta ; question
(slot identidad) ; ID
(slot texto) ; text
(multislot respuestas) ; responses
(slot precursora ; precursor
(default ninguna))) ; none
(deftemplate Responder ; answer
(slot identidad) ; ID
(slot valor)) ; value
(deffacts Preguntas
(Pregunta (identidad AGORAFOBIA)
(texto "1. Siente miedo o ansiedad marcada. (always/frecuently/rare/never)? ")
(respuestas s cs cn n))
(Pregunta (identidad AGORAPUBLICO)
(texto "2. Siente miedo en una multitud. (always/frecuently/rare/never)? ")
(respuestas s cs cn n)
(precursora AGORAFOBIA))
(Pregunta (identidad AGORAMIEDO)
(texto "3. Miedo de estar en una situacion. (always/frecuently/rare/never)? ")
(respuestas s cs cn n)
(precursora AGORAPUBLICO)))
(defrule pedir-pregunta ; ask question
(not (diagnostico ?))
(Pregunta (identidad ?id)
(texto ?t)
(respuestas $?r)
(precursora ?p))
(or (test (eq ?p ninguna))
(Responder (identidad ?p)))
=>
(assert (Responder (identidad ?id)
(valor (funcionPregunta ?t ?r)))))
And your diagnosis rules like this:
(deftemplate Trastorno ; disorder
(slot nombre) ; name
(multislot sintomas)) ; symptoms
(deftemplate Sintoma
(slot identidad) ; ID
(slot responder) ; answer
(multislot valors)) ; values
(deffacts Trastornos
(Trastorno (nombre "TRASTORNO DE ANSIEDAD SOCIAL")
(sintomas AGORAFOBIA-cs-s AGORAPUBLICO-s AGORAMIEDO-s)))
(deffacts Sintomas
(Sintoma (identidad AGORAFOBIA-cs-s)
(responder AGORAFOBIA)
(valors cs s))
(Sintoma (identidad AGORAPUBLICO-s)
(responder AGORAPUBLICO)
(valors s))
(Sintoma (identidad AGORAMIEDO-s)
(responder AGORAMIEDO)
(valors s)))
(defrule Respuesta
(not (diagnostico ?))
(Trastorno (nombre ?n)) ; There is a disorder.
(forall (Trastorno (nombre ?n) ; For every symptom
(sintomas $? ?s $?)) ; of the disorder,
(Sintoma (identidad ?s) ; there is a list
(responder ?r) ; of possible values
(valors $?sv)) ; for that symptom
(Responder (identidad ?r) ; matched by a response.
(valor ?v&:(member$ ?v ?sv))))
=>
(assert (diagnostico ?n)))
Related
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 am trying to retract a deftemplate fact but when I do this CLIPS keeps saying I have to first declare the deffunction yet it is the appropriate deftemplate.What seems to be the problem?
I have attached the related code:
I get this error:
[EXPRNPSR3] Missing function declaration for Agriculture.
What seems to be the problem?
(deftemplate Agriculture
(slot weed
(type SYMBOL)
(allowed-symbols B G))
(slot crop
(type SYMBOL)
(allowed-symbols C S))
(slot organic-matter
(type INTEGER)
(allowed-values 1 2 3)))
(defrule Sencor-1
(and (Agriculture(weed B))
(Agriculture(crop C|S))
(Agriculture(organic-matter 1)))
=>
(printout t "Do not use Sencor!!"crlf))
(defrule Sencor-2
(and (Agriculture(weed B))
(Agriculture(crop C|S))
(Agriculture(organic-matter 2|3)))
=>
(printout t " " crlf "Use 3/4 pt/ac of Sencor" crlf ))
(defrule Lasso-1
(and (Agriculture(weed B|G))
(Agriculture(crop C|S))
(Agriculture(organic-matter 1)))
=>
(printout t crlf"Use 2 pt/ac of Lasso" crlf))
(defrule Lasso-2
(and (Agriculture(weed B|G))
(Agriculture(crop C|S))
(Agriculture(organic-matter 2)))
=>
(printout t crlf "Use 1 pt/ac of Lasso" crlf))
(defrule Lasso-3
(and (Agriculture(weed B|G))
(Agriculture(crop C|S))
(Agriculture(organic-matter 3)))
=>
(printout t crlf "Use 0.5 pt/ac of Lasso" crlf))
(defrule Bicep-1
(and (Agriculture(weed B|G))
(Agriculture(crop C))
(Agriculture(organic-matter 1)))
=>
(printout t crlf "Use 1.5 pt/ac of Bicep" crlf))
(defrule Bicep-2
(and (Agriculture(weed B|G))
(Agriculture(crop C))
(Agriculture(organic-matter 2)))
=>
(printout t crlf"Use 2.5 pt/ac of Bicep" crlf))
(defrule Bicep-3
(and (Agriculture(weed B|G))
(Agriculture(crop C))
(Agriculture(organic-matter 3)))
=>
(printout t crlf "Use 3 pt/ac of Bicep" crlf))
(defrule input
(initial-fact)
=>
(printout t crlf "What is the crop? (C:corn,S:soybean)")
(bind ?a (read))
(assert(Agriculture(crop ?a))) ;gets input from user
(printout t crlf "What is the weed problem? (B:broadleaf, G:grass)")
(bind ?b (read))
(assert(Agriculture(weed ?b)))
(printout t crlf "What is the % of organic matter content? (1:<2%,2:2-4%,3:>4%)")
(bind ?c (read))
(assert(Agriculture(organic-matter ?c)))
?d <- (Agriculture(crop ?a) (weed ?b) (organic-matter ?c))
(printout t ""crlf crlf "RECOMMENDATIONS:"crlf)
(retract ?d))
In the RHS of the input rule you state:
?d <- (Agriculture(crop ?a) (weed ?b) (organic-matter ?c))
This is interpreted as "Run function Agriculture and bind its results into ?d".
What you probably are trying to do is:
(bind ?d (assert (Agriculture (crop ?a) (weed ?b) (organic-matter ?c))))
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 have a task, write a program to count the number of repetitions of a word in the list.
I just started learning the clips so I do not know many things.
I wrote the code, but unfortunately it does not work, what could be the error?
(clear)
(deftemplate list_1
(slot numeral)
)
(deftemplate list_2
(slot numeral)
)
(deftemplate list_3
(slot numeral)
)
(deffacts start
(list_1 (numeral zero))
(list_1 (numeral one))
(list_1 (numeral two))
(list_2 (numeral zero))
(list_2 (numeral two))
(list_2 (numeral three))
(list_3 (numeral zero))
(list_3 (numeral one))
(list_3 (numeral three))
)
(defglobal
?*countword* = 0
)
(defrule inputword
(initial-fact)
=>
(printout t crlf “Enter a word to search for: “)
(bind ?i (read))
(assert (wordforsearch ?i))
)
(defrule searchword
(wordforsearch ?i)
(list_1 (numeral ?i))
(list_2 (numeral ?i))
(list_3 (numeral ?i))
=>
(bind ?*countword* (+ ?*countword* 1))
)
(defrule outputword
(wordforsearch ?i)
=>
(printout t "Number of repetitions for a word: " ?i " = " ?*countword* crlf)
(reset)
(halt)
)
(run)
I really hope the same way that you explain in detail what the error is and maybe tell me another version of the implementation of the code.
P. S. I implemented another version of the program - the search for the number of repetitions of words in the sentence. This code also does not work.
(clear)
(defglobal
?*countword* = 0
)
(defrule inputword
(initial-fact)
=>
(printout t crlf “Enter a sentence: “)
(bind ?s (read))
)
(defrule inputword
(?s)
=>
(printout t crlf “Enter a word to search for: “)
(bind ?i (read))
(assert (wordforsearch ?i))
)
(defrule searchword
(wordforsearch ?i)
(?s ?i)
=>
(bind ?*countword* (+ ?*countword* 1))
)
(defrule outputword
(wordforsearch ?i)
=>
(printout t "Number of repetitions for a word: " ?i " = " ?*countword* crlf)
(reset)
(halt)
)
(run)
I really hope for your help in understanding the clips.
P. P. S. Sorry for my english
I can offer here this option. This has many shortcomings, but as an example this will suitable.
(defglobal
?*i* = 0
?*count* = 0
?*string* = (create$)
?*wordsearch* = ""
?*wordsearch1* = (create$)
)
(defrule Searching
?fact <- (searching)
=>
(retract ?fact)
(bind ?*i* (+ ?*i* 1))
(if (<= ?*i* (length ?*string*))
then
(if (eq ?*wordsearch1* (subseq$ ?*string* ?*i* ?*i*))
then
(bind ?*count* (+ ?*count* 1))
(assert (searching))
else
(assert (searching))
)
else
(printout t "Word " ?*wordsearch* " repeats " ?*count* " times" crlf)
)
)
(defrule Start
=>
(printout t crlf "Enter the string: ")
(bind ?*string* (create$ (explode$ (lowcase (readline)))))
(printout t crlf "Enter a word to search for: ")
(bind ?*wordsearch* (lowcase (readline)))
(bind ?*wordsearch1* (create$ (explode$ ?*wordsearch*)))
(assert (searching))
)
i have a project in clips with three modules, at the end of the second module i ask to user if he want to retract one of the previous answer, if he retract one of the answer of the second module, i need to retract all the answers of the second module and re-ask again. After i retract all the answers of the second module, i expect that this rule is activated
(defrule SECONDMODULE::domanda-esperto
(declare (salience ?*highest-priority*))
(livello-utente (livello esperto)) ;;assert in FIRSTMODULE and not retract
=>
(something)
)
But this rule is never activeted and it not apper in the AGENDA also if the facts that match the LHS is present in the fact list.
Sorry for my bad english.
EDIT.
#Gary First of all i ask 5 question to user, that are this:
(defrule starting-rule
(declare (salience ?*highest-priority*) (auto-focus TRUE))
=>
(printout t "***Inizio***" crlf)
(focus PROFILO)
(set-strategy random))
(defrule PROFILO::chiedi-se-possiede-auto
(not (domanda (nome possiede-auto) (domanda ?) (risposta ?)))
=>
(bind ?risposta (si-o-no "L'auto e' tua? "))
(assert (domanda (nome possiede-auto) (domanda "L'auto e' tua? ") (risposta ?risposta)))
)
(defrule PROFILO::frequenza-utilizzo-auto
(not(domanda (nome frequenza-utilizzo-auto) (domanda ?) (risposta ?)))
=>
(bind ?risposta (risposte-range "Quante volte a settimana in media utilizzi l'auto? " 0 1-2 3-5 5-7 ))
(assert (domanda (nome frequenza-utilizzo-auto) (domanda "Quante volte a settimana in media utilizzi l'auto? " ) (risposta ?risposta)))
)
(defrule PROFILO::conoscenza-meccanica-auto
(not (domanda (nome conoscenza-meccanica-auto) (domanda ?) (risposta ?)))
=>
(bind ?risposta (risposte-range "Quanto ti consideri esperto della meccanica dell'auto?" 0 1 2 3 4 5))
(assert (domanda (nome conoscenza-meccanica-auto) (domanda "Quanto ti consideri esperto della meccanica dell'auto?") (risposta ?risposta)))
)
(defrule PROFILO::kit-riparazione-rapida
(not (domanda (nome kit-riparazione-rapida) (domanda ?) (risposta ?)))
=>
(bind ?risposta (si-o-no "Possiedi un kit di riparazione rapida?"))
(assert (domanda (nome kit-riparazione-rapida) (domanda "Possiedi un kit di riparazione rapida?") (risposta ?risposta)))
)
(defrule PROFILO::anni-possesso-patente
(not(domanda (nome anni-possesso-patente) (domanda ?) (risposta ?)))
=>
(bind ?risposta (risposte-range "Da quanti anni possiedi la patente? " <1 1-5 >5 ))
(assert (domanda (nome anni-possesso-patente) (domanda "Da quanti anni possiedi la patente? ") (risposta ?risposta)))
)
After this i fire a rule that in according with the user asnwers delineate the profile of the user
(defrule PROFILO::livello-utente
?a<-(domanda (nome possiede-auto) (domanda ?) (risposta ?))
?b<-(domanda (nome anni-possesso-patente) (domanda ?) (risposta ?))
?c<-(domanda (nome conoscenza-meccanica-auto) (domanda ?) (risposta ?))
?d<-(domanda (nome kit-riparazione-rapida) (domanda ?) (risposta ?))
?e<-(domanda (nome frequenza-utilizzo-auto) (domanda ?) (risposta ?))
=>
(switch (fact-slot-value ?a risposta)
(case TRUE then (bind ?*punteggio* (+ ?*punteggio* 1)))
)
(switch (fact-slot-value ?d risposta)
(case TRUE then (bind ?*punteggio* (+ ?*punteggio* 1)))
)
(switch (fact-slot-value ?b risposta)
(case <1 then (bind ?*punteggio* (+ ?*punteggio* 1)))
(case 1-5 then (bind ?*punteggio* (+ ?*punteggio* 2)))
(case >5 then (bind ?*punteggio* (+ ?*punteggio* 3)))
)
(switch (fact-slot-value ?c risposta)
(case 1 then (bind ?*punteggio* (+ ?*punteggio* 1)))
(case 2 then (bind ?*punteggio* (+ ?*punteggio* 2)))
(case 3 then (bind ?*punteggio* (+ ?*punteggio* 3)))
(case 4 then (bind ?*punteggio* (+ ?*punteggio* 4)))
(case 5 then (bind ?*punteggio* (+ ?*punteggio* 5)))
)
(switch (fact-slot-value ?e risposta)
(case 1-2 then (bind ?*punteggio* (+ ?*punteggio* 1)))
(case 3-5 then (bind ?*punteggio* (+ ?*punteggio* 2)))
(case 5-7 then (bind ?*punteggio* (+ ?*punteggio* 3)))
)
(bind ?f ?*punteggio*)
(if (> ?f 9) then (assert (livello-utente (livello esperto))))
(if (< ?f 6) then (assert (livello-utente (livello principiante))))
(if (and (> ?f 5) (< ?f 10)) then (assert (livello-utente(livello medio))))
)
After that i go in the second module where one of this two rule ia actived in according with the profile of the user determinate in the fist module
(defrule DIAGNOSI::domanda-esperto
(declare (salience ?*highest-priority*))
(livello-utente (livello esperto))
=>
(bind ?risposta (risposte-range "In quale tra le seguenti aree e' presente il problema?" Olio-motore Olio-freni Acqua Carburante Altro))
(assert (domanda (nome area-problema) (domanda "In quale tra le seguenti aree e' presente il problema?") (risposta ?risposta)))
)
(defrule DIAGNOSI::domanda-medio
(declare (salience ?*highest-priority*))
(livello-utente (livello medio))
=>
(bind ?risposta (si-o-no "Sapresti indicare l'area di provenienza del problema tra le seguenti: Olio motore, Olio freni, Acqua, Carburante, Altro?"))
(assert (domanda (nome domanda-area-problema) (domanda "Sapresti indicare l'area di provenienza del problema tra le seguenti: Olio motore, Olio freni, Acqua, Carburante, Altro?") (risposta ?risposta)))
(if (eq ?risposta TRUE)
then (bind ?risposta (risposte-range "In quale tra le seguenti aree e' presente il problema?" Olio-motore Olio-freni Acqua Carburante Altro))
(assert (domanda (nome area-problema) (domanda "In quale tra le seguenti aree e' presente il problema?") (risposta ?risposta)))
)
After this there is a series of other question that i do to user. After that i ask if he want to retract one of this, and if he chooseone of the two (domanda-medio, domanda-esperto) i have to retract all the answers of the second module. After i retract all the answers of the second module, this two rule is never activeted and it not apper in the AGENDA also if the facts that match the LHS is present in the fact list (livello-utente (livello ?))
#GaryRiley ok i don't know why but adding `
(not (diagnosi (nome ?)))`
to the two rule it work.