""" Very very simple Expert system in python. @version v0.1 @course CIS370 @due Nov 21, 2005 @professor: Theodore L. Nicholson http://web.njit.edu/~theo/ @author Scott Hurring (scott at hurring dot com) http://hurring.com/code/python/expert/ @license GPL """ class Expert: """ The expert engine @example: def is_final(facts): return True e = Expert() e.rules_init(rulemodule) if e.get_answer(is_final): print "An answer was found!" """ def __init__(self): # Unfired rules self.rules = [] # Fired rules self.fired = [] # Log what happens in the system self.logger = Logger() # Initial facts self.facts = Facts(self.logger) def rules_init(self, rulemodule): # Instantiate classes rulemodule that start with "Rule_" for x in dir(rulemodule): if not x.startswith("Rule_"): continue # Instantiate class 'x' in rulemodule rule = vars(rulemodule)[x]() self.rule_add(rule) def rule_add(self, rule): self.rules.append(rule) def rule_del(self, rule): self.rules.remove(rule) def rule_match(self, rule): return rule.match(self.facts) def rule_fire(self, rule): self.logger.log_rule(rule) rule.fire(self.facts) self.rule_del(rule) self.fired.append(rule) def get_answer(self, is_final): """Go through the rules, if a match occurs, test the state of the system against is_final() to determine if we're in a final state (i.e. have found an answer)""" self.logger.clear() for i in range(len(self.rules)+1): self.rules_match() if is_final(self.facts): return True return False def rules_match(self): """Go through the rules, looking for a match""" for rule in self.rules: if self.rule_match(rule): self.rule_fire(rule) return True # No rules were matched return False class Rule(object): """The base rule""" def __init__(self): self.name = self.__class__ #print "Rule %s: %s" % (self.name, self.__doc__) def __str__(self): """Nicely stringify this rule""" return ("Rule %s: '%s'" % (self.name, self.__doc__)) def match(self, props): pass def fire(self, props): pass class Facts(object): """Facts container""" def __init__(self, logger): self.logger = logger self.facts = {} def show(self, prefix="fact> "): """Nicely stringify the facts in this container""" for (x,y) in self.facts.items(): print "%s%-20s %-20s" % (prefix, x, y) def all(self): """Return all facts""" return self.facts def newfact(self): """Return a new fact with value None""" return {'value':None} def set(self, name, value): """Set fact 'name' to 'value', will auto-create new facts""" fact = self.facts.get(name, self.newfact()) self.logger.log_fact(name, fact['value'], value) fact['value'] = value self.facts[name] = fact def get(self, name, key='value'): """Fetch a fact key (typically the fact's value)""" fact = self.facts.get(name, self.newfact()) #print "fact=",fact return fact[key] class Logger(object): """System log, track fact changes and rule firings""" log = [] def __init__(self): self.clear() def show(self, prefix="log> "): """Nicely stringify the log""" for l in self.log: print "%s%s" % (prefix, l) def clear(self): self.log = [] def log_rule(self, rule): text = "Rule fired: %s (%s)" % (rule.name, rule.__doc__) self.log.append(text) def log_fact(self, name, value1, value2): text = "Fact '%s' changed: '%s'=>'%s'" % (name, value1, value2) self.log.append(text)