Marcus von Appen avatar Marcus von Appen committed 8fcc102

Python:
- removed _dynrules C module from the python package
- reorganised python package the code base does not need to be scattered
over multiple files
- renamed RuleManagement and MMapRuleManager to RuleManager and
MMapRuleManager
- updated test framework to be in sync with the python-utils codebase

C++:
- renamed RuleManagement and MMapRuleManager to RuleManager and
MMapRuleManager

Comments (0)

Files changed (58)

-The complete dynrules code is distributed under the Public Domain. Feel
-free to do with it, whatever you want, but be aware, that you are doing
-that on your own risk.
-
-In cases, where the law prohibits the recognition of Public Domain software,
-this software can be licensed under the zlib lincese as stated below:
-
-Copyright (C) 2008-2012 Marcus von Appen <marcus@sysfault.org>
-
-This software is provided 'as-is', without any express or implied
-warranty. In no event will the authors be held liable for any damages
-arising from the use of this software.
-
-Permission is granted to anyone to use this software for any purpose,
-including commercial applications, and to alter it and redistribute it
-freely, subject to the following restrictions:
-
-1. The origin of this software must not be misrepresented; you must not
-   claim that you wrote the original software. If you use this software
-   in a product, an acknowledgment in the product documentation would be
-   appreciated but is not required.
-2. Altered source versions must be plainly marked as such, and must not be
-   misrepresented as being the original software.
-3. This notice may not be removed or altered from any source distribution.
+see doc/copying.rst
 recursive-include cplusplus *
 recursive-include doc *
-recursive-include test *.py
-include src/*.h src/*.c
 include NEWS AUTHORS COPYING TODO Makefile
+PYTHON ?= python
 top_srcdir = `pwd`
-PYTHON ?= python
+PYTHONPATH ?= $(top_srcdir)
 SUBDIRS = \
-	$(top_srcdir)/src \
 	$(top_srcdir)/dynrules \
 	$(top_srcdir)/dynrules/test \
 	$(top_srcdir)/dynrules/test/util \
 	$(top_srcdir)/examples \
 	$(top_srcdir)/cplusplus
 
+INTERPRETERS = python2.7 python3.2 python3.3 pypy2.0
+
 all: clean build
 
 docs:
 	@$(PYTHON) setup.py sdist --format=zip
 	@$(PYTHON) setup.py sdist --format=gztar
 
-bdist:
+bdist: clean docs
 	@echo "Creating bdist..."
 	@$(PYTHON) setup.py bdist
 
 release: clean dist
 
 buildall: clean
-	@python2.6 setup.py build
-	@python2.7 setup.py build
-	@python3.1 setup.py build
-	@python3.2 setup.py build
-	@python3.3 setup.py build
-	@pypy1.9 setup.py build
+	@for interp in $(INTERPRETERS); do \
+		$$interp setup.py build; \
+	done
 
 installall:
-	@python2.6 setup.py build install
-	@make clean
-	@python2.7 setup.py build install
-	@make clean
-	@python3.1 setup.py build install
-	@make clean
-	@python3.2 setup.py build install
-	@make clean
-	@python3.3 setup.py build install
-	@make clean
-	@pypy1.9 setup.py build install
-	@make clean
+	@for interp in $(INTERPRETERS); do \
+		$$interp setup.py install; \
+	done
 
 testall:
-	@-PYTHONPATH=$(PYTHONPATH) python2.6 -B -m dynrules.test.util.runtests
-	@-PYTHONPATH=$(PYTHONPATH) python2.7 -B -m dynrules.test.util.runtests
-	@-PYTHONPATH=$(PYTHONPATH) python3.1 -B -m dynrules.test.util.runtests
-	@-PYTHONPATH=$(PYTHONPATH) python3.2 -B -m dynrules.test.util.runtests
-	@-PYTHONPATH=$(PYTHONPATH) python3.3 -B -m dynrules.test.util.runtests
-	@-PYTHONPATH=$(PYTHONPATH) pypy1.9 -B -m dynrules.test.util.runtests
+	@for interp in $(INTERPRETERS); do \
+		PYTHONPATH=$(PYTHONPATH) $$interp -B -m dynrules.test.util.runtests || true; \
+	done
 
 testpackage:
-	@python2.6 -c "import dynrules.test; dynrules.test.run()"
-	@python2.7 -c "import dynrules.test; dynrules.test.run()"
-	@python3.1 -c "import dynrules.test; dynrules.test.run()"
-	@python3.2 -c "import dynrules.test; dynrules.test.run()"
-	@python3.3 -c "import dynrules.test; dynrules.test.run()"
-	@pypy1.9 -c "import dynrules.test; dynrules.test.run()"
+	@for interp in $(INTERPRETERS); do \
+		$$interp -c "import dynrules.test; dynrules.test.run()" || true \
+	done
 
 purge_installs:
-	rm -rf /usr/local/include/python2.6/dynrules*
-	rm -rf /usr/local/include/python2.7/dynrules*
-	rm -rf /usr/local/include/python3.1/dynrules*
-	rm -rf /usr/local/include/python3.2/dynrules*
-	rm -rf /usr/local/lib/python2.6/site-packages/dynrules*
-	rm -rf /usr/local/lib/python2.7/site-packages/dynrules*
-	rm -rf /usr/local/lib/python3.1/site-packages/dynrules*
-	rm -rf /usr/local/lib/python3.2/site-packages/dynrules*
-	rm -rf /usr/local/lib/python3.3/site-packages/dynrules*
-	rm -rf /usr/local/lib/pypy-1.9/site-packages/dynrules*
-
+	@for interp in $(INTERPRETERS); do \
+		rm -rf /usr/local/lib/$$interp/site-packages/dynrules*; \
+	done
+About dynrules
+==============
+dynrules is a dynamic ruleset scripting package for Python. It uses the
+Dynamic Scripting technique to create adaptive AI scripts automatically
+from predefined rulesets.
+
+Installation
+============
+dynrules is easy to install and integrate within your own projects. Just
+follow Python's standard procedure of installing packages or look for a
+prebuilt package for your operating system or distribution.
+
+Documentation
+=============
+You can find the documentation at *doc/html* or online at
+http://dynrules.readthedocs.org.
+
+License
+=======
+This library is given to the public domain. There are no licensing
+restrictions. Please see *doc/copying.rst* for further details.

cplusplus/Makefile

 HEADERS = \
 	src/dynrules.h \
 	src/LearnSystem.h \
-	src/MMapRuleManagement.h \
+	src/MMapRuleManager.h \
 	src/Rule.h \
-	src/RuleManagement.h \
+	src/RuleManager.h \
 	src/RuleSet.h
 
-SOURCES = Rule.cpp  RuleSet.cpp  LearnSystem.cpp  RuleManagement.cpp \
-	MMapRuleManagement.cpp
+SOURCES = Rule.cpp  RuleSet.cpp  LearnSystem.cpp  RuleManager.cpp \
+	MMapRuleManager.cpp
 
 OBJECTS = $(SOURCES:%.cpp=%.o)
 TARGET = libdynrules.a

cplusplus/src/MMapRuleManagement.cpp

-/*
- * dynrules - Python dynamic rules engine
- *
- * Authors: Marcus von Appen
- *
- * This file is distributed under the Public Domain.
- */
-
-#include "MMapRuleManagement.h"
-
-namespace dynrules
-{
-MMapRuleManagement::MMapRuleManagement (unsigned int maxrules) :
-    RuleManagement (maxrules),
-    _rules(0)
-{
-    unsigned int i;
-    for (i = 0; i < maxrules; i++)
-        this->_rules.push_back (new Rule (i));
-}
-
-MMapRuleManagement::~MMapRuleManagement ()
-{
-    std::vector<Rule*>::iterator iter;
-    for (iter = this->_rules.begin (); iter != this->_rules.end (); iter++)
-    {
-        delete *iter;
-    }
-    this->_rules.clear ();
-}
-
-std::vector<Rule*> MMapRuleManagement::loadRules ()
-{
-    return this->_rules;
-}
-
-std::vector<Rule*> MMapRuleManagement::loadRules (unsigned int maxrules)
-{
-    return this->_rules;
-}
-
-bool MMapRuleManagement::saveRules (std::vector<Rule*> rules)
-{
-    return true;
-}
-
-} // namespace

cplusplus/src/MMapRuleManagement.h

-/*
- * dynrules - Python dynamic rules engine
- *
- * Authors: Marcus von Appen
- *
- * This file is distributed under the Public Domain.
- */
-
-#ifndef _MMAPRULEMANAGEMENT_H_
-#define _MMAPRULEMANAGEMENT_H_
-
-#include "RuleManagement.h"
-
-namespace dynrules
-{
-    /**
-     * \brief A simple memory-mapped RuleManagement implementation that does not
-     * load its rules from an external data source.
-     *
-     * It is an extremely useful class for testing rules and basic algorithms, but
-     * due to the in-memory management of all rules, it should not be used in a
-     * productive environment, especially if large rule sets have to be managed.
-     *
-     * By default, the MMapRuleManagement will reserve enough memory for the rules
-     * to manage, when it is constructed. It will NOT fill the rules with useful
-     * values though. It is up to caller to use loadRules() afterwards and fill the
-     * returned Rule instances with the necessary data.
-     */
-    class MMapRuleManagement : public RuleManagement
-    {
-    public:
-
-        /**
-         * \brief Creates a new MMapRuleManagement instance.
-         *
-         * \param maxrules The amount of Rule objects to create.
-         */
-        MMapRuleManagement (unsigned int maxrules);
-
-        /**
-         * \brief Destroys the MMapRuleManagement.
-         *
-         * Destroys the MMapRuleManagement and frees the memory hold by
-         * the attached Rule instances.
-         */
-        virtual ~MMapRuleManagement();
-
-        /**
-         * \brief Loads all existing rules.
-         *
-         * \return A vector containing the Rule objects hold by this instance.
-         * The caller should not free the returned results.
-         */
-        std::vector<Rule*> loadRules ();
-
-        /**
-         * \brief Loads a specific amount of rules.
-         *
-         * This behaves exactly like loadRules().
-         *
-         * \param maxrules The amount of rules to load.
-         * \return A std::vector containing the loaded rules.
-         */
-        std::vector<Rule*> loadRules (unsigned int maxrules);
-
-        /**
-         * \brief Saves the passed rules to the underlying data source.
-         *
-         * This does nothing.
-         *
-         * \param rules A std::vector containing the rules to save.
-         * \return true, if saving the rules was successful, false otherwise.
-         */
-        bool saveRules (std::vector<Rule*> rules);
-
-    protected:
-
-        /**
-         * \brief In-memory set of Rule objects to use.
-         */
-        std::vector<Rule*> _rules;
-    };
-
-} // namespace
-#endif /* _MMAPRULEMANAGEMENT_H_ */

cplusplus/src/MMapRuleManager.cpp

+/*
+ * dynrules - Python dynamic rules engine
+ *
+ * Authors: Marcus von Appen
+ *
+ * This file is distributed under the Public Domain.
+ */
+
+#include "MMapRuleManager.h"
+
+namespace dynrules
+{
+MMapRuleManager::MMapRuleManager (unsigned int maxrules) :
+    RuleManager (maxrules),
+    _rules(0)
+{
+    unsigned int i;
+    for (i = 0; i < maxrules; i++)
+        this->_rules.push_back (new Rule (i));
+}
+
+MMapRuleManager::~MMapRuleManager ()
+{
+    std::vector<Rule*>::iterator iter;
+    for (iter = this->_rules.begin (); iter != this->_rules.end (); iter++)
+    {
+        delete *iter;
+    }
+    this->_rules.clear ();
+}
+
+std::vector<Rule*> MMapRuleManager::loadRules ()
+{
+    return this->_rules;
+}
+
+std::vector<Rule*> MMapRuleManager::loadRules (unsigned int maxrules)
+{
+    return this->_rules;
+}
+
+bool MMapRuleManager::saveRules (std::vector<Rule*> rules)
+{
+    return true;
+}
+
+} // namespace

cplusplus/src/MMapRuleManager.h

+/*
+ * dynrules - Python dynamic rules engine
+ *
+ * Authors: Marcus von Appen
+ *
+ * This file is distributed under the Public Domain.
+ */
+
+#ifndef _MMAPRULEMANAGER_H_
+#define _MMAPRULEMANAGER_H_
+
+#include "RuleManager.h"
+
+namespace dynrules
+{
+    /**
+     * \brief A simple memory-mapped RuleManager implementation that does not
+     * load its rules from an external data source.
+     *
+     * It is an extremely useful class for testing rules and basic algorithms, but
+     * due to the in-memory management of all rules, it should not be used in a
+     * productive environment, especially if large rule sets have to be managed.
+     *
+     * By default, the MMapRuleManager will reserve enough memory for the rules
+     * to manage, when it is constructed. It will NOT fill the rules with useful
+     * values though. It is up to caller to use loadRules() afterwards and fill the
+     * returned Rule instances with the necessary data.
+     */
+    class MMapRuleManager : public RuleManager
+    {
+    public:
+
+        /**
+         * \brief Creates a new MMapRuleManager instance.
+         *
+         * \param maxrules The amount of Rule objects to create.
+         */
+        MMapRuleManager (unsigned int maxrules);
+
+        /**
+         * \brief Destroys the MMapRuleManager.
+         *
+         * Destroys the MMapRuleManager and frees the memory hold by
+         * the attached Rule instances.
+         */
+        virtual ~MMapRuleManager();
+
+        /**
+         * \brief Loads all existing rules.
+         *
+         * \return A vector containing the Rule objects hold by this instance.
+         * The caller should not free the returned results.
+         */
+        std::vector<Rule*> loadRules ();
+
+        /**
+         * \brief Loads a specific amount of rules.
+         *
+         * This behaves exactly like loadRules().
+         *
+         * \param maxrules The amount of rules to load.
+         * \return A std::vector containing the loaded rules.
+         */
+        std::vector<Rule*> loadRules (unsigned int maxrules);
+
+        /**
+         * \brief Saves the passed rules to the underlying data source.
+         *
+         * This does nothing.
+         *
+         * \param rules A std::vector containing the rules to save.
+         * \return true, if saving the rules was successful, false otherwise.
+         */
+        bool saveRules (std::vector<Rule*> rules);
+
+    protected:
+
+        /**
+         * \brief In-memory set of Rule objects to use.
+         */
+        std::vector<Rule*> _rules;
+    };
+
+} // namespace
+#endif /* _MMAPRULEMANAGER_H_ */

cplusplus/src/RuleManagement.cpp

-/*
- * dynrules - Python dynamic rules engine
- *
- * Authors: Marcus von Appen
- *
- * This file is distributed under the Public Domain.
- */
-
-#include "RuleManagement.h"
-
-namespace dynrules
-{
-
-RuleManagement::RuleManagement (unsigned int maxrules) :
-    _maxrules (maxrules)
-{
-}
-
-RuleManagement::~RuleManagement ()
-{
-}
-
-unsigned int RuleManagement::getMaxRules () const
-{
-    return this->_maxrules;
-}
-
-bool RuleManagement::saveRulesHintFile (std::string filename,
-    LearnSystem& lsystem) const
-{
-    std::ofstream fd;
-
-    fd.open (filename.c_str (), std::ios_base::out);
-    if (!fd)
-        return false; // TODO: error escalation?
-
-    lsystem.createScript (fd, this->_maxrules);
-    fd.close ();
-    return true;
-}
-
-} // namespace

cplusplus/src/RuleManagement.h

-/*
- * dynrules - Python dynamic rules engine
- *
- * Authors: Marcus von Appen
- *
- * This file is distributed under the Public Domain.
- */
-
-#ifndef _RULEMANAGEMENT_H_
-#define _RULEMANAGEMENT_H_
-
-#include <vector>
-#include <sstream>
-#include <fstream>
-
-#include "Rule.h"
-#include "LearnSystem.h"
-
-namespace dynrules
-{
-    /**
-     * \brief The RuleManagement class takes care of loading and saving rules from
-     *  arbitrary data sources.
-     *
-     * The base is an abstract class, which's loadRules() method must be
-     * implemented according to the specific needs of the application.
-     *
-     */
-    class RuleManagement
-    {
-    public:
-
-        /**
-         * \brief Creates a new RuleManagement instance.
-         *
-         * \param maxrules The default amount of rules to manage.
-         */
-        RuleManagement (unsigned int maxrules);
-
-        /**
-         * \brief Destroys the RuleManagement.
-         *
-         * Destroys the RuleManagement and frees the memory hold by it.
-         */
-        virtual ~RuleManagement ();
-
-        /**
-         * \brief Loads all existing rules from the underlying data source.
-         *
-         * \return A std::vector containing the loaded rules.
-         */
-        virtual std::vector<Rule*> loadRules () = 0;
-
-        /**
-         * \brief Loads a specific amount of rules from the underlying data source.
-         *
-         * \param maxrules The amount of rules to load.
-         * \return A std::vector containing the loaded rules.
-         */
-        virtual std::vector<Rule*> loadRules (unsigned int maxrules) = 0;
-
-        /**
-         * \brief Saves the passed rules to the underlying data source.
-         *
-         * \param rules A std::vector containing the rules to save.
-         * \return true, if saving the rules was successful, false otherwise.
-         */
-        virtual bool saveRules (std::vector<Rule*> rules) = 0;
-
-        /**
-         * \brief Saves a LearnSystem/RuleSet combination to a physical
-         * file.
-         *
-         * \param filename The file name.
-         * \param lsystem The LearnSystem to save the rules for.
-         * \return true on success, false otherwise.
-         */
-        bool saveRulesHintFile (std::string filename, LearnSystem& lsystem) const;
-
-        /**
-         * \brief Gets the maximum number of rules, an instance will deal with.
-         *
-         * \return The maximum number of rules to deal with.
-         */
-        unsigned int getMaxRules () const;
-
-    protected:
-
-        /**
-         * \brief The maximum amount of Rule objects the RuleManagement
-         * will manage.
-         */
-        unsigned int _maxrules;
-
-    };
-
-} // namespace
-
-#endif /* _RULEMANAGEMENT_H_ */

cplusplus/src/RuleManager.cpp

+/*
+ * dynrules - Python dynamic rules engine
+ *
+ * Authors: Marcus von Appen
+ *
+ * This file is distributed under the Public Domain.
+ */
+
+#include "RuleManager.h"
+
+namespace dynrules
+{
+
+RuleManager::RuleManager (unsigned int maxrules) :
+    _maxrules (maxrules)
+{
+}
+
+RuleManager::~RuleManager ()
+{
+}
+
+unsigned int RuleManager::getMaxRules () const
+{
+    return this->_maxrules;
+}
+
+bool RuleManager::saveRulesHintFile (std::string filename,
+    LearnSystem& lsystem) const
+{
+    std::ofstream fd;
+
+    fd.open (filename.c_str (), std::ios_base::out);
+    if (!fd)
+        return false; // TODO: error escalation?
+
+    lsystem.createScript (fd, this->_maxrules);
+    fd.close ();
+    return true;
+}
+
+} // namespace

cplusplus/src/RuleManager.h

+/*
+ * dynrules - Python dynamic rules engine
+ *
+ * Authors: Marcus von Appen
+ *
+ * This file is distributed under the Public Domain.
+ */
+
+#ifndef _RULEMANAGER_H_
+#define _RULEMANAGER_H_
+
+#include <vector>
+#include <sstream>
+#include <fstream>
+
+#include "Rule.h"
+#include "LearnSystem.h"
+
+namespace dynrules
+{
+    /**
+     * \brief The RuleManager class takes care of loading and saving rules from
+     *  arbitrary data sources.
+     *
+     * The base is an abstract class, which's loadRules() method must be
+     * implemented according to the specific needs of the application.
+     *
+     */
+    class RuleManager
+    {
+    public:
+
+        /**
+         * \brief Creates a new RuleManager instance.
+         *
+         * \param maxrules The default amount of rules to manage.
+         */
+        RuleManager (unsigned int maxrules);
+
+        /**
+         * \brief Destroys the RuleManager.
+         *
+         * Destroys the RuleManager and frees the memory hold by it.
+         */
+        virtual ~RuleManager ();
+
+        /**
+         * \brief Loads all existing rules from the underlying data source.
+         *
+         * \return A std::vector containing the loaded rules.
+         */
+        virtual std::vector<Rule*> loadRules () = 0;
+
+        /**
+         * \brief Loads a specific amount of rules from the underlying data source.
+         *
+         * \param maxrules The amount of rules to load.
+         * \return A std::vector containing the loaded rules.
+         */
+        virtual std::vector<Rule*> loadRules (unsigned int maxrules) = 0;
+
+        /**
+         * \brief Saves the passed rules to the underlying data source.
+         *
+         * \param rules A std::vector containing the rules to save.
+         * \return true, if saving the rules was successful, false otherwise.
+         */
+        virtual bool saveRules (std::vector<Rule*> rules) = 0;
+
+        /**
+         * \brief Saves a LearnSystem/RuleSet combination to a physical
+         * file.
+         *
+         * \param filename The file name.
+         * \param lsystem The LearnSystem to save the rules for.
+         * \return true on success, false otherwise.
+         */
+        bool saveRulesHintFile (std::string filename, LearnSystem& lsystem) const;
+
+        /**
+         * \brief Gets the maximum number of rules, an instance will deal with.
+         *
+         * \return The maximum number of rules to deal with.
+         */
+        unsigned int getMaxRules () const;
+
+    protected:
+
+        /**
+         * \brief The maximum amount of Rule objects the RuleManager
+         * will manage.
+         */
+        unsigned int _maxrules;
+
+    };
+
+} // namespace
+
+#endif /* _RULEMANAGER_H_ */

cplusplus/src/dynrules.h

 #include "Rule.h"
 #include "RuleSet.h"
 #include "LearnSystem.h"
-#include "RuleManagement.h"
-#include "MMapRuleManagement.h"
+#include "RuleManager.h"
+#include "MMapRuleManager.h"
 
 #endif /* _DYNRULES_H_ */

cplusplus/win32/dynrules.vcproj

 				>
 			</File>
 			<File
-				RelativePath="..\src\MMapRuleManagement.cpp"
+				RelativePath="..\src\MMapRuleManager.cpp"
 				>
 			</File>
 			<File
 				>
 			</File>
 			<File
-				RelativePath="..\src\RuleManagement.cpp"
+				RelativePath="..\src\RuleManager.cpp"
 				>
 			</File>
 			<File
 				>
 			</File>
 			<File
-				RelativePath="..\src\MMapRuleManagement.h"
+				RelativePath="..\src\MMapRuleManager.h"
 				>
 			</File>
 			<File
 				>
 			</File>
 			<File
-				RelativePath="..\src\RuleManagement.h"
+				RelativePath="..\src\RuleManager.h"
 				>
 			</File>
 			<File
+Python API reference
+====================
+
+.. class:: Rule(id : object)
+
+   Creates a new :class:`Rule` object with the given id.
+  
+   :class:`Rule` is a simple class type that carries a weight indicator
+   and arbitrary code data for usage in the dynamic script generation
+   process.
+
+   .. attribute:: code
+
+      Gets or sets the code of the :class:`Rule`.
+  
+   .. attribute:: id
+
+      Gets the id of the :class:`Rule`.
+  
+   .. attribute:: used
+
+      Indicates whether the :class:`Rule` was used or not.
+  
+   .. attribute:: weight
+
+      Gets or sets the weight of the :class:`Rule`.
+
+.. class:: RuleSet(minweight : float, maxweight : float)
+
+   Creates a new, empty :class:`RuleSet`.
+  
+   :class:`RuleSet` is a rule container class that manages rules, their
+   weights and the weight distribution for the rules. The *minweight* and
+   *maxweight* parameters are the minimum and maximum weight boundaries,
+   each rule's weight has to stay in.
+
+   .. attribute:: maxweight
+
+      Gets or sets the maximum weight to use for rules.
+  
+   .. attribute:: minweight
+
+      Gets or sets the minimum weight to use for rules.
+
+   .. attribute:: rules
+
+      Gets the list of currently managed :class:`Rule` objects.
+
+   .. attribute:: weight
+
+      Gets the total weight of all managed :class:`Rule` objects.
+
+   .. method:: add(rule : Rule)
+
+      Adds a :class:`Rule` to the :class:`RuleSet`.
+
+   .. method:: calculate_adjustment(fitness : float) -> float
+
+      Calculates the reward or penalty, each of the activated rules recives.
+      *fitness* hereby can be used as measure of the performance or whatever
+      is suitable in the implementation.
+  
+      This must be implemented by inheriting classes.
+
+   .. method:: clear()
+
+      Removes all rules from the :class:`RuleSet`.
+
+   .. method:: distribute_remainder(remainder : float) -> float
+
+      Distributes the remainder of the weight differences between the
+      last weights and current weights.
+  
+      The method must return a value.
+      This must be implemented by inheriting classes.
+
+   .. method:: find(rid : float) -> Rule
+        
+      Tries to find the :class:`Rule` with the matching id and returns it.
+      In case no :class:`Rule` with the passed id exists, None is returned.
+
+   .. method:: RuleSet.remove(rule : Rule)
+
+      Removes a :class:`Rule` from the :class:`RuleSet`.
+
+   .. method:: RuleSet.update_weights(fitness : float)
+        
+      Updates the weights of all contained rules.
+
+      Adapted from Pieter Spronck's algorithm as explained in
+      Spronck et al: 2005, 'Adaptive Game AI with Dynamic Scripting'.
+
+.. class:: RuleManager(id : object)
+
+   The :class:`RuleManager` class takes care of loading and saving
+   rules from arbitrary data sources.
+   The base is an abstract class, which's :meth:`load_rules` method must be
+   implemented according to the specific needs of the application.
+
+   .. attribute:: maxrules
+
+      Gets the maximum amount of rules to manage.
+  
+   .. method:: load_rules([maxrules=-1]) -> [Rule, Rule ...]
+
+      Loads rules from the underlying data source and returns them as list.
+      The *maxrules* argument defines the amount of rules to load. If it is
+      smaller than 0, all existing rules should be returned.        
+
+      This must be implemented by inheriting classes.
+  
+   .. method:: save_rules(rules : iterable)
+        
+      Saves the passed rules to the underlying data source.
+        
+      This must be implemented by inheriting classes.
+
+   .. method:: save_rules_hint_file(filename : string, learnsystem : LearnSystem)
+        
+      Saves a :class:`LearnSystem`/:class:`RuleSet` combination to a physical
+      file.
+
+.. class:: MMapRuleManager(maxrules : int)
+    
+   A simple memory-mapped :class:`RuleManager` implementation that
+   does not load its rules from an external data source.
+
+   It is an extremely useful class for testing rules and basic algorithms, but
+   due to the in-memory management of all rules, it should not be used in a
+   productive environment, especially if large rule sets have to be managed.
+
+   By default, the :class:`MMapRuleManager` class will reserve enough memory
+   for the rules to manage, when it is constructed. It will **not** fill the
+   rules with useful values though. It is up to caller to use
+   :meth:`load_rules()` afterwards and fill the returned :class:`Rule`
+   instances with the necessary data.
+
+   .. attribute:: maxrules
+
+      Gets the maximum amount of rules to manage.
+  
+   .. method:: load_rules([maxrules=-1]) -> [Rule, Rule ...]
+
+      Returns the internally managed rules or a certain subset.
+  
+   .. method:: save_rules(rules : iterable)
+        
+      This does nothing and will always return True.
+
+   .. method:: save_rules_hint_file(filename : string, learnsystem : LearnSystem)
+        
+      Saves a :class:`LearnSystem`/:class:`RuleSet` combination to a physical
+      file.
+
+.. class:: LearnSystem(ruleset : RuleSet)
+
+   Creates a new :class:`LearnSystem` using a specific :class:`RuleSet`.
+
+   The :class:`LearnSystem` class takes care of creating new scripts
+   based on a predefined :class:`RuleSet`. It does not evaluate the
+   scripts nor modifies the rules written to them.
+
+   The procedure of creating scripts is done using three phases:
+ 
+   * header creation
+   * rule code creation
+   * footer creation
+
+   The header and footer are freely choosable. You can simple override
+   or reassign the :meth:`create_header()` and :meth:`create_footer()` methods
+   to let them return your required code.
+
+   .. attribute:: maxscriptsize
+
+      Gets or sets the maximum script size (in bytes) for inserting rules.
+  
+   .. attribute:: maxtries
+
+      Gets or sets the maximum amount of tries to insert a script rule.
+  
+   .. attribute:: ruleset
+
+      Gets or sets the :class:`RuleSet` to use.
+
+   .. method:: create_footer() -> str
+
+      Creates the footer for the script file.
+  
+      The default implementation does nothing.
+
+   .. method:: create_header() -> str
+    
+      Creates the header for the script file.
+  
+      The default implementation does nothing.  
+
+   .. method:: create_rules(maxrules : int) -> str
+  
+      Creates a rule list from the currently active :class:`RuleSet`.
+      Gets *maxrules* rules from the set :class:`RuleSet` and passes
+      their code back as string for the script file.
+
+      Adapted from Pieter Spronck's algorithm as explained in
+      Spronck et al: 2005, 'Adaptive Game AI with Dynamic Scripting'.
+
+   .. method:: create_script(scriptfile : object, maxrules : int)
+  
+      Creates a script from the available :class:`RuleSet` using the
+      passed script file. A maximum of *maxrules* rules will be written.
+      *scriptfile* can be either a file object or filename. In case of
+      a file object it is assumed to be writeable and won't be closed on
+      leaving the function (but flushed).

doc/capi.rst

-.. default-domain:: c
-
-C API reference
-===============
-
-The :py:mod:`dynrules` C API contains fast C based implementations of
-the dynamic scripting module API.
-
-
-Import
-------
-Include headers::
-
-  dynrules/dynrules.h
-
-.. function:: int import_dynrules (void)
-
-  Imports the :py:mod:`dynrules` module. This returns 0 on success and -1 on
-  failure.
-
-PyRule
-------
-.. type:: PyRule
-.. type:: Py_Type
-
-The :type:`PyRule` object is a simple class type that carries a weight
-indicator and arbitrary code data for usage in the dynamic script
-generation process.
-
-Members
-^^^^^^^
-.. member:: PyObject PyRule.id
-
-  The unique identifier.
-
-.. member:: int PyRule.used
-
-  Indicates whether the rule code was executed. The value is limited to 0 and 1.
-
-.. member:: double PyRule.weight
-
-  The weight of the rule.
-
-.. member:: PyObject PyRule.code
-
-  The code object to be executed.
-
-Functions
-^^^^^^^^^
-.. function:: int PyRule_Check (PyObject *obj)
-
-  Returns true, if the argument is a :type:`PyRule` or a subclass of
-  :type:`PyRule`.
-
-.. function:: PyObject* PyRule_New (PyObject *id)
-
-  Creates a new :type:`PyRule` object with the given id. On failure, this
-  returns NULL.
-
-PyRuleSet
----------
-.. type:: PyRuleSet
-.. type:: PyRuleSet_Type
-
-The PyRuleSet object is a rule container class that manages rules, their
-weights and the weight distribution for the rules.
-
-Members
-^^^^^^^
-.. member:: PyObject PyRuleSet.rules
-
-  A dictionary containing the rules. It uses the :member:`PyRule.id` as key and
-  the :type:`PyRule` as value.
-
-.. member:: double PyRuleSet.weight
-
-  The total weight of all contained rules.
-
-.. member:: double PyRuleSet.minweight
-
-  The minimum weight a contained :type:`PyRule` can retrieve.
-
-.. member:: double PyRuleSet.maxweight
-
-  The maximum weight a contained :type:`PyRule` can retrieve.
-
-Functions
-^^^^^^^^^
-.. function:: int PyRuleSet_Check (PyObject *obj)
-
-  Returns true, if the argument is a :type:`PyRuleSet` or a subclass of
-  :type:`PyRuleSet`.
-
-.. function:: PyObject* PyRuleSet_New (double minw, double maxw)
-
-  Creates a new :type:`PyRuleSet` object with an initial minimum and maximum
-  weight. On failure, this returns NULL.
-
-.. function:: int PyRuleSet_Add (PyObject *ruleset, PyObject *rule)
-
-  Adds a :type:`PyRule` to a :type:`PyRuleSet`. If there is a rule with the
-  same id already in the :type:`PyRuleSet`, it will be removed and the passed
-  *rule* will be used instead. Additionally the :member:`PyRule.weight` member
-  will be set to stay within the boundaries of the
-  :member:`PyRuleSet.minweight` and :member:`PyRuleSet.maxweight` limits.
-  This returns 1 on success and 0 on failure.
-
-.. function:: int PyRuleSet_Remove (PyObject *ruleset, PyObject *rule)
-
-  Removes a :type:`PyRule` from a :type:`PyRuleSet`. This returns 1 on success
-  and 0 on failure.
-
-.. function:: int PyRuleSet_UpdateWeights (PyObject *ruleset, PyObject *fitness)
-
-  Updates the weights of all contained rules. *fitness* will be passed
-  to the user-specific :func:`PyRuleSet.calculate_adjustment`
-  method. This returns 1 on success and 0 on failure.
-
-PyLearnSystem
--------------
-.. type:: PyLearnSystem
-.. type:: PyLearnSystem_Type
-
-The PyLearnSystem object takes care of creating new scripts based on a
-predefined :type:`PyRuleSet`. It does not evaluate the scripts nor
-modifies the rules written to them.
-
-Members
-^^^^^^^
-.. member:: PyObject PyLearnSystem.ruleset
-
-   The :type:`PyRuleSet` to use.
-
-.. member:: int PyLearnSystem.maxtries
-
-   The maximum number of tries to select rules and generate a script.
-
-.. member:: int PyLearnSystem.maxscriptsize
-
-   The maximum size in bytes of the scripts to generate.
-
-Functions
-^^^^^^^^^
-.. function:: int PyLearnSystem_Check (PyObject *obj)
-
-   Returns true, if the argument is a :type:`PyLearnSystem` or a subclass of
-   :type:`PyLearnSystem`.
-
-.. function:: PyObject* PyLearnSystem_New (PyObject *ruleset)
-
-   Creates a new :type:`PyLearnSytem` object for the passed :type:`PyRuleSet`.
-   On failure, this returns NULL.
-
-.. function:: int PyLearnSystem_CreateScript (PyObject *learnsystem, \
-   PyObject *file, int maxrules)
-
-   Creates a script from the set :member:`PyLearnSystem.rulset` using the
-   passed script *file*. A maximum of *maxrules* rules will be written.
-   *file* can be any file-like Python object or a filename. In case of
-   a file object it is assumed to be writeable and won't be closed on
-   leaving the function.
 
 # Add any Sphinx extension module names here, as strings. They can be extensions
 # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = []
+extensions = ['sphinx.ext.intersphinx',
+              'sphinx.ext.todo',
+              'sphinx.ext.coverage',
+              'sphinx.ext.inheritance_diagram'
+              ]
+todo_include_todos = True
 
 # Add any paths that contain templates here, relative to this directory.
 templates_path = []
 # other places throughout the built documents.
 #
 # The short X.Y version.
-version = '0.0.15'
+version = '0.0.16'
 # The full version, including alpha/beta/rc tags.
-release = '0.0.15'
+release = '0.0.16'
 
 # There are two options for replacing |today|: either, you set today to some
 # non-false value, then it is used:
+License
+=======
+ ::
+
+   This software is distributed under the Public Domain.
+
+   In cases, where the law prohibits the recognition of Public Domain
+   software, this software can be licensed under the zlib lincese as
+   stated below:
+
+   Copyright (C) 2008-2013 Marcus von Appen <marcus@sysfault.org>
+
+   This software is provided 'as-is', without any express or implied
+   warranty. In no event will the authors be held liable for any damages
+   arising from the use of this software.
+
+   Permission is granted to anyone to use this software for any purpose,
+   including commercial applications, and to alter it and redistribute it
+   freely, subject to the following restrictions:
+
+   1. The origin of this software must not be misrepresented; you must not
+      claim that you wrote the original software. If you use this software
+      in a product, an acknowledgment in the product documentation would be
+      appreciated but is not required.
+   2. Altered source versions must be plainly marked as such, and must not be
+      misrepresented as being the original software.
+   3. This notice may not be removed or altered from any source distribution.
 Welcome to the dynrules documentation!
 ======================================
+dynrules is a dynamic ruleset scripting package for Python. It uses the
+Dynamic Scripting technique to create adaptive AI scripts automatically
+from predefined rulesets.
 
 Contents:
 
 .. toctree::
    :maxdepth: 2
 
-   intro
-   usage
-   pyapi
-   capi
+   intro.rst
+   usage.rst
+   api.rst
+
+Further readings:
+
+.. toctree::
+   :maxdepth: 1
    
+   news.rst
+   todos.rst
+   copying.rst
+
 Indices and tables
 ==================
 
+* :ref:`genindex`
 * :ref:`search`
 
+
+Documentation TODOs
+===================
+
+.. todolist::
+
+Last generated on: |today|
 Introduction
 ============
-
 This is the documentation for the dynrules dynamic rules creation
 package. dynrules is a small package that allows you to create
 rule-based scripts for adaptive AI systems automatically. It uses the
 supportive system for creating your own adaptive AI quickly.
 
 Prerequisites
-=============
+-------------
+You must have at least one of the following Python versions installed:
 
-dynrules needs at least **Python 2.6** to run and was successfully
-tested with the versions **2.6, 2.7, 3.1, 3.2, 3.3** and **PyPy 1.9**. It
-features both, a C and pure Python implementation, letting you choose
-whatever suits you more. By default, both implementations will be
-installed, but the C implementation will be preferred by the dynrules
-internals.
-
-In case you want to build the C implementation, you will need a C
-compiler, which supports parts of the C99 standard, such as the `GCC
-<http://www.gnu.org/software/gcc/>`_.
+* Python 2.6+           (http://www.python.org)
+* PyPy 1.8.0+           (http://www.pypy.org)
+* IronPython 2.7.2.1+   (http://www.ironpython.net)
 
 Installing dynrules
-===================
-
+-------------------
 You can either use the python way of installing the package using
 distutils or the make command using the Makefile. Simply type ::
 
 anything different from the python way. It simply calls 'python setup.py
 install'.
 
+Trying out
+^^^^^^^^^^
+You also can test out dynrules without actually installing it. You just
+need to set up your ``PYTHONPATH`` to point to the location of the
+source distribution package. On Windows-based platforms, you might use
+something like ::
+
+   set PYTHONPATH=C:\path\to\dynrules\:$PYTHONPATH
+
+to define the ``PYTHONPATH`` on a command shell. On Linux/Unix, use ::
+
+   export PYTHONPATH=/path/to/dynrules:$PYTHONPATH
+
+for bourne shell compatibles or ::
+
+   setenv PYTHONPATH /path/to/dynrules:$PYTHONPATH
+
+for C shell compatibles. You can omit the `:$PYTHONPATH``, if you did not use
+it so far and if your environment settings do not define it.
+
+.. note::
+
+   If you are using IronPython, use ``IRONPYTHONPATH`` instead of
+   ``PYTHONPATH``.
+
+
 Binary packages
-===============
-
+---------------
 dynrules is not provided as binary package by the author. It might be
 that someone else set up such a package for your wanted operating system
 or distribution. Those packages are usually not supported by the author,
 of that package.
 
 Notes on Mercurial usage
-========================
-
+------------------------
 The Mercurial repository version of dynrules is not intended to be used
 in a production environment. Interfaces may change from one checkin to
 another, methods, classes or modules can be broken and so on. If you
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+	set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+set I18NSPHINXOPTS=%SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+	set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+	set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+	:help
+	echo.Please use `make ^<target^>` where ^<target^> is one of
+	echo.  html       to make standalone HTML files
+	echo.  dirhtml    to make HTML files named index.html in directories
+	echo.  singlehtml to make a single large HTML file
+	echo.  pickle     to make pickle files
+	echo.  json       to make JSON files
+	echo.  htmlhelp   to make HTML files and a HTML help project
+	echo.  qthelp     to make HTML files and a qthelp project
+	echo.  devhelp    to make HTML files and a Devhelp project
+	echo.  epub       to make an epub
+	echo.  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+	echo.  text       to make text files
+	echo.  man        to make manual pages
+	echo.  texinfo    to make Texinfo files
+	echo.  gettext    to make PO message catalogs
+	echo.  changes    to make an overview over all changed/added/deprecated items
+	echo.  linkcheck  to check all external links for integrity
+	echo.  doctest    to run all doctests embedded in the documentation if enabled
+	goto end
+)
+
+if "%1" == "clean" (
+	for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+	del /q /s %BUILDDIR%\*
+	goto end
+)
+
+if "%1" == "html" (
+	%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+	goto end
+)
+
+if "%1" == "dirhtml" (
+	%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+	goto end
+)
+
+if "%1" == "singlehtml" (
+	%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+	goto end
+)
+
+if "%1" == "pickle" (
+	%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can process the pickle files.
+	goto end
+)
+
+if "%1" == "json" (
+	%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can process the JSON files.
+	goto end
+)
+
+if "%1" == "htmlhelp" (
+	%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+	goto end
+)
+
+if "%1" == "qthelp" (
+	%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+	echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Priddle.qhcp
+	echo.To view the help file:
+	echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Priddle.ghc
+	goto end
+)
+
+if "%1" == "devhelp" (
+	%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished.
+	goto end
+)
+
+if "%1" == "epub" (
+	%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The epub file is in %BUILDDIR%/epub.
+	goto end
+)
+
+if "%1" == "latex" (
+	%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+	goto end
+)
+
+if "%1" == "text" (
+	%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The text files are in %BUILDDIR%/text.
+	goto end
+)
+
+if "%1" == "man" (
+	%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The manual pages are in %BUILDDIR%/man.
+	goto end
+)
+
+if "%1" == "texinfo" (
+	%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
+	goto end
+)
+
+if "%1" == "gettext" (
+	%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
+	goto end
+)
+
+if "%1" == "changes" (
+	%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.The overview file is in %BUILDDIR%/changes.
+	goto end
+)
+
+if "%1" == "linkcheck" (
+	%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+	goto end
+)
+
+if "%1" == "doctest" (
+	%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+	goto end
+)
+
+:end
+Release News
+============
+This describes the latest changes between the dynrules releases.
+
+0.1.0
+-----
+Released on 2013-XX-XX
+
+Python framework: 
+  * Removed Python C module.
+  * Renamed RuleManagement class to RuleManager.
+  * Renamed MMapRuleManagement class to MMapRuleManager.
+
+C++ framework:
+  * Renamed RuleManagement class to RuleManager.
+  * Renamed MMapRuleManagement class to MMapRuleManager.
+
+0.0.15
+------
+Released on 2012-09-30
+
+Python framework:
+  * Added PyPy support.
+  * More compatibility fixes for Python 3.x.
+  * Fixed a refcount issue in CRuleSet.update_weights(), which might
+    lead to crashes.
+  * Moved unit tests into dynrules package.
+
+0.0.14
+------
+Released on 2011-05-14
+
+Python framework:
+  * Compatibility fixes for Python 3.2.
+
+0.0.13
+------
+Released on 2010-05-19
+
+Python framework:
+  * Fixed constructor for RuleManagement class.
+
+0.0.12
+------
+Released on 2010-03-26
+
+Python framework:
+  * Fixed file recognition issue for Python 3.x in CLearnSystem.
+
+0.0.11
+------
+Released on 2009-12-25
+
+* Fixed documentation distribution.
+
+0.0.10
+------
+Released on 2009-12-24
+
+Python framework:
+  * Changed CRule.id to be an arbitrary object.
+  * Fixed minweight/maxweight range checks for CRuleSet.
+  * Fixed minweight/maxweight checks within the C API interfaces.
+
+0.0.9
+-----
+Released on 2009-12-22
+
+C++ framework:
+  * Changed RuleManagement.save_rules_hint_file() to take a filename instead
+    of prefix and suffix.
+  * Better Makefile support
+  * Fixed several pointer/const/reference issues.
+  * Changed char* exceptions to be invalid_argument types.
+  * Added HTML API reference.
+  * Added Win32 VC++ (VS.NET 2008) support.
+
+Python framework:
+  * Changed RuleManagement.save_rules_hint_file() to take a filename instead
+    of prefix and suffix.
+  * Added C API documentation.
+  * Added C API tests.
+  * import cleanups.
+
+0.0.8
+-----
+Released on 2009-07-03
+
+Python framework:
+  * Fixed an import bug in LearnSystem.
+
+0.0.7
+-----
+Released on 2009-03-09
+
+C++ framework:
+  * Added missing RuleManagement::getMaxRules() method.
+  * Fixed documentation comments.
+  * RuleSet::updateWeights() method receives only a fitness argument now.
+
+Python framework:
+  * Many fixes for correct Python 3.x support.
+  * CLearnSystem.create_script() now can handle file names properly.
+  * Added API reference to documentations.
+
+0.0.6
+-----
+Released on 2008-12-16
+
+Python framework:
+  * Added Python 3.x support.
+    Note that CLearnSystem.create_script() does not accept file names with
+    Python 3.0, only file objects.
+
+0.0.5
+-----
+Released on 2008-11-21
+
+C++ framework:
+  * Fixed a bug in RuleSet::updateWeights() which caused wrong weight
+    results.
+  * Added missing MMapRuleManagement.h include to dynrules.h
+
+Python framework:
+  * Fixed name ambiguity for the Python and C implementation.
+    The visible C types in the dynrules packages were renamed to
+    CRule, CRuleSet and CLearnSystem, the C module types still have their
+    original name.
+  * Fixed C API slots.
+  * Added RuleSet.find() and CRuleSet.find() methods.
+  * New RuleManagement class.
+  * New MMapRuleManagement class for in-memory rule management.
+
+0.0.4
+-----
+Released on 2008-11-20
+
+C++ framework:
+  * New RuleSet.find() method.
+  * New abstract RuleManagement class for managing rules.
+  * New MMapRuleManagement class for in-memory rule management.
+  * Changed API to pass object pointers around instead of objects.
+
+0.0.3
+-----
+Released on 2008-11-09
+
+C++ framework:
+  * Added documentation.
+  * Fixed a minor range issue in the RuleSet constructor that allowed
+    minweight to be smaller than maxweight.
+  * Fixed an int vs. double bug in the LearnSystem constructor.
+
+0.0.2
+-----
+Released on 2008-11-08
+
+* New pure C++ framework under cplusplus
+
+0.0.1
+-----
+Released on 2008-10-06
+
+* Initial release.

doc/pyapi.rst

-Python API reference
-====================
-
-Contents:
-
-.. toctree::
-   :maxdepth: 2
-
-   ref/pycrule
-   ref/pycruleset
-   ref/pyclearnsystem
-   ref/pyrule
-   ref/pyruleset
-   ref/pylearnsystem
-   ref/pymmaprulemanagement
-   ref/pyrulemanagement

doc/ref/pyclearnsystem.rst

-:class:`CLearnSystem` - Rule script generation
-==============================================
-.. class:: CLearnSystem (ruleset) -> CLearnSystem
-
-  Creates a new :class:`CLearnSystem` using a specific :class:`CRuleSet`.
-
-  The :class:`CLearnSystem` class takes care of creating new scripts
-  based on a predefined :class:`CRuleSet`. It does not evaluate the
-  scripts nor modifies the rules written to them.
-
-  The procedure of creating scripts is done using three phases:
-
-  * header creation
-  * rule code creation
-  * footer creation
-
-  The header and footer are freely choosable. You can simple override
-  or reassign the :meth:`CLearnSystem.create_header()` and
-  :meth:`CLearnSystem.create_footer()` methods to let them return your
-  required code.
-
-Attributes
-----------
-
-.. attribute:: CLearnSystem.maxscriptsize
-
-  Gets or sets the maximum script size (in bytes) for inserting rules.
-  
-.. attribute:: CLearnSystem.maxtries
-
-  Gets or sets the maximum amount of tries to insert a script rule.
-  
-.. attribute:: CLearnSystem.ruleset
-
-  Gets or sets the :class:`CRuleSet` to use.
-
-Methods
--------
-
-.. method:: CLearnSystem.create_footer () -> str
-
-  Creates the footer for the script file.
-  
-  The default implementation does nothing.
-
-.. method:: CLearnSystem.create_header () -> str
-    
-  Creates the header for the script file.
-  
-  The default implementation does nothing.  
-
-.. method:: CLearnSystem.create_rules (maxrules) -> str
-  
-  Creates a rule list from the currently active :class:`CRuleSet`.
-  Gets *maxrules* rules from the set :class:`CRuleSet` and passes
-  their code back as string for the script file.
-
-  Adapted from Pieter Spronck's algorithm as explained in
-  Spronck et al: 2005, 'Adaptive Game AI with Dynamic Scripting'.
-
-.. method:: CLearnSystem.create_script (scriptfile, maxrules) -> None
-  
-  Creates a script from the available :class:`CRuleSet` using the
-  passed script file. A maximum of *maxrules* rules will be written.
-  *scriptfile* can be either a file object or filename. In case of
-  a file object it is assumed to be writeable and won't be closed on
-  leaving the function (but flushed).
- 

doc/ref/pycrule.rst

-:class:`CRule` - Rule object
-============================
-.. class:: CRule (id) -> CRule
-
-  Creates a new :class:`CRule` object with the given id.
-  
-  :class:`CRule` is a simple class type that carries a weight indicator
-  and arbitrary code data for usage in the dynamic script generation
-  process.
-
-Attributes
-----------
-
-.. attribute:: CRule.code
-
-  Gets or sets the code of the :class:`CRule`.
-  
-.. attribute:: CRule.id
-
-  Gets the id of the :class:`CRule`.
-  
-.. attribute:: CRule.used
-
-  Indicates whether the :class:`CRule` was used or not.
-  
-.. attribute:: CRule.weight
-
-  Gets or sets the weight of the :class:`CRule`.

doc/ref/pycruleset.rst

-:class:`CRuleSet` - Rule container
-==================================
-.. class:: CRuleSet (minweight, maxweight) -> CRuleSet
-
-  Creates a new, empty :class:`CRuleSet`.
-  
-  :class:`CRuleSet` is a rule container class that manages rules, their
-  weights and the weight distribution for the rules. The *minweight* and
-  *maxweight* parameters are the minimum and maximum weight boundaries,
-  each rule's weight has to stay in.
-
-Attributes
-----------
-
-.. attribute:: CRuleSet.maxweight
-
-  Gets or sets the maximum weight to use for rules.
-  
-.. attribute:: CRuleSet.minweight
-
-  Gets or sets the minimum weight to use for rules.
-
-.. attribute:: CRuleSet.rules
-
-  Gets the list of currently managed :class:`CRule` objects.
-
-.. attribute:: CRuleSet.weight
-
-  Gets the total weight of all managed :class:`CRule` objects.
-
-Methods
--------
-
-.. method:: CRuleSet.add (rule) -> None
-
-  Adds a :class:`CRule` to the :class:`CRuleSet`.
-
-.. method:: CRuleSet.calculate_adjustment (fitness) -> float
-
-  Calculates the reward or penalty, each of the activated rules recives.
-  *fitness* hereby can be used as measure of the performance or whatever
-  is suitable in the implementation.
-  
-  This must be implemented by inheriting classes.
-
-.. method:: CRuleSet.clear () -> None
-
-  Removes all rules from the :class:`CRuleSet`.
-
-.. method:: CRuleSet.distribute_remainder (remainder) -> value
-
-  Distributes the remainder of the weight differences between the
-  last weights and current weights.
-  
-  The method must return a value.
-  This must be implemented by inheriting classes.
-
-.. method:: CRuleSet.find (rid) -> :class:`CRule`
-        
-  Tries to find the :class:`CRule` with the matching id and returns it.
-  In case no :class:`CRule` with the passed id exists, None is returned.
-
-.. method:: CRuleSet.remove (rule) -> None
-
-  Removes a :class:`CRule` from the :class:`CRuleSet`.
-
-.. method:: CRuleSet.update_weights (fitness) -> None
-        
-  Updates the weights of all contained rules.
-
-  Adapted from Pieter Spronck's algorithm as explained in
-  Spronck et al: 2005, 'Adaptive Game AI with Dynamic Scripting'.

doc/ref/pylearnsystem.rst

-:class:`LearnSystem` - Rule script generation
-==============================================
-.. class:: LearnSystem (ruleset) -> LearnSystem
-
-  Creates a new :class:`LearnSystem` using a specific :class:`RuleSet`.
-
-  The :class:`LearnSystem` class takes care of creating new scripts
-  based on a predefined :class:`RuleSet`. It does not evaluate the
-  scripts nor modifies the rules written to them.
-
-  The procedure of creating scripts is done using three phases:
-
-  * header creation
-  * rule code creation
-  * footer creation
-
-  The header and footer are freely choosable. You can simple override
-  or reassign the :meth:`LearnSystem.create_header()` and
-  :meth:`LearnSystem.create_footer()` methods to let them return your
-  required code.
-
-Attributes
-----------
-
-.. attribute:: LearnSystem.maxscriptsize
-
-  Gets or sets the maximum script size (in bytes) for inserting rules.
-  
-.. attribute:: LearnSystem.maxtries
-
-  Gets or sets the maximum amount of tries to insert a script rule.
-  
-.. attribute:: LearnSystem.ruleset
-
-  Gets or sets the :class:`RuleSet` to use.
-
-Methods
--------
-
-.. method:: LearnSystem.create_footer () -> str
-
-  Creates the footer for the script file.
-  
-  The default implementation does nothing.
-
-.. method:: LearnSystem.create_header () -> str
-    
-  Creates the header for the script file.
-  
-  The default implementation does nothing.  
-
-.. method:: LearnSystem.create_rules (maxrules) -> str
-  
-  Creates a rule list from the currently active :class:`RuleSet`.
-  Gets *maxrules* rules from the set :class:`RuleSet` and passes
-  their code back as string for the script file.
-
-  Adapted from Pieter Spronck's algorithm as explained in
-  Spronck et al: 2005, 'Adaptive Game AI with Dynamic Scripting'.
-
-.. method:: LearnSystem.create_script (scriptfile, maxrules) -> None
-  
-  Creates a script from the available :class:`RuleSet` using the
-  passed script file. A maximum of *maxrules* rules will be written.
-  *scriptfile* can be either a file object or filename. In case of
-  a file object it is assumed to be writeable and won't be closed on
-  leaving the function (but flushed).
- 

doc/ref/pymmaprulemanagement.rst

-:class:`MMapRuleManagement` - Memory-mapped rule management
-===========================================================
-.. class:: MMapRuleManagement (maxrules) -> MMapRuleManagement
-    
-    Creates a new :class:`MMapRuleManagement` instance.
-    
-    A simple memory-mapped :class:`RuleManagement` implementation that
-    does not load its rules from an external data source.
-
-    It is an extremely useful class for testing rules and basic algorithms, but
-    due to the in-memory management of all rules, it should not be used in a
-    productive environment, especially if large rule sets have to be managed.
-
-    By default, the :class:`MMapRuleManagement` class will reserve enough memory
-    for the rules to manage, when it is constructed. It will **not** fill the
-    rules with useful values though. It is up to caller to use
-    :meth:`MMapRuleManagement.load_rules()` afterwards and fill the returned
-    :class:`Rule` instances with the necessary data.
-
-Attributes
-----------
-
-.. attribute:: MMapRuleManagement.maxrules
-
-  Gets the maximum amount of rules to manage.
-  
-Methods
--------
-
-.. method:: MMapRuleManagement.load_rules (maxrules=-1) -> [ Rule, Rule ... ]
-
-  Returns the internally managed rules or a certain subset.
-  
-.. method:: MMapRuleManagement.save_rules (rules) -> bool
-        
-  This does nothing and will always return True.
-
-.. method:: MMapRuleManagement.save_rules_hint_file (filename, learnsystem) -> None
-        
-  Saves a :class:`LearnSystem`/:class:`RuleSet` combination to a physical file.

doc/ref/pyrule.rst

-:class:`Rule` - Rule object
-===========================
-.. class:: Rule (id) -> Rule
-
-  Creates a new :class:`Rule` object with the given id.
-  
-  :class:`Rule` is a simple class type that carries a weight indicator
-  and arbitrary code data for usage in the dynamic script generation
-  process.
-
-Attributes
-----------
-
-.. attribute:: Rule.code
-
-  Gets or sets the code of the :class:`Rule`.
-  
-.. attribute:: Rule.id
-
-  Gets the id of the :class:`Rule`.
-  
-.. attribute:: Rule.used
-
-  Indicates whether the :class:`Rule` was used or not.
-  
-.. attribute:: Rule.weight
-
-  Gets or sets the weight of the :class:`Rule`.

doc/ref/pyrulemanagement.rst

-:class:`RuleManagement` - Rule management
-=========================================
-.. class:: RuleManagement (id) -> RuleManagement
-
-    Creates a new, empty :class:`RuleManagement` object.
-
-    The :class:`RuleManagement` class takes care of loading and saving
-    rules from arbitrary data sources.
-    The base is an abstract class, which's
-    :meth:`RuleManagement.load_rules()` method must be implemented
-    according to the specific needs of the application.
-
-Attributes
-----------
-
-.. attribute:: RuleManagement.maxrules
-
-  Gets the maximum amount of rules to manage.
-  
-Methods
--------
-
-.. method:: RuleManagement.load_rules (maxrules=-1) -> [ Rule, Rule ... ]
-
-  Loads rules from the underlying data source and returns them as list.
-  The *maxrules* argument defines the amount of rules to load. If it is
-  smaller than 0, all existing rules should be returned.        
-
-  This must be implemented by inheriting classes.
-  
-.. method:: RuleManagement.save_rules (rules) -> bool
-        
-  Saves the passed rules to the underlying data source and returns True
-  on success or False, if saving the rules was not possible.
-        
-  This must be implemented by inheriting classes.
-
-.. method:: RuleManagement.save_rules_hint_file (filename, learnsystem) -> None
-        
-  Saves a :class:`LearnSystem`/:class:`RuleSet` combination to a physical file.

doc/ref/pyruleset.rst

-:class:`RuleSet` - Rule container
-==================================
-.. class:: RuleSet (minweight, maxweight) -> RuleSet
-
-  Creates a new, empty :class:`RuleSet`.
-  
-  :class:`RuleSet` is a rule container class that manages rules, their
-  weights and the weight distribution for the rules. The *minweight* and
-  *maxweight* parameters are the minimum and maximum weight boundaries,
-  each rule's weight has to stay in.
-
-Attributes
-----------
-
-.. attribute:: RuleSet.maxweight
-
-  Gets or sets the maximum weight to use for rules.
-  
-.. attribute:: RuleSet.minweight
-
-  Gets or sets the minimum weight to use for rules.
-
-.. attribute:: RuleSet.rules
-
-  Gets the list of currently managed :class:`Rule` objects.
-
-.. attribute:: RuleSet.weight
-
-  Gets the total weight of all managed :class:`Rule` objects.
-
-Methods
--------
-
-.. method:: RuleSet.add (rule) -> None
-
-  Adds a :class:`Rule` to the :class:`RuleSet`.
-
-.. method:: RuleSet.calculate_adjustment (fitness) -> float
-
-  Calculates the reward or penalty, each of the activated rules recives.
-  *fitness* hereby can be used as measure of the performance or whatever
-  is suitable in the implementation.
-  
-  This must be implemented by inheriting classes.
-
-.. method:: RuleSet.clear () -> None
-
-  Removes all rules from the :class:`RuleSet`.
-
-.. method:: RuleSet.distribute_remainder (remainder) -> value
-
-  Distributes the remainder of the weight differences between the
-  last weights and current weights.
-  
-  The method must return a value.
-  This must be implemented by inheriting classes.
-
-.. method:: RuleSet.find (rid) -> :class:`Rule`
-        
-  Tries to find the :class:`Rule` with the matching id and returns it.
-  In case no :class:`Rule` with the passed id exists, None is returned.
-
-.. method:: RuleSet.remove (rule) -> None
-
-  Removes a :class:`Rule` from the :class:`RuleSet`.
-
-.. method:: RuleSet.update_weights (fitness) -> None
-        
-  Updates the weights of all contained rules.
-
-  Adapted from Pieter Spronck's algorithm as explained in
-  Spronck et al: 2005, 'Adaptive Game AI with Dynamic Scripting'.
+Todo list for dynrules
+======================
+
+* complete unittests
+* add more examples

dynrules/LearnSystem.py

-##
-## dynrules - Python dynamic rules engine
-##
-## Authors: Marcus von Appen
-##
-## This file is distributed under the Public Domain.
-##
-from random import uniform
-import os
-import sys
-
-try:
-    import cStringIO as stringio
-except ImportError:
-    if sys.version_info[0] >= 3:
-        import io as stringio
-    else:
-        import StringIO as stringio
-
-if sys.version_info[0] >= 3:
-    unicode = str
-
-from dynrules.RuleSet import RuleSet
-
-
-class LearnSystem(object):
-    """The LearnSystem class takes care of creating new scripts based on a
-    predefined RuleSet. It does not evaluate the scripts nor modifies
-    the rules written to them.
-
-    The procedure of creating scripts is done using three phases:
-
-    * header creation
-    * rule code creation
-    * footer creation
-
-    The header and footer are freely choosable. You can simply override
-    or reassign the create_header() and create_footer() methods to let
-    them return your required code.
-    """
-    def __init__(self, ruleset):
-        """Creates a new LearnSystem using a specific RuleSet."""
-        if not isinstance(ruleset, RuleSet):
-            raise TypeError("ruleset must be a RuleSet")
-        self._ruleset = ruleset
-        self._maxtries = 100
-