From ff0c6ad160fb1399d2a33c66b1d27e4cb45af368 Mon Sep 17 00:00:00 2001 From: "marc.andre.gardner" Date: Mon, 16 Jul 2012 15:58:53 -0400 Subject: [PATCH] Added a __setitem__ method in PrimitiveTree to check user input. Currently, these verifications cover three common errors : - Replacing a primitive by another of a different arity - Appending a subtree to the end without changing the current primitives (this will lead to an "unaccessible" part of the tree, meaning that len(ind) will return a different value than len(ind[ind.searchSubtree(0)]), and that some part of the tree will _not_ be evaluated, which can be seriously misleading) - Inserting an incomplete subtree, for instance [add, 1, 2, 3] (considering that add has an arity of 2), which would mess up the tree A quick testing shows virtually no performance loss over the previous (non-checked) method. Also fix a small bug in the C version of the Ant simulator. --HG-- branch : dev --- deap/gp.py | 27 +++++++++++++++++++++++++++ examples/gp/ant/AntSimulatorFast.cpp | 2 ++ examples/gp/ant/buildAntSimFast.py | 4 ++-- 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/deap/gp.py b/deap/gp.py index 814f1f2db..1728831c3 100644 --- a/deap/gp.py +++ b/deap/gp.py @@ -51,6 +51,33 @@ def __deepcopy__(self, memo): new.__dict__.update(copy.deepcopy(self.__dict__, memo)) return new + def __setitem__(self, key, val): + # Check for most common errors + # Does NOT check for STGP constraints + if isinstance(key, slice): + if (key.start >= len(self)): + raise IndexError, "Invalid slice object (try to assign a %s"\ + " in a tree of size %d). Even if this is allowed by the"\ + " list object slice setter, this should not be done in"\ + " the PrimitiveTree context, as this may lead to an"\ + " unpredictable behavior for searchSubtree or evaluate."\ + % (key, len(self)) + total = val[0].arity + for node in val[1:]: + total += node.arity - 1 + if total != 0: + raise ValueError, "Invalid slice assignation : insertion of"\ + " an incomplete subtree is not allowed in PrimitiveTree."\ + " A tree is defined as incomplete when some nodes cannot"\ + " be mapped to any position in the tree, considering the"\ + " primitives' arity. For instance, the tree [sub, 4, 5,"\ + " 6] is incomplete if the arity of sub is 2, because it"\ + " would produce an orphan node (the 6)." + elif val.arity != self[key].arity: + raise ValueError, "Invalid node replacement with a node of a"\ + " different arity." + list.__setitem__(self, key, val) + @property def height(self): """Return the height of the tree, or the depth of the diff --git a/examples/gp/ant/AntSimulatorFast.cpp b/examples/gp/ant/AntSimulatorFast.cpp index fa7168ae4..7ade207a6 100644 --- a/examples/gp/ant/AntSimulatorFast.cpp +++ b/examples/gp/ant/AntSimulatorFast.cpp @@ -367,6 +367,8 @@ PyTypeObject AntSimulatorWrapper_Type = { PyObject* progn(PyObject *self, PyObject *args){ for(Py_ssize_t i = 0; i < PyTuple_Size(args); i++) PyObject_CallFunctionObjArgs(PyTuple_GET_ITEM(args, i), NULL); + Py_INCREF(Py_None); + return Py_None; } static PyMethodDef AntC_functions[] = { diff --git a/examples/gp/ant/buildAntSimFast.py b/examples/gp/ant/buildAntSimFast.py index a7ac202eb..651b412aa 100644 --- a/examples/gp/ant/buildAntSimFast.py +++ b/examples/gp/ant/buildAntSimFast.py @@ -1,9 +1,9 @@ from distutils.core import setup, Extension -module1 = Extension('cAnt', +module1 = Extension('AntC', sources = ['AntSimulatorFast.cpp']) -setup (name = 'cAnt', +setup (name = 'AntC', version = '1.0', description = 'Fast version of the Ant Simulator (aims to replace the AntSimulator class)', ext_modules = [module1])