Reputation: 141
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:
I'm receiving the following 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()
Upvotes: 0
Views: 352
Reputation: 15060
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.
Upvotes: 2