clipsexpert-system

Finding the fittest car in clips


So we have a project that we need to make an expert system that by giving it the facts of some cars, it chooses the fittest one for the user.

First of all, in the class we learned little things about clips, such us deftemplate, deffacts and defrule. Nothing more (!!!) So my project, i think, cannot contain code like modules or fucntions.

Second, according to given data, the code should be like that i am writing further down.

The thing is:

  1. we didnt learn other way exept the (retract).
  2. if im right: 2a. is there any way my code to find what is should retract and not need the expert to write down the facts that is irrelevant? 2b. what should i write so it can have results every time? (for example if we give type family and price high we will not have a ruselt). 2c. is there any way that after that "Subtraction method" i though, the programm to print ,after the questions, the remaining facts but not with the " (facts) " way??

the code is:

(deftemplate car_template
(slot brand_name (type STRING))
(slot type (type STRING)(allowed-symbols family city super))
(slot price (type SYMBOL) (allowed-symbols low mid high))
;;; low = 0-10000 mid = 10001-20000 high = 20001-10000 
(slot performance (type SYMBOL) (allowed-symbols low mid high))
(slot equipment (type SUMBOL) (allowed-symbols low mid high))
)

(deffacts car_facts
(car (brand_name "Opel Astra")(type family)(price mid)(performance low)
(car (brand_name "Peugeot 106a")(type city)(price low)(performance high)
(car (brand_name "Mercedes E200")(type super)(price high)(performance mid)
(car (brand_name "Rover 25")(type family)(price mid)(performance mid)
(car (brand_name "Ferrari F40")(type super)(price high)(performance high)
)

  
(defrule type_rule
(initial-fact)

=>

(printout t "Give the Type you want (possible options: family city super): "
    (bind ?response (read))
    (if (eq ?response family) then
        ;;;retracting city               
        (retract 2)
        ;;;rectarting super
        (retract 3 5)
    else (if (eq ?response city) then
        ;;;retracting family
        (retract 1 4)
        ;;;rectarting super
        (retract 3 5) 
          else
                ;;;retracting city
        (retract 2)
        ;;;retracting family               
        (retract 1 4)
    ))))

(defrule price_rule
(initial-fact)

=>

(printout t "Give the price you want (possible options: low mid high): "
    (bind ?response (read))
    (if (eq ?response low) then
        ;;;retracting mid               
        (retract 1 4)
        ;;;rectarting high
        (retract 3 5)
    else (if (eq ?response mid) then
        ;;;retracting low
        (retract 2)
        ;;;rectarting high
        (retract 3 5) 
          else
                ;;;retracting mid
        (retract 1 4)
        ;;;retracting low               
        (retract 2)
    ))))

(defrule performance_rule
(initial-fact)

=>

(printout t "Give the performance you want (possible options: low mid high): "
    (bind ?response (read))
    (if (eq ?response low) then
        ;;;retracting mid               
        (retract 3 4)
        ;;;rectarting high
        (retract 2 5)
    else (if (eq ?response mid) then
        ;;;retracting low
        (retract 1)
        ;;;rectarting high
        (retract 2 5) 
          else
                ;;;retracting mid
        (retract 3 4)
        ;;;retracting low               
        (retract 1)
    ))))

(defrule print_facts
(initial-fact)

=>

(printout t "The car that fits you is: "
    (facts)
))

Solution

  • This is a better method to retract your facts:

    (deftemplate car
       (slot brand_name (type STRING))
       (slot type (type SYMBOL)(allowed-symbols family city super))
       (slot price (type SYMBOL) (allowed-symbols low mid high))
       (slot performance (type SYMBOL) (allowed-symbols low mid high))
       (slot equipment (type SYMBOL) (allowed-symbols low mid high)))
    
    (deffacts car_facts
       (car (brand_name "Opel Astra") (type family) (price mid) (performance low))
       (car (brand_name "Peugeot 106a") (type city) (price low) (performance high))
       (car (brand_name "Mercedes E200") (type super) (price high) (performance mid))
       (car (brand_name "Rover 25") (type family) (price mid) (performance mid))
       (car (brand_name "Ferrari F40") (type super) (price high) (performance high)))
    
    (defrule questions
       =>
       (printout t "Give the Type you want (possible options: family city super): ")
       (assert (type (read)))
       (printout t "Give the price you want (possible options: low mid high): ")
       (assert (price (read)))
       (printout t "Give the performance you want (possible options: low mid high): ")
       (assert (performance (read))))
    
    (defrule type_rule
       (type ?type)
       ?c <- (car (type ~?type))
       =>
       (retract ?c))
    
    (defrule price_rule
       (price ?price)
       ?c <- (car (price ~?price))
       =>
       (retract ?c))
    
    (defrule performance_rule
       (performance ?performance)
       ?c <- (car (performance ~?performance))
       =>
       (retract ?c))
    
    (defrule match
       (declare (salience -100))
       (car (brand_name ?name))
       =>
       (printout t "The car that fits you is: " ?name crlf))
    

    Here's how you can print a listing of the cars based on the number of criteria matched:

    (deftemplate car
       (slot brand_name (type STRING))
       (slot type (type SYMBOL)(allowed-symbols family city super))
       (slot price (type SYMBOL) (allowed-symbols low mid high))
       (slot performance (type SYMBOL) (allowed-symbols low mid high))
       (slot equipment (type SYMBOL) (allowed-symbols low mid high))
       (multislot matches))
    
    (deffacts car_facts
       (car (brand_name "Opel Astra") (type family) (price mid) (performance low))
       (car (brand_name "Peugeot 106a") (type city) (price low) (performance high))
       (car (brand_name "Mercedes E200") (type super) (price high) (performance mid))
       (car (brand_name "Rover 25") (type family) (price mid) (performance mid))
       (car (brand_name "Ferrari F40") (type super) (price high) (performance high)))
    
    (defrule questions
       =>
       (printout t "Give the Type you want (possible options: family city super): ")
       (assert (type (read)))
       (printout t "Give the price you want (possible options: low mid high): ")
       (assert (price (read)))
       (printout t "Give the performance you want (possible options: low mid high): ")
       (assert (performance (read))))
    
    (defrule type_rule
       (type ?type)
       ?c <- (car (type ?type) (matches $?m))
       (test (not (member$ type ?m)))
       =>
       (modify ?c (matches ?m type)))
    
    (defrule price_rule
       (price ?price)
       ?c <- (car (price ?price) (matches $?m))
       (test (not (member$ price ?m)))
       =>
       (modify ?c (matches ?m price)))
    
    (defrule performance_rule
       (performance ?performance)
       ?c <- (car (performance ?performance) (matches $?m))
       (test (not (member$ performance ?m)))
       =>
       (modify ?c (matches ?m performance)))
    
    (defrule match-header
       (declare (salience -100))
       =>
       (printout t "Cars matching your criteria: " crlf))
    
    (defrule match-3
       (declare (salience -200))
       (car (brand_name ?name) (matches $?m))
       (test (= (length$ ?m) 3))
       =>
       (printout t "   " ?name " : " (implode$ ?m) crlf))
    
    (defrule match-2
       (declare (salience -300))
       (car (brand_name ?name) (matches $?m))
       (test (= (length$ ?m) 2))
       =>
       (printout t "   " ?name " : " (implode$ ?m) crlf))
    
    (defrule match-1
       (declare (salience -400))
       (car (brand_name ?name) (matches $?m))
       (test (= (length$ ?m) 1))
       =>
       (printout t "   " ?name " : " (implode$ ?m) crlf))
    
    (defrule match-none
       (declare (salience -200))
       (not (and (car (brand_name ?name) (matches $?m))
                 (test (> (length$ ?m) 0))))
       =>
       (printout t "   None" crlf))
    

    Using the sort and find-all-fact functions to help print the results:

    (deftemplate car
       (slot brand_name (type STRING))
       (slot type (type SYMBOL)(allowed-symbols family city super))
       (slot price (type SYMBOL) (allowed-symbols low mid high))
       (slot performance (type SYMBOL) (allowed-symbols low mid high))
       (slot equipment (type SYMBOL) (allowed-symbols low mid high))
       (multislot matches))
    
    (deffacts car_facts
       (car (brand_name "Opel Astra") (type family) (price mid) (performance low))
       (car (brand_name "Peugeot 106a") (type city) (price low) (performance high))
       (car (brand_name "Mercedes E200") (type super) (price high) (performance mid))
       (car (brand_name "Rover 25") (type family) (price mid) (performance mid))
       (car (brand_name "Ferrari F40") (type super) (price high) (performance high)))
    
    (defrule questions
       =>
       (printout t "Give the Type you want (possible options: family city super): ")
       (assert (type (read)))
       (printout t "Give the price you want (possible options: low mid high): ")
       (assert (price (read)))
       (printout t "Give the performance you want (possible options: low mid high): ")
       (assert (performance (read))))
    
    (defrule type_rule
       (type ?type)
       ?c <- (car (type ?type) (matches $?m))
       (test (not (member$ type ?m)))
       =>
       (modify ?c (matches ?m type)))
    
    (defrule price_rule
       (price ?price)
       ?c <- (car (price ?price) (matches $?m))
       (test (not (member$ price ?m)))
       =>
       (modify ?c (matches ?m price)))
    
    (defrule performance_rule
       (performance ?performance)
       ?c <- (car (performance ?performance) (matches $?m))
       (test (not (member$ performance ?m)))
       =>
       (modify ?c (matches ?m performance)))
    
    (defrule match-header
       (declare (salience -100))
       =>
       (printout t "Cars matching your criteria: " crlf))
    
    (deffunction sort-cars (?f1 ?f2)
       (< (length$ (fact-slot-value ?f1 matches)) 
          (length$ (fact-slot-value ?f2 matches))))
    
    (defrule match-some
       (declare (salience -200))
       (exists (and (car (matches $?m))
                    (test (> (length$ ?m) 0))))
       =>
       (bind ?cars (find-all-facts ((?c car)) (> (length$ ?c:matches) 0)))
       (bind ?cars (sort sort-cars ?cars))
       (progn$ (?c ?cars)
          (printout t "   " (fact-slot-value ?c brand_name) " : " (implode$ (fact-slot-value ?c matches)) crlf)))
    
    (defrule match-none
       (declare (salience -200))
       (not (and (car (matches $?m))
                 (test (> (length$ ?m) 0))))
       =>
       (printout t "   None" crlf))
    

    The final results when you run the program:

    CLIPS> (reset)
    CLIPS> (run)
    Give the Type you want (possible options: family city super): super
    Give the price you want (possible options: low mid high): high
    Give the performance you want (possible options: low mid high): mid
    Cars matching your criteria: 
       Mercedes E200 : performance type price
       Ferrari F40 : price type
       Rover 25 : performance
    CLIPS>