diff --git a/eo/contrib/mathsym/GNUmakefile b/eo/contrib/mathsym/GNUmakefile index d4acdf17c..1e30a61a8 100644 --- a/eo/contrib/mathsym/GNUmakefile +++ b/eo/contrib/mathsym/GNUmakefile @@ -1,7 +1,7 @@ COMPILEFLAGS=-Wno-deprecated -g -Wall -Wshadow #-DINTERVAL_DEBUG OPTFLAGS= -O2 -DNDEBUG -PROFILE_FLAGS=#-pg +PROFILE_FLAGS=-pg INCLUDES=-I. -Isym -Ifun -Igen -Ieval -Iregression -I../../src -Ieo_interface -I.. @@ -16,9 +16,9 @@ VPATH=sym fun gen eval regression eo_interface CXXSOURCES=FunDef.cpp Sym.cpp SymImpl.cpp SymOps.cpp sym_compile.cpp TreeBuilder.cpp LanguageTable.cpp\ Dataset.cpp ErrorMeasure.cpp Scaling.cpp TargetInfo.cpp BoundsCheck.cpp util.cpp NodeSelector.cpp\ - eoSymCrossover.cpp + eoSymCrossover.cpp sym_operations.cpp eoSymMutate.cpp -PROGRAMS=test/test test/test_compile test/testeo +TESTPROGRAMS=test/test_compile test/testeo test/test_simplify OBJS= $(CXXSOURCES:.cpp=.o) c_compile.o @@ -27,7 +27,7 @@ all: tcc/ symreg include $(CXXSOURCES:.cpp=.d) symreg.d clean: - rm *.o *.d $(PROGRAMS) $(SYMLIB) symreg || true + rm *.o *.d $(TESTPROGRAMS) $(SYMLIB) symreg || true distclean: clean rm -rf tcc @@ -38,11 +38,8 @@ symreg: libsym.a symreg.o $(EXTLIBS) libsym.a: $(OBJS) rm libsym.a; ar cq $(SYMLIB) $(OBJS) -check: $(PROGRAMS) - test/test && test/test_compile && test/testeo && echo "all tests succeeded" - -test/test: test/test.o ${SYMLIB} - $(CXX) -o test/test test/test.o ${SYMLIB} ${LIBS} +check: $(TESTPROGRAMS) + test/test_compile && test/testeo && test_simplify && echo "all tests succeeded" test/test_compile: test/test_compile.o ${SYMLIB} $(CXX) -o test/test_compile test/test_compile.o $(SYMLIB) ${LIBS} @@ -50,6 +47,9 @@ test/test_compile: test/test_compile.o ${SYMLIB} test/testeo: test/testeo.o ${SYMLIB} $(CXX) -o test/testeo test/testeo.o $(SYMLIB) ${LIBS} +test/test_simplify: test/test_simplify.o $(SYMLIB) + $(CXX) -o test/test_simplify test/test_simplify.o $(SYMLIB) ${LIBS} + # eo ../../src/libeo.a: make -C ../../src diff --git a/eo/contrib/mathsym/eo_interface/eoSymMutate.cpp b/eo/contrib/mathsym/eo_interface/eoSymMutate.cpp new file mode 100644 index 000000000..49cc3b288 --- /dev/null +++ b/eo/contrib/mathsym/eo_interface/eoSymMutate.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2005 Maarten Keijzer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +using namespace std; + +std::pair do_mutate(Sym sym, double p, const LanguageTable& table) { + + bool changed = false; + SymVec args = sym.args(); + if (rng.flip(p)) { + token_t new_token = table.get_random_function( args.size()); + if (new_token != sym.token()) changed = true; + sym = Sym(new_token, args); + } + + for (unsigned i = 0; i < args.size(); ++i) { + std::pair r = do_mutate(args[i], p, table); + changed |= r.second; + if (r.second) + args[i] = r.first; + } + + if (changed) + return std::make_pair(Sym(sym.token(), args), true); + // else + return std::make_pair(sym, false); +} + + +// these two can (should?) move to an impl file +bool mutate(Sym& sym, double p, const LanguageTable& table) { + std::pair r = do_mutate(sym, p, table); + sym = r.first; + return r.second; +} + + +bool mutate_constants(Sym& sym, double stdev) { + + vector values = get_constants(sym); + + if (values.empty()) { + return false; + } + + for (unsigned i = 0; i < values.size(); ++i) { + values[i] += rng.normal() * stdev; + } + + sym = set_constants(sym, values); + + return true; +} + diff --git a/eo/contrib/mathsym/eo_interface/eoSymMutate.h b/eo/contrib/mathsym/eo_interface/eoSymMutate.h index 03a95d1d2..e1f9b6201 100644 --- a/eo/contrib/mathsym/eo_interface/eoSymMutate.h +++ b/eo/contrib/mathsym/eo_interface/eoSymMutate.h @@ -53,6 +53,8 @@ class eoSymSubtreeMutate : public eoMonOp { * is_rate_absolute : don't rescale the rate to the size of the tree */ +extern bool mutate(Sym& sym, double p, const LanguageTable& table); + template class eoSymNodeMutate : public eoMonOp { @@ -60,36 +62,7 @@ class eoSymNodeMutate : public eoMonOp { double own_mutation_rate; bool own_is_rate_absolute; - // these two can (should?) move to an impl file - bool mutate(Sym& sym, double p) { - std::pair r = do_mutate(sym, p); - sym = r.first; - return r.second; - } - - std::pair do_mutate(Sym sym, double p) { - - bool changed = false; - SymVec args = sym.args(); - if (rng.flip(p)) { - token_t new_token = table.get_random_function( args.size()); - if (new_token != sym.token()) changed = true; - sym = Sym(new_token, args); - } - for (unsigned i = 0; i < args.size(); ++i) { - std::pair r = do_mutate(args[i], p); - changed |= r.second; - if (r.second) - args[i] = r.first; - } - - if (changed) - return std::make_pair(Sym(sym.token(), args), true); - // else - return std::make_pair(sym, false); - } - public: double& mutation_rate; @@ -114,9 +87,29 @@ class eoSymNodeMutate : public eoMonOp { double p = mutation_rate; if (!is_rate_absolute) p /= _eo.size(); - return mutate(_eo, p); + return mutate(_eo, p, table); } }; +/** + * Simple constant mutation class, adds gaussian noise (configurable variance) to the individuals + **/ +extern bool mutate_constants(Sym& sym, double stdev); +template +class eoSymConstantMutate : public eoMonOp { + + double& stdev; + + + public : + eoSymConstantMutate(double& _stdev) : stdev(_stdev) {} + + bool operator()(EoType& _eo) { + return mutate_constants(_eo, stdev); + } + + +}; + #endif diff --git a/eo/contrib/mathsym/eval/sym_compile.cpp b/eo/contrib/mathsym/eval/sym_compile.cpp index 81254e5fc..4d3ce9161 100644 --- a/eo/contrib/mathsym/eval/sym_compile.cpp +++ b/eo/contrib/mathsym/eval/sym_compile.cpp @@ -45,7 +45,7 @@ string make_prototypes() { return prot; } -// contains variable names, like 'a0', 'a1', etc. +// contains variable names, like 'a0', 'a1', etc. or regular code typedef hash_map HashMap; HashMap::iterator find_entry(Sym sym, ostream& os, HashMap& map) { diff --git a/eo/contrib/mathsym/fun/FunDef.cpp b/eo/contrib/mathsym/fun/FunDef.cpp index b2ac4f4da..967f5986f 100644 --- a/eo/contrib/mathsym/fun/FunDef.cpp +++ b/eo/contrib/mathsym/fun/FunDef.cpp @@ -287,7 +287,7 @@ Sym set_constants(Sym sym, vector::const_iterator& it) { SymVec args = sym.args(); for (unsigned i = 0; i < args.size(); ++i) { - args[i] = set_constants(sym, it); + args[i] = set_constants(args[i], it); } return Sym(token, args); diff --git a/eo/contrib/mathsym/fun/FunDef.h b/eo/contrib/mathsym/fun/FunDef.h index 997f1ebf8..6fa1c248f 100644 --- a/eo/contrib/mathsym/fun/FunDef.h +++ b/eo/contrib/mathsym/fun/FunDef.h @@ -85,6 +85,12 @@ extern bool is_constant(token_t token); /** Create variable */ extern Sym SymVar(unsigned idx); +/** simplifies a sym (sym_operations.cpp) */ +extern Sym simplify(Sym sym); + +/** differentiates a sym to a token (sym_operations.cpp) */ +extern Sym differentiate(Sym sym, token_t var_token); + /* Add function to the language table (and take a guess at the arity) */ class LanguageTable; extern void add_function_to_table(LanguageTable& table, token_t token); diff --git a/eo/contrib/mathsym/fun/sym_operations.cpp b/eo/contrib/mathsym/fun/sym_operations.cpp new file mode 100644 index 000000000..dba1de30a --- /dev/null +++ b/eo/contrib/mathsym/fun/sym_operations.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2005 Maarten Keijzer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +using namespace std; + +Sym simplify_constants(Sym sym) { + + SymVec args = sym.args(); + token_t token = sym.token(); + + bool has_changed = false; + bool all_constants = true; + + for (unsigned i = 0; i < args.size(); ++i) { + + Sym arg = simplify_constants(args[i]); + + if (arg != args[i]) { + has_changed = true; + } + args[i] = arg; + + + all_constants &= is_constant(args[i].token()); + } + + if (args.size() == 0) return sym; // variable or constant + + + if (all_constants) { + // evaluate + + vector dummy; + + vector vals(args.size()); + for (unsigned i = 0; i < vals.size(); ++i) { + vals[i] = eval(sym, dummy); + } + + Sym result = SymConst( get_element(token).eval(vals, dummy) ); + + + return result; + } + + if (has_changed) { + return Sym(token, args); + } + + return sym; + +} + +// currently only simplifies constants +Sym simplify(Sym sym) { + + return simplify_constants(sym); + +} + diff --git a/eo/contrib/mathsym/regression/ErrorMeasure.cpp b/eo/contrib/mathsym/regression/ErrorMeasure.cpp index b6a5795f4..b5937ce8c 100644 --- a/eo/contrib/mathsym/regression/ErrorMeasure.cpp +++ b/eo/contrib/mathsym/regression/ErrorMeasure.cpp @@ -167,17 +167,43 @@ class ErrorMeasureImpl { } vector calc_error(const vector& pop) { - + + // first declone + typedef hash_map HashMap; + + HashMap clone_map; + vector decloned; + decloned.reserve(pop.size()); + + for (unsigned i = 0; i < pop.size(); ++i) { + HashMap::iterator it = clone_map.find(pop[i]); + + if (it == clone_map.end()) { // new + clone_map[ pop[i] ] = decloned.size(); + decloned.push_back(pop[i]); + } + + } + + // evaluate + vector dresult; // currently we can only accumulate simple measures such as absolute and mean_squared switch(measure) { case ErrorMeasure::mean_squared: case ErrorMeasure::absolute: - return multi_function_eval(pop); + dresult = multi_function_eval(decloned); + break; case ErrorMeasure::mean_squared_scaled: - return single_function_eval(pop); + dresult = single_function_eval(decloned); + break; } - return vector(); + vector result(pop.size()); + for (unsigned i = 0; i < result.size(); ++i) { + result[i] = dresult[ clone_map[pop[i]] ]; + } + + return result; } }; diff --git a/eo/contrib/mathsym/symreg.cpp b/eo/contrib/mathsym/symreg.cpp index 35430f502..0416b9c6f 100644 --- a/eo/contrib/mathsym/symreg.cpp +++ b/eo/contrib/mathsym/symreg.cpp @@ -244,10 +244,16 @@ int main(int argc, char* argv[]) { NodeSelector& node_selector = select(use_uniform, random_sel, biased_sel); - eoProportionalOp genetic_operator; + //eoProportionalOp genetic_operator; + eoSequentialOp genetic_operator; eoSymSubtreeMutate submutate(builder, node_selector); genetic_operator.add( submutate, subtree_mut_prob); + + // todo, make this parameter, etc + double std = 0.01; + eoSymConstantMutate constmutate(std); + genetic_operator.add( constmutate, 0.1); eoSymNodeMutate nodemutate(table); genetic_operator.add(nodemutate, node_mut_prob);