Reputation: 505
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))
=>
...
)
Upvotes: 0
Views: 230
Reputation: 10757
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>
Upvotes: 1
Reputation: 505
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>
Upvotes: 0