[2922d1]: pyke / fc_rule.py Maximize Restore History

Download this file

fc_rule.py    111 lines (90 with data), 4.4 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
# $Id$
# coding=utf-8
#
# Copyright Š 2007-2008 Bruce Frederiksen
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
'''
Forward chaining rules (fc_rule) are one of two types of rules in a
rule_base (the other being backward chaining rules -- bc_rule).
All forward chaining is done automatically as each rule_base is
activated. This is done in two steps:
1. All fc_rules are registered with the fact_lists referenced in
their 'foreach' clause by calling fc_rule.register_rule() on
each fc_rule (including the parent rule_base's fc_rules).
This will cause the fact_list to invoke fc_rule.new_fact each time
a new fact for that fact_list (by that name) is asserted (by the
same or another fc_rule).
2. The fc_rule.run() function is called on each fc_rule (including
the parent rule_base's fc_rules).
The forward chaining rule is compiled into a python function which does
the actual inferencing work for both the 'run' case and the 'new_fact'
case, depending on the arguments passed to it. Each fc_rule object
remembers its associated compiled python function.
The fc_rule object tracks the progress of the forward chaining for that
rule. If the rule has not been run yet, it ignores new_facts since it
will see the new fact when it is later run.
'''
from pyke import contexts, fact_base
import itertools
class rule(object):
''' Common to both fc_rules and bc_rules. '''
def __init__(self, name, rule_base, patterns):
self.name = name
self.rule_base = rule_base
self.patterns = patterns
def __repr__(self):
return "<%s %s>" % (self.__class__.__name__, self.name)
def pattern(self, pattern_index):
return self.patterns[pattern_index]
class fc_rule(rule):
def __init__(self, name, rule_base, rule_fn, foreach_facts, patterns):
super(fc_rule, self).__init__(name, rule_base, patterns)
rule_base.add_fc_rule(self)
self.rule_fn = rule_fn
self.foreach_facts = foreach_facts # (kb_name, fact_name, arg_pats,
# multi_match?)...
self.ran = False
def register_rule(self):
for i, (kb_name, fact_name, arg_patterns, multi_match) \
in enumerate(self.foreach_facts):
self.rule_base.engine.get_kb(kb_name, fact_base.fact_base) \
.add_fc_rule_ref(fact_name, self, i)
def reset(self):
self.ran = False
def run(self):
self.ran = True
self.rule_fn(self)
def new_fact(self, fact_args, n):
if self.ran:
arg_patterns = self.foreach_facts[n][2]
if len(fact_args) == len(arg_patterns):
context = contexts.simple_context()
if all(itertools.imap(lambda pat, arg:
pat.match_data(context, context, arg),
arg_patterns,
fact_args)):
self.rule_base.num_fc_rules_rerun += 1
if self.foreach_facts[n][3]:
self.rule_fn(self)
else:
self.rule_fn(self, context, n)
context.done()
def foreach_patterns(self, foreach_index):
return self.foreach_facts[foreach_index][2]