如何在CLIPS中生成多槽整数和为指定值的所有组合
Absolutely, you can implement this with CLIPS rules—you just need to add a combinatorial generation layer to your existing logic. The key challenge is generating all integer tuples for days-distribution that sum to your benchmark value, while ensuring each place gets at least 1 day (since you can’t spend 0 days in a destination).
Here’s a complete, step-by-step solution that builds on your existing templates and facts:
Full Implementation Code
First, keep your original templates and facts, then add helper structures and rules to handle combination generation:
; Original templates and facts (deftemplate trip (multislot place-sequence) (multislot days-distribution)) (deftemplate travel-banchmark (slot name) (slot value)) (deffacts initial-data (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)) ) ; Helper templates for tracking generation state (deffacts counters (trip-id-counter 0) ) (deftemplate trip-with-id (slot original-trip) (slot id) (slot num-places) ) (deftemplate combination-state (slot trip-id) (multislot current-combo) (slot remaining-days) (slot remaining-places) ) (deftemplate value-generator (slot trip-id) (slot current-value) (slot max-value) (slot state-ref) ) (deftemplate trip-processed (slot id) ) ; Rule 1: Assign unique IDs to each trip for tracking (defrule assign-trip-id ?counter <- (trip-id-counter ?id) ?trip <- (trip (place-sequence $?places)) (not (trip-with-id (original-trip ?trip))) => (assert (trip-with-id (original-trip ?trip) (id ?id) (num-places (length$ ?places)))) (modify ?counter (trip-id-counter (+ ?id 1))) ) ; Rule 2: Start combination generation for valid trips (duration >= number of places) (defrule start-combination-generation (travel-banchmark (name travel-duration) (value ?duration)) ?trip-info <- (trip-with-id (id ?tid) (num-places ?n)) (test (>= ?duration ?n)) (not (combination-state (trip-id ?tid))) (not (trip-processed (id ?tid))) => (assert (combination-state (trip-id ?tid) (current-combo) (remaining-days (- ?duration ?n)) (remaining-places ?n))) ) ; Rule 3: Initiate value generation for non-final places (defrule initiate-value-generation ?state <- (combination-state (trip-id ?tid) (current-combo $?current) (remaining-days ?r) (remaining-places ?p)) (test (> ?p 1)) => (assert (value-generator (trip-id ?tid) (current-value 0) (max-value ?r) (state-ref ?state))) (retract ?state) ) ; Rule 4: Generate each possible value for the current place and recurse (defrule generate-next-value ?generator <- (value-generator (trip-id ?tid) (current-value ?v) (max-value ?r) (state-ref ?state)) (test (<= ?v ?r)) => (bind ?current-combo (fact-slot-value ?state current-combo)) (bind ?remaining-places (- (fact-slot-value ?state remaining-places) 1)) (bind ?new-remaining-days (- ?r ?v)) (assert (combination-state (trip-id ?tid) (current-combo ?current-combo ?v) (remaining-days ?new-remaining-days) (remaining-places ?remaining-places))) (if (< ?v ?r) then (modify ?generator (current-value (+ ?v 1))) else (retract ?generator) ) ) ; Rule 5: Finalize combinations and assert new trip facts (defrule finalize-combination ?state <- (combination-state (trip-id ?tid) (current-combo $?current) (remaining-days ?r) (remaining-places 1)) => (bind ?final-extra-combo (create$ ?current ?r)) (bind ?actual-days (map$ ?x (+ ?x 1) ?final-extra-combo)) (trip-with-id (id ?tid) (original-trip ?original-trip)) (bind ?places (fact-slot-value ?original-trip place-sequence)) (assert (trip (place-sequence ?places) (days-distribution ?actual-days))) (retract ?state) ) ; Rule 6: Mark trips as processed once all combinations are generated (defrule mark-trip-processed ?trip-info <- (trip-with-id (id ?tid)) (not (trip-processed (id ?tid))) (not (combination-state (trip-id ?tid))) (not (value-generator (trip-id ?tid))) => (assert (trip-processed (id ?tid))) )
How It Works
- Trip Tracking: Each original trip gets a unique ID to link generated combinations back to their source.
- Validity Check: We only generate combinations if the travel duration is at least the number of places (since each destination needs at least 1 day).
- Combination Generation:
- We calculate "extra days" (total duration minus number of places) to distribute across destinations.
- Using recursive state facts, we build combinations one place at a time, generating all possible values for each position.
- Finalization: Convert the extra days to actual days (add 1 to each element) and assert new
tripfacts with the validdays-distributioncombinations.
Expected Output
For your sample data, this will generate 6 new trip facts per original trip, including combinations like:
(trip (place-sequence milano roma venezia) (days-distribution 3 1 1))(trip (place-sequence milano roma venezia) (days-distribution 2 2 1))(trip (place-sequence milano roma venezia) (days-distribution 1 3 1))
All combinations will sum to the travel-duration value of 5.
内容的提问来源于stack exchange,提问作者Marco Caldera

