Michael Cariaso
2008-01-30
while the pyke documentation is extensive, it seems a bit light on examples. Can anyone show me a PyKE analog for this topic from the CLIPS forum?
http://groups.google.com/group/CLIPSESG/browse_thread/thread/211d246a12fae3cb
Short version: I need a rule that lets me ask if at least X of these Y tests pass. The tests are all simple 'is this fact true'.
Bruce Frederiksen
2008-01-30
Here's a way to do it with backward chaining:
---------- cut here ----------------
# rules.krb
#
# This creates a rule base called 'rules' (filename, minus the .krb suffix).
have_at_least:
# This rule just provides a simplier interface to have_at_least_excluding.
use have_at_least($n)
when
have_at_least_excluding($n, ())
have_at_lease_excluding_0:
# We always have at least 0 students!
use have_at_least_excluding(0, $_)
# Without a 'when' clause, this rule succeeds if the 'use' pattern can
# be matched.
have_at_least_excluding_n:
# To prove whether we have at least $n students, excluding $exclude_list,
use have_at_least_excluding($n, $exclude_list)
when
# Find a student
fact.student($name)
# That is not already in the $exclude_list
check $name not in $exclude_list
# And prove that there are $n - 1 students, excluding this one and
# the ones in $exclude_list. The pattern "($name, *$exclude_list)"
# is a tuple whose first element is $name, with the rest of the
# elements being the $exclude_list tuple.
$n_1 = $n - 1
have_at_least_excluding($n_1, ($name, *$exclude_list))
--------- end cut ---------------
You can run this with:
---------- cut here -------------
# run.py
import pyke
# Add our 'student' facts. We'll put these facts in the 'fact' fact base.
pyke.add_universal_fact('fact', 'student', ('Alice',))
pyke.add_universal_fact('fact', 'student', ('Bob',))
pyke.add_universal_fact('fact', 'student', ('Charles',))
pyke.add_universal_fact('fact', 'student', ('Dave',))
# Load the .krb files. Defaults to looking recursively in the current
# directory. Will place the compiled .py files in a (new) ./compiled_krb
# directory.
pyke.load()
# Activate the 'rules' rule base.
pyke.activate('rules')
def have_at_least(n):
'''
The python function to call the pyke rule.
>>> have_at_least(3)
True
>>> have_at_least(4)
True
>>> have_at_least(5)
False
'''
try:
pyke.prove_1('rules', 'have_at_least', (n,), 0)
return True
except pyke.CanNotProve:
return False
def test():
import doctest
import sys
sys.exit(doctest.testmod()[0])
if __name__ == "__main__":
test()
------------ end cut --------------------
Run:
$ python run.py
to run the doctests. Note that it creates the ./compiled_krb/rules_bc.py the first time it is run, but not the second (unless you change the rules.krb file).
Hope this helps!
Bruce Frederiksen
2008-01-30
Oops! The sourceforge forum destroyed the indenting. Let's try it again. You'll have to delete the first character on each line here...
-------------- cut here ----------------
|# rules.krb
|#
|# This creates a rule base called 'rules' (filename, minus the .krb suffix).
|
|have_at_least:
| # This rule just provides a simplier interface to have_at_least_excluding.
| use have_at_least($n)
| when
| have_at_least_excluding($n, ())
|
|have_at_lease_excluding_0:
| # We always have at least 0 students!
| use have_at_least_excluding(0, $_)
| # Without a 'when' clause, this rule succeeds if the 'use' pattern can
| # be matched.
|
|have_at_least_excluding_n:
| # To prove whether we have at least $n students, excluding $exclude_list,
| use have_at_least_excluding($n, $exclude_list)
| when
| # Find a student
| fact.student($name)
| # That is not already in the $exclude_list
| check $name not in $exclude_list
| # And prove that there are $n - 1 students, excluding this one and
| # the ones in $exclude_list. The pattern "($name, *$exclude_list)"
| # is a tuple whose first element is $name, with the rest of the
| # elements being the $exclude_list tuple.
| $n_1 = $n - 1
| have_at_least_excluding($n_1, ($name, *$exclude_list))
--------------- second cut -------------------
|# run.py
|
|import pyke
|
|# Add our 'student' facts. We'll put these facts in the 'fact' fact base.
|pyke.add_universal_fact('fact', 'student', ('Alice',))
|pyke.add_universal_fact('fact', 'student', ('Bob',))
|pyke.add_universal_fact('fact', 'student', ('Charles',))
|pyke.add_universal_fact('fact', 'student', ('Dave',))
|
|# Load the .krb files. Defaults to looking recursively in the current
|# directory. Will place the compiled .py files in a (new) ./compiled_krb
|# directory.
|pyke.load()
|
|# Activate the 'rules' rule base.
|pyke.activate('rules')
|
|def have_at_least(n):
| '''
| The python function to call the pyke rule.
|
| >>> have_at_least(3)
| True
| >>> have_at_least(4)
| True
| >>> have_at_least(5)
| False
| '''
| try:
| pyke.prove_1('rules', 'have_at_least', (n,), 0)
| return True
| except pyke.CanNotProve:
| return False
|
|def test():
| import doctest
| import sys
| sys.exit(doctest.testmod()[0])
|
|if __name__ == "__main__":
| test()
Bruce Frederiksen
2008-01-30
Nope that didn't work either...
Third time's a charm (I hope)! You'll have to pipe this through "sed 's/^/ /g'"...
-------- cut here --------------
# rules.krb
#
# This creates a rule base called 'rules' (filename, minus the .krb suffix).
have_at_least:
^^^^# This rule just provides a simplier interface to have_at_least_excluding.
^^^^use have_at_least($n)
^^^^when
^^^^^^^^have_at_least_excluding($n, ())
have_at_lease_excluding_0:
^^^^# We always have at least 0 students!
^^^^use have_at_least_excluding(0, $_)
^^^^# Without a 'when' clause, this rule succeeds if the 'use' pattern can
^^^^# be matched.
have_at_least_excluding_n:
^^^^# To prove whether we have at least $n students, excluding $exclude_list,
^^^^use have_at_least_excluding($n, $exclude_list)
^^^^when
^^^^^^^^# Find a student
^^^^^^^^fact.student($name)
^^^^^^^^# That is not already in the $exclude_list
^^^^^^^^check $name not in $exclude_list
^^^^^^^^# And prove that there are $n - 1 students, excluding this one and
^^^^^^^^# the ones in $exclude_list. The pattern "($name, *$exclude_list)"
^^^^^^^^# is a tuple whose first element is $name, with the rest of the
^^^^^^^^# elements being the $exclude_list tuple.
^^^^^^^^$n_1 = $n - 1
^^^^^^^^have_at_least_excluding($n_1, ($name, *$exclude_list))
------------------ second cut ---------------------
# run.py
import pyke
# Add our 'student' facts. We'll put these facts in the 'fact' fact base.
pyke.add_universal_fact('fact', 'student', ('Alice',))
pyke.add_universal_fact('fact', 'student', ('Bob',))
pyke.add_universal_fact('fact', 'student', ('Charles',))
pyke.add_universal_fact('fact', 'student', ('Dave',))
# Load the .krb files. Defaults to looking recursively in the current
# directory. Will place the compiled .py files in a (new) ./compiled_krb
# directory.
pyke.load()
# Activate the 'rules' rule base.
pyke.activate('rules')
def have_at_least(n):
^^^^'''
^^^^^^^^The python function to call the pyke rule.
^^^^^^^^>>> have_at_least(3)
^^^^^^^^True
^^^^^^^^>>> have_at_least(4)
^^^^^^^^True
^^^^^^^^>>> have_at_least(5)
^^^^^^^^False
^^^^'''
^^^^try:
^^^^^^^^pyke.prove_1('rules', 'have_at_least', (n,), 0)
^^^^^^^^return True
^^^^except pyke.CanNotProve:
^^^^^^^^return False
def test():
^^^^import doctest
^^^^import sys
^^^^sys.exit(doctest.testmod()[0])
if __name__ == "__main__":
^^^^test()
Michael Cariaso
2008-02-16
Thanks Bruce,
The example needed a few tweaks to work for me. I've posted the updated version at
http://www.runblast.com/wiki/index.php?title=Pyke_example
mike