Added mathsym+tcc and boost against all advice

This commit is contained in:
maartenkeijzer 2005-10-06 12:13:53 +00:00
commit 90702a435d
136 changed files with 14409 additions and 0 deletions

View file

@ -0,0 +1,569 @@
/*
* 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 <sstream>
#if __GNUC__ == 3
#include <backward/hash_map.h>
#else
#include <hash_map.h>
using std::hash_map;
#endif
#include "Sym.h"
#include "FunDef.h"
#include <LanguageTable.h>
using namespace std;
using namespace boost::numeric;
vector<const FunDef*> language;
token_t add_function(FunDef* function) {
language.push_back(function);
return token_t(language.size()-1);
}
const FunDef& get_element(token_t token) { return *language[token]; }
/* Printing */
string c_print(const Sym& sym) {
return c_print(sym, vector<string>());
}
string c_print(const Sym& sym, const vector<string>& vars) {
const SymVec& args = sym.args();
vector<string> names(args.size());
for (unsigned i = 0; i < args.size(); ++i) {
names[i] = c_print(args[i], vars);
}
return language[sym.token()]->c_print(names, vars);
}
/* Evaluation */
double eval(const Sym& sym, const std::vector<double>& inputs) {
return language[sym.token()]->eval(sym.args(), inputs);
}
/* Interval Logic */
Interval eval(const Sym& sym, const vector<Interval>& inputs) {
const SymVec& args = sym.args();
vector<Interval> interv(args.size());
for (unsigned i = 0; i < args.size(); ++i) {
interv[i] = eval(args[i], inputs);
if (!valid(interv[i])) throw interval_error();
}
return language[sym.token()]->eval(interv, inputs);
}
/* */
void add_function_to_table(LanguageTable& table, token_t token) {
const FunDef& fundef = *language[token];
if (fundef.has_varargs() == false) {
table.add_function(token, fundef.min_arity());
} else { // sum or prod (or min or max)
table.add_function(token, 2);
}
}
// by default it is eager
double FunDef::eval(const SymVec& args, const vector<double>& inputs) const {
vector<double> values(args.size());
for (unsigned i = 0; i < args.size(); ++i) {
values[i] = ::eval(args[i], inputs);
}
return eval(values, inputs);
}
/* Variable Handling */
FunDef* make_var(int idx); // defined in FunDefs.h
static vector<token_t> var_token;
Sym SymVar(unsigned idx) {
if (var_token.size() <= idx) {
// it is new
var_token.resize(idx+1, token_t(-1));
var_token[idx] = add_function( make_var(idx) );
} else if (var_token[idx] == token_t(-1)) {
var_token[idx] = add_function( make_var(idx) );
}
return Sym(var_token[idx]);
}
/* Constant Handling */
struct HashDouble{
size_t operator()(double val) const {
unsigned long h = 0;
char* s = (char*)&val;
for (unsigned i=0 ; i<sizeof(double); ++i)
h = 5*h + s[i];
return size_t(h);
}
};
typedef hash_map<double, token_t, HashDouble> DoubleSet;
static DoubleSet doubleSet; // for quick checking if a constant already exists
static vector<bool> is_constant;
static vector<double> token_value;
static std::vector<token_t> free_list;
void delete_val(token_t token) { // clean up the information about this constant
if (is_constant[token]) {
double value = token_value[token];
delete language[token];
language[token] = 0;
doubleSet.erase(value);
free_list.push_back(token);
}
}
FunDef* make_const(double value);
Sym SymConst(double value) {
Sym::set_extra_dtor(delete_val);
DoubleSet::iterator it = doubleSet.find(value);
if (it != doubleSet.end()) {
return Sym(it->second);
}
if (free_list.empty()) { // make space for tokens;
unsigned sz = language.size();
language.resize(sz + sz+1); // double
is_constant.resize(language.size(), false);
token_value.resize(language.size(), 0.0);
for (unsigned i = sz; i < language.size(); ++i) {
free_list.push_back(i);
}
}
token_t token = free_list.back();
free_list.pop_back();
assert(language[token] == 0);
language[token] = make_const(value);
doubleSet[value] = token;
is_constant[token] = true;
token_value[token] = value;
return Sym(token);
}
/* LanguageTable depends on this one, XXX move somewhere safe.*/
#include <utils/eoRNG.h>
extern Sym default_const() { return SymConst(rng.normal()); }
/* The functions */
class Var : public FunDef {
public :
int idx;
string default_str;
Var(int _idx) : idx(_idx) {
ostringstream os;
os << "x[" << idx << ']'; // CompiledCode expects this form
default_str = os.str();
}
double eval(const vector<double>& _, const vector<double>& inputs) const { return inputs[idx]; }
double eval(const SymVec& _, const vector<double>& inputs) const { return inputs[idx]; }
string c_print(const vector<string>& _, const vector<string>& names) const {
if (names.empty()) {
return default_str;
}
return names[idx];
}
Interval eval(const vector<Interval>& _, const vector<Interval>& inputs) const {
return inputs[idx];
}
unsigned min_arity() const { return 0; }
string name() const { return "var"; }
};
class Const : public FunDef {
private:
double value;
string value_str;
public:
Const(double _value) : value(_value) {
ostringstream os;
os.precision(17);
os.setf(ios::showpoint);
os << '(' << value << ')';
value_str = os.str();
}
double eval(const vector<double>& _, const vector<double>& inputs) const { return value; }
double eval(const SymVec& _, const vector<double>& inputs) const { return value; }
string c_print(const vector<string>& _, const vector<string>& names) const {
return value_str;
}
Interval eval(const vector<Interval>& _, const vector<Interval>& inputs) const {
// Profil/Bias seems to have a problem with 0 * inf when the Interval is exact zero (fpe)
//if (value == 0.0) return Interval(-BiasEpsilon,BiasEpsilon);
return Interval(value);
}
unsigned min_arity() const { return 0; }
string name() const { return "parameter"; }
};
// Get functions out, excluding Const and Var
vector<const FunDef*> get_defined_functions() {
vector<const FunDef*> res;
for (unsigned i = 0; i < language.size(); ++i) {
res.push_back(language[i]);
if (dynamic_cast<const Const*>(language[i]) != 0 || (dynamic_cast<const Var*>(language[i]) != 0) ) {
res.back() = 0; // erase
}
}
return res;
}
class Sum : public FunDef {
public :
double eval(const vector<double>& vals, const vector<double>& _) const {
double res = 0;
for (unsigned i = 0; i < vals.size(); ++i) res += vals[i];
return res;
}
string c_print(const vector<string>& args, const vector<string>& _) const {
if (args.empty()) { return "0.0"; }
ostringstream os;
os << "(" << args[0];
for (unsigned i = 1; i < args.size(); ++i) {
os << "+" << args[i];
}
os << ")";
return os.str();
}
Interval eval(const vector<Interval>& args, const vector<Interval>& inputs) const {
Interval interv(0.0); //(0.0-BiasEpsilon, 0.0+BiasEpsilon); // Profil/Bias seems to have a problem with 0 * inf when the Interval is exact zero (fpe)
for (unsigned i = 0; i < args.size(); ++i) {
Interval a = args[i]; // Profil doesn't know much about const correctness
interv += a;
}
return interv;
}
unsigned min_arity() const { return 0; }
bool has_varargs() const { return true; }
string name() const { return "sum"; }
};
class Prod : public FunDef {
public :
double eval(const vector<double>& vals, const vector<double>& _) const {
double res = 1;
for (unsigned i = 0; i < vals.size(); ++i) res *= vals[i];
return res;
}
string c_print(const vector<string>& args, const vector<string>& _) const {
if (args.empty()) { return "1.0"; }
ostringstream os;
os << "(" << args[0];
for (unsigned i = 1; i < args.size(); ++i) {
os << "*" << args[i];
}
os << ")";
return os.str();
}
Interval eval(const vector<Interval>& args, const vector<Interval>& inputs) const {
Interval interv(1.0);
for (unsigned i = 0; i < args.size(); ++i) {
Interval a = args[i]; // Profil doesn't know much about const correctness
interv *= a;
}
return interv;
}
unsigned min_arity() const { return 0; }
bool has_varargs() const { return true; }
string name() const { return "prod"; }
};
class Power : public FunDef {
public :
double eval(const vector<double>& vals, const vector<double>& _) const {
return pow(vals[0], vals[1]);
}
string c_print(const vector<string>& args, const vector<string>& _) const {
return "pow(" + args[0] + ',' + args[1] + ')';
}
Interval eval(const vector<Interval>& args, const vector<Interval>& _) const {
Interval first = args[0];
Interval second = args[1];
Interval lg = log(first);
if (!valid(lg)) throw interval_error();
return exp(second * lg);
}
unsigned min_arity() const { return 2; }
string name() const { return "pow"; }
};
class IsNeg : public FunDef {
public:
double eval(const vector<double>& vals, const vector<double>& _) const {
if (vals[0] < 0.0) return vals[1];
return vals[2];
}
double eval(const Sym& sym, const vector<double>& inputs) const {
const SymVec& args = sym.args();
double arg0 = ::eval(args[0], inputs);
if (arg0 < 0.0) {
return ::eval(args[1], inputs);
}
return ::eval(args[2], inputs);
}
string c_print(const vector<string>& args, const vector<string>& _) const {
return "((" + args[0] + "<0.0)?" + args[1] + ":" + args[2]+")";
}
Interval eval(const vector<Interval>& args, const vector<Interval>& _) const {
Interval a0 = args[0];
if (a0.upper() < 0.0) return args[1];
if (a0.lower() >= 0.0) return args[2];
return Interval( std::min(args[1].lower(), args[2].lower()), std::max(args[1].upper(), args[2].upper()));
}
unsigned min_arity() const { return 3; }
string name() const { return "ifltz"; }
};
template <typename Func>
class Unary : public FunDef {
Func un;
double eval(const vector<double>& vals, const vector<double>& _) const {
return un(vals[0]);
}
string c_print(const vector<string>& args, const vector<string>& _) const {
return un(args[0]);
}
Interval eval(const vector<Interval>& args, const vector<Interval>& _) const {
return un(args[0]);
}
unsigned min_arity() const { return 1; }
string name() const { return un.name(); }
};
struct Inv {
double operator()(double val) const { return 1.0 / val; }
string operator()(string v) const { return "(1./" + v + ")"; }
Interval operator()(Interval v) const { return 1.0 / v; }
string name() const { return "inv"; }
};
struct Min {
double operator()(double val) const { return -val; }
string operator()(string v) const { return "(-" + v + ")"; }
Interval operator()(Interval v) const { return -v; }
string name() const { return "min"; }
};
string prototypes = "double pow(double, double);";
string get_prototypes() { return prototypes; }
unsigned add_prototype(string str) { prototypes += string("double ") + str + "(double);"; return prototypes.size(); }
#define FUNCDEF(funcname) struct funcname##_struct { \
double operator()(double val) const { return funcname(val); }\
string operator()(string val) const { return string(#funcname) + '(' + val + ')'; }\
Interval operator()(Interval val) const { return funcname(val); }\
string name() const { return string(#funcname); }\
};\
const token_t funcname##_token = add_function( new Unary<funcname##_struct>);\
unsigned funcname##_size = add_prototype(#funcname);
FunDef* make_var(int idx) { return new Var(idx); }
FunDef* make_const(double value) { return new Const(value); }
const token_t sum_token = add_function( new Sum );
const token_t prod_token = add_function( new Prod);
const token_t inv_token = add_function( new Unary<Inv>);
const token_t min_token = add_function( new Unary<Min>);
const token_t pow_token = add_function( new Power);
const token_t ifltz_token = add_function( new IsNeg);
FUNCDEF(sin);
FUNCDEF(cos);
FUNCDEF(tan);
FUNCDEF(asin);
FUNCDEF(acos);
FUNCDEF(atan);
FUNCDEF(sinh);
FUNCDEF(cosh);
FUNCDEF(tanh);
FUNCDEF(asinh);
FUNCDEF(acosh);
FUNCDEF(atanh);
FUNCDEF(exp);
FUNCDEF(log);
double sqr(double x) { return x*x; }
FUNCDEF(sqr);
FUNCDEF(sqrt);
/* Serialization */
void write_raw(ostream& os, const Sym& sym) {
token_t token = sym.token();
const SymVec& args = sym.args();
if (is_constant.size() > token && is_constant[token]) {
os << "c" << language[token]->c_print(vector<string>(), vector<string>());
} else {
const Var* var = dynamic_cast<const Var*>( language[token] );
if (var != 0) {
os << "v" << var->idx;
} else {
os << "f" << token << ' ' << args.size();
}
}
for (unsigned i = 0; i < args.size(); ++i) {
write_raw(os, args[i]);
}
}
string write_raw(const Sym& sym) {
ostringstream os;
write_raw(os, sym);
return os.str();
}
Sym read_raw(istream& is) {
char id = is.get();
switch (id) {
case 'c' :
{
double val;
is.get(); // skip '('
is >> val;
is.get(); // skip ')'
return SymConst(val);
}
case 'v' :
{
unsigned idx;
is >> idx;
return SymVar(idx);
}
case 'f' :
{
token_t token;
unsigned arity;
is >> token;
is >> arity;
SymVec args(arity);
for (unsigned i = 0; i < arity; ++i) {
args[i] = read_raw(is);
}
return Sym(token, args);
}
default : {
cerr << "Character = " << id << " Could not read formula from stream" << endl;
exit(1);
}
}
return Sym();
}
Sym read_raw(string str) {
istringstream is(str);
return read_raw(is);
}
void read_raw(istream& is, Sym& sym) {
sym = read_raw(is);
}

View file

@ -0,0 +1,124 @@
/*
* 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
*/
#ifndef FUNCTION_DEF_H_
#define FUNCTION_DEF_H_
#include <string>
#include <vector>
#include <memory>
#include "Sym.h"
#include "Interval.h"
class FunDef {
public:
virtual ~FunDef() {}
// (possibly) lazy evaluation function, default implementation calls 'eager' eval
virtual double eval(const SymVec& args, const std::vector<double>& inputs) const;
// eager evaluation function
virtual double eval(const std::vector<double>& args, const std::vector<double>& inputs) const = 0;
// interval evaluation
virtual Interval eval(const std::vector<Interval>& args, const std::vector<Interval>& inputs) const = 0;
// prints 'c' like code
virtual std::string c_print(const std::vector<std::string>& names, const std::vector<std::string>& names) const = 0;
virtual unsigned min_arity() const = 0;
virtual bool has_varargs() const { return false; } // sum, prod, min, max are variable arity
virtual std::string name() const = 0;
protected:
};
extern std::vector<const FunDef*> get_defined_functions();
extern const FunDef& get_element(token_t token);
/* Single case evaluation */
extern double eval(const Sym& sym, const std::vector<double>& inputs);
/* Static analysis through interval arithmetic */
extern Interval eval(const Sym& sym, const std::vector<Interval>& inputs);
/* Pretty printers, second version allows setting of variable names */
extern std::string c_print(const Sym& sym);
extern std::string c_print(const Sym& sym, const std::vector<std::string>& var_names);
/* Pretty printer streamer */
inline std::ostream& operator<<(std::ostream& os, Sym sym) { return os << c_print(sym); }
/* Create constant */
extern Sym SymConst(double value);
/* Create variable */
extern Sym SymVar(unsigned idx);
/* 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);
// token names
extern const token_t sum_token;
extern const token_t prod_token;
extern const token_t inv_token;
extern const token_t min_token;
extern const token_t pow_token;
extern const token_t ifltz_token;
#define HEADERFUNC(name) extern const token_t name##_token;\
inline Sym name(Sym arg) { return Sym(name##_token, arg); }
/* This defines the tokens: sin_token, cos_token, etc. */
HEADERFUNC(sin);
HEADERFUNC(cos);
HEADERFUNC(tan);
HEADERFUNC(asin);
HEADERFUNC(acos);
HEADERFUNC(atan);
HEADERFUNC(sinh);
HEADERFUNC(cosh);
HEADERFUNC(tanh);
HEADERFUNC(asinh);
HEADERFUNC(acosh);
HEADERFUNC(atanh);
HEADERFUNC(exp);
HEADERFUNC(log);
HEADERFUNC(sqr);
HEADERFUNC(sqrt);
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 Sym read_raw(std::string str);
extern Sym read_raw(std::istream& is);
extern void read_raw(std::istream& is, Sym& sym);
#include "SymOps.h"
#endif

View file

@ -0,0 +1,109 @@
/*
* 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 "FunDef.h"
#include "SymOps.h"
#include "Sym.h"
using namespace std;
void collect(token_t t, Sym a, SymVec& args) {
if (a.token() == t) {
const SymVec& a_args = a.args();
for (unsigned i = 0; i < a_args.size(); ++i) {
collect(t, a_args[i], args);
}
return;
}
args.push_back(a);
}
Sym operator+(Sym a, Sym b) {
SymVec args;
collect(sum_token, a, args);
collect(sum_token, b, args);
return Sym(sum_token, args);
}
Sym operator*(Sym a, Sym b) {
SymVec args;
collect(prod_token, a, args);
collect(prod_token, b, args);
return Sym(prod_token, args);
}
Sym operator/(Sym a, Sym b) {
SymVec args;
collect(prod_token, a, args);
SymVec args2;
collect(prod_token, b, args2);
SymVec inv;
inv.push_back(Sym(prod_token, args2));
args.push_back( Sym(inv_token, inv) );
return Sym(prod_token, args);
}
Sym operator-(Sym a, Sym b) {
SymVec args;
collect(sum_token, a, args);
SymVec args2;
collect(sum_token, b, args2);
SymVec min;
min.push_back(Sym(sum_token, args2));
args.push_back( Sym(min_token, min) );
return Sym(sum_token, args);
}
Sym operator-(Sym a) {
return Sym(min_token, a);
}
Sym pow(Sym a, Sym b) {
SymVec args;
args.push_back(a);
args.push_back(b);
return Sym(pow_token, args);
}
Sym ifltz(Sym a, Sym b, Sym c) {
SymVec args;
args.push_back(a);
args.push_back(b);
args.push_back(c);
return Sym(ifltz_token, args);
}

View file

@ -0,0 +1,31 @@
/*
* 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
*/
#ifndef SYMOPS_H
#define SYMOPS_H
#include "Sym.h"
extern Sym operator+(Sym a, Sym b);
extern Sym operator*(Sym a, Sym b);
extern Sym operator/(Sym a, Sym b);
extern Sym operator-(Sym a, Sym b);
extern Sym pow(Sym a, Sym b);
extern Sym ifltz(Sym a, Sym b, Sym c);
extern Sym operator-(Sym a);
#endif

View file

@ -0,0 +1,27 @@
/*
* 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 <string>
#include <iostream>
using namespace std;
double error(string errstr) {
cerr << "ERROR: " << errstr << endl;
exit(1);
}