Various bugfixes and additions
This commit is contained in:
parent
14c3182200
commit
44876f0926
24 changed files with 889 additions and 187 deletions
26
eo/contrib/mathsym/eval/MultiFuncs.cpp
Normal file
26
eo/contrib/mathsym/eval/MultiFuncs.cpp
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
|
||||
namespace multi_function {
|
||||
|
||||
double plus(arg_ptr args) {
|
||||
return *args[0] + *args[1];
|
||||
}
|
||||
|
||||
double mult(arg_ptr args) {
|
||||
return *args[0] * *args[1];
|
||||
}
|
||||
|
||||
double min(arg_ptr args) {
|
||||
return -**args;
|
||||
}
|
||||
|
||||
double inv(arg_ptr args) {
|
||||
return 1 / **args;
|
||||
}
|
||||
|
||||
//template <typename f> class F { public: double operator()(double a) { return f(a); } };
|
||||
|
||||
double exp(arg_ptr args) {
|
||||
return ::exp(**args);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
341
eo/contrib/mathsym/eval/MultiFunction.cpp
Normal file
341
eo/contrib/mathsym/eval/MultiFunction.cpp
Normal file
|
|
@ -0,0 +1,341 @@
|
|||
#include <vector.h>
|
||||
|
||||
|
||||
#include "MultiFunction.h"
|
||||
#include "Sym.h"
|
||||
#include "FunDef.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
typedef vector<double>::const_iterator data_ptr;
|
||||
typedef vector<data_ptr> data_ptrs;
|
||||
typedef data_ptrs::const_iterator arg_ptr;
|
||||
|
||||
#include "MultiFuncs.cpp"
|
||||
|
||||
typedef double (*fptr)( arg_ptr );
|
||||
|
||||
string print_function( fptr f) {
|
||||
if (f == multi_function::plus) return "+";
|
||||
if (f == multi_function::mult) return "*";
|
||||
if (f == multi_function::min) return "-";
|
||||
if (f == multi_function::inv) return "/";
|
||||
if (f == multi_function::exp) return "e";
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
|
||||
struct Function {
|
||||
|
||||
fptr function;
|
||||
arg_ptr args;
|
||||
|
||||
double operator()() const { return function(args); }
|
||||
};
|
||||
|
||||
static vector<Function> token_2_function;
|
||||
|
||||
Sym make_binary(Sym sym) {
|
||||
if (sym.args().size() == 2) return sym;
|
||||
SymVec args = sym.args();
|
||||
Sym an = args.back();
|
||||
args.pop_back();
|
||||
Sym nw = make_binary( Sym( sym.token(), args) );
|
||||
args.resize(2);
|
||||
args[0] = nw;
|
||||
args[1] = an;
|
||||
return Sym(sym.token(), args);
|
||||
}
|
||||
|
||||
class Compiler {
|
||||
|
||||
public:
|
||||
|
||||
enum func_type {constant, variable, function};
|
||||
|
||||
typedef pair<func_type, unsigned> entry;
|
||||
|
||||
#if USE_TR1
|
||||
typedef std::tr1::unordered_map<Sym, entry, HashSym> HashMap;
|
||||
#else
|
||||
typedef hash_map<Sym, entry, HashSym> HashMap;
|
||||
#endif
|
||||
|
||||
HashMap map;
|
||||
|
||||
vector<double> constants;
|
||||
vector<unsigned> variables;
|
||||
vector< fptr > functions;
|
||||
vector< vector<entry> > function_args;
|
||||
|
||||
unsigned total_args;
|
||||
|
||||
vector<entry> outputs;
|
||||
|
||||
Compiler() : total_args(0) {}
|
||||
|
||||
entry do_add(Sym sym) {
|
||||
|
||||
HashMap::iterator it = map.find(sym);
|
||||
|
||||
if (it == map.end()) { // new entry
|
||||
|
||||
token_t token = sym.token();
|
||||
|
||||
if (is_constant(token)) {
|
||||
constants.push_back( get_constant_value(token) ); // set value
|
||||
entry e = make_pair(constant, constants.size()-1);
|
||||
map.insert( make_pair(sym, e) );
|
||||
return e;
|
||||
|
||||
} else if (is_variable(token)) {
|
||||
unsigned idx = get_variable_index(token);
|
||||
variables.push_back(idx);
|
||||
entry e = make_pair(variable, variables.size()-1);
|
||||
map.insert( make_pair(sym, e) );
|
||||
return e;
|
||||
} // else
|
||||
|
||||
fptr f;
|
||||
vector<entry> vec;
|
||||
const SymVec& args = sym.args();
|
||||
|
||||
switch (token) {
|
||||
case sum_token:
|
||||
{
|
||||
if (args.size() == 0) {
|
||||
return do_add( SymConst(0.0));
|
||||
}
|
||||
if (args.size() == 1) {
|
||||
return do_add(args[0]);
|
||||
}
|
||||
if (args.size() == 2) {
|
||||
vec.push_back(do_add(args[0]));
|
||||
vec.push_back(do_add(args[1]));
|
||||
f = multi_function::plus;
|
||||
//cout << "Adding + " << vec[0].second << ' ' << vec[1].second << endl;
|
||||
break;
|
||||
|
||||
} else {
|
||||
return do_add( make_binary(sym) );
|
||||
}
|
||||
|
||||
}
|
||||
case prod_token:
|
||||
{
|
||||
if (args.size() == 0) {
|
||||
return do_add( SymConst(1.0));
|
||||
}
|
||||
if (args.size() == 1) {
|
||||
return do_add(args[0]);
|
||||
}
|
||||
if (args.size() == 2) {
|
||||
vec.push_back(do_add(args[0]));
|
||||
vec.push_back(do_add(args[1]));
|
||||
f = multi_function::mult;
|
||||
//cout << "Adding * " << vec[0].second << ' ' << vec[1].second << endl;
|
||||
break;
|
||||
|
||||
|
||||
} else {
|
||||
return do_add( make_binary(sym) );
|
||||
}
|
||||
}
|
||||
case sqr_token:
|
||||
{
|
||||
SymVec newargs(2);
|
||||
newargs[0] = args[0];
|
||||
newargs[1] = args[0];
|
||||
return do_add( Sym(prod_token, newargs));
|
||||
}
|
||||
default :
|
||||
{
|
||||
if (args.size() != 1) {
|
||||
cerr << "Unknown function " << sym << " encountered" << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
vec.push_back(do_add(args[0]));
|
||||
|
||||
switch (token) {
|
||||
case min_token: f = multi_function::min; break;
|
||||
case inv_token: f = multi_function::inv; break;
|
||||
case exp_token :f = multi_function::exp; break;
|
||||
default :
|
||||
{
|
||||
cerr << "Unimplemented token encountered " << sym << endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
//cout << "Adding " << print_function(f) << ' ' << vec[0].second << endl;
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
total_args += vec.size();
|
||||
function_args.push_back(vec);
|
||||
functions.push_back(f);
|
||||
|
||||
entry e = make_pair(function, functions.size()-1);
|
||||
map.insert( make_pair(sym, e) );
|
||||
return e;
|
||||
|
||||
}
|
||||
|
||||
return it->second; // entry
|
||||
}
|
||||
|
||||
void add(Sym sym) {
|
||||
entry e = do_add(sym);
|
||||
outputs.push_back(e);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class MultiFunctionImpl {
|
||||
public:
|
||||
|
||||
// input mapping
|
||||
vector<unsigned> input_idx;
|
||||
|
||||
unsigned constant_offset;
|
||||
unsigned var_offset;
|
||||
|
||||
// evaluation
|
||||
vector<double> data;
|
||||
vector<Function> funcs;
|
||||
data_ptrs args;
|
||||
|
||||
vector<unsigned> output_idx;
|
||||
|
||||
MultiFunctionImpl() {}
|
||||
|
||||
void clear() {
|
||||
input_idx.clear();
|
||||
data.clear();
|
||||
funcs.clear();
|
||||
args.clear();
|
||||
output_idx.clear();
|
||||
constant_offset = 0;
|
||||
}
|
||||
|
||||
void eval(const double* x, double* y) {
|
||||
unsigned i;
|
||||
// evaluate variables
|
||||
for (i = constant_offset; i < constant_offset + input_idx.size(); ++i) {
|
||||
data[i] = x[input_idx[i-constant_offset]];
|
||||
}
|
||||
|
||||
for(; i < data.size(); ++i) {
|
||||
data[i] = funcs[i-var_offset]();
|
||||
//cout << i << " " << data[i] << endl;
|
||||
}
|
||||
|
||||
for (i = 0; i < output_idx.size(); ++i) {
|
||||
y[i] = data[output_idx[i]];
|
||||
}
|
||||
}
|
||||
|
||||
void eval(const vector<double>& x, vector<double>& y) {
|
||||
eval(&x[0], &y[0]);
|
||||
}
|
||||
|
||||
void setup(const vector<Sym>& pop) {
|
||||
|
||||
clear();
|
||||
Compiler compiler;
|
||||
|
||||
for (unsigned i = 0; i < pop.size(); ++i) {
|
||||
Sym sym = (expand_all(pop[i]));
|
||||
compiler.add(sym);
|
||||
}
|
||||
|
||||
// compiler is setup so get the data
|
||||
constant_offset = compiler.constants.size();
|
||||
var_offset = constant_offset + compiler.variables.size();
|
||||
int n = var_offset + compiler.functions.size();
|
||||
|
||||
data.resize(n);
|
||||
funcs.resize(compiler.functions.size());
|
||||
args.resize(compiler.total_args);
|
||||
|
||||
// constants
|
||||
for (unsigned i = 0; i < constant_offset; ++i) {
|
||||
data[i] = compiler.constants[i];
|
||||
//cout << i << ' ' << data[i] << endl;
|
||||
}
|
||||
|
||||
// variables
|
||||
input_idx = compiler.variables;
|
||||
|
||||
//for (unsigned i = constant_offset; i < var_offset; ++i) {
|
||||
//cout << i << " x" << input_idx[i-constant_offset] << endl;
|
||||
//}
|
||||
|
||||
// functions
|
||||
unsigned which_arg = 0;
|
||||
for (unsigned i = 0; i < funcs.size(); ++i) {
|
||||
|
||||
Function f;
|
||||
f.function = compiler.functions[i];
|
||||
|
||||
//cout << i+var_offset << ' ' << print_function(f.function);
|
||||
|
||||
// interpret args
|
||||
for (unsigned j = 0; j < compiler.function_args[i].size(); ++j) {
|
||||
|
||||
Compiler::entry e = compiler.function_args[i][j];
|
||||
|
||||
unsigned idx = e.second;
|
||||
|
||||
switch (e.first) {
|
||||
case Compiler::function: idx += compiler.variables.size();
|
||||
case Compiler::variable: idx += compiler.constants.size();
|
||||
case Compiler::constant: {}
|
||||
}
|
||||
|
||||
args[which_arg + j] = data.begin() + idx;
|
||||
//cout << ' ' << idx << "(" << e.second << ")";
|
||||
}
|
||||
|
||||
//cout << endl;
|
||||
|
||||
f.args = args.begin() + which_arg;
|
||||
which_arg += compiler.function_args[i].size();
|
||||
funcs[i] = f;
|
||||
}
|
||||
|
||||
// output indices
|
||||
output_idx.resize(compiler.outputs.size());
|
||||
for (unsigned i = 0; i < output_idx.size(); ++i) {
|
||||
output_idx[i] = compiler.outputs[i].second;
|
||||
switch(compiler.outputs[i].first) {
|
||||
case Compiler::function: output_idx[i] += compiler.variables.size();
|
||||
case Compiler::variable: output_idx[i] += compiler.constants.size();
|
||||
case Compiler::constant: {}
|
||||
}
|
||||
//cout << "out " << output_idx[i] << endl;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
MultiFunction::MultiFunction(const std::vector<Sym>& pop) : pimpl(new MultiFunctionImpl) {
|
||||
pimpl->setup(pop);
|
||||
}
|
||||
|
||||
MultiFunction::~MultiFunction() { delete pimpl; }
|
||||
|
||||
void MultiFunction::operator()(const std::vector<double>& x, std::vector<double>& y) {
|
||||
pimpl->eval(x,y);
|
||||
}
|
||||
|
||||
void MultiFunction::operator()(const double* x, double* y) {
|
||||
pimpl->eval(x,y);
|
||||
}
|
||||
26
eo/contrib/mathsym/eval/MultiFunction.h
Normal file
26
eo/contrib/mathsym/eval/MultiFunction.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef MULTIFUNCTION_H_
|
||||
#define MULTIFUNCTION_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
class Sym;
|
||||
class MultiFunctionImpl;
|
||||
|
||||
class MultiFunction {
|
||||
MultiFunction& operator=(const MultiFunction&);
|
||||
MultiFunction(const MultiFunction&);
|
||||
|
||||
MultiFunctionImpl* pimpl;
|
||||
|
||||
public:
|
||||
|
||||
MultiFunction(const std::vector<Sym>& pop);
|
||||
~MultiFunction();
|
||||
|
||||
void operator()(const std::vector<double>& x, std::vector<double>& y);
|
||||
void operator()(const double* x, double* y);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -9,25 +9,42 @@ extern void symc_init() {
|
|||
tcc_delete(s);
|
||||
}
|
||||
s = tcc_new();
|
||||
|
||||
if (s == 0) {
|
||||
fprintf(stderr, "Tiny cc doesn't function properly");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
|
||||
}
|
||||
|
||||
extern void symc_compile(const char* func_str) {
|
||||
extern int symc_compile(const char* func_str) {
|
||||
//printf("Compiling %s\n", func_str);
|
||||
tcc_compile_string(s, func_str);
|
||||
int err = tcc_compile_string(s, func_str);
|
||||
|
||||
if (err) {
|
||||
fprintf(stderr,"Compile failed");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
extern void symc_link() {
|
||||
tcc_relocate(s);
|
||||
extern int symc_link() {
|
||||
int err = tcc_relocate(s);
|
||||
if (err) {
|
||||
fprintf(stderr,"Compile failed");
|
||||
exit(1);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
extern void* symc_get_fun(const char* func_name) {
|
||||
unsigned long val;
|
||||
tcc_get_symbol(s, &val, func_name);
|
||||
|
||||
if (val == 0) {
|
||||
fprintf(stderr,"getfun failed");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return (void*) val;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ using namespace std;
|
|||
|
||||
extern "C" {
|
||||
void symc_init();
|
||||
void symc_compile(const char* func_str);
|
||||
void symc_link();
|
||||
int symc_compile(const char* func_str);
|
||||
int symc_link();
|
||||
void* symc_get_fun(const char* func_name);
|
||||
void* symc_make(const char* func_str, const char* func_name);
|
||||
}
|
||||
|
|
@ -46,33 +46,6 @@ typedef std::tr1::unordered_map<Sym, string, HashSym> HashMap;
|
|||
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
|
||||
const SymVec& args = sym.args();
|
||||
vector<string> argstr(args.size());
|
||||
for (unsigned i = 0; i < args.size(); ++i) {
|
||||
argstr[i] = find_entry(args[i], os, map)->second;
|
||||
}
|
||||
|
||||
unsigned current_entry = map.size(); // current number of variables defined
|
||||
|
||||
// write out the code
|
||||
const FunDef& fun = get_element(sym.token());
|
||||
string code = fun.c_print(argstr, vector<string>());
|
||||
os << "double a" << current_entry << "=" << code << ";\n";
|
||||
|
||||
// insert variable ref in map
|
||||
ostringstream str;
|
||||
str << 'a' << current_entry;
|
||||
|
||||
result = map.insert( make_pair(sym, str.str()) ).first; // only want iterator
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// prints 'num' in reverse notation. Does not matter as it's a unique id
|
||||
string make_var(unsigned num) {
|
||||
string str = "a";
|
||||
|
|
@ -83,37 +56,6 @@ string make_var(unsigned 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;
|
||||
|
|
@ -121,22 +63,50 @@ string to_string(T t) {
|
|||
return os.str();
|
||||
}
|
||||
|
||||
void write_entry(const Sym& sym, string& str, HashMap& map, unsigned out) {
|
||||
HashMap::iterator it = find_entry2(sym, str, map);
|
||||
|
||||
HashMap::iterator find_entry(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_entry(args[i], str, map)->second;
|
||||
}
|
||||
|
||||
string var = make_var(map.size()); // map.size(): unique id
|
||||
string code;
|
||||
// write out the code
|
||||
const FunDef& fun = get_element(sym.token());
|
||||
code = fun.c_print(argstr, vector<string>() );
|
||||
|
||||
str += "double " + var + "=" + code + ";\n";
|
||||
result = map.insert( make_pair(sym, var ) ).first; // only want iterator
|
||||
}
|
||||
|
||||
str += "y[" + to_string(out) + "]=" + it->second + ";\n";
|
||||
return result;
|
||||
}
|
||||
|
||||
//#include <fstream>
|
||||
void write_entry(const Sym& sym, string& str, HashMap& map, unsigned out) {
|
||||
HashMap::iterator it = find_entry(sym, str, map);
|
||||
|
||||
str += "y[" + to_string(out) + "]=" + it->second + ";\n";
|
||||
//cout << "wrote " << out << '\n';
|
||||
}
|
||||
|
||||
#include <fstream>
|
||||
multi_function compile(const std::vector<Sym>& syms) {
|
||||
|
||||
//cout << "Multifunction " << syms.size() << endl;
|
||||
// static stream to avoid fragmentation of these LARGE strings
|
||||
static string str;
|
||||
str.clear();
|
||||
str += make_prototypes();
|
||||
|
||||
str += "double func(const double* x, double* y) { \n ";
|
||||
str += "extern double func(const double* x, double* y) { \n ";
|
||||
|
||||
multi_function result;
|
||||
HashMap map(Sym::get_dag().size());
|
||||
|
||||
for (unsigned i = 0; i < syms.size(); ++i) {
|
||||
|
|
@ -144,34 +114,27 @@ multi_function compile(const std::vector<Sym>& syms) {
|
|||
}
|
||||
|
||||
str += ";}";
|
||||
|
||||
// ofstream cmp("compiled.c");
|
||||
// cmp << str;
|
||||
// cmp.close();
|
||||
|
||||
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("");
|
||||
/*static int counter = 0;
|
||||
ostringstream nm;
|
||||
nm << "cmp/compiled" << (counter++) << ".c";
|
||||
cout << "Saving as " << nm.str() << endl;
|
||||
ofstream cmp(nm.str().c_str());
|
||||
cmp << str;
|
||||
cmp.close();
|
||||
|
||||
os << make_prototypes();
|
||||
//cout << "Multifunction " << syms.size() << endl;
|
||||
cout << "Size of map " << map.size() << endl;
|
||||
*/
|
||||
|
||||
os << "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], os, map, i);
|
||||
result = (multi_function) symc_make(str.c_str(), "func");
|
||||
|
||||
if (result==0) { // error
|
||||
cout << "Error in compile " << endl;
|
||||
}
|
||||
|
||||
os << ";}";
|
||||
|
||||
return (multi_function) symc_make(os.str().c_str(), "func");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
single_function compile(Sym sym) {
|
||||
|
|
@ -238,7 +201,7 @@ void compile(const std::vector<Sym>& syms, std::vector<single_function>& functio
|
|||
#ifdef INTERVAL_DEBUG
|
||||
//cout << "Compiling " << os.str() << endl;
|
||||
#endif
|
||||
|
||||
|
||||
symc_compile(os.str().c_str());
|
||||
symc_link();
|
||||
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@
|
|||
#include <vector>
|
||||
|
||||
|
||||
typedef double (*single_function)(const double *);
|
||||
typedef void (*multi_function)(const double*, double*); // last argument is output
|
||||
typedef double (*single_function)(const double []);
|
||||
typedef double (*multi_function)(const double[], double[]);
|
||||
|
||||
/*
|
||||
* Important, after every call of the functions below, the function pointers of the previous
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue