Solved some issues and prepared the library for using unordered_map instead of hash_map (C++ TR1). Can only use this when g++-4.0.3 is out

This commit is contained in:
maartenkeijzer 2005-10-15 21:27:47 +00:00
commit bac6644915
11 changed files with 149 additions and 33 deletions

View file

@ -1,7 +1,7 @@
COMPILEFLAGS=-Wno-deprecated -g -Wall -Wshadow #-DINTERVAL_DEBUG
OPTFLAGS= -O3 -DNDEBUG
COMPILEFLAGS=-Wno-deprecated -g -Wall #-DINTERVAL_DEBUG
OPTFLAGS= #-O3 -DNDEBUG
PROFILE_FLAGS=-pg
PROFILE_FLAGS=#-pg
INCLUDES=-I. -Isym -Ifun -Igen -Ieval -Iregression -I../../src -Ieo_interface -I..
@ -33,7 +33,7 @@ distclean: clean
rm -rf tcc
symreg: libsym.a symreg.o $(EXTLIBS)
$(CXX) -o symreg symreg.o libsym.a $(LIBS) $(PROFILE_FLAGS)
$(CXX) -o symreg symreg.o libsym.a $(LIBS) $(PROFILE_FLAGS)
libsym.a: $(OBJS)
rm libsym.a; ar cq $(SYMLIB) $(OBJS)

View file

@ -33,20 +33,20 @@ class EoSym : public EO<Fitness>, public Sym {
static_cast<Sym*>(this)->operator=(sym);
}
virtual void printOn(ostream& os) const;
virtual void readFrom(istream& is);
virtual void printOn(std::ostream& os) const;
virtual void readFrom(std::istream& is);
};
template <class Fitness>
void EoSym<Fitness>::printOn(ostream& os) const {
void EoSym<Fitness>::printOn(std::ostream& os) const {
EO<Fitness>::printOn(os);
os << ' ';
write_raw(os, *this);
}
template <class Fitness>
void EoSym<Fitness>::readFrom(istream& is) {
void EoSym<Fitness>::readFrom(std::istream& is) {
EO<Fitness>::readFrom(is);
read_raw(is, *this);
}
@ -54,7 +54,7 @@ void EoSym<Fitness>::readFrom(istream& is) {
template <class Fitness>
inline std::ostream& operator<<(std::ostream& os, const EoSym<Fitness>& f) { f.printOn(os); return os; }
template <class Fitness>
inline istream& operator>>(std::istream& is, EoSym<Fitness>& f) { f.readFrom(is); return is; }
inline std::istream& operator>>(std::istream& is, EoSym<Fitness>& f) { f.readFrom(is); return is; }
#endif

View file

@ -39,9 +39,14 @@ string make_prototypes() {
}
// contains variable names, like 'a0', 'a1', etc. or regular code
typedef hash_map<Sym, string, HashSym> HashMap;
HashMap::iterator find_entry(Sym sym, ostream& os, HashMap& map) {
#if USE_TR1
typedef std::tr1::unordered_map<Sym, string, HashSym> HashMap;
#else
typedef hash_map<Sym, string, HashSym> HashMap;
#endif
HashMap::iterator find_entry(const Sym& sym, ostream& os, HashMap& map) {
HashMap::iterator result = map.find(sym);
if (result == map.end()) { // new entry
@ -68,13 +73,82 @@ HashMap::iterator find_entry(Sym sym, ostream& os, HashMap& map) {
return result;
}
void write_entry(Sym sym, ostream& os, HashMap& map, unsigned out) {
HashMap::iterator it = find_entry(sym, os, map);
// prints 'num' in reverse notation. Does not matter as it's a unique id
string make_var(unsigned num) {
string str = "a";
do {
str += char('0' + (num % 10));
num /= 10;
} while (num);
return str;
}
HashMap::iterator find_entry2(const Sym& sym, string& str, HashMap& map) {
HashMap::iterator result = map.find(sym);
if (result == map.end()) { // new entry
const SymVec& args = sym.args();
vector<string> argstr(args.size());
for (unsigned i = 0; i < args.size(); ++i) {
argstr[i] = find_entry2(args[i], str, map)->second;
}
string var = make_var(map.size()); // map.size(): unique id
// write out the code
const FunDef& fun = get_element(sym.token());
string code = fun.c_print(argstr, vector<string>() );
str += "double " + var + "=" + code + ";\n";
result = map.insert( make_pair(sym, var ) ).first; // only want iterator
}
return result;
}
void write_entry(const Sym& sym, ostream& os, HashMap& map, unsigned out) {
string s;
HashMap::iterator it = find_entry2(sym, s, map);
os << s;
os << "y[" << out << "]=" << it->second << ";\n";
}
template <class T>
string to_string(T t) {
ostringstream os;
os << t;
return os.str();
}
void write_entry(const Sym& sym, string& str, HashMap& map, unsigned out) {
HashMap::iterator it = find_entry2(sym, str, map);
str += "y[" + to_string(out) + "]=" + it->second + ";\n";
}
multi_function compile(const std::vector<Sym>& syms) {
// static stream to avoid fragmentation of these LARGE strings
static string str;
str += make_prototypes();
str += "double func(const double* x, double* y) { \n ";
HashMap map(Sym::get_dag().size());
for (unsigned i = 0; i < syms.size(); ++i) {
write_entry(syms[i], str, map, i);
}
str += ";}";
return (multi_function) symc_make(str.c_str(), "func");
}
multi_function compile2(const std::vector<Sym>& syms) {
// static stream to avoid fragmentation of these LARGE strings
static ostringstream os;
os.str("");
@ -83,7 +157,8 @@ multi_function compile(const std::vector<Sym>& syms) {
os << "double func(const double* x, double* y) { \n ";
HashMap map;
HashMap map(Sym::get_dag().size());
for (unsigned i = 0; i < syms.size(); ++i) {
write_entry(syms[i], os, map, i);
@ -143,7 +218,7 @@ void compile(const std::vector<Sym>& syms, std::vector<single_function>& functio
os.str("");
os << make_prototypes();
HashMap map;
HashMap map(Sym::get_dag().size());
for (unsigned i = 0; i < syms.size(); ++i) {
os << "double func" << i << "(const double* x) { return ";

View file

@ -120,7 +120,11 @@ struct HashDouble{
}
};
#if USE_TR1
typedef std::tr1::unordered_map<double, token_t> DoubleSet;
#else
typedef hash_map<double, token_t, HashDouble> DoubleSet;
#endif
static DoubleSet doubleSet; // for quick checking if a constant already exists
static vector<bool> is_constant_flag;
@ -186,6 +190,7 @@ bool is_constant(token_t token) {
extern Sym default_const() { return SymConst(rng.normal()); }
/* The functions */
namespace {
class Var : public FunDef {
public :
@ -247,7 +252,8 @@ class Const : public FunDef {
string name() const { return "parameter"; }
};
} // namespace
void get_constants(Sym sym, vector<double>& ret) {
token_t token = sym.token();
if (is_constant_flag[token]) {
@ -305,6 +311,12 @@ vector<const FunDef*> get_defined_functions() {
return res;
}
FunDef* make_var(int idx) { return new Var(idx); }
FunDef* make_const(double value) { return new Const(value); }
namespace {
class Sum : public FunDef {
public :
@ -478,6 +490,8 @@ struct Min {
string name() const { return "min"; }
};
} // namespace
string prototypes = "double pow(double, double);";
string get_prototypes() { return prototypes; }
unsigned add_prototype(string str) { prototypes += string("double ") + str + "(double);"; return prototypes.size(); }
@ -488,6 +502,7 @@ token_t add_function(FunDef* function, token_t where) {
return 0;
}
namespace {
#define FUNCDEF(funcname) struct funcname##_struct { \
double operator()(double val) const { return funcname(val); }\
@ -498,9 +513,6 @@ token_t add_function(FunDef* function, token_t where) {
static const token_t funcname##_token_static = add_function( new Unary<funcname##_struct>, funcname##_token);\
unsigned funcname##_size = add_prototype(#funcname);
FunDef* make_var(int idx) { return new Var(idx); }
FunDef* make_const(double value) { return new Const(value); }
static token_t ssum_token = add_function( new Sum , sum_token);
static token_t sprod_token = add_function( new Prod, prod_token);
static token_t sinv_token = add_function( new Unary<Inv>, inv_token);
@ -524,11 +536,14 @@ FUNCDEF(atanh);
FUNCDEF(exp);
FUNCDEF(log);
} // namespace
double sqr(double x) { return x*x; }
namespace {
FUNCDEF(sqr);
FUNCDEF(sqrt);
} // namespace
/* Serialization */
void write_raw(ostream& os, const Sym& sym) {

View file

@ -21,6 +21,7 @@
#include <string>
#include <vector>
#include <memory>
#include <iostream>
#include "Sym.h"
#include "Interval.h"
@ -142,7 +143,7 @@ extern std::string get_prototypes();
// reading and writing in internal format
extern std::string write_raw(const Sym& sym);
extern void write_raw(ostream& os, const Sym& sym);
extern void write_raw(std::ostream& os, const Sym& sym);
extern Sym read_raw(std::string str);
extern Sym read_raw(std::istream& is);
extern void read_raw(std::istream& is, Sym& sym);

View file

@ -232,8 +232,11 @@ class ErrorMeasureImpl {
vector<ErrorMeasure::result> calc_error(const vector<Sym>& pop) {
// first declone
#if USE_TR1
typedef std::tr1::unordered_map<Sym, unsigned, HashSym> HashMap;
#else
typedef hash_map<Sym, unsigned, HashSym> HashMap;
#endif
HashMap clone_map;
vector<Sym> decloned;
decloned.reserve(pop.size());

View file

@ -46,7 +46,7 @@ size_t get_depth(const SymVec& vec) {
return dp;
}
Sym::Sym(token_t tok, const SymVec& args_)
Sym::Sym(token_t tok, const SymVec& args_) : node(dag.end())
{
detail::SymKey key(tok, detail::SymArgs(args_));
detail::SymValue val;
@ -64,7 +64,7 @@ Sym::Sym(token_t tok, const SymVec& args_)
else incref();
}
Sym::Sym(token_t tok, const Sym& a) {
Sym::Sym(token_t tok, const Sym& a) : node(dag.end()) {
SymVec args_; args_.push_back(a);
detail::SymKey key(tok, detail::SymArgs(args_));
detail::SymValue val;
@ -82,7 +82,7 @@ Sym::Sym(token_t tok, const Sym& a) {
else incref();
}
Sym::Sym(token_t tok) {
Sym::Sym(token_t tok) : node(dag.end()) {
detail::SymKey key(tok);
detail::SymValue val;
node = dag.insert(pair<const detail::SymKey, detail::SymValue>(key, val)).first;

View file

@ -22,7 +22,7 @@
#if __GNUC__ >= 3
#include <backward/hash_map.h>
#else
#elif __GNUC__ < 3
#include <hash_map.h>
using std::hash_map;
#endif
@ -33,15 +33,23 @@ struct UniqueNodeStats { virtual ~UniqueNodeStats(){} };
#include "SymImpl.h"
#include "token.h"
typedef hash_map<detail::SymKey, detail::SymValue, detail::SymKey::Hash> SymMap;
typedef SymMap::iterator SymIterator;
class Sym;
#if __GNUC__ == 444
#define USE_TR1 1
#else
#define USE_TR1 0
#endif
typedef std::vector<Sym> SymVec;
#if USE_TR1
#include <tr1/unordered_map>
typedef std::tr1::unordered_map<detail::SymKey, detail::SymValue, detail::SymKey::Hash> SymMap;
#else
typedef hash_map<detail::SymKey, detail::SymValue, detail::SymKey::Hash> SymMap;
#endif
typedef SymMap::iterator SymIterator;
/* Sym is the tree, for which all the nodes are stored in a hash table.
* This makes checking for equality O(1) */
class Sym
{
public:
@ -67,7 +75,7 @@ class Sym
/* Unique Stats are user defined */
UniqueNodeStats* extra_stats() const { return empty()? 0 : node->second.uniqueNodeStats; }
int hashcode() const { detail::SymKey::Hash hash; return hash(node->first); }
int hashcode() const { return node->first.get_hash_code(); } //detail::SymKey::Hash hash; return hash(node->first); }
// Friends, need to touch the node
friend struct detail::SymKey::Hash;

View file

@ -21,7 +21,7 @@ namespace detail {
class SymArgsImpl {
public:
vector<Sym> owned_args;
std::vector<Sym> owned_args;
};
size_t SymArgs::len() const {
@ -76,7 +76,7 @@ int SymKey::calc_hash() const {
unsigned long hash = unsigned(token);
hash *= PRIMET;
const SymVec& v = args.vec();
const std::vector<Sym>& v = args.vec();
for (unsigned i = 0; i < v.size(); ++i) {
hash += ( (v[i].address() >> 3) * primes[i%nprimes]) % HASHMOD;
}

View file

@ -22,6 +22,16 @@
#include "token.h"
class Sym;
#if __GNUC__ > 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
#include <ext/pool_allocator.h>
typedef std::vector<Sym, __gnu_cxx::__pool_alloc<Sym> > std::vector<Sym>;
//typedef std::vector<Sym> SymVec;
#else
typedef std::vector<Sym> SymVec;
#endif
namespace detail {
class SymArgsImpl;
@ -47,8 +57,8 @@ class SymArgs {
class SymKey
{
public:
SymKey(token_t _token) : args(), token(_token) {}
SymKey(token_t _token, const detail::SymArgs& _args) : args(_args), token(_token) {}
SymKey(token_t _token) : args(), token(_token), hash_code(calc_hash()) {}
SymKey(token_t _token, const detail::SymArgs& _args) : args(_args), token(_token), hash_code(calc_hash()) {}
private:
@ -69,8 +79,11 @@ class SymKey
// fixates (i.e. claims memory) for the embedded vector of Syms
void fixate() const { args.fixate(); }
int get_hash_code() const { return hash_code; }
private:
int calc_hash() const;
int hash_code;
};
struct SymValue

View file

@ -306,6 +306,7 @@ int main(int argc, char* argv[]) {
genmon.add(avgSize);
genmon.add(dagSize);
genmon.add(sumSize);
genmon.add(term); // add generation counter
checkpoint.add(genmon);