Marco Caldera
Marco Caldera

Reputation: 505

How to sum integer in multislot fields trying all the possibile combinations in 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))
   =>
   ...
)

Upvotes: 0

Views: 230

Answers (2)

Gary Riley
Gary Riley

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

Marco Caldera
Marco Caldera

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

Related Questions