.. $Id: creating_engine.txt efc7674a8d3a 2010-03-29 mtnyogi $
.. 
.. Copyright © 2010 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.

restindex
    crumb: Creating an Engine
    page-description:
        How to create a Pyke *inference engine* object.
    /description
    format: rest
    encoding: utf8
    output-encoding: utf8
    include: yes
    initialheaderlevel: 2
/restindex

uservalues
    filedate: $Id: creating_engine.txt efc7674a8d3a 2010-03-29 mtnyogi $
/uservalues

===================================
Creating an Inference Engine Object
===================================

The ``engine`` object is your gateway into Pyke.  Each engine object manages
multiple `knowledge bases`_ related to accomplishing some task.

You may create multiple Pyke engines, each with it's own knowledge bases to
accomplish different disconnected tasks.

When you create a Pyke engine object, Pyke scans for Pyke `.kfb`_, `.krb`_
and `.kqb`_ source files and compiles these into .fbc pickle files,
Python .py source files and .qbc pickle files, respectively.

Each time a Pyke engine object is created it checks the file modification
times of the Pyke source files to see whether they need to be recompiled.
If you change a Pyke source file, you may create a new Pyke engine to compile
the changes and run with the new knowledge bases without having to restart
your application.

Pyke also lets you zip these compiled files into Python eggs and can load the
files from the egg.  By including the compiled files in your application's
distribution, you don't need to include your Pyke source files if you don't
want to.

Once you have an ``engine`` object; generally, all of the Pyke functions that
you need are provided directly by this object:

.. this code is hidden and will set __file__ to the doc/examples directory.
   >>> import os
   >>> __file__ = \
   ...   os.path.join(os.path.dirname(os.path.dirname(os.getcwd())),
   ...                'examples')

knowledge_engine.engine(\*paths, \*\*kws)

    Pyke recursively searches for Pyke source files (`.kfb files`_,
    `.krb files`_, and `.kqb files`_) starting at each source directory
    indicated in *paths* and places all of the compiled files in the
    associated *target packages*.  This causes all of the `knowledge bases`_
    to be loaded and made ready to activate_.

    Pyke source files may be spread out over multiple directories and may be
    compiled into one or more target packages.  Multiple target packages
    would be used when more than one application wants to share a set of
    `knowledge bases`_, perhaps adding some of its own knowledge that it
    compiles into its own target package.

    Each ``path`` argument specifies a Pyke source directory and an optional
    target package.  The source directories do not have to be Python package
    directories, but the target packages do.

    The target package defaults to ``.compiled_krb``.  The leading dot (.)
    indicates that the compiled_krb directory will be subordinate to the
    lowest Python package directory on the path to the Pyke source directory.
    This uses Python's `relative import`_ notation, so multiple dots go up to
    higher directories (one per dot).  If the target package does not start
    with a dot, it is taken to be an absolute package path and will be located
    using Python's sys.path like a normal Python ``import``.

    The Pyke source directory may be specified as a path (a string) or by
    passing a Python module.  If a module is passed, its __file__ attribute
    is used.  If the path points to a file, rather than a directory, the final
    filename is discarded.  In the simple case, when the Pyke source files are
    in the same directory as the module creating the ``engine`` object, you
    can just pass ``__file__`` as the sole argument.

    >>> from pyke import knowledge_engine
    >>> my_engine = knowledge_engine.engine(__file__)

    Passing a package instead, this example could also be written:

    >>> import doc.examples
    >>> my_engine = knowledge_engine.engine(doc.examples)

    or, you can pass a module within the desired package:

    >>> from doc.examples import some_module
    >>> my_engine = knowledge_engine.engine(some_module)

    In the all three cases, the final filename is stripped from the value of
    the module's __file__ attribute to get the directory that the package
    is in.  This directory will then be recursively searched for Pyke source
    files.

    If you change some of your Pyke source files, you can create a new engine
    object to compile and reload the generated Python modules without
    restarting your program.  But note that you'll need to rerun the
    ``add_universal_fact`` calls that you made (a reason to use `.kfb files`_
    instead).

    All of the compiled Python .py source files and .fbc/.qbc pickle files
    generated from each source directory are placed, by default, in a
    ``compiled_krb`` target package.  You may specify a different target
    package for any source directory by passing that source directory
    along with the target package name as a 2-tuple.  Thus, specifying the
    default target package explicitly would look like:

    >>> my_engine = knowledge_engine.engine((__file__, '.compiled_krb'))

    You may specify the same target package for multiple source directories.

    The last component of the target package will be created automatically
    if it does not already exist.

    .. note::
       You will probably want to add ``compiled_krb`` (or whatever you've
       chosen to call it) to your source code repository's list of files to
       ignore.

    If you want to distribute your application *without* the knowledge bases,
    you can use the 2-tuple notation with ``None`` as the source directory.
    In this case, all of the Pyke source files must already be compiled,
    and Pyke will simply load these files.  Also, the target package must be
    specified in absolute form (with no leading dots).

    Finally, there are four optional keyword arguments that you may also pass
    to the ``engine`` constructor.  These are all booleans that default to
    ``True``:

    - ``load_fb`` -- load fact bases
    - ``load_fc`` -- load forward-chaining rules
    - ``load_bc`` -- load backward-chaining rules and
    - ``load_qb`` -- load question bases

    These parameters must be passed as keyword parameters and let you
    selectively load the various kinds of compiled files.

