I'm trying to do a comparation in a rule on CLIPS thah check if one of three conditions it's true to assert a new fact. The code is:
(defrule empresa_cae_mucho
(Empresa (nombre ?n)(var_anio ?anio)(var_sem ?sem)(var_tri ?tri))
=>
(or (or (test(> ?anio 30))(test (> ?sem 30))(test (> ?tri 30))))
(assert valor_infravalorado
(nombre ?n))
(assert (Explicacion
(nombre ?n)
(motivo "la empresa ha caido bastante aunque no en el ultimo mes
pero su PER es bajo")))
)
But it doesn't work and I can't find the right form of do this in internet. Any help?
CLIPS> (clear)
CLIPS>
(deftemplate Empresa
(slot nombre)
(slot var_anio)
(slot var_sem)
(slot var_tri))
CLIPS>
(deftemplate valor_infravalorado
(slot nombre))
CLIPS>
(deftemplate Explicacion
(slot nombre)
(slot motivo))
CLIPS>
(deffacts start
(Empresa (nombre 1) (var_anio 40) (var_sem 10) (var_tri 25))
(Empresa (nombre 2) (var_anio 0) (var_sem 35) (var_tri 10))
(Empresa (nombre 3) (var_anio 30) (var_sem 20) (var_tri 55))
(Empresa (nombre 4) (var_anio 30) (var_sem 30) (var_tri 30)))
CLIPS>
(defrule empresa_cae_mucho
(Empresa (nombre ?n)
(var_anio ?anio)
(var_sem ?sem)
(var_tri ?tri))
(test (or (> ?anio 30)
(> ?sem 30)
(> ?tri 30)))
=>
(assert (valor_infravalorado (nombre ?n)))
(assert (Explicacion
(nombre ?n)
(motivo "la empresa ..."))))
CLIPS> (reset)
CLIPS> (watch rules)
CLIPS> (watch facts)
CLIPS> (run)
FIRE 1 empresa_cae_mucho: f-3
==> f-5 (valor_infravalorado (nombre 3))
==> f-6 (Explicacion (nombre 3) (motivo "la empresa ..."))
FIRE 2 empresa_cae_mucho: f-2
==> f-7 (valor_infravalorado (nombre 2))
==> f-8 (Explicacion (nombre 2) (motivo "la empresa ..."))
FIRE 3 empresa_cae_mucho: f-1
==> f-9 (valor_infravalorado (nombre 1))
==> f-10 (Explicacion (nombre 1) (motivo "la empresa ..."))
CLIPS> (facts)
f-0 (initial-fact)
f-1 (Empresa (nombre 1) (var_anio 40) (var_sem 10) (var_tri 25))
f-2 (Empresa (nombre 2) (var_anio 0) (var_sem 35) (var_tri 10))
f-3 (Empresa (nombre 3) (var_anio 30) (var_sem 20) (var_tri 55))
f-4 (Empresa (nombre 4) (var_anio 30) (var_sem 30) (var_tri 30))
f-5 (valor_infravalorado (nombre 3))
f-6 (Explicacion (nombre 3) (motivo "la empresa ..."))
f-7 (valor_infravalorado (nombre 2))
f-8 (Explicacion (nombre 2) (motivo "la empresa ..."))
f-9 (valor_infravalorado (nombre 1))
f-10 (Explicacion (nombre 1) (motivo "la empresa ..."))
For a total of 11 facts.
CLIPS>
Related
I would like to know in each day which activities I do, so I constructed the following code:
(deftemplate schedule
(slot activity)
(slot starthour)
(slot endhour)
)
(defrule r1
(schedule (activity ?a) (starthour ?start) (endhour ?end))
(not (busy ?start ?a))
=>
(assert (busy ?start ?a))
)
(defrule r2
(busy ?d ?a)
(schedule (activity ?a) (starthour ?start) (endhour ?end))
(test (< ?d ?end))
=>
(assert (busy ( + ?d 1) ?a))
)
CLIPS> (assert (schedule (activity reading) (starthour 3) (endhour 5)))
<Fact-1>
CLIPS> (assert (schedule (activity music) (starthour 4) (endhour 7)))
<Fact-2>
For the facts that I inserted I obtained a result that does not order the days.
How CLIPS interpret the order of the facts?
Is there a way to me to combine in a day more than 1 activity?
Thanks very much!
By default CLIPS uses a depth first strategy for determining which rule to execute next, so generally the next rule executed will have been activated by the last fact asserted or retracted. Section 5.3, Conflict Resolution Strategies, in the Basic Programming Guide describes this process in greater detail.
As long as the correct facts are being generated by the rules, you shouldn't be particularly concerned with the order in which they're place on the fact-list because 1) It's not practical to use the fact-list to display the output of a program and 2) forcing a particular order of placement can be difficult and overly complex.
Instead, to order facts in your program output, collect all of the relevant facts using one of the fact query functions and then use the sort function with a custom comparator to order the facts before printing them:
CLIPS (6.4 2/9/21)
CLIPS>
(deftemplate schedule
(slot activity)
(slot starthour)
(slot endhour))
CLIPS>
(deftemplate busy
(slot activity)
(slot hour))
CLIPS>
(defrule r1
(schedule (activity ?a) (starthour ?start) (endhour ?end))
(not (busy (activity ?a) (hour ?start)))
=>
(assert (busy (activity ?a) (hour ?start))))
CLIPS>
(defrule r2
(busy (activity ?a) (hour ?d))
(schedule (activity ?a) (starthour ?start) (endhour ?end))
(test (< ?d ?end))
=>
(assert (busy (activity ?a) (hour (+ ?d 1)))))
CLIPS>
(deffacts schedules
(schedule (activity reading) (starthour 3) (endhour 5))
(schedule (activity music) (starthour 4) (endhour 7)))
CLIPS>
(deffunction busy-compare (?f1 ?f2)
;; Sort by hour
(if (> (fact-slot-value ?f2 hour) (fact-slot-value ?f1 hour))
then (return FALSE))
(if (< (fact-slot-value ?f2 hour) (fact-slot-value ?f1 hour))
then (return TRUE))
;; And then sort by activity
(if (> (str-compare (fact-slot-value ?f2 activity)
(fact-slot-value ?f1 activity)) 0)
then (return FALSE)
else (return TRUE)))
CLIPS>
(defrule print
(declare (salience -10))
=>
(bind ?schedule (find-all-facts ((?f busy)) TRUE))
(bind ?schedule (sort busy-compare ?schedule))
(foreach ?s ?schedule
(format t "%2d %s%n" (fact-slot-value ?s hour) (fact-slot-value ?s activity))))
CLIPS> (reset)
CLIPS> (run)
3 reading
4 music
4 reading
5 music
5 reading
6 music
7 music
CLIPS> (facts)
f-1 (schedule (activity reading) (starthour 3) (endhour 5))
f-2 (schedule (activity music) (starthour 4) (endhour 7))
f-3 (busy (activity music) (hour 4))
f-4 (busy (activity music) (hour 5))
f-5 (busy (activity music) (hour 6))
f-6 (busy (activity music) (hour 7))
f-7 (busy (activity reading) (hour 3))
f-8 (busy (activity reading) (hour 4))
f-9 (busy (activity reading) (hour 5))
For a total of 9 facts.
CLIPS>
Here's another way to do it storing multiple activities in each busy fact:
CLIPS> (clear)
CLIPS>
(deftemplate schedule
(slot activity)
(slot starthour)
(slot endhour))
CLIPS>
(deftemplate busy
(multislot activity)
(slot hour))
CLIPS>
(defrule r1
(schedule (activity ?a) (starthour ?start) (endhour ?end))
=>
(loop-for-count (?hour ?start ?end)
(assert (busy (activity ?a) (hour ?hour)))))
CLIPS>
(defrule combine
?b1 <- (busy (activity $?a) (hour ?d))
?b2 <- (busy (activity ?n&:(not (member$ ?n ?a))) (hour ?d))
=>
(modify ?b1 (activity ?a ?n))
(retract ?b2))
CLIPS>
(deffacts schedules
(schedule (activity reading) (starthour 3) (endhour 5))
(schedule (activity music) (starthour 4) (endhour 7)))
CLIPS>
(deffunction busy-compare (?f1 ?f2)
(if (> (fact-slot-value ?f2 hour) (fact-slot-value ?f1 hour))
then (return FALSE))
(if (< (fact-slot-value ?f2 hour) (fact-slot-value ?f1 hour))
then (return TRUE))
(return FALSE))
CLIPS>
(defrule print
(declare (salience -10))
=>
(bind ?schedule (find-all-facts ((?f busy)) TRUE))
(bind ?schedule (sort busy-compare ?schedule))
(foreach ?s ?schedule
(format t "%2d %s%n" (fact-slot-value ?s hour) (implode$ (fact-slot-value ?s activity)))))
CLIPS> (reset)
CLIPS> (run)
3 reading
4 reading music
5 reading music
6 music
7 music
CLIPS> (facts)
f-1 (schedule (activity reading) (starthour 3) (endhour 5))
f-2 (schedule (activity music) (starthour 4) (endhour 7))
f-5 (busy (activity music) (hour 6))
f-6 (busy (activity music) (hour 7))
f-7 (busy (activity reading) (hour 3))
f-8 (busy (activity reading music) (hour 4))
f-9 (busy (activity reading music) (hour 5))
For a total of 7 facts.
CLIPS>
I have a situation like this:
(deftemplate trip
(multislot place-sequence)
(multislot days-distribution)
)
(deftemplate travel-banchmark
(slot name)
(slot value)
)
(trip (place-sequence milano roma venezia) (days-distribution 1 1 1))
(trip (place-sequence roma milano venezia) (days-distribution 1 1 1))
(travel-banchmark (name travel-duration) (value 5))
Now for every trip-fact I have to assert all the possible trip with different days-distribution (the sum of days-distribution needs to be the travel-duration (e.g., 5))
Example:
(trip (place-sequence milano roma venezia) (days-distribution 3 1 1))
(trip (place-sequence milano roma venezia) (days-distribution 1 3 1))
(trip (place-sequence milano roma venezia) (days-distribution 1 1 3))
(trip (place-sequence milano roma venezia) (days-distribution 2 2 1))
(trip (place-sequence milano roma venezia) (days-distribution 1 1 2))
...
Is it possible to do this using rules? I have some problem in understanding the best way to do this kind of things with a rule-based system
Edit:
This is my way to calculate the sum inside the multislot but I still have a problem figuring out how to calculate the different days-distrubtion
(defrule test
(travel-banchmark (name travel-duration) (value ?duration))
?p <- (trip
(days-distribution $?d))
(test (<= (+ 0 (expand$ ?d)) ?duration))
=>
...
)
You don't have to use rules to do everything, particularly if there's an obvious algorithmic solution. For example, it doesn't make sense to do this:
(defrule hello
?f <- (count ?c&:(> ?c 0))
=>
(printout t "Hello" crlf)
(retract ?f)
(assert (count (- ?c 1))))
When you can do this:
(deffunction hello (?count)
(loop-for-count ?count (printout t "Hello" crlf)))
Generating the distributions using a recursive function call is pretty straightforward and can do so from a single rule firing without having to incrementally build the solution and then remove the intermediate steps.
CLIPS (6.31 6/12/19)
CLIPS>
(deftemplate trip
(multislot place-sequence)
(multislot days-distribution))
CLIPS>
(deftemplate travel-banchmark
(slot name)
(slot value))
CLIPS>
(deffacts initial
(travel-banchmark (name travel-duration) (value 5))
(trip (place-sequence milano roma venezia) (days-distribution)))
CLIPS>
(deffunction create-distributions (?cc ?cities ?days ?duration $?distribution)
(bind ?max-alloc (- ?duration ?days (- ?cc 1)))
(if (= ?cc 1)
then
(assert (trip (place-sequence ?cities) (days-distribution ?distribution ?max-alloc)))
(return))
(loop-for-count (?a ?max-alloc)
(create-distributions (- ?cc 1) ?cities (+ ?days ?a) ?duration ?distribution ?a)))
CLIPS>
(defrule test
(travel-banchmark (name travel-duration) (value ?duration))
?p <- (trip (place-sequence $?cities) (days-distribution))
=>
(bind ?city-count (length$ ?cities))
(create-distributions ?city-count ?cities 0 ?duration)
(retract ?p))
CLIPS> (reset)
CLIPS> (run)
CLIPS> (facts)
f-0 (initial-fact)
f-1 (travel-banchmark (name travel-duration) (value 5))
f-3 (trip (place-sequence milano roma venezia) (days-distribution 1 1 3))
f-4 (trip (place-sequence milano roma venezia) (days-distribution 1 2 2))
f-5 (trip (place-sequence milano roma venezia) (days-distribution 1 3 1))
f-6 (trip (place-sequence milano roma venezia) (days-distribution 2 1 2))
f-7 (trip (place-sequence milano roma venezia) (days-distribution 2 2 1))
f-8 (trip (place-sequence milano roma venezia) (days-distribution 3 1 1))
For a total of 8 facts.
CLIPS>
Ok, I have found an answer to my question:
CLIPS>
(deftemplate trip
(multislot place-sequence)
(multislot days-distribution)
)
CLIPS>
(deftemplate travel-banchmark
(slot name)
(slot value)
)
CLIPS>
(deffacts initial
(travel-banchmark (name travel-duration) (value 5))
(trip (place-sequence milano roma venezia) (days-distribution 1 1 1))
)
CLIPS>
(defrule test
(travel-banchmark (name travel-duration) (value ?duration))
?p <- (trip
(place-sequence $?cities)
(days-distribution $?days-distribution))
(test (< (+ 0 (expand$ ?days-distribution)) ?duration))
=>
(retract ?p)
(loop-for-count (?cnt1 1 (length$ ?days-distribution)) do
(bind ?new-days-distribution (replace$ ?days-distribution ?cnt1 ?cnt1 (+ (nth$ ?cnt1 ?days-distribution) 1)))
(assert (trip
(place-sequence ?cities)
(days-distribution ?new-days-distribution))
)
)
)
CLIPS>
(defrule clean
(declare (salience -5))
?p <- (trip
(place-sequence $?cities)
(days-distribution $?days-distribution))
?p2 <- (trip
(place-sequence $?cities)
(days-distribution $?days-distribution))
(test (neq ?p ?p2))
=>
(retract ?p)
)
CLIPS> (reset)
CLIPS> (run)
CLIPS> (facts)
f-0 (initial-fact)
f-1 (travel-banchmark (name travel-duration) (value 5))
f-6 (trip (place-sequence milano roma venezia) (days-distribution 2 1 2))
f-7 (trip (place-sequence milano roma venezia) (days-distribution 1 2 2))
f-8 (trip (place-sequence milano roma venezia) (days-distribution 1 1 3))
f-9 (trip (place-sequence milano roma venezia) (days-distribution 2 2 1))
f-10 (trip (place-sequence milano roma venezia) (days-distribution 1 3 1))
f-12 (trip (place-sequence milano roma venezia) (days-distribution 3 1 1))
For a total of 8 facts.
CLIPS>
I'm trying to build a simple expert system for recommending courses and want to implement certainty factor in my program, however I'm stuck looking for a simple integration method.
I've stumbled upon this example but can't seems to figure out how to make it fire.
; Allow facts that are duplicates:
(defrule start
(declare (salience 1000))
(initial-fact)
=>
(set-fact-duplication TRUE))
(defrule combine-certainities-both-positive
?fact1 <- (organism ?attribute ?value ?C1&:(>= ?C1 0))
?fact2 <- (organism ?attribute ?value ?C2&:(>= ?C2 0))
(test (neq ?fact1 ?fact2))
=>
(retract ?fact1 ?fact2)
(bind ?C3 (- (+ ?C1 ?C2) (* ?C1 ?C2)))
(assert (organism ?attribute ?value ?C3)))
(defrule combine-certainities-both-negative
?fact1 <- (organism ?attribute ?value ?C1&:(< ?C1 0))
?fact2 <- (organism ?attribute ?value ?C2&:(< ?C2 0))
(test (neq ?fact1 ?fact2))
=>
(retract ?fact1 ?fact2)
(bind ?C3 (+ (+ ?C1 ?C2) (* ?C1 ?C2)))
(assert (organism ?attribute ?value ?C3)))
(defrule combine-certainities-with-opposite-signs
?fact1 <- (organism ?attribute ?value ?C1)
?fact2 <- (organism ?attribute ?value ?C2)
(test (< (* ?C1 ?C2) 0))
(test (neq ?fact1 ?fact2))
=>
(retract ?fact1 ?fact2)
(bind ?C3 (/ (+ ?C1 ?C2) (- 1 (min (abs ?C1) (abs ?C2)))))
(assert (organism ?attribute ?value ?C3)))
I try to assert two new organism facts to kick start the first rule:
CLIPS> (assert (organism morpholgy1 rod1 0.25)
(organism morpholgy2 rod2 0.25))
==> f-4 (organism morpholgy1 rod1 0.25)
==> f-5 (organism morpholgy2 rod2 0.25)
<Fact-5>
CLIPS> (run)
<== Focus MAIN
0 rules fired Run time is 0.00300693511962891 seconds.
0.0 rules per second.
2 mean number of facts (2 maximum).
0 mean number of instances (0 maximum).
0 mean number of activations (0 maximum).
And use the matches but still don't get how to make it match here..
CLIPS> (matches combine-certainities-both-positive)
Matches for Pattern 1
f-4
f-5
Matches for Pattern 2
f-4
f-5
Partial matches for CEs 1 - 2
None
Activations
None
(4 0 0)
The attribute and the value have to match (morpholgy1 != morpholgy2 and rod1 != rod2). That's why fact duplication has to be enabled to allow multiple copies of the same attribute/value.
CLIPS> (set-fact-duplication TRUE)
FALSE
CLIPS>
(assert (organism morpholgy rod 0.25)
(organism morpholgy rod 0.25))
<Fact-2>
CLIPS> (watch facts)
CLIPS> (run)
<== f-2 (organism morpholgy rod 0.25)
<== f-1 (organism morpholgy rod 0.25)
==> f-3 (organism morpholgy rod 0.4375)
CLIPS>
I'm asking if there is a possibility of accessing a get the index of fact in RHS of defrule ?
It gives me that undefined every time I try to index a fact in a RHS of defrule.
because I have a while loop , I want to be able to modify elevator fact depending on my input data.
(deftemplate elevator
(slot goal))
(deffacts elevator
(elevator (goal 0)))
(defrule read-data
=>
?f1 <- (elevator)
(modify ?f2 (goal 1))
)
this an example of my code , since I can't put all online :
(deftemplate data
(slot data)
)
(deffacts data
(data (data 1))
)
(defrule rule1
?f1 <-(data)
=>
(bind ?value (readline input) )
(while (neq ?value EOF)
do
(bind ?data (fact-slot-value ?f1 data))
(printout t "data " ?data crlf )
(retract ?f1)
(modify ?f1 (data ?value))
(bind ?value (readline input)
)
)
)
this is my input file :
2
3
4
5
6
7
this is what I'm getting :
CLIPS> (run)
data 1
data FALSE
data FALSE
data FALSE
data FALSE
data FALSE
CLIPS>
I want it to print out
data 2
data 3
data 4 ..ect
You can do it this way from the RHS of a rule, but if your rule actually has no LHS conditions, it's pointless to use a rule to change the value of the fact. Just use a function.
CLIPS>
(deftemplate elevator
(slot goal))
CLIPS>
(deffacts elevator
(elevator (goal 0)))
CLIPS>
(defrule read-data
=>
(do-for-fact ((?f elevator)) TRUE
(modify ?f (goal 1))))
CLIPS> (watch facts)
CLIPS> (reset)
<== f-0 (initial-fact)
==> f-0 (initial-fact)
==> f-1 (elevator (goal 0))
CLIPS> (run)
<== f-1 (elevator (goal 0))
==> f-2 (elevator (goal 1))
CLIPS>
Alternately, you can bind the fact you want to modify in the conditions of the rule:
CLIPS> (clear)
CLIPS>
(deftemplate elevator
(slot goal))
CLIPS>
(deffacts elevator
(elevator (goal 0)))
CLIPS>
(defrule read-data
?f <- (elevator (goal 0))
=>
(modify ?f (goal 1)))
CLIPS> (watch facts)
CLIPS> (reset)
<== f-0 (initial-fact)
==> f-0 (initial-fact)
==> f-1 (elevator (goal 0))
CLIPS> (run)
<== f-1 (elevator (goal 0))
==> f-2 (elevator (goal 1))
CLIPS>
Updated:
You can get your original rule to "work" by removing the retract and rebinding ?f1 to the value returned by modify:
CLIPS> (clear)
CLIPS>
(deftemplate data
(slot data))
CLIPS>
(deffacts data
(data (data 1)))
CLIPS>
(defrule rule1
?f1 <- (data)
=>
(bind ?value (readline input))
(while (neq ?value EOF)
(bind ?data (fact-slot-value ?f1 data))
(printout t "data " ?data crlf )
(bind ?f1 (modify ?f1 (data ?value)))
(bind ?value (readline input))))
CLIPS> (reset)
CLIPS> (open input.txt input)
TRUE
CLIPS> (run)
data 1
data 2
data 3
data 4
data 5
data 6
CLIPS> (close input)
TRUE
CLIPS>
It's still suspiciously complicated to be modifying the same fact multiple times on the RHS.
I am trying to return a message if the user types in a value within certain range. Is this possible on CLIPS? In addition the system should only accept values in increments of 10.
If the user types in a number less or equal to 10 it should say "A"
If the user types in a number greater than 10 and less than 40 it should say "B"
- so it should only accept values 10,20,30,40
This is the code I have so far:
(defrule b-a1
(b-a "a")
=>
(bind ?reply (get-text-from-user "How many points did you achieve?"))
(assert (b-a1 ?reply )))
(defrule b-a2
(b-a1 <= 10)
=>
(assert (conclusion "A")))
(defrule b-a2
(10 < b-a1 < 40)
=>
(assert (conclusion "B")))
Any ideas on how I can get this working?
CLIPS>
(defrule b-a1
(b-a "a")
=>
(printout t "How many points did you achieve? ")
(bind ?reply (read))
(assert (b-a1 ?reply )))
CLIPS>
(defrule b-a2
(b-a1 ?v&:(<= ?v 10))
=>
(assert (conclusion "A")))
CLIPS>
(defrule b-a2
(b-a1 ?v&:(< 10 ?v)&:(< ?v 40))
=>
(assert (conclusion "B")))
CLIPS> (assert (b-a "a"))
<Fact-1>
CLIPS> (run)
How many points did you achieve? 24
CLIPS> (facts)
f-0 (initial-fact)
f-1 (b-a "a")
f-2 (b-a1 24)
f-3 (conclusion "B")
For a total of 4 facts.
CLIPS>