Search code examples
conditional-statementsclips

CLIPS asserting facts with OR condition in RHS


is there a way in CLIPS to handle rules like:

(defrule temperature
    (IT-IS-COLD-INSIDE TRUE)
    =>
    (assert 
        (IT-IS-COLD-OUTSIDE TRUE)
    )
    (or
        (assert (WINDOW-IS-OPEN TRUE))
        (assert (DOOR-IS-OPEN TRUE))
    )
)

What I am curious about is that, for example, another rule fires and let's say the result of that rule is that the DOOR-IS-OPEN gets asserted to FALSE, then can CLIPS conclude that this means that the WINDOW-IS-OPEN must be TRUE (if of course IT-IS-COLD-INSIDE is TRUE already)?

or I should just write it in the other way around like:

(defrule temperature 
    (or
        (WINDOW-IS-OPEN TRUE)
        (DOOR-IS-OPEN TRUE)
    )
    (IT-IS-COLD-OUTSIDE TRUE)
    =>
    (assert (IT-IS-COLD-INSIDE TRUE))    
)

The problem with this one is that it is not always true in my use case (the first example always covers the truth though). Let's say maybe there is very strong heating inside. I could just add this also to the picture, but it is not always possible. I am trying to develop a system that can work on data that are partially defined.

When I run my original example, it asserts the first fact (WINDOW-IS-OPEN TRUE) but never the second.

The syntax is probably wrong, but I guess you have the idea of what I am trying to achieve.


Solution

  • First define two deftemplates: one for representing known attribute values and another for representing deducible attribute values. Groupings of deducible attribute values will be grouped together using the link slot.

             CLIPS (6.31 6/12/19)
    CLIPS> 
    (deftemplate av
       (slot attribute)
       (slot value))
    CLIPS> 
    (deftemplate dav
       (slot attribute)
       (slot value)
       (slot link))
    CLIPS>    
    (deffacts initial
       (av (attribute it-is-cold-inside)
           (value TRUE)))
    CLIPS> 
    

    Your temperature rule can then be implemented with the following code.

    CLIPS> 
    (defrule temperature
       (av (attribute it-is-cold-inside)
           (value TRUE))
       =>
       (assert (av (attribute it-is-cold-outside)
                   (value TRUE))
               (dav (attribute window-is-open)
                    (value TRUE)
                    (link temperature))
               (dav (attribute door-is-open)
                    (value TRUE)
                    (link temperature))))      
    CLIPS> 
    

    Next create rules for managing the deducible attribute values. The remove-dav rule will remove any dav fact when there is a known av fact that conflicts with it. The one-remaining-dav rule will convert a dav fact into an av fact when it is the last remaining dav fact for a specific link.

    CLIPS> 
    (defrule remove-dav
       (declare (salience 10))
       ?dav <- (dav (attribute ?a)
                    (value ?v))
       (av (attribute ?a)
           (value ~?v))
       =>
       (retract ?dav))
    CLIPS>    
    (defrule one-remaining-dav
       ?dav <- (dav (attribute ?a)
                    (value ?v)
                    (link ?l))
       (not (and (dav (attribute ?a2)
                      (value ?v2)
                      (link ?l))
                 (test (or (neq ?a ?a2) 
                           (neq ?v ?v2)))))
       =>
       (retract ?dav)
       (assert (av (attribute ?a)
                   (value ?v))))
    CLIPS>
    

    So when the temperature rule initially creates the deductible attribute values:

    CLIPS> (reset)
    CLIPS> (watch rules)
    CLIPS> (watch facts)
    CLIPS> (run)
    FIRE    1 temperature: f-1
    ==> f-2     (av (attribute it-is-cold-outside) (value TRUE))
    ==> f-3     (dav (attribute window-is-open) (value TRUE) (link temperature))
    ==> f-4     (dav (attribute door-is-open) (value TRUE) (link temperature))
    CLIPS> 
    

    The appropriate deductions can be made when new information is later added:

    CLIPS> (assert (av (attribute door-is-open) (value FALSE)))
    ==> f-5     (av (attribute door-is-open) (value FALSE))
    <Fact-5>
    CLIPS> (run)
    FIRE    1 remove-dav: f-4,f-5
    <== f-4     (dav (attribute door-is-open) (value TRUE) (link temperature))
    FIRE    2 one-remaining-dav: f-3,*
    <== f-3     (dav (attribute window-is-open) (value TRUE) (link temperature))
    ==> f-6     (av (attribute window-is-open) (value TRUE))
    CLIPS>