0

I altered some CLIPS/CLIPSpy code to look for when the Variable column in a CSV is the word Oil Temp and when the duration of that column is above 600 or above. The rule should fire twice according to the CSV I'm using:
Sample Data

I'm receiving the following error.
Error

Here is my code currently. I think it's failing on the variable check or the logical and check.

import sys
from tempfile import mkstemp
import os
import clips


CLIPS_CONSTRUCTS = """
(defglobal ?*oil-too-hot-times* = 0)

(deftemplate oil-is-too-hot-too-long
  (slot Variable (type STRING))  
  (slot Duration (type INTEGER)))

(defrule check-for-hot-oil-too-long-warning
  (oil-is-too-hot-too-long (Variable ?variable) (Duration ?duration))
  (test (?variable Oil Temp))
  (and (>= ?duration 600))
  =>
  (printout t "Warning! Check engine light on!" tab ?*oil-too-hot-times* crlf)) 

"""


def main():
    environment = clips.Environment()

    # use environment.load() to load constructs from a file
    constructs_file, constructs_file_name = mkstemp()
    file = open(constructs_file, 'wb')
    file.write(CLIPS_CONSTRUCTS.encode())
    file.close()

    environment.load(constructs_file_name)
    os.remove(constructs_file_name)

    # enable fact duplication as data has duplicates
    environment.eval("(set-fact-duplication TRUE)")


    # Template facts can be built from their deftemplate
    oil_too_hot_too_long_template = environment.find_template("oil-is-too-hot-too-long")

    for variable, duration in get_data_frames(sys.argv[1]):
        new_fact = oil_too_hot_too_long_template.new_fact()

        # Template facts are represented as dictionaries
        new_fact["Variable"] = variable
        new_fact["Duration"] = int(duration)

        # Add the fact into the environment Knowledge Base
        new_fact.assertit()

    # Fire all the rules which got activated
    environment.run()

def get_data_frames(file_path):
    """Parse a CSV file returning the dataframes."""
    with open(file_path) as data_file:
        return [l.strip().split(",") for i, l in enumerate(data_file) if i > 1]


if __name__ == "__main__":
    main()
noxdafox
  • 14,439
  • 4
  • 33
  • 45
Jay Py
  • 141
  • 9

1 Answers1

2

CLIPS adopts Polish/Prefix notation. Therefore, your rule should be written as follows.

(defrule check-for-hot-oil-too-long-warning
  (oil-is-too-hot-too-long (Variable ?variable) (Duration ?duration))
  (test (and (eq ?variable "Oil Temp") 
             (>= ?duration 600)))
  =>
  (printout t "Warning! Check engine light on!" tab ?*oil-too-hot-times* crlf)) 

Also notice how the type STRING requires double quotes ".

Yet I'd suggest you to leverage the alpha network matching of the engine which is more concise and efficient.

(defrule check-for-hot-oil-too-long-warning
  (oil-is-too-hot-too-long (Variable "Oil Temp") (Duration ?duration))
  (test (>= ?duration 600))
  =>
  (printout t "Warning! Check engine light on!" tab ?*oil-too-hot-times* crlf)) 

The engine can immediately see that your Variable slot is a constant and can optimize the matching logic accordingly. I am not sure it can make the same assumption within the joint test.

noxdafox
  • 14,439
  • 4
  • 33
  • 45
  • 1
    It is more efficient to use constant constraints in a pattern than it is to use a predicate constraint or a test conditional element. If you have a large number of constants, it is significantly faster. http://rileyonlife.blogspot.com/2014/01/pattern-matching-constants-in-clips.html – Gary Riley Jan 17 '19 at 16:53
  • I was expecting so as it is harder to infer that the content of a test is actually the equivalent of a constant constraint which would easily fit the alpha network. What about predicate constraints against static values (example with `Duration` slot)? Would CLIPS be able to optimize them as well? – noxdafox Jan 17 '19 at 19:16
  • It's possible, but the question is whether to do that or spend time working on some other improvement. – Gary Riley Jan 17 '19 at 20:24
  • I know it's doable as other expert systems already provide similar optimizations. I was wondering whether CLIPS was including such feature or not. I do agree though there are better areas to focus. – noxdafox Jan 17 '19 at 20:28
  • @noxdafox I incorporated the rules as instructed to meet the logical and condition however the rule is only firing once. See image here: https://imgur.com/a/2NTPmIH – Jay Py Jan 17 '19 at 21:19
  • Depending on the input you give this might be correct. I would suggest to open a new question formulating what is you are trying to do, what is the data you are using as input, what happens and what you expect to happen. Keep in mind that in CLIPS a fact activates a rule once. If the rule fires, that specific fact won't activate the rule anymore. It is, in fact, a common practice to retract facts in the RHS of the rule to retain memory. – noxdafox Jan 18 '19 at 13:37
  • @noxdafox I run this example, but have nothing on my screen. Should I expect "Warning! Check engine light on!"? I use Win/Python3.7/clipspy0.3.3. Thnx – Sergey Sep 24 '20 at 10:04
  • Please do not re-use other questions for unrelated issues. Open a new SO question according to the guidelines: https://stackoverflow.com/help/how-to-ask – noxdafox Sep 24 '20 at 10:14
  • Is this comment-level "yes/no" question worth to open a full-fledged question? – Sergey Sep 24 '20 at 10:26
  • The answer is yes – noxdafox Sep 24 '20 at 10:57
  • Ok. Thnx. I'll check problems again – Sergey Sep 24 '20 at 11:27
  • There is a solution for hidden log here https://github.com/noxdafox/clipspy/issues/27 – Sergey Sep 24 '20 at 17:31