How to remove redundancies in a multifield in CLIPS? - clips

Suppose we have ordered multifield facts such as:
(serie-1 7 7 5 5 1 1)
(serie-2 8 3 8 3 8 3)
(serie-3 6 4 9 4 6 2)
The problem is to remove redundant fields from this ordered multifield facts to obtain:
(serie-1 7 5 1)
(serie-2 8 3)
(serie-3 6 4 9 2)
The question is: how to proceed ?

CLIPS (6.4 2/9/21)
CLIPS>
(deftemplate serie
(slot id)
(multislot nums))
CLIPS>
(deffacts start
(serie (id 1) (nums 7 7 5 5 1 1))
(serie (id 2) (nums 8 3 8 3 8 3))
(serie (id 3) (nums 6 4 9 4 6 2)))
CLIPS>
(defrule remove
?s <- (serie (nums $?b ?n $?m ?n $?e))
=>
(modify ?s (nums $?b ?n $?m $?e)))
CLIPS> (reset)
CLIPS> (facts)
f-1 (serie (id 1) (nums 7 7 5 5 1 1))
f-2 (serie (id 2) (nums 8 3 8 3 8 3))
f-3 (serie (id 3) (nums 6 4 9 4 6 2))
For a total of 3 facts.
CLIPS> (run)
CLIPS> (facts)
f-1 (serie (id 1) (nums 7 5 1))
f-2 (serie (id 2) (nums 8 3))
f-3 (serie (id 3) (nums 6 4 9 2))
For a total of 3 facts.
CLIPS>

Related

CLIPS: counting different products

I have some facts in the form of a list: (list day1 apple milk bread) (list day 2 bread milk) and I would like to count the different products in that facts for each day. How can I count them?
The result that I want is (list day1 3) (list day2 2)
CLIPS (6.4 2/9/21)
CLIPS>
(defrule list-count
(list ?day $?items)
=>
(assert (count ?day (length$ ?items))))
CLIPS>
(assert (list day1 apple milk bread)
(list day2 bread milk))
<Fact-2>
CLIPS> (agenda)
0 list-count: f-2
0 list-count: f-1
For a total of 2 activations.
CLIPS> (run)
CLIPS> (facts)
f-1 (list day1 apple milk bread)
f-2 (list day2 bread milk)
f-3 (count day2 2)
f-4 (count day1 3)
For a total of 4 facts.
CLIPS>

Matching two vectors with same elements but not ordered the same

I'm trying to write a general rule that will activate when two facts like these two are present:
(Vector v1 3 4 5)
(Vector v2 1 3 10 15 5 2 4)
(Elements 4 5 3)
So, my problem is that I don't know how to match ALL the unordered elements in the vector, in order to fire the rule.
I want the rule to activate only when ALL the elements from Elements are present, not taking in consideration if they follow the same order.
I haven't been able to achieve it, so I ask for help.
Examples of rules not doing what I want:
(defrule Equal
(Elements $?x)
(Vector ?name $?y)
(test (member$ $?x $?y))
=>
(printout t ?name crlf)
)
*The problem of this one is that it fires when both are blank, and mainly when a single member of ?x is contained in ?y, but I want the rule to fire when ALL elements in ?x are in ?y.
I tried using this simplier one too:
(defrule Equal
(Elements $? $?x $?)
(Vector ?name $? $?y $?)
=>
(printout t ?name crlf)
)
But in this case the rule only activates when the elements are exactly the same and ordered in the same way, but I want to have the flexibility of elements not having to be ordered exactly as they appear in the vector.
Use the subsetp function rather than member$:
CLIPS (6.31 4/1/19)
CLIPS>
(defrule equal
(elements $?elements)
(test (> (length$ ?elements) 0))
(vector ?name $?values)
(test (subsetp ?elements ?values))
=>
(printout t ?name crlf))
CLIPS>
(assert (vector v1 3 4 5)
(vector v2 1 3 10 15 5 2 4)
(vector v3 4 5 7 2)
(elements 4 5 3))
<Fact-4>
CLIPS>
(agenda)
0 equal: f-4,f-2
0 equal: f-4,f-1
For a total of 2 activations.
CLIPS> (run)
v2
v1
CLIPS>
You can also do it this way without a function call:
CLIPS> (clear)
CLIPS>
(defrule equal
(elements ? $?)
(vector ?name $?list)
(forall (elements $? ?v $?)
(vector ?name $? ?v $?))
=>
(printout t ?name crlf))
CLIPS>
(assert (vector v1 3 4 5)
(vector v2 1 3 10 15 5 2 4)
(vector v3 4 5 7 2)
(elements 4 5 3))
<Fact-4>
CLIPS> (agenda)
0 equal: f-4,f-2,*
0 equal: f-4,f-1,*
For a total of 2 activations.
CLIPS> (run)
v2
v1
CLIPS>

defrule never makes it in the agenda | CLIPS

I want to build an expert system in which in a case of emergency at a building with some floors (it needs to work for any amount of floors) the elevator should take the people into the ground.
The thing is, that the defrule to send the elevator at any floor never makes it in the agenda, so the system just does nothing. The correct action should be to fire the rule and then another rule that takes the people from the floor.
The code for the defrule is this:
(defrule move_to_floor "elevator moves to any floor "
?i <- (elevator is_at floor ?x has ?y adults and ?z minors)
(floor ?fl&~?x has ?n adult and ?m minor people)
(test (> (+ ?n ?m) 0))
=>
(retract ?i)
(assert (elevator is_at floor ?fl has ?y adults and ?z minors))
)
The facts as they have been initialized from the user in another defrule above are these:
f-0 (initial-fact)
f-1 (elevator is_at 0 has 0 adults and 0 minors)
f-3 (capacity 4)
f-4 (floors 3)
f-5 (initCanEnter 0) ;At 0 this prevents from entering the init_defrule again
f-6 (floor 3 has 2 adult and 1 minor people)
f-7 (floor 2 has 4 adult and 5 minor people)
f-8 (floor 1 has 1 adult and 2 minor people)
I can't seem to find the solution. Also, I'm using deffacts and not deftemplate as I have seen many people using on the internet.
You can use the matches command to see which patterns in a rule are matched.
CLIPS (6.31 2/3/18)
CLIPS>
(defrule move_to_floor "elevator moves to any floor "
?i <- (elevator is_at floor ?x has ?y adults and ?z minors)
(floor ?fl&~?x has ?n adult and ?m minor people)
(test (> (+ ?n ?m) 0))
=>
(retract ?i)
(assert (elevator is_at floor ?fl has ?y adults and ?z minors)))
CLIPS>
(deffacts initial
(elevator is_at 0 has 0 adults and 0 minors)
(capacity 4)
(floors 3)
(initCanEnter 0) ;At 0 this prevents from entering the init_defrule again
(floor 3 has 2 adult and 1 minor people)
(floor 2 has 4 adult and 5 minor people)
(floor 1 has 1 adult and 2 minor people))
CLIPS> (reset)
CLIPS> (matches move_to_floor)
Matches for Pattern 1
None
Matches for Pattern 2
f-5
f-6
f-7
Partial matches for CEs 1 - 2
None
Activations
None
(3 0 0)
CLIPS>
In this case, the first pattern is not matched. That's because your pattern expects is_at floor ?x but your fact contains is_at 0 (the symbol floor is missing in your fact). If you correct this issue, the rule will be placed on the agenda.
CLIPS>
(deffacts initial
(elevator is_at floor 0 has 0 adults and 0 minors)
(capacity 4)
(floors 3)
(initCanEnter 0) ;At 0 this prevents from entering the init_defrule again
(floor 3 has 2 adult and 1 minor people)
(floor 2 has 4 adult and 5 minor people)
(floor 1 has 1 adult and 2 minor people))
CLIPS> (reset)
CLIPS> (agenda)
0 move_to_floor: f-1,f-7
0 move_to_floor: f-1,f-6
0 move_to_floor: f-1,f-5
For a total of 3 activations.
CLIPS>
If you issue a (run) command at this point, the rules will endlessly fire in a loop moving from floor to floor, so that's something you'll need to address next.
If you use deftemplate facts rather than ordered facts, you'll get an error if you misspell slot names, so it's better to use these if you have a fact with multiple attributes.
CLIPS> (clear)
CLIPS>
(deftemplate elevator
(slot at_floor (type INTEGER))
(slot adults (type INTEGER))
(slot minors (type INTEGER)))
CLIPS>
(deftemplate floor
(slot # (type INTEGER))
(slot adults (type INTEGER))
(slot minors (type INTEGER)))
CLIPS>
(deffacts initial
(elevator (at_floor 0))
(capacity 4)
(floors 3)
(initCanEnter 0)
(floor (# 3) (adults 2) (minors 1))
(floor (# 2) (adults 4) (minors 5))
(floor (# 1) (adults 1) (minors 2)))
CLIPS>
(defrule move_to_floor
?i <- (elevator (at_floor ?x))
(floor (# ?fl&~?x) (adults ?n) (minors ?m))
(test (> (+ ?n ?m) 0))
=>
(modify ?i (at_floor ?fl)))
CLIPS> (reset)
CLIPS> (facts)
f-0 (initial-fact)
f-1 (elevator (at_floor 0) (adults 0) (minors 0))
f-2 (capacity 4)
f-3 (floors 3)
f-4 (initCanEnter 0)
f-5 (floor (# 3) (adults 2) (minors 1))
f-6 (floor (# 2) (adults 4) (minors 5))
f-7 (floor (# 1) (adults 1) (minors 2))
For a total of 8 facts.
CLIPS> (agenda)
0 move_to_floor: f-1,f-7
0 move_to_floor: f-1,f-6
0 move_to_floor: f-1,f-5
For a total of 3 activations.
CLIPS>

cannot update the object in CLIPS, getting compile time error in clips

(bind ?existing_total_count (nth$ 2 (send ?INSTANCE ?get-INTS)))
(send (nth$ 2 (send ?INSTANCE put-INTS)) (+ ?total_count ?existing_total_count))
first line compiles fine, but second line throwing error
Function send expected argument #2 to be of type symbol
I cant findout what the issue is. I am trying to update the second entry in slot INTS.
CLIPS>
(defclass A
(is-a USER)
(multislot INTS))
CLIPS> (make-instance [a] of A (INTS 1 2 3))
[a]
CLIPS> (send [a] print)
[a] of A
(INTS 1 2 3)
CLIPS> (bind ?INSTANCE [a])
[a]
CLIPS> (bind ?existing_total_count (nth$ 2 (send ?INSTANCE get-INTS)))
2
CLIPS> (bind ?total_count 3)
3
CLIPS> (slot-replace$ ?INSTANCE INTS 2 2 (+ ?total_count ?existing_total_count))
(1 5 3)
CLIPS> (send [a] print)
[a] of A
(INTS 1 5 3)
CLIPS> (bind ?total_count 5)
5
CLIPS> (send ?INSTANCE put-INTS (replace$ (send ?INSTANCE get-INTS) 2 2 (+ ?total_count ?existing_total_count)))
(1 7 3)
CLIPS> (send [a] print)
[a] of A
(INTS 1 7 3)
CLIPS>

Clips - print a list of numbers in pyramid

I am trying to print my 1234 list like:
1
12
123
1234
Here is my code:
(deffacts lists
(list 1 2 3 4)
)
(defrule print
(list $?x ? $?)
=>
(printout t ?x )
)
I'm not sure exactly how I should continue...
CLIPS>
(deffacts lists
(list 1 2 3 4))
CLIPS>
(deffunction pyramid-print (?list)
(loop-for-count (?i (length$ ?list))
(printout t (implode$ (subseq$ ?list 1 ?i)) crlf)))
CLIPS>
(defrule print
(list $?x)
=>
(pyramid-print ?x))
CLIPS> (reset)
CLIPS> (run)
1
1 2
1 2 3
1 2 3 4
CLIPS>

Resources