We were intrigued to learn of Pyke. The artificial intelligence angle got our interest. From the documentation on the website, Pyke is an inference engine completely written in Python. Simplistically, an inference engine is what an expert system uses to make decisions.

Let’s remind ourselves what exactly an inference engine is:

In computer science, and specifically the branches of knowledge engineering and artificial intelligence, an inference engine is a computer program that tries to derive answers from a knowledge base. It is the “brain” that expert systems use to reason about the information in the knowledge base for the ultimate purpose of formulating new conclusions. Inference engines are considered to be a special case of reasoning engines, which can use more general methods of reasoning.

Pyke is a knowledge-based inference engine (expert system) written in 100% python that can:

  • Do both forward-chaining (data driven) and backward-chaining (goal directed) inferencing.
    • Pyke may be embedded into any python program.
  • Automatically generate python programs by assembling individual python functions into complete call graphs.
    • This is done through a unique design where the individual python functions are attached to backward-chaining rules.
    • Unlike other approaches to code reuse (e.g. Zope adapters and generic functions), this allows the inference engine to ensure that all of the function’s requirements are completely satisfied, by examining the entire call graph down to the leaves, before any of the functions are executed.
    • This is an optional feature. You don’t need to use it if you just want the inferencing capability by itself.


The knowledge engine supports:

  • Multiple fact bases, each with its own list of facts.
  • Both forward-chaining rules and backward-chaining rules.
  • Multiple rule bases, each with its own list of forward-chaining and/or backward-chaining rules.
  • Rule base inheritance — activating the derived rule base includes the rules from the parent rule base.
  • The inference rules are compiled into python functions, allowing python code snippets to be used within the rules. This greatly enhances the expressiveness of the rules.


Automatic program generation:

  • Calls the generated python programs plans.
  • Plans may be run multiple times without needing to rerun the inference rules.
  • Plans may be pickled and cached to disk to be used by other programs or in later runs of the same program.
  • No pyke modules are required to run the plans.


Potential pyke applications:

  • Complicated decision making applications.
  • The back-end (code generation and optimization) of compilers. Pyke is used as the back-end of its own compiler that translates rules into python code.
  • Automatic SQL statement generation.
  • Automatic HTML generation and automatic HTML template processing.
  • Automatic program builder to reuse a common set of functions for many different specific situations. This could also easily incorporate a new custom function into a much larger program, where the use of the custom function might influence the choice of other standard functions in other parts of the program.
  • The control module for a web framework tool.
  • A high-level planner to automatically distribute the modules of a large system over several computers in a distributed system to meet specific performance and capacity goals. This could be used to automatically scale the same system code from a small one program, one computer system to much larger distributed systems to meet a wide range of performance goals.
  • Diagnosis systems, including automated customer service systems.
  • Program or library customization for specific uses.
  • In addition to being able to build programs, pyke can instantiate, configure and interconnect a network of objects to meet a specific need or situation.





Pyke is an inference engine that applies rules to facts to establish additional facts (through forward-chaining rules), and/or to prove goals and optionally assemble python functions into customized call graphs, called plans (through backward-chaining rules).

Pyke may then be reset, deleting the last set of facts, so that the cycle may be repeated. For each cycle a different rule base may be activated.

The plan capability allows the postponement of code execution until the top-level goal has been completely proven. This shields the code from blind alleys and backtracking within the rules.

Once a plan has been created, it may be executed multiple times with different arguments. It may also be pickled, and later run again without requiring any pyke modules.




Knowledge Bases

Knowledge is made up of both facts and rules. These are organized into named repositories called knowledge bases. A knowledge base is like a directory for files on disk, except that knowledge bases may not be nested. Therefore, facts and goals always have a two-level name.

Here are some examples of facts you might see in a web server application:

request.path_segment(0, my)
request.path_segment(1, 'site.html')
request.path_segment(-2, my)
request.path_segment(-1, 'site.html')

Note that three different knowledge bases (all fact bases) are shown here named header, cookie, and request; each with multiple facts.

There are different types of knowledge bases.

  • Those that contain facts are called fact bases.
  • Those that contain rules are called rule bases.
  • It is also possible to create other kinds of knowledge bases that lookup facts and prove goals in different ways. The only one of these in pyke is the special knowledge base.

All knowledge bases share the same name space; so that no two of them, regardless of their type, may have the same name.




Premises and Conclusions

Rules have two parts to them: an if part (the premises), and a then part (the conclusions). (Though pyke uses different names for these). Each of these if and then parts contain one or more facts or goals represented by patterns.

Logically, the rule says that if all of the premises in the if part of the rule are true, then each of the conclusions in the then part of the rule must also be true.



Rules are specified individually within a rule base. They are not nested or explicitly linked to each other. So pyke must automatically figure out how to combine these rules to accomplish some larger task. This is called inferencing and there are two different approaches that pyke uses, depending on the rule’s type.


Plans and Automatic Program Generation

Once you understand how backward-chaining works, it is relatively easy to do automatic program generation.


Adding Plans to Backward-Chaining Rules

The way this is done is by attaching python functions to the backward-chaining rules. These functions are written at the end of each rule in the .krb file. They don’t affect how the rules run, but are gathered up to form a call graph that is returned along with the pattern variable bindings that prove the top-level goal.



Consider a small rule base to construct programs to transfer money between bank accounts. Each from_acct and to_acct takes one of two forms:

  1. (name, account_type)
    • This is a local account with this bank.
    • Example: (‘bruce’, ‘checking’).
  2. (bank, name, account_type)
    • This is a foreign account with another bank.
    • Example: (‘my_other_bank’, ‘bruce’, ‘checking’).

At least one of the bank accounts must be a local account.

Here’s the example rule base:

 1  transfer1:
 2      use transfer($from_acct, $to_acct) taking (amount)
 3      when
 4          withdraw($from_acct)
 5              $$(amount)
 6          deposit($to_acct)
 7              $$(amount)

 8  transfer2:
 9      use transfer($from_acct, $to_acct) taking (amount)
10      when
11          transfer_ach($from_acct, $to_acct)
12              $$(amount)

13  withdraw:
14      use withdraw(($who, $acct_type)) taking (amount)
15      with
16          print "withdraw", amount, "from", $who, $acct_type

17  deposit:
18      use deposit(($who, $acct_type)) taking (amount)
19      with
20          print "deposit", amount, "to", $who, $acct_type

21  transfer_ach1:
22      use transfer_ach($from_acct, ($bank, $who, $acct_type)) taking (amount)
23      when
24          withdraw($from_acct)
25              $$(amount)
26          deposit((central_accts, ach_send_acct))
27              $$(amount)
28      with
29          print "send", amount, "to bank", $bank, "acct", $who, $acct_type

30  transfer_ach2:
31      use transfer_ach($from_acct, $to_acct) taking (amount)
32      when
33          get_ach($from_acct)
34              $$(amount)
35          withdraw((central_accts, ach_recv_acct))
36              $$(amount)
37          deposit($to_acct)
38              $$(amount)

39  get_ach:
40      use get_ach(($bank, $who, $acct_type)) taking (amount)
41      with
42          print "get", amount, "from bank", $bank, "acct", $who, $acct_type


Running the Example

The plan is created as a byproduct of proving the goal:

>>> import pyke
>>> pyke.load('examples')
>>> pyke.activate('plan_example')
>>> no_vars, plan1 = pyke.prove_1('plan_example', 'transfer',
...                               (('bruce', 'checking'),
...                                ('bruce', 'savings')),
...                               0)

plan1 is now a program to transfer X amount from ‘bruce’, ‘checking’ to ‘bruce’, ‘savings’.

>>> plan1(100)
withdraw 100 from bruce checking
deposit 100 to bruce savings

The program may be used multiple times:

>>> plan1(50)
withdraw 50 from bruce checking
deposit 50 to bruce savings

Notice the strings: bruce, checking and savings in the output. These were specified as pattern variables in the code and are cooked into the plan along with the function call graph.

Let’s create another program:

>>> no_vars, plan2 = pyke.prove_1('plan_example', 'transfer',
...                               (('my_other_bank', 'bruce', 'checking'),
...                                ('bruce', 'savings')),
...                               0)

plan2 is now a program to transfer X amount from ‘my_other_bank’, ‘bruce’, ‘checking’ to ‘bruce’, ‘savings’.

>>> plan2(150)
get 150 from bank my_other_bank acct bruce checking
withdraw 150 from central_accts ach_recv_acct
deposit 150 to bruce savings

And the final use case:

>>> no_vars, plan3 = pyke.prove_1('plan_example', 'transfer',
...                               (('bruce', 'checking'),
...                                ('my_other_bank', 'bruce', 'savings')),
...                               0)
>>> plan3(200)
withdraw 200 from bruce checking
deposit 200 to central_accts ach_send_acct
send 200 to bank my_other_bank acct bruce savings



So you can see that it quite easy to use pyke to automatically combine python functions into programs!

It also allows data within each python function to be specified using a pattern variable so that pyke can customize these values to match the specific situation.

Most text taken from the Pyke homepage.


0 Responses to “Pyke”

  1. Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: