Hi there first of all English is not my main language sorry for orthographic errors or maybe doing questions the wrong way.
I'm using Clips 6.3 64bit version.
I'm learning this for school but my teacher ain't giving us a lot information about the programming part, where only learning the theory behind it all, so my problem is i'm running this fine program https://github.com/JherezTaylor/cheese-classification/blob/master/wichCheese.clp on my clips to see how it works, and everything works fine except when 2 items have the same attributes, it wont keep filtering it just blanks the command line and i have to start over, more specific when i run the program and answer the 2 first questions with 1. Blue 2. Creamy it does the error i'm talking about, my first thought is that its crashing because there is more then 1 registry that start with those 2 attributes.
Sorry for the long text first time asking, any help is appreciated and any comment about my way of asking is well received.
thanks for advance to anyone willing to help.
The issue is that the check-facts-at-texture rule removes the fact needed to activate the mainQuestion-Colour rule:
(defrule check-facts-at-texture
?f <- (cheeseTexture ?)
=>
(cheeseFound)
(cheeseNotFound)
(retract ?f)
)
(defrule mainQuestion-Colour
(cheeseTexture ?tx)
=>
(bind ?colour (ask-question "### What is the general colour of the cheese? (white yellow pale-yellow green) ### " "" "" white yellow pale-yellow green))
(assert (cheeseColour ?colour))
)
The program halts because there are no more applicable rules. If you make appropriate changes to these rules, you can get them to fire correctly:
(defrule check-facts-at-texture
?f <- (cheeseTexture ?)
=>
(assert (ask-color))
(cheeseFound)
(cheeseNotFound)
(retract ?f)
)
(defrule mainQuestion-Colour
(declare (salience -10))
(ask-color)
;; only ask if there are at least two cheeses left
(exists (cheese (name ?name))
(cheese (name ~?name)))
=>
(bind ?colour (ask-question "### What is the general colour of the cheese? (white yellow pale-yellow green) ### " "" "" white yellow pale-yellow green))
(assert (cheeseColour ?colour))
)
You'll run into the same problem with the subsequent rules in the program and these will need to be changed as well.
You can simplify the original program by writing generic rules to ask the questions and remove cheeses that don't match. The globals and functions which keep track of the number of cheeses are also unnecessary.
Keep the original cheese deftemplate and cheese-list deffacts.
(deftemplate cheese
(multislot name)
(multislot milk-source)
(multislot country)
(multislot type)
(multislot texture)
(multislot colour)
(multislot flavour)
(multislot aroma)
(multislot common-useage))
(deffacts cheese-list
(cheese (name "gouda")
(milk-source cow)
(country "netherlands")
(type semi-hard)
(texture firm)
(colour yellow)
(flavour rich)
(aroma pungent)
(common-useage table-cheese))
.
.
.
)
Remove the other code. Use the following code for asking questions:
(deffunction ask-question (?question $?allowed-values)
(printout t ?question " " ?allowed-values " ")
(bind ?answer (read))
(if (lexemep ?answer)
then (bind ?answer (lowcase ?answer)))
(while (not (member ?answer ?allowed-values)) do
(printout t ?question " " ?allowed-values " ")
(bind ?answer (read))
(if (lexemep ?answer)
then (bind ?answer (lowcase ?answer))))
?answer)
(deftemplate question
(slot text)
(slot priority (default 0))
(slot attribute)
(multislot values))
(deftemplate response
(slot attribute)
(slot value))
(deffacts questions
(question (text "What type of cheese is it?")
(priority 1)
(attribute type)
(values semi-soft soft semi-hard hard blue))
(question (text "How would you describe the texture of the cheese?")
(priority 2)
(attribute texture)
(values crumbly springy firm creamy smooth))
(question (text "What is the general colour of the cheese?")
(priority 3)
(attribute colour)
(values white yellow pale-yellow green))
(question (text "How would you describe the flavour of the cheese?")
(priority 4)
(attribute flavour)
(values strong mild rich sweet spicy creamy))
(question (text "How would you describe the aroma of the cheese?")
(priority 5)
(attribute aroma)
(values strong mild pleasant pungent none))
(question (text "What is the most common use of the cheese?")
(priority 6)
(attribute common-useage)
(values table-cheese bread cooking pasta salad melting dip dessert dressing pizza cheesecake)))
(defrule ask-question
(declare (salience -10))
?f <- (question (text ?text)
(priority ?p)
(attribute ?attribute)
(values $?values))
;; Verify that this is the highest priority question
(not (question (priority ?p2&:(< ?p2 ?p))))
;; Keep asking questions as long there
;; are at least two cheeses
(exists (cheese (name ?name))
(cheese (name ~?name)))
=>
(retract ?f)
(bind ?response (ask-question ?text ?values))
(assert (response (attribute ?attribute) (value ?response))))
Use the following rule to filter cheeses based on the responses:
(defrule filter-response
(declare (salience 10))
(response (attribute ?attribute) (value ?value))
?f <- (cheese)
(test (not (member$ ?value (fact-slot-value ?f ?attribute))))
=>
(retract ?f))
Use the following code to detect matching cheeses:
(deffunction fsv (?fact ?slot)
(nth$ 1 (fact-slot-value ?fact ?slot)))
(defrule match-not-found
(not (cheese))
=>
(printout t crlf "No matching cheese found." crlf))
(defrule match-found
?f <- (cheese (name ?name))
(not (cheese (name ~?name)))
=>
(printout t crlf "Cheese found:" crlf)
(printout t " Name: " ?name crlf)
(printout t " Milk Source: " (fsv ?f milk-source) crlf)
(printout t " Type: " (fsv ?f type) crlf)
(printout t " Country: " (fsv ?f country) crlf)
(printout t " Texture: " (fsv ?f texture) crlf)
(printout t " Colour: " (fsv ?f colour) crlf)
(printout t " Flavour: " (fsv ?f flavour) crlf)
(printout t " Aroma: " (fsv ?f aroma) crlf)
(printout t " Common Useage: " (fsv ?f common-useage) crlf))
(defrule multiple-matches-found
(exists (cheese (name ?name))
(cheese (name ~?name)))
(not (question))
=>
(printout t crlf "Multiple matching cheeses: ")
(do-for-all-facts ((?c cheese)) TRUE
(printout t (fsv ?c name) " "))
(printout t crlf))
The resulting program will now have 5 rules rather than 19 in the original program.