Added monitors and statistics, also made a module with some

specific python stuff in __init__.py
This commit is contained in:
maartenkeijzer 2003-01-10 15:41:17 +00:00
commit ea2e369542
19 changed files with 503 additions and 47 deletions

View file

@ -26,24 +26,25 @@
CXX = g++ #-3.2
CXXFLAGS = #-g #-DNDEBUG
CPPFLAGS = -Wall -O2
CPPFLAGS = -Wall -O2 #-g #-O2
LDFLAGS =
COMPILE = $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c
LINK = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS)
INC=-I/usr/include/python2.2 -I/usr/include/stlport -I.. -ftemplate-depth-50
INC=-I/usr/include/python2.2 -I.. -ftemplate-depth-50 -I/usr/include/stlport
OBJECTS=eoFunctorStore.o PyEO.o abstract1.o algos.o \
random_numbers.o geneticOps.o selectOne.o continuators.o\
reduce.o replacement.o selectors.o breeders.o\
mergers.o valueParam.o perf2worth.o
mergers.o valueParam.o perf2worth.o monitors.o\
statistics.o
all: PyEO.so
all: PyEO/PyEO.so
clean:
rm *.so *.o test/*.pyc
PyEO.so: $(OBJECTS)
$(LINK) -o PyEO.so $(OBJECTS) -lboost_python -lpython2.2 -shared -lstlport
PyEO/PyEO.so: $(OBJECTS)
$(LINK) -o PyEO/PyEO.so $(OBJECTS) -lboost_python -lpython2.2 -shared -lstlport
eoFunctorStore.o: ../eoFunctorStore.h ../eoFunctorStore.cpp
$(COMPILE) -o eoFunctorStore.o ../eoFunctorStore.cpp $(INC)

View file

@ -11,7 +11,8 @@ INC=-I/usr/include/python2.2 -I/usr/include/stlport -I.. -ftemplate-depth-50
OBJECTS=eoFunctorStore.o PyEO.o abstract1.o algos.o \
random_numbers.o geneticOps.o selectOne.o continuators.o\
reduce.o replacement.o selectors.o breeders.o\
mergers.o valueParam.o perf2worth.o
mergers.o valueParam.o perf2worth.o monitors.o\
statistics.o
all: PyEO.so

View file

@ -156,6 +156,8 @@ extern void breeders();
extern void mergers();
extern void valueParam();
extern void perf2worth();
extern void monitors();
extern void statistics();
BOOST_PYTHON_MODULE(PyEO)
{
@ -170,7 +172,7 @@ BOOST_PYTHON_MODULE(PyEO)
.def("__str__", &PyEO::to_string)
;
class_<eoPop<PyEO> >("Pop", init<>() )
class_<eoPop<PyEO> >("eoPop", init<>() )
.def( init< unsigned, eoInit<PyEO>& >() )
.def("append", &eoPop<PyEO>::append)
.def("__str__", to_string<eoPop<PyEO> >)
@ -195,6 +197,8 @@ BOOST_PYTHON_MODULE(PyEO)
selectOne();
selectors();
perf2worth();
monitors();
statistics();
continuators();
reduce();
replacement();

View file

@ -23,6 +23,7 @@
#include <EO.h>
#include <string>
#include <vector>
#include <boost/python.hpp>

View file

@ -0,0 +1,87 @@
from PyEO import *
try:
import Gnuplot
except ImportError:
print "Python support for Gnuplot not found"
else:
class eoGnuplot1DMonitor(eoMonitor):
def __init__(self):
eoMonitor.__init__(self)
self.values = []
self.indices = []
self.g = Gnuplot.Gnuplot()
self.g.reset();
def handleParam(self, i, param):
param = float(param)
while len(self.values) <= i:
self.values.append( [] )
self.values[i].append(param)
def __call__(self):
l = len(self)
if l > 3 or l == 0:
print 'Can only handle 1 to 3 params currently'
i = 0
for param in self:
self.handleParam(i,param)
i += 1
self.indices.append( len(self.indices) )
data1 = Gnuplot.Data(self.indices, self.values[0], with = 'lines')
if l == 1:
self.g.plot(data1)
else:
data2 = Gnuplot.Data(self.indices, self.values[1], with = 'lines')
if l == 2:
self.g.plot(data1, data2)
else:
data3 = Gnuplot.Data(self.indices, self.values[2], with = 'lines')
self.g.plot(data1, data2, data3)
def SeperatedVolumeMonitor(eoMonitor):
def __init__(self, file):
eoMonitor.__init__(self)
self.file = file
self.initialized = None;
def __call__(self):
pass
class eoStat(eoStatBase, eoValueParamPy):
def __init__(self):
eoStatBase.__init__(self)
eoValueParamPy.__init__(self)
class eoSortedStat(eoSortedStatBase, eoValueParamPy):
def __init__(self):
eoSortedStatBase.__init__(self)
eoValueParamPy.__init__(self)
class eoAverageStat(eoStat):
def __call__(self, pop):
sum = 0.0;
for indy in pop:
sum += indy.fitness
sum /= len(pop)
self.object = sum
class eoBestFitnessStat(eoSortedStat):
def __call__(self, pop):
self.object = pop[0].fitness

View file

@ -23,6 +23,8 @@
#include <eoEvalContinue.h>
#include <eoFitContinue.h>
#include <eoSteadyFitContinue.h>
#include <utils/eoCheckPoint.h>
#include <utils/eoStat.h>
#include "PyEO.h"
#include "def_abstract_functor.h"
@ -31,6 +33,8 @@
#define DEF2(x, i1) class_<x<PyEO>, bases<eoContinue<PyEO > > >(#x, init<i1>() ).def("__call__", &eoContinue<PyEO>::operator())
#define DEF3(x, i1, i2) class_<x<PyEO>, bases<eoContinue<PyEO > > >(#x, init<i1, i2 >() ).def("__call__", &eoContinue<PyEO>::operator())
void add_checkpoint();
void continuators()
{
/* Counters, wrappers etc */
@ -60,4 +64,23 @@ void continuators()
DEF2(eoFitContinue, object); // object is the fitness type
DEF3(eoSteadyFitContinue, unsigned long, unsigned long);
add_checkpoint();
}
void addContinue(eoCheckPoint<PyEO>& c, eoContinue<PyEO>& cc) { c.add(cc); }
void addMonitor(eoCheckPoint<PyEO>& c, eoMonitor& m) { c.add(m);}
void addStat(eoCheckPoint<PyEO>& c, eoStatBase<PyEO>& s) { c.add(s);}
void addSortedStat(eoCheckPoint<PyEO>& c, eoSortedStatBase<PyEO>& s) { c.add(s);}
void add_checkpoint()
{
class_<eoCheckPoint<PyEO>, bases< eoContinue<PyEO> > >("eoCheckPoint",
init<eoContinue<PyEO>&>())
.def("add", addContinue)
.def("add", addMonitor, with_custodian_and_ward<1,2>() )
.def("add", addStat)
.def("add", addSortedStat)
.def("__call__", &eoCheckPoint<PyEO>::operator())
;
}

View file

@ -18,11 +18,53 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <utils/eoParam.h>
#include <utils/eoMonitor.h>
#include "PyEO.h"
class MonitorWrapper : public eoMonitor
{
public:
PyObject* self;
list objects;
MonitorWrapper(PyObject* p) :self(p) {}
eoMonitor& operator()()
{
call_method<void>(self, "__call__");
return *this;
}
std::string getString(int i)
{
if (static_cast<unsigned>(i) >= vec.size())
{
throw index_error("Index out of bounds");
}
return vec[i]->getValue();
}
unsigned size() { return vec.size(); }
};
void monitors()
{
/**
* Change of interface: I encountered some difficulties with
* transferring eoParams from and to Python, so now we can
* only get at the strings contained in the eoParams.
* sorry
*/
class_<eoMonitor, MonitorWrapper, boost::noncopyable>("eoMonitor", init<>())
.def("lastCall", &eoMonitor::lastCall)
.def("add", &eoMonitor::add)
.def("__call__", &MonitorWrapper::operator(), return_internal_reference<1>() )
.def("__getitem__", &MonitorWrapper::getString,
"Returns the string value of the indexed Parameter")
.def("__len__", &MonitorWrapper::size)
;
}

View file

@ -57,12 +57,17 @@ struct CachedPerf2WorthWrapper : public eoPerf2WorthCached<PyEO, double>
void perf2worth()
{
numeric::array::set_module_and_type("Numeric", "ArrayType");
//numeric::array::set_module_and_type("Numeric", "ArrayType");
class_<eoPerf2Worth<PyEO, double>, Perf2WorthWrapper, boost::noncopyable>("eoPerf2Worth", init<>())
.def("__call__", &Perf2WorthWrapper::operator())
.def("sort_pop", &eoPerf2Worth<PyEO, double>::sort_pop)
.def("value", get_worths)
class_<
eoPerf2Worth<PyEO, double>,
Perf2WorthWrapper,
bases< eoValueParam<std::vector<double> > >,
boost::noncopyable>("eoPerf2Worth", init<>())
.def("__call__", &Perf2WorthWrapper::operator())
.def("sort_pop", &eoPerf2Worth<PyEO, double>::sort_pop)
//.def("value", get_worths)
;
class_<eoPerf2WorthCached<PyEO, double>, CachedPerf2WorthWrapper, bases<eoPerf2Worth<PyEO, double> >, boost::noncopyable>

View file

@ -0,0 +1,61 @@
#include <utils/eoStat.h>
#include "PyEO.h"
#include "valueParam.h"
class StatBaseWrapper : public eoStatBase<PyEO>
{
public:
PyObject* self;
StatBaseWrapper(PyObject* p) : self(p) {}
void operator()(const eoPop<PyEO>& pop)
{
call_method<void>(self, "__call__", boost::ref(pop));
}
};
class SortedStatBaseWrapper : public eoSortedStatBase<PyEO>
{
public:
PyObject* self;
SortedStatBaseWrapper(PyObject* p) : self(p) {}
void operator()(const std::vector<const PyEO*>& pop)
{
call_method<void>(self, "__call__", boost::ref(pop));
}
};
typedef std::vector<const PyEO*> eoPopView;
const PyEO& popview_getitem(const std::vector<const PyEO*>& pop, int it)
{
unsigned item = unsigned(it);
if (item > pop.size())
throw index_error("too much");
return *pop[item];
}
void statistics()
{
class_<eoStatBase<PyEO>, StatBaseWrapper, boost::noncopyable>
("eoStatBase", init<>())
.def("lastCall", &eoStatBase<PyEO>::lastCall)
.def("__call__", &StatBaseWrapper::operator())
;
class_< eoPopView >("eoPopView")
.def("__getitem__", popview_getitem, return_internal_reference<>() )
.def("__len__", &eoPopView::size)
;
class_<eoSortedStatBase<PyEO>, SortedStatBaseWrapper, boost::noncopyable>
("eoSortedStatBase", init<>())
.def("lastCall", &eoSortedStatBase<PyEO>::lastCall)
.def("__call__", &SortedStatBaseWrapper::operator())
;
}

View file

@ -8,10 +8,20 @@ print 'done'
from copy import copy
class MinimFit(float):
def __cmp__(self, other):
if other == None: # I seem to be getting None's, don't know why
return 1
return float.__cmp__(other, self)
class EvalFunc(eoEvalFunc):
def __call__(self, eo):
eo.fitness = reduce(lambda x,y: x+y, eo.genome, 0)
class MinEvalFunc(eoEvalFunc):
def __call__(self, eo):
f = reduce(lambda x,y: x+y, eo.genome, 0 )
eo.fitness = MinimFit(f)
class Init(eoInit):
def __init__(self, genome_length = 10):
@ -68,7 +78,7 @@ if __name__ == '__main__':
print
print
pop = Pop(1, init)
pop = eoPop(1, init)
pop[0] = eo;

View file

@ -2,7 +2,8 @@
for i in *.py
do
python $i
python $i > /dev/null
done

View file

@ -10,10 +10,10 @@ class TestSGA(unittest.TestCase):
def runtest(self, breed):
pop = Pop(50, init)
pop = eoPop(50, init)
for indy in pop: evaluate(indy)
newpop = Pop();
newpop = eoPop();
breed(pop,newpop)
@ -33,5 +33,9 @@ class TestSGA(unittest.TestCase):
self.runtest(breed)
def suite():
return unittest.makeSuite(TestSGA,'test')
if __name__=='__main__':
unittest.main()

View file

@ -1,7 +1,115 @@
from maxone import *
from math import exp
import unittest
class TestSGA(unittest.TestCase):
class MyInit(eoInit):
def __call__(self, eo):
eo.genome = [rng().normal(), rng().normal(), rng().normal()];
class MyMutate(eoMonOp):
def __call__(self, eo):
std = 0.05
eo.genome = copy(eo.genome)
eo.genome[0] += rng().normal() * std
eo.genome[1] += rng().normal() * std
eo.genome[2] += rng().normal() * std
return 1
class AnEval(eoEvalFunc):
def __init__(self):
eoEvalFunc.__init__(self)
setObjectivesSize(2);
setObjectivesValue(0,1);
setObjectivesValue(1,1);
def __call__(self, eo):
x = abs(eo.genome[0])
y = abs(eo.genome[1])
z = abs(eo.genome[2])
eo.fitness = [ x / (x+y+z), y /(x+y+z) ]
import Gnuplot
g = Gnuplot.Gnuplot()
g.reset()
def do_plot(pop):
l1 = []
l2 = []
for indy in pop:
l1.append(indy.fitness[0])
l2.append(indy.fitness[1])
d = Gnuplot.Data(l1,l2, with = 'points')
d2 = Gnuplot.Data([0,1],[1,0], with='lines')
g.plot(d,d2)
class NSGA_II(eoAlgo):
def __init__(self, ngens):
self.cont = eoGenContinue(ngens);
self.selectOne = eoDetTournamentSelect(2);
self.evaluate = AnEval()
self.mutate = MyMutate()
self.init = MyInit()
self.seq = eoProportionalOp()
self.seq.add(self.mutate, 1.0)
self.perf2worth = eoNDSorting_II()
def __call__(self, pop):
sz = len(pop)
i = 0
while self.cont(pop):
newpop = eoPop()
populator = eoSelectivePopulator(pop, newpop, self.selectOne);
while len(newpop) < sz:
self.seq(populator)
for indy in newpop:
self.evaluate(indy)
pop.push_back(indy)
self.perf2worth(pop)
self.perf2worth.sort_pop(pop)
#print pop[0].fitness, pop[0].genome
pop.resize(sz)
#worth = self.perf2worth.getValue()
#print worth[0], worth[sz-1]
i += 1
if i%100 == 0:
pass #do_plot(pop)
worths = self.perf2worth.getValue()
w0 = int(worths[0]-0.001)
for i in range(len(pop)):
if worths[i] <= w0:
break;
print pop[i].genome
print pop[i].fitness
class TestNSGA_II(unittest.TestCase):
def testIndividuals(self):
setObjectivesSize(2);
@ -26,12 +134,11 @@ class TestSGA(unittest.TestCase):
self.failUnlessEqual(dominates(eo2, eo2), 0)
def testNDSorting(self):
setObjectivesSize(2);
setObjectivesValue(0,-1)
setObjectivesValue(1,-1);
pop = Pop()
pop = eoPop()
pop.resize(6)
pop[5].fitness = [0.15,0.87]
@ -50,10 +157,20 @@ class TestSGA(unittest.TestCase):
print indy.fitness
worths = srt.value()
worths = srt.getValue()
print worths
print type(worths)
def testNSGA_II(self):
init = MyInit();
evaluate = AnEval();
pop = eoPop(25, init)
for indy in pop: evaluate(indy)
nsga = NSGA_II(50)
nsga(pop)
if __name__=='__main__':
unittest.main()

View file

@ -48,7 +48,7 @@ class TestPickling(unittest.TestCase):
def testPop(self):
pop = Pop(40, init)
pop = eoPop(40, init)
for indy in pop:
evaluate(indy)

View file

@ -22,7 +22,7 @@ class Xover(Crossover):
class TestPopulator(unittest.TestCase):
def make_pop(self):
pop = Pop(20, init)
pop = eoPop(20, init)
for indy in pop: evaluate(indy)
return pop
@ -57,7 +57,7 @@ class TestPopulator(unittest.TestCase):
seq.add(xover, 0.8)
pop = self.make_pop();
offspring = Pop()
offspring = eoPop()
sel = eoDetTournamentSelect(2)

View file

@ -4,7 +4,7 @@ import unittest
class TestReduce(unittest.TestCase):
def run_test(self, ReduceClass, Arg = None):
pop = Pop(10, init)
pop = eoPop(10, init)
for indy in pop: evaluate(indy)
if Arg:

View file

@ -9,7 +9,7 @@ class TestSGA(unittest.TestCase):
def __init__(self, a):
unittest.TestCase.__init__(self, a)
self.pop = Pop(4, Init())
self.pop = eoPop(4, Init())
for i in range(len(self.pop)):
self.pop[i].fitness = i;

View file

@ -3,23 +3,42 @@ import unittest
class TestSGA(unittest.TestCase):
def test(self):
evaluate = EvalFunc()
def dotestSGA(self, evaluate):
init = Init(20)
mutate = Mutate()
xover = Crossover()
pop = Pop(50, init)
pop = eoPop(50, init)
for indy in pop: evaluate(indy)
select = eoDetTournamentSelect(3);
cont = eoGenContinue(20);
cont1 = eoGenContinue(20);
cont = eoCheckPoint(cont1)
mon = eoGnuplot1DMonitor()
avg = eoAverageStat()
bst = eoBestFitnessStat()
mon.add(avg)
mon.add(bst)
# add it to the checkpoint
cont.add(avg)
#cont.add(mon)
cont.add(bst)
sga = eoSGA(select, xover, 0.6, mutate, 0.4, evaluate, cont);
sga(pop)
print pop.best()
def testSGA_Max(self):
evaluate = EvalFunc()
self.dotestSGA(evaluate)
def testSGA_Min(self):
evaluate = MinEvalFunc()
self.dotestSGA(evaluate)
if __name__=='__main__':
unittest.main()

View file

@ -19,7 +19,12 @@
*/
#include <utils/eoParam.h>
#include <boost/python.hpp>
#include <stdexcept>
// Here's 'len'. Why? dunno
#include "valueParam.h"
#include <boost/python/detail/api_placeholder.hpp>
using namespace boost::python;
@ -38,31 +43,92 @@ public:
std::string getValue() const
{
return call_method<std::string>(self, "getValue");
return call_method<std::string>(self, "getValueAsString");
}
void setValue(std::string s)
{
call_method<void>(self, "setValue", s);
call_method<void>(self, "setValueAsString", s);
}
};
template <class T> T getv(const eoValueParam<T>& v) { return v.value(); }
template <class T> void setv(eoValueParam<T>& v, T val) { v.value() = val; }
template <class T>
template <class T, class U>
U getv(const eoValueParam<T>& v) { return v.value(); }
template <class T, class U>
void setv(eoValueParam<T>& v, U val) { v.value() = val; }
template <>
numeric::array getv< std::vector<double>, numeric::array >
(const eoValueParam< std::vector<double> >& param)
{
const std::vector<double>& v = param.value();
list result;
for (unsigned i =0; i < v.size(); ++i)
result.append(v[i]);
return numeric::array(result);
}
template <>
void setv< std::vector<double>, numeric::array >
(eoValueParam< std::vector<double> >& param, numeric::array val)
{
std::vector<double>& v = param.value();
v.resize( boost::python::len(val) );
for (unsigned i = 0; i < v.size(); ++i)
{
extract<double> x(val[i]);
if (!x.check())
throw std::runtime_error("double expected");
v[i] = x();
}
}
template <>
tuple getv<std::pair<double, double>, tuple >
(const eoValueParam< std::pair<double,double> >& p)
{
return make_tuple(p.value().first, p.value().second);
}
template <>
void setv< std::pair<double, double>, tuple >
(eoValueParam< std::pair<double,double> >& p, tuple val)
{
extract<double> first(val[0]);
extract<double> second(val[1]);
if (!first.check())
throw std::runtime_error("doubles expected");
if (!second.check())
throw std::runtime_error("doubles expected");
p.value().first = first();
p.value().second = second();
}
template <class T, class U>
void define_valueParam(std::string prefix)
{
class_<eoValueParam<T>, bases<eoParam> >( (prefix + "ValueParam").c_str(), init<>())
std::string name = "eoValueParam";
name += prefix;
class_<eoValueParam<T>, bases<eoParam> >(name.c_str(), init<>())
.def(init<T, std::string, std::string, char, bool>())
.def(init<T, std::string, std::string, char>())
.def(init<T, std::string, std::string>())
.def(init<T, std::string>())
.def("getValue", &eoValueParam<T>::getValue)
.def("getValueAsString", &eoValueParam<T>::getValue)
.def("__str__", &eoValueParam<T>::getValue)
.def("setValue", &eoValueParam<T>::setValue)
//.add_property("value", getv<T>, setv<T>)
.def("setValueAsString", &eoValueParam<T>::setValue)
.def("getValue", getv<T, U>)
.def("setValue", setv<T, U>)
//.add_property("value", getv<T, U>, setv<T, U>)
;
}
@ -70,8 +136,8 @@ void valueParam()
{
class_<eoParam, ParamWrapper, boost::noncopyable>("eoParam", init<>())
.def(init< std::string, std::string, std::string, char, bool>())
.def("getValue", &ParamWrapper::getValue)
.def("setValue", &ParamWrapper::setValue)
.def("getValueAsString", &ParamWrapper::getValue)
.def("setValueAsString", &ParamWrapper::setValue)
.def("longName", &eoParam::longName, return_value_policy<copy_const_reference>())
//.def("defValue", &eoParam::defValue, return_value_policy<copy_const_reference>())
.def("description", &eoParam::description, return_value_policy<copy_const_reference>())
@ -79,7 +145,21 @@ void valueParam()
.def("required", &eoParam::required)
;
define_valueParam<int>("int");
define_valueParam<std::vector<double> >("vec");
define_valueParam<int, int>("Int");
define_valueParam<double, double>("Float");
define_valueParam<std::vector<double>, numeric::array >("Vec");
define_valueParam< std::pair<double, double>, tuple >("Pair");
class_<ValueParam, bases<eoParam> >("eoValueParamPy", init<>())
//.def(init<object, std::string, std::string, char, bool>())
//.def(init<object, std::string, std::string, char>())
//.def(init<object, std::string, std::string>())
//.def(init<object, std::string>())
.def("getValueAsString", &ValueParam::getValue)
.def("__str__", &ValueParam::getValue)
.def("setValueAsString", &ValueParam::setValue)
.add_property("object", &ValueParam::getObj, &ValueParam::setObj)
;
}