From 1f4a944064bc42284c33e6b755353d191cf288e8 Mon Sep 17 00:00:00 2001 From: astrojhgu Date: Mon, 15 Dec 2008 07:26:12 +0000 Subject: git-svn-id: file:///home/svn/opt_utilities@1 ed2142bd-67ad-457f-ba7c-d818d4011675 --- core/default_data_set.hpp | 47 ++ core/fitter.hpp | 1043 ++++++++++++++++++++++++++ core/freeze_param.hpp | 204 ++++++ core/opt_exception.hpp | 106 +++ core/opt_traits.hpp | 64 ++ core/optimizer.hpp | 289 ++++++++ guide.pdf | Bin 0 -> 27213 bytes history.log | 239 ++++++ interface/makefile | 13 + interface/opt.cc | 181 +++++ interface/opt.h | 29 + makefile | 67 ++ methods/gsl_simplex/gsl_simplex.hpp | 199 +++++ methods/powell/bas_util.hpp | 63 ++ methods/powell/brent.hpp | 110 +++ methods/powell/linmin.hpp | 102 +++ methods/powell/mnbrak.hpp | 81 +++ methods/powell/powell_method.hpp | 251 +++++++ misc/bootstrap.hpp | 132 ++++ misc/data_loaders.hpp | 180 +++++ models/add_model.hpp | 169 +++++ models/beta1d.hpp | 49 ++ models/beta2d.hpp | 60 ++ models/beta2d2.hpp | 73 ++ models/bl1d.hpp | 56 ++ models/bpl1d.hpp | 56 ++ models/bremss.hpp | 44 ++ models/constant.hpp | 42 ++ models/dbeta1d.hpp | 62 ++ models/dbeta2d.hpp | 92 +++ models/dbeta2d2.hpp | 100 +++ models/dbeta2d3.hpp | 91 +++ models/dl_model.hpp | 178 +++++ models/dlmodel_template.c | 36 + models/func_model.hpp | 57 ++ models/gauss1d.hpp | 47 ++ models/lin1d.hpp | 42 ++ models/models.cc | 176 +++++ models/models.hpp | 36 + models/mul_model.hpp | 171 +++++ models/nbeta1d.hpp | 49 ++ models/nfw1d.hpp | 45 ++ models/pl1d.hpp | 43 ++ models/poly1d.hpp | 67 ++ models/pow_model.hpp | 120 +++ models/strmodel1d.cc | 82 +++ models/strmodel1d.hpp | 39 + models/vecn.hpp | 62 ++ muparser/makefile | 16 + muparser/muParser.cpp | 259 +++++++ muparser/muParser.h | 104 +++ muparser/muParserBase.cpp | 1364 +++++++++++++++++++++++++++++++++++ muparser/muParserBase.h | 324 +++++++++ muparser/muParserBytecode.cpp | 396 ++++++++++ muparser/muParserBytecode.h | 148 ++++ muparser/muParserCallback.cpp | 198 +++++ muparser/muParserCallback.h | 94 +++ muparser/muParserDLL.cpp | 657 +++++++++++++++++ muparser/muParserDLL.h | 123 ++++ muparser/muParserDef.h | 239 ++++++ muparser/muParserError.cpp | 300 ++++++++ muparser/muParserError.h | 160 ++++ muparser/muParserFixes.h | 196 +++++ muparser/muParserInt.cpp | 264 +++++++ muparser/muParserInt.h | 93 +++ muparser/muParserStack.h | 120 +++ muparser/muParserTest.cpp | 1125 +++++++++++++++++++++++++++++ muparser/muParserTest.h | 176 +++++ muparser/muParserToken.h | 464 ++++++++++++ muparser/muParserTokenReader.cpp | 822 +++++++++++++++++++++ muparser/muParserTokenReader.h | 156 ++++ run_me | 5 + samples/a | Bin 0 -> 9817 bytes samples/a.cc | 36 + samples/a.dat | 4 + samples/bpl.dat | 901 +++++++++++++++++++++++ samples/gauss.dat | 901 +++++++++++++++++++++++ samples/linear.dat | 4 + samples/powerlaw.dat | 901 +++++++++++++++++++++++ statistics/chisq.hpp | 163 +++++ statistics/cstat.hpp | 66 ++ test.cc | 142 ++++ test1.cc | 149 ++++ utilities/opt_types.hpp | 29 + version_ctrl.cc | 18 + 85 files changed, 16661 insertions(+) create mode 100644 core/default_data_set.hpp create mode 100644 core/fitter.hpp create mode 100644 core/freeze_param.hpp create mode 100644 core/opt_exception.hpp create mode 100644 core/opt_traits.hpp create mode 100644 core/optimizer.hpp create mode 100644 guide.pdf create mode 100644 history.log create mode 100644 interface/makefile create mode 100644 interface/opt.cc create mode 100644 interface/opt.h create mode 100644 makefile create mode 100644 methods/gsl_simplex/gsl_simplex.hpp create mode 100644 methods/powell/bas_util.hpp create mode 100644 methods/powell/brent.hpp create mode 100644 methods/powell/linmin.hpp create mode 100644 methods/powell/mnbrak.hpp create mode 100644 methods/powell/powell_method.hpp create mode 100644 misc/bootstrap.hpp create mode 100644 misc/data_loaders.hpp create mode 100644 models/add_model.hpp create mode 100644 models/beta1d.hpp create mode 100644 models/beta2d.hpp create mode 100644 models/beta2d2.hpp create mode 100644 models/bl1d.hpp create mode 100644 models/bpl1d.hpp create mode 100644 models/bremss.hpp create mode 100644 models/constant.hpp create mode 100644 models/dbeta1d.hpp create mode 100644 models/dbeta2d.hpp create mode 100644 models/dbeta2d2.hpp create mode 100644 models/dbeta2d3.hpp create mode 100644 models/dl_model.hpp create mode 100644 models/dlmodel_template.c create mode 100644 models/func_model.hpp create mode 100644 models/gauss1d.hpp create mode 100644 models/lin1d.hpp create mode 100644 models/models.cc create mode 100644 models/models.hpp create mode 100644 models/mul_model.hpp create mode 100644 models/nbeta1d.hpp create mode 100644 models/nfw1d.hpp create mode 100644 models/pl1d.hpp create mode 100644 models/poly1d.hpp create mode 100644 models/pow_model.hpp create mode 100644 models/strmodel1d.cc create mode 100644 models/strmodel1d.hpp create mode 100644 models/vecn.hpp create mode 100644 muparser/makefile create mode 100644 muparser/muParser.cpp create mode 100644 muparser/muParser.h create mode 100644 muparser/muParserBase.cpp create mode 100644 muparser/muParserBase.h create mode 100644 muparser/muParserBytecode.cpp create mode 100644 muparser/muParserBytecode.h create mode 100644 muparser/muParserCallback.cpp create mode 100644 muparser/muParserCallback.h create mode 100644 muparser/muParserDLL.cpp create mode 100644 muparser/muParserDLL.h create mode 100644 muparser/muParserDef.h create mode 100644 muparser/muParserError.cpp create mode 100644 muparser/muParserError.h create mode 100644 muparser/muParserFixes.h create mode 100644 muparser/muParserInt.cpp create mode 100644 muparser/muParserInt.h create mode 100644 muparser/muParserStack.h create mode 100644 muparser/muParserTest.cpp create mode 100644 muparser/muParserTest.h create mode 100644 muparser/muParserToken.h create mode 100644 muparser/muParserTokenReader.cpp create mode 100644 muparser/muParserTokenReader.h create mode 100755 run_me create mode 100755 samples/a create mode 100644 samples/a.cc create mode 100644 samples/a.dat create mode 100644 samples/bpl.dat create mode 100644 samples/gauss.dat create mode 100644 samples/linear.dat create mode 100644 samples/powerlaw.dat create mode 100644 statistics/chisq.hpp create mode 100644 statistics/cstat.hpp create mode 100644 test.cc create mode 100644 test1.cc create mode 100644 utilities/opt_types.hpp create mode 100644 version_ctrl.cc diff --git a/core/default_data_set.hpp b/core/default_data_set.hpp new file mode 100644 index 0000000..be06c04 --- /dev/null +++ b/core/default_data_set.hpp @@ -0,0 +1,47 @@ +#ifndef DEFAULT_DATA_SET +#define DEFAULT_DATA_SET +#include "fitter.hpp" +#include + + +namespace opt_utilities +{ + +template +class default_data_set + :public data_set +{ +private: + std::vector > data_vec; + + data_set* do_clone()const + { + return new default_data_set(*this); + } + + + const data& do_get_data(int i)const + { + return data_vec.at(i); + } + + int do_size()const + { + return data_vec.size(); + } + + void do_push_back(const data& d) + { + data_vec.push_back(d); + } + + void do_clear() + { + data_vec.clear(); + } + +}; +} + +#endif +//EOF diff --git a/core/fitter.hpp b/core/fitter.hpp new file mode 100644 index 0000000..ed90a83 --- /dev/null +++ b/core/fitter.hpp @@ -0,0 +1,1043 @@ +#ifndef FITTER_HPP +#define FITTER_HPP +#include "opt_exception.hpp" +#include "optimizer.hpp" +#include +#include +#include +#include +#include +namespace opt_utilities +{ + + /////////////////////////////////// + //////class data/////////////////// + //////contain single data point//// + /////////////////////////////////// + template + class statistic; + + template + class param_modifier; + + + template + class data + { + private: + Tx x,x_lower_err,x_upper_err; + Ty y,y_lower_err,y_upper_err; + public: + data(const Tx& _x,const Ty& _y,const Ty& _y_lower_err,const Ty& _y_upper_err,const Tx& _x_lower_err,const Tx& _x_upper_err) + { + opt_eq(x,_x); + opt_eq(x_lower_err,_x_lower_err); + opt_eq(x_upper_err,_x_upper_err); + opt_eq(y,_y); + opt_eq(y_lower_err,_y_lower_err); + opt_eq(y_upper_err,_y_upper_err); + + } + + data() + :x(), + x_lower_err(), + x_upper_err(), + y(), + y_lower_err(), + y_upper_err() + {} + + data(const data& rhs) + { + opt_eq(x,rhs.x); + opt_eq(x_lower_err,rhs.x_lower_err); + opt_eq(x_upper_err,rhs.x_upper_err); + opt_eq(y,rhs.y); + opt_eq(y_lower_err,rhs.y_lower_err); + opt_eq(y_upper_err,rhs.y_upper_err); + } + + data& operator=(const data& rhs) + { + opt_eq(x,rhs.x); + opt_eq(x_lower_err,rhs.x_lower_err); + opt_eq(x_upper_err,rhs.x_upper_err); + opt_eq(y,rhs.y); + opt_eq(y_lower_err,rhs.y_lower_err); + opt_eq(y_upper_err,rhs.y_upper_err); + return *this; + } + + public: + const Tx& get_x()const + { + return x; + } + + const Tx& get_x_lower_err()const + { + return x_lower_err; + } + + const Tx& get_x_upper_err()const + { + return x_upper_err; + } + + const Ty& get_y()const + { + return y; + } + + const Ty& get_y_lower_err()const + { + return y_lower_err; + } + + const Ty& get_y_upper_err()const + { + return y_upper_err; + } + + + void set_x(const Tx& _x) + { + opt_eq(x,_x); + } + + void set_x_lower_err(const Tx& _x) + { + opt_eq(x_lower_err,_x); + } + + void set_x_upper_err(const Tx& _x) + { + opt_eq(x_upper_err,_x); + } + + void set_y(const Ty& _y) + { + opt_eq(y,_y); + } + + void set_y_lower_err(const Ty& _y) + { + opt_eq(y_lower_err,_y); + } + + void set_y_upper_err(const Ty& _y) + { + opt_eq(y_upper_err,_y); + } + + + }; + + //////////////////////////////////// + ///class data_set/////////////////// + ///contain a set of data//////////// + //////////////////////////////////// + + + template + class data_set + { + private: + + virtual const data& do_get_data(int i)const=0; + virtual int do_size()const=0; + virtual void do_push_back(const data&)=0; + virtual void do_clear()=0; + virtual data_set* do_clone()const=0; + + virtual void do_destroy() + { + delete this; + } + public: + const data& get_data(int i)const + { + return this->do_get_data(i); + } + int size()const + { + return do_size(); + } + void push_back(const data& d) + { + return do_push_back(d); + } + void clear() + { + do_clear(); + } + + data_set* clone()const + { + return this->do_clone(); + } + + void destroy() + { + do_destroy(); + } + + virtual ~data_set(){} + + }; + + /////////////////////////////////////////////// + /////class param_info////////////////////////// + /////record the information of one parameter/// + /////including the name, default value///////// + /////////////////////////////////////////////// + + + template + class param_info + { + private: + Tstr name; + //bool frozen; + typename element_type_trait::element_type default_value; + + public: + param_info(const Tstr& _name, + const typename element_type_trait::element_type& _v) + :name(_name),default_value(_v){} + + param_info() + :name() + {} + + param_info(const param_info& rhs) + :name(rhs.name) + { + opt_eq(default_value,rhs.default_value); + } + + param_info& operator=(const param_info& rhs) + { + name=rhs.name; + opt_eq(default_value,rhs.default_value); + return *this; + } + + const Tstr& get_name()const + { + return this->name; + } + + const typename element_type_trait::element_type& get_default_value()const + { + return default_value; + } + + void set_default_value(const typename element_type_trait::element_type& x) + { + opt_eq(default_value,x); + } + + void set_name(const Tstr& _name) + { + name=_name; + } + }; + + + + + + template + class model + { + private: + std::vector > param_info_list; + param_info null_param; + // int num_free_params; + param_modifier* p_param_modifier; + private: + virtual model* do_clone()const=0; + + virtual void do_destroy() + { + delete this; + } + public: + model* clone()const + { + return do_clone(); + } + + void destroy() + { + do_destroy(); + } + public: + model() + :p_param_modifier(0) + {} + + model(const model& rhs) + :p_param_modifier(0) + { + if(rhs.p_param_modifier!=0) + { + set_param_modifier(*(rhs.p_param_modifier)); + } + param_info_list=rhs.param_info_list; + null_param=rhs.null_param; + + } + + model& operator=(const model& rhs) + { + if(this==&rhs) + { + return *this; + } + if(rhs.p_param_modifier!=0) + { + set_param_modifier(*(rhs.p_param_modifier)); + } + param_info_list=rhs.param_info_list; + null_param=rhs.null_param; + return *this; + } + + virtual ~model() + { + if(p_param_modifier) + { + //delete p_param_modifier; + p_param_modifier->destroy(); + } + } + + void set_param_modifier(const param_modifier& pm) + { + if(p_param_modifier!=0) + { + //delete p_param_modifier; + p_param_modifier->destroy(); + } + p_param_modifier=pm.clone(); + p_param_modifier->set_model(*this); + } + + void set_param_modifier() + { + if(p_param_modifier!=0) + { + //delete p_param_modifier; + p_param_modifier->destroy(); + } + p_param_modifier=0; + } + + param_modifier& get_param_modifier() + { + if(p_param_modifier==0) + { + throw param_modifier_undefined(); + } + return *p_param_modifier; + } + + Tstr report_param_status(const Tstr& s)const + { + if(p_param_modifier==0) + { + return Tstr(); + } + + return p_param_modifier->report_param_status(s); + + } + + + const param_info& get_param_info(const Tstr& pname) + { + for(typename std::vector >::iterator i=param_info_list.begin(); + i!=param_info_list.end();++i) + { + if(i->get_name()==pname) + { + return *i; + } + } + std::cerr<<"Param unfound!"<& get_param_info(int n)const + { + return param_info_list[n%get_num_params()]; + } + + + Tp get_all_params()const + { + Tp result; + resize(result,param_info_list.size()); + for(size_t i=0;iget_num_free_params(); + } + return get_num_params(); + } + + void set_param_value(const Tstr& pname, + const typename element_type_trait::element_type& v) + { + //int porder=0; + for(typename std::vector >::iterator i=param_info_list.begin(); + i!=param_info_list.end();++i) + { + if(i->get_name()==pname) + { + i->set_default_value(v); + return; + } + } + std::cerr<<"param "<& pinfo) + { + param_info_list.push_back(pinfo); + // this->num_free_params++; + } + + void clear_param_info() + { + // this->num_free_params=0; + param_info_list.clear(); + } + + + + public: + Tstr to_string()const + { + return do_to_string(); + } + + Tp reform_param(const Tp& p)const + { + if(p_param_modifier==0) + { + return p; + } + return p_param_modifier->reform(p); + } + + Tp deform_param(const Tp& p)const + { + if(p_param_modifier==0) + { + return p; + } + return p_param_modifier->deform(p); + } + + + Ty eval(const Tx& x,const Tp& p) + { + return do_eval(x,reform_param(p)); + } + + virtual Ty do_eval(const Tx& x,const Tp& p)=0; + + private: + virtual Tstr do_to_string()const + { + return Tstr(); + } + + }; + + + + template + class fitter + { + public: + model* p_model; + statistic* p_statistic; + data_set* p_data_set; + optimizer optengine; + public: + fitter() + :p_model(0),p_statistic(0),p_data_set(0),optengine() + {} + + + fitter(const fitter& rhs) + :p_model(0),p_statistic(0),p_data_set(0),optengine() + { + if(rhs.p_model!=0) + { + set_model(*(rhs.p_model)); + } + if(rhs.p_statistic!=0) + { + set_statistic(*(rhs.p_statistic)); + assert(p_statistic->p_fitter!=0); + } + if(rhs.p_data_set!=0) + { + load_data(*(rhs.p_data_set)); + } + optengine=rhs.optengine; + } + + fitter& operator=(const fitter& rhs) + { + if(this==&rhs) + { + return *this; + } + if(rhs.p_model!=0) + { + set_model(*(rhs.p_model)); + } + if(rhs.p_statistic!=0) + { + set_statistic(*(rhs.p_statistic)); + } + if(rhs.p_data_set!=0) + { + load_data(*(rhs.p_data_set)); + } + optengine=rhs.optengine; + return *this; + } + + virtual ~fitter() + { + if(p_model!=0) + { + //delete p_model; + p_model->destroy(); + } + if(p_statistic!=0) + { + //delete p_statistic; + p_statistic->destroy(); + } + if(p_data_set!=0) + { + //delete p_data_set; + p_data_set->destroy(); + } + } + + + Ty eval_model(const Tx& x,const Tp& p) + { + if(p_model==0) + { + throw model_undefined(); + } + return p_model->eval(x,p); + } + + + public: + void set_model(const model& m) + { + if(p_model!=0) + { + //delete p_model; + p_model->destroy(); + } + p_model=m.clone(); + //p_model=&m; + // current_param.resize(m.get_num_params()); + } + /* + void set(const model& m) + { + set_model(m); + } + */ + void set_statistic(const statistic& s) + { + if(p_statistic!=0) + { + //delete p_statistic; + p_statistic->destroy(); + } + p_statistic=s.clone(); + //p_statistic=&s; + p_statistic->set_fitter(*this); + } + /* + void set(const statistic& s) + { + set_statistic(s); + } + */ + + void set_param_modifier(const param_modifier& pm) + { + if(p_model==0) + { + throw model_undefined(); + } + p_model->set_param_modifier(pm); + } + + void set_param_modifier() + { + if(p_model==0) + { + throw model_undefined(); + } + p_model->set_param_modifier(); + } + + param_modifier& get_param_modifier() + { + if(p_model==0) + { + throw model_undefined(); + } + return p_model->get_param_modifier(); + } + + Tstr report_param_status(const Tstr& s)const + { + if(p_model==0) + { + throw model_undefined(); + } + return p_model->report_param_status(s); + } + + /* + void set(const param_modifier& pm) + { + set_param_modifier(pm); + } + */ + void load_data(const data_set& da) + { + if(p_data_set!=0) + { + //delete p_data_set; + p_data_set->destroy(); + } + p_data_set=da.clone(); + if(p_statistic!=0) + { + p_statistic->set_fitter(*this); + } + } + + const data_set& datas()const + { + if(p_data_set==0) + { + throw data_unloaded(); + } + return *(this->p_data_set); + } + + model& model() + { + if(p_model==0) + { + throw model_undefined(); + } + return *(this->p_model); + } + + statistic& statistic() + { + if(p_statistic==0) + { + throw statistic_undefined(); + } + return *(this->p_statistic); + } + + opt_method& method() + { + return optengine.method(); + } + + + public: + void set_param_value(const Tstr& pname, + const typename element_type_trait::element_type& v) + { + if(p_model==0) + { + throw model_undefined(); + } + p_model->set_param_value(pname,v); + } + + void set_param_value(const Tp& param) + { + if(p_model==0) + { + throw model_undefined(); + } + p_model->set_param_value(param); + } + + typename element_type_trait::element_type get_param_value(const Tstr& pname)const + { + if(p_model==0) + { + throw model_undefined(); + } + return p_model->get_param_info(pname).get_default_value(); + } + + const param_info& get_param_info(const Tstr& pname)const + { + if(p_model==0) + { + throw model_undefined(); + } + return p_model->get_param_info(pname); + } + + const param_info& get_param_info(int n)const + { + if(p_model==0) + { + throw model_undefined(); + } + return p_model->get_param_info(n); + } + + const int get_param_order(const Tstr& pname)const + { + if(p_model==0) + { + throw model_undefined(); + } + return p_model->get_param_order(pname); + } + + int get_num_params()const + { + if(p_model==0) + { + throw model_undefined(); + } + return p_model->get_num_params(); + } + + Tp get_all_params()const + { + if(p_model==0) + { + throw model_undefined(); + } + //return current_param; + return p_model->get_all_params(); + } + + void set_method(const opt_method& pm) + { + //assert(p_optimizer!=0); + optengine.set_opt_method(pm); + } + /* + void set(const opt_method& pm) + { + set_method(pm); + } + */ + void set_precision(typename element_type_trait::element_type y) + { + optengine.set_precision(y); + } + + Tp fit() + { + // assert(p_model!=0); + if(p_model==0) + { + throw model_undefined(); + } + if(p_data_set==0) + { + throw data_unloaded(); + } + //assert(p_optimizer!=0); + //assert(p_data_set!=0); + //assert(p_statistic!=0); + if(p_statistic==0) + { + throw statistic_undefined(); + } + + optengine.set_func_obj(*p_statistic); + Tp current_param; + opt_eq(current_param,p_model->get_all_params()); + Tp start_point; + opt_eq(start_point,p_model->deform_param(current_param)); + // std::cout<get_all_params(); + } + optengine.set_start_point(start_point); + + Tp result; + opt_eq(result,optengine.optimize()); + + Tp decurrent_param; + opt_eq(decurrent_param,p_model->reform_param(result)); + //current_param.resize(decurrent_param.size()); + resize(current_param,get_size(decurrent_param)); + opt_eq(current_param,decurrent_param); + p_model->set_param_value(current_param); + // return current_param; + return p_model->get_all_params(); + } + + }; + + + template + class statistic + :public func_obj + { + public: + fitter* p_fitter; + + private: + virtual statistic* do_clone()const=0; + + virtual void do_destroy() + { + delete this; + } + + public: + statistic* clone()const + { + return this->do_clone(); + } + + void destroy() + { + return do_destroy(); + } + statistic() + :p_fitter(0) + {} + + statistic(const statistic& rhs) + :p_fitter(rhs.p_fitter) + {} + + statistic& operator=(const statistic& rhs) + { + if(this==&rhs) + { + return *this; + } + p_fitter=rhs.p_fitter; + return *this; + } + + virtual ~statistic() + {} + + virtual void set_fitter(fitter& pfitter) + { + p_fitter=&pfitter; + } + + virtual const fitter& get_fitter()const + { + if(p_fitter==0) + { + throw fitter_unset(); + } + return *p_fitter; + } + + Ty eval_model(const Tx& x,const Tp& p) + { + if(p_fitter==0) + { + throw fitter_unset(); + } + return p_fitter->eval_model(x,p); + } + + + const data_set& datas()const + { + if(p_fitter==0) + { + throw fitter_unset(); + } + return p_fitter->datas(); + } + + }; + + template + class param_modifier + { + private: + model* p_model; + public: + Tp reform(const Tp& p)const + { + return do_reform(p); + } + Tp deform(const Tp& p)const + { + return do_deform(p); + } + + param_modifier* clone()const + { + return do_clone(); + } + + void destroy() + { + do_destroy(); + } + + public: + + param_modifier() + :p_model(0) + {} + + param_modifier(const param_modifier& rhs) + :p_model(rhs.p_model) + {} + + param_modifier& operator=(const param_modifier& rhs) + { + if(this==&rhs) + { + return *this; + } + p_model=rhs.p_model; + return *this; + } + + public: + void set_model(model& pf) + { + p_model=&pf; + update(); + } + + const model& get_model()const + { + if(p_model==0) + { + std::cout<<"dajf;asdjfk;"; + throw model_undefined(); + } + return *(this->p_model); + } + + int get_num_free_params()const + { + return do_get_num_free_params(); + } + + Tstr report_param_status(const Tstr& name)const + { + return do_report_param_status(name); + } + + + virtual ~param_modifier(){} + private: + virtual Tp do_reform(const Tp& p)const=0; + virtual Tp do_deform(const Tp& p)const=0; + virtual int do_get_num_free_params()const=0; + virtual Tstr do_report_param_status(const Tstr&)const=0; + virtual void update(){} + + virtual param_modifier* do_clone()const=0; + + virtual void do_destroy() + { + delete this; + } + + }; + + + +}; + + +#endif +//EOF diff --git a/core/freeze_param.hpp b/core/freeze_param.hpp new file mode 100644 index 0000000..8ba677a --- /dev/null +++ b/core/freeze_param.hpp @@ -0,0 +1,204 @@ +#ifndef FREEZE_PARAM_HPP +#define FREEZE_PARAM_HPP +#include "fitter.hpp" +#include +#include + +namespace opt_utilities +{ + template + class freeze_param + :public param_modifier + { + private: + std::set param_names; + std::vector param_num; + int num_free; + + public: + freeze_param() + { + + } + + freeze_param(const Tstr& name) + { + param_names.insert(name); + } + + private: + freeze_param* do_clone()const + { + return new freeze_param(*this); + } + + + + void update() + { + param_num.clear(); + for(typename std::set::const_iterator i=param_names.begin(); + i!=param_names.end();++i) + { + try + { + param_num.push_back(this->get_model().get_param_order(*i)); + } + catch(opt_exception& e) + { + param_names.erase(*i); + throw; + } + + } + } + + int do_get_num_free_params()const + { + return this->get_model().get_num_params()-param_num.size(); + } + + bool is_frozen(int i)const + { + if(find(param_num.begin(),param_num.end(),i)==param_num.end()) + { + return false; + } + return true; + } + + + Tp do_reform(const Tp& p)const + { + int nparams=(this->get_model().get_num_params()); + Tp reformed_p(nparams); + int i=0,j=0; + for(i=0;i<(int)nparams;++i) + { + if(this->is_frozen(i)) + { + const param_info& pinf=this->get_model().get_param_info(i); + //std::cout<<"frozen:"<get_model().get_num_params()); + for(;i<(int)get_size(p);++i) + { + //std::cout<is_frozen(i)) + { + //opt_eq(get_element(deformed_p,j),get_element(p,i)); + set_element(deformed_p,j,get_element(p,i)); + j++; + } + } + + assert(j==do_get_num_free_params()); + return deformed_p; + } + + + Tstr do_report_param_status(const Tstr& name)const + { + if(param_names.find(name)==param_names.end()) + { + return "thawed"; + } + return "frozen"; + } + + public: + freeze_param operator+(const freeze_param& fp)const + { + freeze_param result(*this); + for(typename std::set::const_iterator i=fp.param_names.begin(); + i!=fp.param_names.end(); + ++i) + { + result.param_names.insert(*i); + } + return result; + } + + freeze_param& operator+=(const freeze_param& fp) + { + //param_names.insert(param_names.end(), + //fp.param_names.begin(), + //fp.param_names.end()); + for(typename std::set::const_iterator i=fp.param_names.begin(); + i!=fp.param_names.end(); + ++i) + { + param_names.insert(*i); + } + try + { + update(); + } + catch(opt_exception& e) + { + throw; + } + return *this; + } + + freeze_param& operator-=(const freeze_param& fp) + { + //param_names.insert(param_names.end(), + //fp.param_names.begin(), + //fp.param_names.end()); + for(typename std::set::const_iterator i=fp.param_names.begin(); + i!=fp.param_names.end(); + ++i) + { + param_names.erase(*i); + } + try + { + update(); + } + catch(opt_exception& e) + { + throw; + } + return *this; + } + + }; + + template + freeze_param freeze(const Tstr& name) + { + return freeze_param(name); + } + +}; + + +#endif +//EOF diff --git a/core/opt_exception.hpp b/core/opt_exception.hpp new file mode 100644 index 0000000..925e4b5 --- /dev/null +++ b/core/opt_exception.hpp @@ -0,0 +1,106 @@ +#ifndef OPT_EXCEPTION +#define OPT_EXCEPTION +#include +#include +namespace opt_utilities +{ + class opt_exception + :public std::exception + { + private: + std::string _what; + public: + opt_exception() + {}; + + ~opt_exception()throw() + {} + + opt_exception(const std::string& str) + :_what(str) + {} + + const char* what()const throw() + { + return _what.c_str(); + } + }; + + class target_function_undefined + :public opt_exception + { + public: + target_function_undefined() + :opt_exception("target function undefined") + {} + }; + + class opt_method_undefined + :public opt_exception + { + public: + opt_method_undefined() + :opt_exception("opt method undefined") + {} + }; + + class fitter_unset + :public opt_exception + { + public: + fitter_unset() + :opt_exception("fitter_unset") + {} + }; + + class model_undefined + :public opt_exception + { + public: + model_undefined() + :opt_exception("model_undefined") + {} + }; + + class data_unloaded + :public opt_exception + { + public: + data_unloaded() + :opt_exception("data not loaded") + {} + }; + + + class statistic_undefined + :public opt_exception + { + public: + statistic_undefined() + :opt_exception("statistic undefined") + {} + }; + + class param_not_found + :public opt_exception + { + public: + param_not_found() + :opt_exception("param name invalid") + {} + }; + + class param_modifier_undefined + :public opt_exception + { + public: + param_modifier_undefined() + :opt_exception("param modifier undefined") + {} + }; + +}; + + +#endif +//EOF diff --git a/core/opt_traits.hpp b/core/opt_traits.hpp new file mode 100644 index 0000000..c539a63 --- /dev/null +++ b/core/opt_traits.hpp @@ -0,0 +1,64 @@ +#ifndef ARRAY_OPERATION +#define ARRAY_OPERATION +#include +namespace opt_utilities +{ + /////////Useful function/////////////////////////////////// + template + inline size_t get_size(const T& x) + { + return x.size(); + } + + template + class element_type_trait + { + public: + typedef typename T::value_type element_type; + }; + + template + class return_type_trait + { + public: + typedef T value_type; + typedef T& reference_type; + typedef const T& const_reference_type; + }; + + template + inline typename return_type_trait::element_type>::const_reference_type get_element(const T& x,size_t i) + { + return x[i]; + } + /* + template + inline typename element_type_trait::element_type& get_element(T& x,size_t i) + { + return x[i]; + } + */ + + template + inline void set_element(T& x,size_t i, + const TX& v) + { + x[i]=v; + } + + template + inline void resize(T& x,size_t s) + { + x.resize(s); + } + + template + inline Tl& opt_eq(Tl& lhs,const Tr& rhs) + { + return (lhs=rhs); + } +}; + + + +#endif diff --git a/core/optimizer.hpp b/core/optimizer.hpp new file mode 100644 index 0000000..ca73775 --- /dev/null +++ b/core/optimizer.hpp @@ -0,0 +1,289 @@ +#ifndef OPTIMZER_H_ +#define OPTIMZER_H_ +//#define DEBUG +#include +#include "opt_traits.hpp" +#include "opt_exception.hpp" +#include +#include +#ifdef DEBUG +#include +using namespace std; +#endif + +namespace opt_utilities +{ + /////////Forward declare/////////////////////////////////// + template + class optimizer; + + template + class func_obj; + + template + class opt_method; + + + //////////////Target Function///////////////////// + ///An eval function should be implemented///////// + ///The eval function return the function value//// + ///which is wrapped by the func_obj/////////////// + ////////////////////////////////////////////////// + template + class func_obj + :public std::unary_function + { + private: + virtual rT do_eval(const pT&)=0; + virtual func_obj* do_clone()const=0; + virtual void do_destroy() + { + delete this; + } + + public: + public: + func_obj* clone()const + { + return do_clone(); + } + + void destroy() + { + do_destroy(); + } + + rT operator()(const pT& p) + { + return do_eval(p); + } + + + rT eval(const pT& p) + { + return do_eval(p); + }; + virtual ~func_obj(){}; + // virtual XT walk(XT,YT)=0; + }; + + + ///////////////Optimization method////////////////////// + + template + class opt_method + { + public: + virtual void do_set_optimizer(optimizer&)=0; + virtual void do_set_precision(rT)=0; + virtual pT do_optimize()=0; + virtual void do_set_start_point(const pT& p)=0; + virtual opt_method* do_clone()const=0; + + virtual void do_destroy() + { + delete this; + } + public: + void set_optimizer(optimizer& op) + { + do_set_optimizer(op); + }; + + void set_precision(rT x) + { + do_set_precision(x); + } + + void set_start_point(const pT& p) + { + do_set_start_point(p); + } + + pT optimize() + { + return do_optimize(); + }; + + opt_method* clone()const + { + return do_clone(); + } + + void destroy() + { + do_destroy(); + } + + virtual ~opt_method(){}; + }; + + + ///////////Optimizer//////////////////////////////////// + template + class optimizer + { + public: + + private: + + ////////////pointer to an optimization method objection//////////// + ////////////The optimization method implements a certain method /// + ////////////Currently only Mont-carlo method is implemented//////// + opt_method* p_opt_method; + func_obj* p_func_obj; + + public: + optimizer() + :p_opt_method(0),p_func_obj(0) + {} + + optimizer(func_obj& fc,const opt_method& om) + :p_func_obj(fc.clone()),p_opt_method(om.clone()) + { + p_opt_method->set_optimizer(*this); + } + + optimizer(const optimizer& rhs) + :p_opt_method(0),p_func_obj(0) + { + if(rhs.p_func_obj!=0) + { + set_func_obj(*(rhs.p_func_obj)); + } + if(rhs.p_opt_method!=0) + { + set_opt_method(*(rhs.p_opt_method)); + } + } + + optimizer& operator=(const optimizer& rhs) + { + if(this==&rhs) + { + return *this; + } + if(rhs.p_func_obj!=0) + { + set_func_obj(*(rhs.p_func_obj)); + } + if(rhs.p_opt_method!=0) + { + set_opt_method(*(rhs.p_opt_method)); + } + return *this; + } + + + virtual ~optimizer() + { + if(p_func_obj!=0) + { + //delete p_func_obj; + p_func_obj->destroy(); + } + if(p_opt_method!=0) + { + //delete p_opt_method; + p_opt_method->destroy(); + } + }; + + public: + ////////////Re-set target function object/////////////////////////// + void set_func_obj(const func_obj& fc) + { + if(p_func_obj!=0) + { + //delete p_func_obj; + p_func_obj->destroy(); + } + p_func_obj=fc.clone(); + if(p_opt_method!=0) + { + p_opt_method->set_optimizer(*this); + } + } + + ////////////Re-set optimization method////////////////////////////// + void set_opt_method(const opt_method& om) + { + if(p_opt_method!=0) + { + //delete p_opt_method; + p_opt_method->destroy(); + } + + p_opt_method=om.clone(); + p_opt_method->set_optimizer(*this); + } + + opt_method& method() + { + if(p_opt_method==0) + { + throw opt_method_undefined(); + } + return *(this->p_opt_method); + } + + void set_precision(rT x) + { + if(p_opt_method==0) + { + throw opt_method_undefined(); + } + p_opt_method->set_precision(x); + } + + void set_start_point(const pT& x) + { + if(p_opt_method==0) + { + throw opt_method_undefined(); + } + p_opt_method->set_start_point(x); + } + + ////////////Just call the eval function in the target function object/// + ////////////In case the pointer to a target function is uninitialed///// + ////////////a zero-value is returned//////////////////////////////////// + rT eval(const pT& x) + { + if(p_func_obj==0) + { + throw target_function_undefined(); + } + return p_func_obj->eval(x); + } + + + + ////////////Just call the optimize() function in the optimization method// + ////////////If no optimization method is given, an zero-value is returned/ + pT optimize() + { + if(p_opt_method==0) + { + throw opt_method_undefined(); + } + if(p_func_obj==0) + { + throw target_function_undefined(); + } + return p_opt_method->optimize(); + } + + ////////////Function that offers the access to the target function object/// + func_obj* ptr_func_obj() + { + return p_func_obj; + } + + }; +}; + +#endif +//EOF + + diff --git a/guide.pdf b/guide.pdf new file mode 100644 index 0000000..3a8a39d Binary files /dev/null and b/guide.pdf differ diff --git a/history.log b/history.log new file mode 100644 index 0000000..7adefdd --- /dev/null +++ b/history.log @@ -0,0 +1,239 @@ +2008 Jan 21 + changed all std::string in parameter table to const std::string& + version 2.9.12 +2008 Jan 22 + changed optimizer::eval(pT& x) -> optimizer::eval(const pT& x) + version 2.9 13 +2008 Jan 22 + changed data::set_x(Tx x)->data::set_x(const Tx& x) + version 2.9.14 +2008 Jan 22 + changed the parameter set_param_value to a const reference. + version 2.10.1 + +2008 Jan 23 + removed the declaration of init_model_map etc. in models.hpp + version 2.10.2 + +2008 Jan 24 + added get_strm1d() interface to models.hpp and models.cc + version 2.10.3 + +2008 Feb 11 + modified some mistakes in models/ modified the nr_util, add T() in '?' expressions + version 2.11.1 +2008 Feb 12 + modified powell_method.hpp to enable the lib work around apfloat + version 2.11.2 + +2008 Feb 19 + modified the design of the data_loaders, add members:load_from, deleted the friend template declear in the class. + modified the fitter class, corrected a bug which happens when all parameters are frozen, the fitter will crash. + version 2.11.3 + + +2008 March 14 + Added a condition compiling to the dynamical load model + + +2008 March 21 + Modified a contition compiling to the dynamical load model, changed the marco from LINUX__ to __linux__ + +2008 March 27 + Made std::unary_function the base class of func_obj + version 2.12.1 + +2008 April 18 + Added nbeta1d into the model list + version 2.12.2 + +2008 May 10 + Added a bremss model + Added an opt_type.hpp + version 2.12.3 + +2008 May 12 + Added the declearation of virtual dstr function to some class + version 2.12.4 + + +2008 May 13 + Modified the makefile, to generate liboptutil.a + version 2.12.5 + +2008 May 14 + Updated the c/fortran callable interface + version 2.12.6 + +2008 May 22 + Modified the symbol definition of interface + version 2.12.7 + +2008 June 1 + Added the in the file fitter.hpp + version 2.12.8 + +2008 June 12 + Added NFW1D model + Cleaned some warnings + version 2.12.9 + +2008 Jun 19 + Modified fit2d task. Enables it to write fits file. + version 2.12.10 + +2008 Jun 23 + Modified the LINUX marco in models.cc + version 2.12.11 + +2008 Jun 25 + Added a pow_model, to enable power computation on models. + version 2.12.12 + +2008 Jun 27 + Added the function to query the number of build-in 1d and 2d models. + version 2.12.13 + + +2008 Jul 1 + Added a to_string and corresponding do_to_string method to class model. + version 2.13.0 + + +2008 Jul 1 + Implemented the do_to_string method in most 1d models + version 2.13.1 + + +2008 Jul 7 + Added another gsl_simplex method to perform the optimization. + version 2.14.0 + +2008 Jul 8 + Modified one bug caused by the head inclusion. The should be included. + version 2.14.1 + + +2008 Jul 8 + Enables the optcli program to display model infomation + version 2.14.2 + +2008 Jul 8 + Changed the methods include of head files. + Version 2.14.3 + +2008 Jul 10 + Corrected the include of optimizer.hpp in gsl_methods/gsl_simplex.hpp + version 2.14.4 + +2008 Jul 12 + Corrected the ``comparison between signed and unsigned integer'' warning + version 2.14.5 + +2008 Jul 14 + Modified the interface get_data in data_set class. + Changed the return value from data to const data& + version 2.15.0 + +2008 Jul 19 + Corrected a bug in gsl_simplex.hpp + version 2.15.1 + +2008 Jul 21 + Corrected the makefile in interface/ + version 2.15.2 + +2008 Jul 22 + Moved some files from core/ to separated folder. + version 2.15.3 + +2008 Jul 22 + version 2.15.4 + +2008 Jul 24 + Modified the makefile + version 2.15.5 + +2008 Jul 24 + Changed the project name from optimizer to opt_utilities + version 2.15.6 + +2008 Jul 25 + Enable the 'ls' command to display with color + version 2.15.7 + +2008 Aug 15 + Changed the x[i] into get_element(x,i), + Changed the x.size() into get_size(x). + version 2.16.0 + +2008 Aug 15 + Some further modification, added opt_eq function to represent '=' operation. + version 2.16.1 + +2008 Aug 15 + Modified some bugs + version 2.16.2 + +2008 Aug 16 + Added a set_element function + version 2.16.3 + +2008 Aug 17 + Changed the argument type of opt_get from single 'T' to 'Tl' and 'Tr' + version 2.16.4 + +2008 Aug 18 + Make the makefile more standard. + version 2.16.5 + +2008 Aug 22 + Added the inclusion of in array_operation.h + version 2.16.6 + +2008 Aug 24 + Added ./termcap to the inclusion of CFLAG + version 2.16.7 + +2008 Aug 25 + Modified the return type of param_info::get_default_value from T to const T& + version 2.16.8 +2008 Aug 25 + modifier a return type, added a const + version 2.16.9 + +2008 Aug 26 + Enabled the chisq statistic to take account of the x error + version 2.16.10 + +2008 Sep 2 + added a virtual function to some classes to enable them to destroy themselves. + version 2.16.11 + +2008 Sep 5 + changed the name value_type_trait to element_type_trait, added a return_type_trait + version 2.16.12 + +2008 Sep 27 + Corrected two bugs in the add_model.hpp and mul_model.hpp + version 2.16.13 + +2008 Oct 3 + Stripped the subpackages that uses GPL from it + version 2.17.0 + +2008 Nov 24 + Replaced all std::string with an extra template parameter Tstr, enables the ability of treating Unicode strings + version 2.18.0 + +2008 Nov 25 + Completed the exception tree + version 2.19.0 + +2008 Nov 25 + modified some string type related codes + version 2.19.1 + +2008 Nov 27 + corrected const correction in freeze_param.hpp + version 2.19.2 diff --git a/interface/makefile b/interface/makefile new file mode 100644 index 0000000..5cf7a99 --- /dev/null +++ b/interface/makefile @@ -0,0 +1,13 @@ +INC=-I../ + + +libopt.a:opt.o + $(AR) $@ opt.o + +opt.o:opt.cc opt.h + $(CPP) $< -o $@ $(INC) $(CPPFLAGS) + + +clean: + $(RM) *.o + $(RM) *~ diff --git a/interface/opt.cc b/interface/opt.cc new file mode 100644 index 0000000..51762f5 --- /dev/null +++ b/interface/opt.cc @@ -0,0 +1,181 @@ +#include "opt.h" +#include +#include +#include +#include +#include +//#include + +using namespace std; +using namespace opt_utilities; +const static int max_fit_space_num=100; +struct fit_space; +static map fit_space_map; +struct fit_space +{ + dopt::fitter fit; + /// dopt::model model; + fit_space() + { + fit.set_method(dopt::powell_method()); + dopt::chisq cq; + // cq.verbose(true); + fit.set_statistic(cq); + } + +}; + + +extern "C" +{ + +void alloc_fit_(int& n) +{ + n=0; + for(int i=1;i::iterator iter=fit_space_map.find(n); + if(iter==fit_space_map.end()) + { + return; + } + fit_space_map.erase(iter); +} + +void load_data_(const int& nfit,const int& ndatas,double* x,double* y,double* yl,double* yu,double* xl,double* xu) +{ + map::iterator iter=fit_space_map.find(nfit); + if(iter==fit_space_map.end()) + { + return; + } + // cout< ds; + for(int i=0;i d(x[i],y[i],yl[i],(yu==0?yl[i]:yu[i]),(xl==0?0:xl[i]),(xu==0?0:xu[i])); + // cout<second.fit.load_data(ds); +} + + +void set_model_(const int& nfit,const char* model_name) +{ + map::iterator iter=fit_space_map.find(nfit); + + if(iter==fit_space_map.end()) + { + cerr<<"fit not found"<second.fit.set_model(opt_utilities::get_1dmodel_by_name(model_name)); + } + catch(opt_exception& e) + { + //cout<::iterator iter=fit_space_map.find(nfit); + cerr<<"pname="<second.fit.set_param_value(pname,value); +} + + +void freeze_param_(const int& nfit,const char* pname) +{ + map::iterator iter=fit_space_map.find(nfit); + if(iter==fit_space_map.end()) + { + return; + } + opt_utilities::freeze_param > fp(pname); + try + { + dynamic_cast >& >(iter->second.fit.get_param_modifier())+=fp; + } + catch(opt_exception& e) + { + iter->second.fit.set_param_modifier(fp); + } +} + + +void thaw_param_(const int& nfit,const char* pname) +{ + map::iterator iter=fit_space_map.find(nfit); + if(iter==fit_space_map.end()) + { + return; + } + opt_utilities::freeze_param > fp(pname); + try + { + dynamic_cast >& >(iter->second.fit.get_param_modifier())-=fp; + } + catch(opt_exception& e) + { + //iter->second.fit.set_param_modifier(fp); + } +} + +void perform_fit_(const int& nfit) +{ + map::iterator iter=fit_space_map.find(nfit); + if(iter==fit_space_map.end()) + { + return; + } + iter->second.fit.fit(); +} + + +void get_param_(const int& nfit,double& r,const char* pname) +{ + map::iterator iter=fit_space_map.find(nfit); + if(iter==fit_space_map.end()) + { + //return 0; + cerr<<"fit not found"<second.fit.get_param_value(pname); + +} + + + +} + diff --git a/interface/opt.h b/interface/opt.h new file mode 100644 index 0000000..e9c3221 --- /dev/null +++ b/interface/opt.h @@ -0,0 +1,29 @@ +#ifndef OPT_H +#define OPT_H +#define F77 +#ifdef F77 +#define alloc_fit_ alloc_fit__ +#define free_fit_ free_fit__ +#define load_data_ load_data__ +#define set_model_ set_model__ +#define set_param_ set_param__ +#define freeze_param_ freeze_param__ +#define thaw_param_ thaw_param__ +#define perform_fit_ perform_fit__ +#define get_param_ get_param__ +#endif + +extern "C" +{ + void alloc_fit_(int&); + void free_fit_(const int& nxc); + void load_data_(const int& nfit,const int& ndatas,double* x,double* y,double* yl,double* yu=0,double* xl=0,double* xu=0); + void set_model_(const int& nfit,const char* model_name); + void set_param_(const int& nfit,const char* param_name,const double& value); + void freeze_param_(const int& nfit,const char* param_name); + void thraw_param_(const int& nfit,const char* param_name); + void perform_fit_(const int& nfit); + void get_param_(const int& nfit,double& r,const char* param_name); +} + +#endif diff --git a/makefile b/makefile new file mode 100644 index 0000000..e40ac11 --- /dev/null +++ b/makefile @@ -0,0 +1,67 @@ +OPT_HEADS=models/beta1d.hpp statistics/chisq.hpp models/lin1d.hpp\ + models/pl1d.hpp models/bl1d.hpp\ + core/fitter.hpp models/models.hpp\ + core/opt_traits.hpp\ + methods/powell/powell_method.hpp models/bpl1d.hpp\ + core/freeze_param.hpp\ + models/gauss1d.hpp core/optimizer.hpp\ + misc/bootstrap.hpp\ + models/dl_model.hpp\ + models/mul_model.hpp\ + models/add_model.hpp\ + +LDL=-ldl + +export CPP=g++ +export CC=gcc +export AR = ar rv +export RANLIB = ranlib +export RM=rm -f +export CFLAGS=-DNDEBUG -g -O2 -Wall -c -I . +export CPPFLAGS=-DNDEBUG -g -O2 -Wall -c -I . --ansi -DHAVE_X_ERROR + + +INC=-I. -I/usr/include/gsl/ +LIB= -L./muparser $(LDL) -lmuparser -g -lgsl -lgslcblas +OPT_OBJ=models/models.o version_ctrl.o models/strmodel1d.o + +TARGET=liboptcall test_dl.so models/strmodel1d.o models/models.o + +all: $(TARGET) + +models/models.o:models/models.cc ${OPT_HEADS} + $(CPP) -c $< -o $@ ${INC} ${CPPFLAGS} + +version_ctrl.o:version_ctrl.cc + $(CPP) -c $< ${CPPFLAGS} + +bin/test.o:test.cc ${OPT_HEADS} + $(CPP) -c $< -o $@ ${INC} ${CPPFLAGS} --ansi + +test:${OPT_OBJ} bin/test.o + $(CPP) bin/test.o models/strmodel1d.o models/models.o version_ctrl.o -o $@ ${LIB} + +test_dl.so:models/dlmodel_template.c + gcc $< --shared -o $@ + + +models/strmodel1d.o:models/strmodel1d.cc models/strmodel1d.hpp + $(CPP) -c $< -o $@ -I./muparser $(INC) $(CPPFLAGS) + + +libmuparser: + make -C muparser + +liboptcall: + make -C interface + +clean: + rm -f `find .|grep \~` + rm -f `find .|grep '\.o'` + rm -f muparser/libmuparser.a + make -C muparser clean + make -C interface clean + +distclean:clean + rm -f `find . -iname *.a` + rm -f $(TARGET) diff --git a/methods/gsl_simplex/gsl_simplex.hpp b/methods/gsl_simplex/gsl_simplex.hpp new file mode 100644 index 0000000..442c9f0 --- /dev/null +++ b/methods/gsl_simplex/gsl_simplex.hpp @@ -0,0 +1,199 @@ +#ifndef GSL_SIMPLEX_METHOD +#define GSL_SIMPLEX_METHOD +#include +//#include +#include +#include +#include +#include +#include +#include +/* + * +*/ +#include + + +namespace opt_utilities +{ + template + double gsl_func_adapter(const gsl_vector* v,void* params) + { + pT temp; + temp.resize(v->size); + for(size_t i=0;i*)params)->eval(temp); + } + + + template + class gsl_simplex + :public opt_method + { + public: + typedef pT array1d_type; + typedef rT T; + private: + func_obj* p_fo; + optimizer* p_optimizer; + + //typedef blitz::Array array2d_type; + + + private: + array1d_type start_point; + array1d_type end_point; + + private: + rT threshold; + private: + rT func(const pT& x) + { + assert(p_fo!=0); + return p_fo->eval(x); + } + + + public: + gsl_simplex() + :threshold(1e-4) + {} + + virtual ~gsl_simplex() + { + }; + + gsl_simplex(const gsl_simplex& rhs) + :p_fo(rhs.p_fo),p_optimizer(rhs.p_optimizer), + start_point(rhs.start_point), + end_point(rhs.end_point), + threshold(rhs.threshold) + { + } + + gsl_simplex& operator=(const gsl_simplex& rhs) + { + threshold=rhs.threshold; + p_fo=rhs.p_fo; + p_optimizer=rhs.p_optimizer; + opt_eq(start_point,rhs.start_point); + opt_eq(end_point,rhs.end_point); + } + + opt_method* do_clone()const + { + return new gsl_simplex(*this); + } + + void do_set_start_point(const array1d_type& p) + { + start_point.resize(get_size(p)); + opt_eq(start_point,p); + + } + + void do_set_precision(rT t) + { + threshold=t; + } + + void do_set_optimizer(optimizer& o) + { + p_optimizer=&o; + p_fo=p_optimizer->ptr_func_obj(); + } + + + + pT do_optimize() + { + const gsl_multimin_fminimizer_type *T = + gsl_multimin_fminimizer_nmsimplex; + gsl_multimin_fminimizer *s = NULL; + gsl_vector *ss, *x; + gsl_multimin_function minex_func; + + size_t iter = 0; + int status; + double size; + + /* Starting point */ + x = gsl_vector_alloc (get_size(start_point)); + // gsl_vector_set (x, 0, 5.0); + //gsl_vector_set (x, 1, 7.0); + for(size_t i=0;i!=get_size(start_point);++i) + { + gsl_vector_set(x,i,get_element(start_point,i)); + } + + + /* Set initial step sizes to 1 */ + ss = gsl_vector_alloc (get_size(start_point)); + gsl_vector_set_all (ss, 1.0); + + + //foo f; + /* Initialize method and iterate */ + minex_func.n = get_size(start_point); + minex_func.f = &gsl_func_adapter >; + minex_func.params = (void *)p_fo; + + s = gsl_multimin_fminimizer_alloc (T, get_size(start_point)); + gsl_multimin_fminimizer_set (s, &minex_func, x, ss); + + do + { + iter++; + status = gsl_multimin_fminimizer_iterate(s); + + if (status) + break; + //std::cerr<<"threshold="<x, 0), + //gsl_vector_get (s->x, 1), + // s->fval, size); + } + while (status == GSL_CONTINUE && iter < 100); + + /* + foo f; + gsl_vector_set (x, 0, 0.0); + gsl_vector_set (x, 1, 0.0); + cout<<"fdsa "; + cout< >(x,(void*)&f)<x,i)); + } + + gsl_vector_free(x); + gsl_vector_free(ss); + gsl_multimin_fminimizer_free (s); + + + return end_point; + } + }; + +}; + + +#endif +//EOF diff --git a/methods/powell/bas_util.hpp b/methods/powell/bas_util.hpp new file mode 100644 index 0000000..743dc3c --- /dev/null +++ b/methods/powell/bas_util.hpp @@ -0,0 +1,63 @@ +#ifndef BAS_UTIL +#define BAS_UTIL +#include +namespace opt_utilities +{ + template + T tabs(T x) + { + return T(x) + T sqr(T x) + { + return x*x; + } + + + template + void shft3(T&a,T& b,T& c,T d) + { + opt_eq(a,b); + opt_eq(b,c); + opt_eq(c,d); + } + + template + void shft(T& a,T& b,T& c,T d) + { + opt_eq(a,b); + opt_eq(b,c); + opt_eq(c,d); + } + template + void swap(T& ax,T& bx) + { + // swap(ax,bx); + T temp; + opt_eq(temp,ax); + opt_eq(ax,bx); + opt_eq(bx=temp); + } + + template + T sign(const T& a,const T& b) + { + return b>=0?T(a>=0?T(a):T(-a)):T(a>=0?T(-a):T(a)); + } + + template + T max(T a,T b) + { + return b>a?T(b):T(a); + } + + template + void mov3(T& a,T& b,T& c, T& d,T& e,T& f) + { + opt_eq(a,d);opt_eq(b,e);opt_eq(c,f); + } +} + +#endif diff --git a/methods/powell/brent.hpp b/methods/powell/brent.hpp new file mode 100644 index 0000000..cb3b962 --- /dev/null +++ b/methods/powell/brent.hpp @@ -0,0 +1,110 @@ +#ifndef BRENT_HPP +#define BRENT_HPP +#include +#include "bas_util.hpp" +//#include "optimizer.hpp" +namespace opt_utilities +{ + template + T brent(T ax,T bx,T cx,func_obj& f,T tol,T& xmin) + { + const int ITMAX=100; + const T CGOLD=0.3819660; + const T ZEPS=std::numeric_limits::epsilon()*1.e-3; + + int iter; + T a=0,b=0,d(0),etemp=0,fu=0,fv=0,fw=0,fx=0,p=0,q=0 + ,r=0,tol1=0,tol2=0,u=0,v=0,w=0,x=0,xm=0; + T e=0.; + a=(axcx?ax:cx); + x=w=v=bx; + fw=fv=fx=f.eval(x); + for(iter=0;itertol1) + { + r=(x-w)*(fx-fv); + q=(x-v)*(fx-fw); + p=(x-v)*q-(x-w)*r; + q=2.*(q-r); + if(q>0.) + { + p=-p; + } + q=tabs(q); + etemp=e; + e=d; + if(tabs(p)>=tabs(T(T(.5)*p*etemp))||p<=q*(a-x)||p>=q*(b-x)) + { + d=CGOLD*(e=(x>=xm?a-x:b-x)); + } + else + { + d=p/q; + u=x+d; + if(u-a=xm?a-x:b-x)); + } + u=(tabs(d)>=tol1?x+d:x+sign(tol1,d)); + fu=f.eval(u); + if(fu<=fx) + { + if(u>=x) + { + a=x; + } + else + { + b=x; + } + shft3(v,w,x,u); + shft3(fv,fw,fx,fu); + } + else + { + if(u + +namespace opt_utilities +{ + template + class func_adaptor + :public func_obj + { + private: + const pT p1,xi1; + const func_obj* pfoo; + func_adaptor(){} + func_adaptor(const func_adaptor&){} + + public: + /* + void set_origin(pT& p2) + { + p1=p2; + } + + void set_direction(pT& xi2) + { + xi1=xi2; + } + + void set_func_obj(func_obj& foo) + { + pfoo=&foo; + }*/ + public: + func_adaptor(const pT& _p,const pT& _xi,const func_obj& pf) + :p1(_p),xi1(_xi),pfoo(&pf) + {} + + private: + func_obj* do_clone()const + { + return new func_adaptor(*this); + } + + rT do_eval(const rT& x) + { + //assert(p1.size()==xi1.size()); + + pT xt; + opt_eq(xt,p1); + for(size_t i=0;i&>(*pfoo).eval(xt); + //return x; + } + }; + + + template + void linmin(pT& p,pT& xi,rT& fret,func_obj& func) + { + + // assert(p.size()==10); + //assert(xi.size()==10); + func_adaptor fadpt(p,xi,func); + + int j=0; + const rT TOL=sqrt(std::numeric_limits::epsilon()); + rT xx=0,xmin=0,fx=0,fb=0,fa=0,bx=0,ax=0; + int n=(int)get_size(p); + + + ax=0.; + xx=1.; + + + mnbrak(ax,xx,bx,fa,fx,fb,fadpt); + //cout< + void mnbrak(T& ax,T& bx,T& cx,T& fa,T& fb,T& fc,func_obj& func) + { + const T GOLD=1.618034; + const T GLIMIT=100; + const T TINY=std::numeric_limits::epsilon(); + T ulim,u,r,q,fu; + fa=func.eval(ax); + fb=func.eval(bx); + + if(fb>fa) + { + //shft(dum,ax,bx,dum); + //shft(dum,fb,fa,dum); + std::swap(ax,bx); + std::swap(fa,fb); + } + + cx=bx+GOLD*(bx-ax); + fc=func.eval(cx); + while(fb>fc) + { + r=(bx-ax)*(fb-fc); + q=(bx-cx)*(fb-fa); + u=bx-T((bx-cx)*q-(bx-ax)*r)/ + T(T(2.)*sign(T(max(T(tabs(T(q-r))),T(TINY))),T(q-r))); + ulim=bx+GLIMIT*(cx-bx); + if((bx-u)*(u-cx)>0.) + { + fu=func.eval(u); + if(fufb) + { + cx=u; + fc=fu; + return; + } + u=cx+GOLD*(cx-bx); + fu=func.eval(u); + } + else if((cx-u)*(u-ulim)>0.) + { + fu=func.eval(u); + if(fu=0) + { + u=ulim; + fu=func.eval(u); + } + else + { + u=cx+GOLD*(cx-bx); + fu=func.eval(u); + } + shft3(ax,bx,cx,u); + shft3(fa,fb,fc,fu); + } + } +} + +#endif diff --git a/methods/powell/powell_method.hpp b/methods/powell/powell_method.hpp new file mode 100644 index 0000000..bec12b7 --- /dev/null +++ b/methods/powell/powell_method.hpp @@ -0,0 +1,251 @@ +#ifndef POWELL_METHOD +#define POWELL_METHOD +#include +//#include +#include +#include +#include +#include "linmin.hpp" +#include +/* + * +*/ +#include + +namespace opt_utilities +{ + /* + template + T tabs(T x) + { + return x<0?-x:x; + } + */ + + template + class powell_method + :public opt_method + { + public: + typedef pT array1d_type; + typedef rT T; + private: + func_obj* p_fo; + optimizer* p_optimizer; + + //typedef blitz::Array array2d_type; + + + private: + array1d_type start_point; + array1d_type end_point; + + private: + int ncom; + array1d_type pcom_p; + array1d_type xicom_p; + rT threshold; + T** xi; + T* xi_1d; + private: + rT func(const pT& x) + { + assert(p_fo!=0); + return p_fo->eval(x); + } + + + private: + void clear_xi() + { + if(xi_1d!=0) + { + delete[] xi_1d; + } + if(xi!=0) + { + delete[] xi; + } + } + + void init_xi(int n) + { + clear_xi(); + xi_1d=new T[n*n]; + xi=new T*[n]; + for(int i=0;i!=n;++i) + { + xi[i]=xi_1d+i*n; + } + for(int i=0;i!=n;++i) + { + for(int j=0;j!=n;++j) + { + xi[i][j]=(j==i?1:0); + } + } + } + + + + void powell(array1d_type& p,const T ftol, + int& iter,T& fret) + { + const int ITMAX=200; + const T TINY=std::numeric_limits::epsilon(); + int i,j,ibig; + T del,fp,fptt,t; + int n=(int)get_size(p); + array1d_type pt(n); + array1d_type ptt(n); + array1d_type xit(n); + fret=p_fo->eval(p); + + for(j=0;jdel) + { + del=fptt-fret; + ibig=i+1; + } + } + if(T(2.)*(fp-fret)<=ftol*(tabs(fp)+tabs(fret))+TINY) + { + return; + } + if(iter==ITMAX) + { + std::cerr<<"powell exceeding maximun iterations."<& rhs) + :p_fo(rhs.p_fo),p_optimizer(rhs.p_optimizer), + start_point(rhs.start_point), + end_point(rhs.end_point), + ncom(rhs.ncom), + threshold(rhs.threshold),xi(0),xi_1d(0) + { + } + + powell_method& operator=(const powell_method& rhs) + { + threshold=rhs.threshold; + xi=0; + xi_1d=0; + p_fo=rhs.p_fo; + p_optimizer=rhs.p_optimizer; + start_point=rhs.start_point; + end_point=rhs.end_point; + ncom=rhs.ncom; + threshold=rhs.threshold; + } + + opt_method* do_clone()const + { + return new powell_method(*this); + } + + void do_set_start_point(const array1d_type& p) + { + resize(start_point,get_size(p)); + opt_eq(start_point,p); + + } + + void do_set_precision(rT t) + { + threshold=t; + } + + void do_set_optimizer(optimizer& o) + { + p_optimizer=&o; + p_fo=p_optimizer->ptr_func_obj(); + } + + + + pT do_optimize() + { + + init_xi((int)get_size(start_point)); + + + for(int i=0;i<(int)get_size(start_point);++i) + { + for(int j=0;j<(int)get_size(start_point);++j) + { + xi[i][j]=(i==j)?1:0; + } + } + + int iter=100; + opt_eq(end_point,start_point); + rT fret; + powell(end_point,threshold,iter,fret); + return end_point; + } + }; + +}; + + +#endif +//EOF diff --git a/misc/bootstrap.hpp b/misc/bootstrap.hpp new file mode 100644 index 0000000..b46748d --- /dev/null +++ b/misc/bootstrap.hpp @@ -0,0 +1,132 @@ +#ifndef BOOT_STRIP +#define BOOT_STRIP +#include +#include +#include +#include +#include +#include +#include +using std::cout; +namespace opt_utilities +{ + template + class bootstrap + { + private: + Ty rand_norm(Ty y0,Ty y_err)const + { + Ty y; + do + { + y=(rand()/(Ty)RAND_MAX-(Ty).5)*(10*y_err)+y0; + } + while(rand()/(Ty)RAND_MAX>exp(-(y-y0)*(y-y0)/(y_err*y_err))); + return y; + + } + public: + std::vector param_pool; + default_data_set current_data_set; + default_data_set origin_data_set; + fitter* p_fitter; + Tp origin_param; + public: + bootstrap() + :p_fitter(NULL) + {} + + void set_fitter(fitter& pf) + { + param_pool.clear(); + p_fitter=&pf; + origin_data_set=dynamic_cast&>(pf.datas()); + origin_param=pf.get_all_params(); + } + + + + void sample(int n) + { + if(p_fitter!=NULL) + { + for(int i=0;iload_data(origin_data_set); + p_fitter->set_param_value(origin_param); + } + else + { + throw opt_exception("Fitter unset"); + } + } + + const Tp& get_param(int i)const + { + return param_pool.at(i); + } + + private: + void sample() + { + current_data_set=default_data_set(); + for(int i=0;i d; + d=origin_data_set.get_data(i); + d.set_y(rand_norm(d.get_y(),(d.get_y_upper_err()+d.get_y_lower_err())/2)); + current_data_set.push_back(d); + } + p_fitter->load_data(current_data_set); + p_fitter->set_param_value(origin_param); + param_pool.push_back(p_fitter->fit()); + for(size_t i=0;i<(param_pool.back()).size();++i) + { + cout<::element_type,typename element_type_trait::element_type> + interval(std::string param_name,double level) + { + if(p_fitter==NULL) + { + throw opt_exception("Fitter unset"); + } + if(param_pool.empty()) + { + throw opt_exception("Bootstrap not done"); + } + //sample(); + std::vector::element_type> _tmp; + int order=p_fitter->get_param_order(param_name); + for(typename std::vector::iterator i=param_pool.begin(); + i!=param_pool.end();++i) + { + _tmp.push_back((*i)[order]); + } + sort(_tmp.begin(),_tmp.end()); + std::pair::element_type>::iterator, + typename std::vector::element_type>::iterator> + itv=equal_range(_tmp.begin(),_tmp.end(),origin_param[order]); + int current_param_position=itv.second-_tmp.begin(); + std::cout<<_tmp.size()<::element_type, + typename element_type_trait::element_type>( + _tmp.at((int)((1-level)*current_param_position)), + _tmp.at((int)(current_param_position+level*(_tmp.size()-current_param_position))) + ); + + } + + }; + +}; + +#endif +//EOF diff --git a/misc/data_loaders.hpp b/misc/data_loaders.hpp new file mode 100644 index 0000000..6d2195d --- /dev/null +++ b/misc/data_loaders.hpp @@ -0,0 +1,180 @@ +#ifndef DATA_LOADERS_H +#define DATA_LOADERS_H +#include +#include +#include +#include +#include + +namespace opt_utilities +{ + template + class dl_x_y_ye; + + template + std::istream& operator>>(std::istream& ifs,dl_x_y_ye& dl); + + template + class dl_x_xe_y_ye; + + template + std::istream& operator>>(std::istream& ifs,dl_x_xe_y_ye& dl); + + template + class dl_x_xu_xl_y_yu_yl; + + template + std::istream& operator>> (std::istream& ifs,dl_x_xu_xl_y_yu_yl& dl); + + template + class dl_x_y_ye + { + private: + default_data_set ds; + public: + data_set& get_data_set() + { + return ds; + } + + void load_from(std::istream& ifs) + { + for(;;) + { + Tx x; + Tx x_err; + Ty y; + Ty y_err(1); + + ifs>>x>>y>>y_err; + + if(!ifs.good()) + { + break; + } + data d(x,y,y_err,y_err,x_err,x_err); + ds.push_back(d); + } + //return ifs; + } + + void load_from(const char* name) + { + std::ifstream ifs(name); + load_from(ifs); + + } + //friend std::istream& operator>> <>(std::istream& ifs,dl_x_y_ye& dl); + }; + + template + std::istream& operator>>(std::istream& ifs,dl_x_y_ye& dl) + { + dl.load_from(ifs); + return ifs; + } + + + template + class dl_x_xe_y_ye + { + private: + default_data_set ds; + public: + data_set& get_data_set() + { + return ds; + } + + void load_from(std::istream& ifs) + { + for(;;) + { + Tx x; + Tx x_err; + Ty y; + Ty y_err(1); + + ifs>>x>>x_err>>y>>y_err; + + if(!ifs.good()) + { + break; + } + data d(x,y,y_err,y_err,x_err,x_err); + ds.push_back(d); + } + } + + void load_from(const char* name) + { + std::ifstream ifs(name); + load_from(ifs); + } + }; + + template + std::istream& operator>>(std::istream& ifs,dl_x_xe_y_ye& dl) + { + dl.load_from(ifs); + return ifs; + } + + template + class dl_x_xu_xl_y_yu_yl + { + private: + + default_data_set ds; + public: + data_set& get_data_set() + { + return ds; + } + + void load_from(std::istream& ifs) + { + for(;;) + { + Tx x; + Tx xl,xu; + Ty y; + Ty yl(1),yu(1); + + ifs>>x>>xu>>xl>>y>>yu>>yl; + + xu=std::abs(xu); + xl=std::abs(xl); + yu=std::abs(yu); + yl=std::abs(yl); + + if(!ifs.good()) + { + break; + } + data d(x,y,yl,yu,xl,xu); + ds.push_back(d); + } + } + + void load_from(const char* name) + { + std::ifstream ifs(name); + load_from(ifs); + } + }; + + template + std::istream& operator>> (std::istream& ifs,dl_x_xu_xl_y_yu_yl& dl) + { + dl.load_from(ifs); + return ifs; + } + + + +} + + +#endif +//EOF diff --git a/models/add_model.hpp b/models/add_model.hpp new file mode 100644 index 0000000..ffac9dc --- /dev/null +++ b/models/add_model.hpp @@ -0,0 +1,169 @@ +#ifndef ADD_MODEL_H_ +#define ADD_MODEL_H_ +#include +#include + +namespace opt_utilities +{ + template + class add_model + :public model + { + private: + model* do_clone()const + { + return new add_model(*this); + } + private: + add_model() + { + } + + private: + model* pm1; + model* pm2; + + public: + add_model(const model& m1, + const model& m2) + :pm1(m1.clone()),pm2(m2.clone()) + { + int np1=m1.get_num_params(); + int np2=m2.get_num_params(); + for(int i=0;i p(m1.get_param_info(i)); + param_info p1(p.get_name()+"1",p.get_default_value()); + this->push_param_info(p1); + } + for(int i=0;i p(m2.get_param_info(i)); + param_info p2(p.get_name()+"2",p.get_default_value()); + this->push_param_info(p2); + } + } + + add_model(const add_model& rhs) + :pm1(NULL),pm2(NULL) + { + int np1(0),np2(0); + if(rhs.pm1) + { + pm1=rhs.pm1->clone(); + np1=rhs.pm1->get_num_params(); + for(int i=0;i p(rhs.pm1->get_param_info(i)); + param_info p1(p.get_name()+"1",p.get_default_value()); + this->push_param_info(p1); + } + } + if(rhs.pm2) + { + pm2=rhs.pm2->clone(); + np2=rhs.pm2->get_num_params(); + for(int i=0;i p(rhs.pm2->get_param_info(i)); + param_info p2(p.get_name()+"2",p.get_default_value()); + this->push_param_info(p2); + } + } + } + + add_model& operator=(const add_model& rhs) + { + if(this==&rhs) + { + return *this; + } + if(!pm1) + { + //delete pm1; + pm1->destroy(); + } + if(!pm2) + { + //delete pm2; + pm2->destroy(); + } + int np1(0),np2(0); + if(rhs.pm1) + { + pm1=rhs.pm1->clone(); + np1=rhs.pm1->get_num_params(); + for(int i=0;i p(rhs.pm1->get_param_info(i)); + param_info p1(p.get_name()+"1",p.get_default_value()); + this->push_param_info(p1); + } + } + if(rhs.pm2) + { + pm2=rhs.pm2->clone(); + np2=rhs.pm2->get_num_params(); + for(int i=0;i p(rhs.pm2->get_param_info(i)); + param_info p2(p.get_name()+"2",p.get_default_value()); + this->push_param_info(p2); + } + } + return *this; + } + + ~add_model() + { + if(!pm1) + { + //delete pm1; + pm1->destroy(); + } + if(!pm2) + { + //delete pm2; + pm2->destroy(); + } + } + + public: + Ty do_eval(const Tx& x,const Tp& param) + { + if(!pm1) + { + throw opt_exception("incomplete model!"); + } + if(!pm2) + { + throw opt_exception("incomplete model!"); + } + Tp p1(pm1->get_num_params()); + Tp p2(pm2->get_num_params()); + int i=0; + int j=0; + for(i=0;iget_num_params();++i,++j) + { + set_element(p1,i,get_element(param,j)); + } + for(i=0;iget_num_params();++i,++j) + { + set_element(p2,i,get_element(param,j)); + } + return pm1->eval(x,p1)+pm2->eval(x,p2); + } + }; + + template + add_model operator+(const model& m1, + const model& m2) + { + return add_model(m1,m2); + } +}; + + + +#endif +//EOF diff --git a/models/beta1d.hpp b/models/beta1d.hpp new file mode 100644 index 0000000..e18aa34 --- /dev/null +++ b/models/beta1d.hpp @@ -0,0 +1,49 @@ +#ifndef BETA_MODEL_H_ +#define BETA_MODEL_H_ +#include +#include +#include + +namespace opt_utilities +{ + template + class beta1d + :public model,std::string> + { + private: + model >* do_clone()const + { + return new beta1d(*this); + } + public: + beta1d() + { + this->push_param_info(param_info >("S0",1)); + this->push_param_info(param_info >("rc",10)); + this->push_param_info(param_info >("beta",2./3.)); + this->push_param_info(param_info >("bkg",0)); + } + + + T do_eval(const T& x,const std::vector& param) + { + T S0=get_element(param,0); + T r_c=get_element(param,1); + T beta=get_element(param,2); + T bkg=get_element(param,3); + + return bkg+S0*pow(1+(x*x)/(r_c*r_c),-3*beta+static_cast(.5)); + } + + std::string do_to_string()const + { + return "Beta model\n" + "S=S0*(1+(r/rc)^2)^(-3*beta+0.5)\n"; + } + }; +}; + + + +#endif +//EOF diff --git a/models/beta2d.hpp b/models/beta2d.hpp new file mode 100644 index 0000000..abb6da1 --- /dev/null +++ b/models/beta2d.hpp @@ -0,0 +1,60 @@ +#ifndef BETA_MODEL2d_H_ +#define BETA_MODEL2d_H_ +#include +#include +#include +#include "vecn.hpp" + + +namespace opt_utilities +{ + + template + class beta2d + :public model,std::vector,std::string> + { + private: + model,std::vector >* do_clone()const + { + return new beta2d(*this); + } + public: + beta2d() + { + this->push_param_info(param_info >("S0",1)); + this->push_param_info(param_info >("rc1",100)); + this->push_param_info(param_info >("rc2",100)); + this->push_param_info(param_info >("rho",0)); + this->push_param_info(param_info >("x0",100)); + this->push_param_info(param_info >("y0",100)); + this->push_param_info(param_info >("beta",2./3.)); + this->push_param_info(param_info >("bkg",0)); + } + + + T do_eval(const vecn& xy,const std::vector& param) + { + T S0=get_element(param,0); + T rc1=get_element(param,1); + T rc2=get_element(param,2); + T rho=get_element(param,3); + T x0=get_element(param,4); + T y0=get_element(param,5); + T beta=get_element(param,6); + T bkg=get_element(param,7); + T x=xy[0]; + T y=xy[1]; + + T r=(x-x0)*(x-x0)/(rc1*rc1)+(y-y0)*(y-y0)/(rc2*rc2) + -2*rho*(x-x0)*(y-y0)/(rc1*rc2); + r=r<0?0:r; + + return bkg+S0*pow(1+r,-3*beta+static_cast(.5)); + } + }; +}; + + + +#endif +//EOF diff --git a/models/beta2d2.hpp b/models/beta2d2.hpp new file mode 100644 index 0000000..bb473a3 --- /dev/null +++ b/models/beta2d2.hpp @@ -0,0 +1,73 @@ +#ifndef BETA_MODEL2d2_H_ +#define BETA_MODEL2d2_H_ +#include +#include +#include +#include "vecn.hpp" + + +namespace opt_utilities +{ + + template + class beta2d2 + :public model,std::vector,std::string> + { + private: + model,std::vector >* do_clone()const + { + return new beta2d2(*this); + } + public: + beta2d2() + { + this->push_param_info(param_info >("r0",20)); + this->push_param_info(param_info >("x0",100)); + this->push_param_info(param_info >("y0",100)); + this->push_param_info(param_info >("epsilon",0)); + this->push_param_info(param_info >("theta",100)); + this->push_param_info(param_info >("ampl",3)); + this->push_param_info(param_info >("beta",2./3.)); + this->push_param_info(param_info >("bkg",0)); + } + + + T do_eval(const vecn& xy,const std::vector& param) + { + T x=xy[0]; + T y=xy[1]; + + T r0=get_element(param,0); + T x0=get_element(param,1); + T y0=get_element(param,2); + T epsilon=get_element(param,3); + T theta=get_element(param,4); + T ampl=get_element(param,5); + T beta=get_element(param,6); + T bkg=get_element(param,7); + + T x_new=(x-x0)*cos(theta)+(y-y0)*sin(theta); + T y_new=(y-y0)*cos(theta)-(x-x0)*sin(theta); + + //T _epsilon=sin(epsilon)-0.00001; + + T _epsilon=epsilon; + + // T r=sqrt(x_new*x_new*(1-_epsilon)*(1-_epsilon) + // + y_new*y_new); + + //r/=(1-_epsilon); + T r_r=x_new*x_new/exp(_epsilon)+y_new*y_new/exp(-_epsilon); + + + return bkg+ampl*pow(1+r_r/r0/r0,-3*beta+static_cast(.5)); + } + + + }; +}; + + + +#endif +//EOF diff --git a/models/bl1d.hpp b/models/bl1d.hpp new file mode 100644 index 0000000..bd0ce7d --- /dev/null +++ b/models/bl1d.hpp @@ -0,0 +1,56 @@ +#ifndef BROKEN_LINE_MODEL_H_ +#define BROKEN_LINE_MODEL_H_ +#include +#include + +namespace opt_utilities +{ + template + class bl1d + :public model,std::string> + { + private: + model >* do_clone()const + { + return new bl1d(*this); + } + public: + bl1d() + { + this->push_param_info(param_info >("break point y value",1)); + this->push_param_info(param_info >("break point x value",1)); + this->push_param_info(param_info >("slop 1",1)); + this->push_param_info(param_info >("slop 2",1)); + } + + public: + T do_eval(const T& x,const std::vector& param) + { + T x_b=get_element(param,0); + T f_b=get_element(param,1); + T k1=get_element(param,2); + T k2=get_element(param,3); + if(x +#include + +namespace opt_utilities +{ + template + class bpl1d + :public model,std::string> + { + private: + model >* do_clone()const + { + return new bpl1d(*this); + } + public: + bpl1d() + { + this->push_param_info(param_info >("bpx",1)); + this->push_param_info(param_info >("bpy",1)); + this->push_param_info(param_info >("gamma1",1)); + this->push_param_info(param_info >("gamma2",1)); + } + + T do_eval(const T& x,const std::vector& param) + { + T x_b=get_element(param,0); + T f_b=get_element(param,1); + T gamma1=get_element(param,2); + T gamma2=get_element(param,3); + if(x +#include + +namespace opt_utilities +{ + template + class bremss + :public model,std::string> + { + private: + model >* do_clone()const + { + return new bremss(*this); + } + public: + bremss() + { + this->push_param_info(param_info >("norm",1)); + this->push_param_info(param_info >("kT",1)); + } + + T do_eval(const T& x,const std::vector& param) + { + T norm=get_element(param,0); + T kT=get_element(param,1); + + return norm*sqrt(kT)*exp(-x/kT); + } + + private: + std::string do_to_string()const + { + return "Simplified bremss model\n" + "flux=norm*kT^0.5*e^{-E/kT}\n"; + } + }; +}; + + + +#endif +//EOF diff --git a/models/constant.hpp b/models/constant.hpp new file mode 100644 index 0000000..8d06279 --- /dev/null +++ b/models/constant.hpp @@ -0,0 +1,42 @@ +#ifndef CONSTANT_MODEL_H_ +#define CONSTANT_MODEL_H_ +#include +#include + +namespace opt_utilities +{ + template + class constant + :public model,std::string> + { + private: + model >* do_clone()const + { + return new constant(*this); + } + public: + constant() + { + this->push_param_info(param_info >("c",1)); + } + + public: + T do_eval(const T& x,const std::vector& param) + { + //return x*param[0]+param[1]; + return get_element(param,0); + } + + private: + std::string do_to_string()const + { + return "Constant\n" + "y=C\n"; + } + }; +}; + + + +#endif +//EOF diff --git a/models/dbeta1d.hpp b/models/dbeta1d.hpp new file mode 100644 index 0000000..71a1f52 --- /dev/null +++ b/models/dbeta1d.hpp @@ -0,0 +1,62 @@ +#ifndef DBETA_MODEL_H_ +#define DBETA_MODEL_H_ +#include +#include +#include +namespace opt_utilities +{ + template + class dbeta1d + :public model,std::string> + { + private: + model >* do_clone()const + { + return new dbeta1d(*this); + } + public: + dbeta1d() + { + this->push_param_info(param_info >("S01",1)); + this->push_param_info(param_info >("rc1",30)); + this->push_param_info(param_info >("beta1",.6)); + + this->push_param_info(param_info >("S02",.5)); + this->push_param_info(param_info >("rc2",20)); + this->push_param_info(param_info >("beta2",.4)); + + + this->push_param_info(param_info >("bkg",0)); + } + + + T do_eval(const T& x,const std::vector& param) + { + T S01=get_element(param,0); + T r_c1=get_element(param,1); + T beta1=get_element(param,2); + + T S02=get_element(param,3); + T r_c2=get_element(param,4); + T beta2=get_element(param,5); + + + T bkg=get_element(param,6); + + return bkg+S01*pow(1+(x*x)/(r_c1*r_c1),-3*beta1+static_cast(.5)) + +S02*pow(1+(x*x)/(r_c2*r_c2),-3*beta2+static_cast(.5)); + } + + private: + std::string do_to_string()const + { + return "double 1d beta model\n" + "S=beta(S01,beta1,rc1)+beta(S02,beta2,rc2)\n"; + } + }; +}; + + + +#endif +//EOF diff --git a/models/dbeta2d.hpp b/models/dbeta2d.hpp new file mode 100644 index 0000000..6811270 --- /dev/null +++ b/models/dbeta2d.hpp @@ -0,0 +1,92 @@ +#ifndef DBETA_MODEL2d_H_ +#define DBETA_MODEL2d_H_ +#include +#include +#include +#include "vecn.hpp" + +namespace opt_utilities +{ + + template + class dbeta2d + :public model,std::vector,std::string> + { + private: + model,std::vector >* do_clone()const + { + return new dbeta2d(*this); + } + + + + public: + dbeta2d() + { + push_param_info(param_info >("S01",1)); + push_param_info(param_info >("rc11",50)); + push_param_info(param_info >("rc21",50)); + push_param_info(param_info >("rho1",0)); + push_param_info(param_info >("x01",200)); + push_param_info(param_info >("y01",200)); + push_param_info(param_info >("beta1",2./3.)); + + push_param_info(param_info >("S02",1)); + push_param_info(param_info >("rc12",60)); + push_param_info(param_info >("rc22",60)); + push_param_info(param_info >("rho2",0)); + push_param_info(param_info >("x02",200)); + push_param_info(param_info >("y02",200)); + push_param_info(param_info >("beta2",2./2.5)); + push_param_info(param_info >("bkg",0)); + } + + T do_eval(const vecn& xy,const std::vector& param) + { + T S01=get_element(param,0); + T rc11=get_element(param,1); + T rc21=get_element(param,2); + T rho1=get_element(param,3); + T x01=get_element(param,4); + T y01=get_element(param,5); + T beta1=get_element(param,6); + T S02=get_element(param,7); + T rc12=get_element(param,8); + T rc22=get_element(param,9); + T rho2=get_element(param,10); + T x02=get_element(param,11); + T y02=get_element(param,12); + T beta2=get_element(param,13); + T bkg=get_element(param,14); + + + T x=xy[0]; + T y=xy[1]; + + rho1=rho1>1?1:rho1; + rho1=rho1<-1?-1:rho1; + rho2=rho2>1?1:rho2; + rho2=rho2<-1?-1:rho2; + + T r1=(x-x01)*(x-x01)/(rc11*rc11)+(y-y01)*(y-y01)/(rc21*rc21) + -2*rho1*(x-x01)*(y-y01)/(rc11*rc21); + + T r2=(x-x02)*(x-x02)/(rc12*rc12)+(y-y02)*(y-y02)/(rc22*rc22) + -2*rho2*(x-x02)*(y-y02)/(rc12*rc22); + // r1=r1<0?0:r1; + //r2=r2<0?0:r2; + assert(r1>=0); + assert(r2>=0); + + + return bkg+S01*pow(1+r1,-3*beta1+static_cast(.5))+ + S02*pow(1+r2,-3*beta2+static_cast(.5)); + } + }; +}; + + + +#endif +//EOF + diff --git a/models/dbeta2d2.hpp b/models/dbeta2d2.hpp new file mode 100644 index 0000000..d968dbc --- /dev/null +++ b/models/dbeta2d2.hpp @@ -0,0 +1,100 @@ +#ifndef DDBETA_OOOMODEL2d2_H_ +#define DDBETA_OOOMODEL2d2_H_ +#include +#include +#include +#include "vecn.hpp" + + +namespace opt_utilities +{ + + template + class dbeta2d2 + :public model,std::vector,std::string> + { + private: + model,std::vector >* do_clone()const + { + return new dbeta2d2(*this); + } + public: + dbeta2d2() + { + this->push_param_info(param_info >("ampl1",1));//0 + this->push_param_info(param_info >("r01",1));//1 + this->push_param_info(param_info >("x01",100));//2 + this->push_param_info(param_info >("y01",100));//3 + this->push_param_info(param_info >("theta1",0));//4 + this->push_param_info(param_info >("beta1",2./3.));//5 + this->push_param_info(param_info >("epsilon1",0));//6 + + + this->push_param_info(param_info >("ampl2",1));//7 + this->push_param_info(param_info >("r02",1));//8 + this->push_param_info(param_info >("x02",100));//9 + this->push_param_info(param_info >("y02",100));//10 + this->push_param_info(param_info >("theta2",0));//11 + this->push_param_info(param_info >("beta2",2./4.));//12 + this->push_param_info(param_info >("epsilon2",0));//13 + + this->push_param_info(param_info >("bkg",0));//14 + } + + + T do_eval(const vecn& xy,const std::vector& param) + { + T x=xy[0]; + T y=xy[1]; + + T ampl1=get_element(param,0); + T r01=get_element(param,1); + T x01=get_element(param,2); + T y01=get_element(param,3); + + T theta1=get_element(param,4); + + T beta1=get_element(param,5); + T epsilon1=get_element(param,6); + + T ampl2=get_element(param,7); + T r02=get_element(param,8); + T x02=get_element(param,9); + T y02=get_element(param,10); + + T theta2=get_element(param,11); + + T beta2=get_element(param,12); + + T epsilon2=get_element(param,13); + T bkg=get_element(param,14); + + T x_new1=(x-x01)*cos(theta1)+(y-y01)*sin(theta1); + T y_new1=(y-y01)*cos(theta1)-(x-x01)*sin(theta1); + + //T r1=sqrt(x_new1*x_new1*(1-epsilon1)*(1-epsilon1) + // + y_new1*y_new1); + //r1/=(1-epsilon1); + + T r1_r1=x_new1*x_new1/exp(epsilon1/30)+y_new1*y_new1/exp(-epsilon1/30); + + T x_new2=(x-x02)*cos(theta2)+(y-y02)*sin(theta2); + T y_new2=(y-y02)*cos(theta2)-(x-x02)*sin(theta2); + + T r2_r2=x_new2*x_new2/exp(epsilon2/30)+y_new2*y_new2/exp(-epsilon2/30); + // T r2=sqrt(x_new2*x_new2*(1-epsilon2)*(1-epsilon2) + // + y_new2*y_new2); + //r2/=(1-epsilon2); + + + + return bkg+ampl1*pow(1+(r1_r1/r01/r01),-3*beta1+static_cast(.5)) + +ampl2*pow(1+(r2_r2/r02/r02),-3*beta2+static_cast(.5)); + } + }; +}; + + + +#endif +//EOF diff --git a/models/dbeta2d3.hpp b/models/dbeta2d3.hpp new file mode 100644 index 0000000..e2edb78 --- /dev/null +++ b/models/dbeta2d3.hpp @@ -0,0 +1,91 @@ +#ifndef DDBETA3_MODEL2d2_H_ +#define DDBETA3_MODEL2d2_H_ +#include +#include +#include +#include "vecn.hpp" + + +namespace opt_utilities +{ + + template + class dbeta2d3 + :public model,std::vector,std::string> + { + private: + model,std::vector >* do_clone()const + { + return new dbeta2d3(*this); + } + public: + dbeta2d3() + { + + this->push_param_info(param_info >("x0",256));//1 + this->push_param_info(param_info >("y0",256));//2 + this->push_param_info(param_info >("epsilon",0));//3 + this->push_param_info(param_info >("theta",0));//4 + + this->push_param_info(param_info >("ampl1",1));//5 + this->push_param_info(param_info >("beta1",0.6));//6 + this->push_param_info(param_info >("r01",30));//7 + + this->push_param_info(param_info >("ampl2",.5));//8 + this->push_param_info(param_info >("beta2",.4));//9 + this->push_param_info(param_info >("r02",20));//10 + + this->push_param_info(param_info >("bkg",0));//11 + + + } + + + T do_eval(const vecn& xy,const std::vector& param) + { + T x=xy[0]; + T y=xy[1]; + + T x0=get_element(param,0); + T y0=get_element(param,1); + T epsilon=get_element(param,2); + T theta=get_element(param,3); + + T ampl1=(get_element(param,4)); + T beta1=(get_element(param,5)); + T r01=(get_element(param,6)); + + T ampl2=(get_element(param,7)); + T beta2=(get_element(param,8)); + T r02=(get_element(param,9)); + + T bkg=get_element(param,10); + + T x_new1=(x-x0)*cos(theta)+(y-y0)*sin(theta); + T y_new1=(y-y0)*cos(theta)-(x-x0)*sin(theta); + + + T r1_r1=x_new1*x_new1/exp(epsilon/30)+y_new1*y_new1/exp(-epsilon/30); + //T r1=sqrt(x_new1*x_new1*(1-epsilon)*(1-epsilon)+y_new1*y_new1)/(1-epsilon); + + T x_new2=(x-x0)*cos(theta)+(y-y0)*sin(theta); + T y_new2=(y-y0)*cos(theta)-(x-x0)*sin(theta); + + T r2_r2=x_new2*x_new2/exp(epsilon/30)+y_new2*y_new2/exp(-epsilon/30); + //T r2=sqrt(x_new2*x_new2*(1-epsilon)*(1-epsilon)+y_new2*y_new2)/(1-epsilon); + + + + return bkg+ampl1*pow(1+(r1_r1/r01/r01),-3*beta1+static_cast(.5)) + +ampl2*pow(1+(r2_r2/r02/r02),-3*beta2+static_cast(.5)); + + //return bkg+pow(1+r1*r1/r01/r01,-3*beta1+static_cast(.5))+ + //pow(1+r2*r2/r02/r02,-3*beta2+static_cast(.5)); + } + }; +}; + + + +#endif +//EOF diff --git a/models/dl_model.hpp b/models/dl_model.hpp new file mode 100644 index 0000000..2fcf227 --- /dev/null +++ b/models/dl_model.hpp @@ -0,0 +1,178 @@ +#ifdef __linux__ + +#ifndef DL_MODEL_H_ +#define DL_MODEL_H_ +#include +#include +#include +#include +#include +#include + +namespace opt_utilities +{ + template + class dl_model + :public model,std::string> + { + private: + T (*calc_model)(T x,const T* p); + int nparams; + mutable void* handle; + private: + model >* do_clone()const + { + dl_model* result=new dl_model(*this); + this->handle=NULL; + return result; + } + + // public: + public: + dl_model() + :handle(NULL) + {} + + + public: + dl_model(const char* file_name) + :handle(NULL) + { + + handle=dlopen(file_name,RTLD_LAZY); + + if(!handle) + { + throw opt_exception("faild loading object"); + } + + calc_model=(T (*)(T,const T*))dlsym(handle,"calc_model"); + + if(!calc_model) + { + throw opt_exception("symble undefined"); + } + + const char* (*get_param_name)(int) + =(const char* (*)(int))dlsym(handle,"get_param_name"); + + if(!get_param_name) + { + throw opt_exception("symble undefined"); + } + + int (*get_num_params)() + =(int (*)())dlsym(handle,"get_num_params"); + + if(!get_num_params) + { + throw opt_exception("symble undefined"); + if(!get_num_params) + { + throw opt_exception("symble undefined"); + } } + + T (*get_default_value)(int) + =(T (*)(int))dlsym(handle,"get_default_value"); + + if(!get_default_value) + { + throw opt_exception("symble undefined"); + } + + nparams=get_num_params(); + + for(int i=0;i!=nparams;++i) + { + this->push_param_info(param_info >(get_param_name(i), + get_default_value(i))); + } + } + + ~dl_model() + { + if(handle) + { + dlclose(handle); + } + } + + void bind(const char* file_name) + { + if(handle) + { + dlclose(handle); + } + this->clear_param_info(); + handle=dlopen(file_name,RTLD_LAZY); + + if(!handle) + { + throw opt_exception("faild loading object"); + } + + calc_model=(T (*)(T,const T*))dlsym(handle,"calc_model"); + + if(!calc_model) + { + throw opt_exception("symble undefined"); + } + + const char* (*get_param_name)(int) + =(const char* (*)(int))dlsym(handle,"get_param_name"); + + if(!get_param_name) + { + throw opt_exception("symble undefined"); + } + + + int (*get_num_params)() + =(int (*)())dlsym(handle,"get_num_params"); + + if(!get_num_params) + { + throw opt_exception("symble undefined"); + } + + + T (*get_default_value)(int) + =(T (*)(int))dlsym(handle,"get_default_value"); + + + if(!get_default_value) + { + throw opt_exception("symble undefined"); + } + + + nparams=get_num_params(); + for(int i=0;i!=nparams;++i) + { + this->push_param_info(param_info >(get_param_name(i), + get_default_value(i))); + } + } + + T do_eval(const T& x,const std::vector& param) + { + if(handle==NULL) + { + throw opt_exception("dl object unloaded"); + } + return calc_model(x,&get_element(param,0)); + } + + std::string do_to_string()const + { + return "Dynamical load model\n" + "Should be loaded from an shared object file\n"; + } + }; +}; + + + +#endif +#endif +//EOF diff --git a/models/dlmodel_template.c b/models/dlmodel_template.c new file mode 100644 index 0000000..fd7aadb --- /dev/null +++ b/models/dlmodel_template.c @@ -0,0 +1,36 @@ +#include + +char p1name[2]="k"; +char p2name[2]="b"; + +int main(int argc,char* argv[]) +{} + + +int get_num_params() +{ + return 2; +} + +const char* get_param_name(int n) +{ + if(n==0) + { + return p1name; + } + return p2name; +} + +double get_default_value(int n) +{ + if(n==0) + return 1; + return 0; +} + +double calc_model(double x,double p[]) +{ + return p[0]*x+p[1]; +} + + diff --git a/models/func_model.hpp b/models/func_model.hpp new file mode 100644 index 0000000..4eda8d5 --- /dev/null +++ b/models/func_model.hpp @@ -0,0 +1,57 @@ +#ifndef FUNC_MODEL_H_ +#define FUNC_MODEL_H_ +#include +#include +#include +#include +#include +namespace opt_utilities +{ + template + class func_model + :public model,std::string> + { + private: + T (*func)(T x,const T* const& p); + int nparams; + private: + model >* do_clone()const + { + return new func_model(*this); + } + + // public: + private: + func_model() + {} + + + public: + func_model(T (*_func)(T x,const T* const& p),int n) + :func(_func),nparams(n) + { + for(int i=0;i!=n;++i) + { + std::ostringstream oss; + oss<push_param_info(param_info >(oss.str(),0)); + } + } + + + T do_eval(const T& x,const std::vector& param) + { + return func(x,&get_element(param,0)); + } + private: + std::string do_to_string()const + { + return "Wrapper for necked C function\n"; + } + }; +}; + + + +#endif +//EOF diff --git a/models/gauss1d.hpp b/models/gauss1d.hpp new file mode 100644 index 0000000..958cec9 --- /dev/null +++ b/models/gauss1d.hpp @@ -0,0 +1,47 @@ +#ifndef GAUSS_MODEL_H_ +#define GAUSS_MODEL_H_ +#include +#include + +namespace opt_utilities +{ + template + class gauss1d + :public model,std::string> + { + private: + model >* do_clone()const + { + return new gauss1d(*this); + } + public: + gauss1d() + { + this->push_param_info(param_info >("N",1)); + this->push_param_info(param_info >("x0",0)); + this->push_param_info(param_info >("sigma",1)); + } + + public: + T do_eval(const T& x,const std::vector& param) + { + T N=get_element(param,0); + T x0=get_element(param,1); + T sigma=get_element(param,2); + T y=(x-x0)/sigma; + return N*exp(-y*y); + } + + private: + std::string do_to_string()const + { + return "Gaussian model\n" + "y=N*exp(-(x-x0)^2/sigma^2\n"; + } + }; +}; + + + +#endif +//EOF diff --git a/models/lin1d.hpp b/models/lin1d.hpp new file mode 100644 index 0000000..b0ddd31 --- /dev/null +++ b/models/lin1d.hpp @@ -0,0 +1,42 @@ +#ifndef LINEAR_MODEL_H_ +#define LINEAR_MODEL_H_ +#include +#include + +namespace opt_utilities +{ + template + class lin1d + :public model,std::string> + { + private: + model >* do_clone()const + { + return new lin1d(*this); + } + public: + lin1d() + { + this->push_param_info(param_info >("k",1)); + this->push_param_info(param_info >("b",0)); + } + + public: + T do_eval(const T& x,const std::vector& param) + { + return x*get_element(param,0)+get_element(param,1); + } + + private: + std::string do_to_string()const + { + return "linear model\n" + "y=k*x+b\n"; + } + }; +}; + + + +#endif +//EOF diff --git a/models/models.cc b/models/models.cc new file mode 100644 index 0000000..7481b88 --- /dev/null +++ b/models/models.cc @@ -0,0 +1,176 @@ +#include "models.hpp" +#include +#include "gauss1d.hpp" +#include "bl1d.hpp" +#include "nfw1d.hpp" +#include "bpl1d.hpp" +#include "beta1d.hpp" +#include "nbeta1d.hpp" +#include "dbeta1d.hpp" +#include "lin1d.hpp" +#include "pl1d.hpp" +#include "poly1d.hpp" +#include "bremss.hpp" +#include "beta2d2.hpp" +#include "beta2d.hpp" +#include "dbeta2d2.hpp" +#include "dbeta2d3.hpp" +#include "dbeta2d.hpp" +#include "dl_model.hpp" +#include +using namespace std; + + +namespace opt_utilities +{ + strmodel1d strm1d; + std::map,std::string>* > model_map; + std::map,std::vector,std::string>* > model2d_map; + std::list get_model_name_list() + { + std::list result; + for(std::map,std::string>* >::iterator i=model_map.begin(); + i!=model_map.end();++i) + { + result.push_back(i->first); + } + return result; + } + + std::list get_model2d_name_list() + { + std::list result; + for(map,std::vector,std::string>* > ::iterator i=model2d_map.begin(); + i!=model2d_map.end();++i) + { + result.push_back(i->first); + } + return result; + } + +model,std::string>& get_1dmodel_by_name(const char* name) + { + std::map,std::string >* >::iterator iter; + iter=model_map.find(name); + if(iter==model_map.end()||iter->second==0) + { + throw opt_exception("model does not exist"); + } + return *(iter->second); + } + + strmodel1d& get_strm1d() + { + return strm1d; + } + +model,std::vector,std::string>& get_2dmodel_by_name(const char* name) + { + std::map,std::vector,std::string>* >::iterator iter; + iter=model2d_map.find(name); + if(iter==model2d_map.end()||iter->second==0) + { + throw opt_exception("model does not exist"); + } + return *(iter->second); + } + + int get_n_1dmodels() + { + return model_map.size(); + } + + int get_n_2dmodels() + { + return model2d_map.size(); + } + + class model_map_keeper_class + { + private: + void init_model_map() + { + + //#define DECL_POLY(n) model_map["poly1d##n"]=new poly1d; + + + model_map["lin1d"]=new lin1d; + model_map["pl1d"]=new pl1d; + model_map["bl1d"]=new bl1d; + model_map["bpl1d"]=new bpl1d; + model_map["beta1d"]=new beta1d; + model_map["bremss"]=new bremss; + model_map["nbeta1d"]=new nbeta1d; + model_map["2beta1d"]=new dbeta1d; + model_map["nfw"]=new nfw1d; + model_map["gauss1d"]=new gauss1d; + model_map["poly1d2"]=new poly1d; + model_map["poly1d3"]=new poly1d; + model_map["poly1d4"]=new poly1d; + model_map["poly1d5"]=new poly1d; +#ifdef __linux__ + model_map["dlmodel"]=new dl_model; +#endif + //DECL_POLY(7) + } + + void release_model_map() + { + for(std::map,std::string>* >::iterator i=model_map.begin(); + i!=model_map.end();++i) + { + delete i->second; + } + } + public: + model_map_keeper_class() + { + init_model_map(); + std::cerr<<"1d models Initialized"<; + model2d_map["beta2d2"]=new beta2d2; + model2d_map["dbeta2d"]=new dbeta2d; + model2d_map["dbeta2d2"]=new dbeta2d2; + model2d_map["dbeta2d3"]=new dbeta2d3; + } + + void release_model_map() + { + for(std::map,std::vector,std::string>* >::iterator i=model2d_map.begin(); + i!=model2d_map.end();++i) + { + delete i->second; + } + } + public: + model2d_map_keeper_class() + { + init_model_map(); + std::cerr<<"2d models Initialized"< +#include +#include +#include +#include "vecn.hpp" +#include "strmodel1d.hpp" + + + +namespace opt_utilities +{ + extern std::map,std::string>* > model_map; + extern std::map,std::vector,std::string >* > model2d_map; + + extern strmodel1d strm1d; + extern std::list get_model_name_list(); + extern int get_n_1dmodels(); + // extern void init_model_map(); + // extern void release_model_map(); + + extern std::list get_model2d_name_list(); + // extern void init_model2d_map(); + // extern void release_model2d_map(); + extern int get_n_2dmodels(); + + extern model,std::string >& get_1dmodel_by_name(const char*); + extern model,std::vector,std::string >& get_2dmodel_by_name(const char*); + + extern strmodel1d& get_strm1d(); +} + + +#endif diff --git a/models/mul_model.hpp b/models/mul_model.hpp new file mode 100644 index 0000000..0e64c1b --- /dev/null +++ b/models/mul_model.hpp @@ -0,0 +1,171 @@ +#ifndef MUL_MODEL_H_ +#define MUL_MODEL_H_ +#include +#include + +namespace opt_utilities +{ + template + class mul_model + :public model + { + private: + model* do_clone()const + { + return new mul_model(*this); + } + private: + mul_model() + { + } + + private: + model* pm1; + model* pm2; + + public: + mul_model(const model& m1, + const model& m2) + :pm1(m1.clone()),pm2(m2.clone()) + { + int np1=m1.get_num_params(); + int np2=m2.get_num_params(); + for(int i=0;i p(m1.get_param_info(i)); + param_info p1(p.get_name()+"1",p.get_default_value()); + this->push_param_info(p1); + } + for(int i=0;i p(m2.get_param_info(i)); + param_info p2(p.get_name()+"2",p.get_default_value()); + this->push_param_info(p2); + } + } + + mul_model(const mul_model& rhs) + :pm1(NULL),pm2(NULL) + { + int np1(0),np2(0); + if(rhs.pm1) + { + pm1=rhs.pm1->clone(); + np1=rhs.pm1->get_num_params(); + for(int i=0;i p(rhs.pm1->get_param_info(i)); + param_info p1(p.get_name()+"1",p.get_default_value()); + this->push_param_info(p1); + } + } + if(rhs.pm2) + { + pm2=rhs.pm2->clone(); + np2=rhs.pm2->get_num_params(); + for(int i=0;i p(rhs.pm2->get_param_info(i)); + param_info p2(p.get_name()+"2",p.get_default_value()); + this->push_param_info(p2); + } + } + } + + mul_model& operator=(const mul_model& rhs) + { + if(this==&rhs) + { + return *this; + } + if(!pm1) + { + //delete pm1; + pm1->destroy(); + } + if(!pm2) + { + //delete pm2; + pm2->destroy(); + } + int np1(0),np2(0); + if(rhs.pm1) + { + pm1=rhs.pm1->clone(); + np1=rhs.pm1->get_num_params(); + for(int i=0;i p(rhs.pm1->get_param_info(i)); + param_info p1(p.get_name()+"1",p.get_default_value()); + this->push_param_info(p1); + } + } + if(rhs.pm2) + { + pm2=rhs.pm2->clone(); + np2=rhs.pm2->get_num_params(); + for(int i=0;i p(rhs.pm2->get_param_info(i)); + param_info p2(p.get_name()+"2",p.get_default_value()); + this->push_param_info(p2); + } + } + return *this; + } + + + ~mul_model() + { + if(!pm1) + { + //delete pm1; + pm1->destroy(); + } + if(!pm2) + { + //delete pm2; + pm2->destroy(); + } + } + + public: + Ty do_eval(const Tx& x,const Tp& param) + { + if(!pm1) + { + throw opt_exception("incomplete model!"); + } + if(!pm2) + { + throw opt_exception("incomplete model!"); + } + Tp p1(pm1->get_num_params()); + Tp p2(pm2->get_num_params()); + int i=0; + int j=0; + for(i=0;iget_num_params();++i,++j) + { + set_element(p1,i,get_element(param,j)); + } + for(i=0;iget_num_params();++i,++j) + { + set_element(p2,i,get_element(param,j)); + } + return pm1->eval(x,p1)*pm2->eval(x,p2); + } + }; + + template + mul_model operator*(const model& m1, + const model& m2) + { + return mul_model(m1,m2); + } + +}; + + + +#endif +//EOF diff --git a/models/nbeta1d.hpp b/models/nbeta1d.hpp new file mode 100644 index 0000000..3806fe9 --- /dev/null +++ b/models/nbeta1d.hpp @@ -0,0 +1,49 @@ +#ifndef NBETA_MODEL_H_ +#define NBETA_MODEL_H_ +#include +#include +#include +namespace opt_utilities +{ + template + class nbeta1d + :public model ,std::string> + { + private: + model >* do_clone()const + { + return new nbeta1d(*this); + } + public: + nbeta1d() + { + this->push_param_info(param_info >("S0",1)); + this->push_param_info(param_info >("rc",10)); + this->push_param_info(param_info >("beta",2./3.)); + this->push_param_info(param_info >("bkg",0)); + } + + + T do_eval(const T& x,const std::vector& param) + { + T S0=get_element(param,0); + T r_c=get_element(param,1); + T beta=get_element(param,2); + T bkg=get_element(param,3); + + return bkg+S0*pow(1+(x*x)/(r_c*r_c),-3./2.*beta); + } + + private: + std::string do_to_string()const + { + return "density beta model\n" + "n=n0*(1+(r/rc)^2)^(-1.5*beta)\n"; + } + }; +}; + + + +#endif +//EOF diff --git a/models/nfw1d.hpp b/models/nfw1d.hpp new file mode 100644 index 0000000..9c2dfd4 --- /dev/null +++ b/models/nfw1d.hpp @@ -0,0 +1,45 @@ +#ifndef NFW_MODEL_H_ +#define NFW_MODEL_H_ +#include +#include +#include +namespace opt_utilities +{ + template + class nfw1d + :public model,std::string> + { + private: + model >* do_clone()const + { + return new nfw1d(*this); + } + public: + nfw1d() + { + this->push_param_info(param_info >("rho0",1.)); + this->push_param_info(param_info >("rs",1.)); + } + + + T do_eval(const T& x,const std::vector& param) + { + T rho0=get_element(param,0); + T rs=get_element(param,1); + + + return rho0/(x/rs*(1+x/rs)*(1+x/rs)); + } + + std::string do_to_string()const + { + return "NFW model\n" + "y=rho0/(r/rs*(1+r/rs)^2\n"; + } + }; +}; + + + +#endif +//EOF diff --git a/models/pl1d.hpp b/models/pl1d.hpp new file mode 100644 index 0000000..50b4c50 --- /dev/null +++ b/models/pl1d.hpp @@ -0,0 +1,43 @@ +#ifndef POWER_LAW_MODEL_H_ +#define POWER_LAW_MODEL_H_ +#include +#include + +namespace opt_utilities +{ + template + class pl1d + :public model,std::string> + { + private: + model >* do_clone()const + { + return new pl1d(*this); + } + public: + pl1d() + { + this->push_param_info(param_info >("Ampl",1)); + this->push_param_info(param_info >("gamma",1)); + } + + T do_eval(const T& x,const std::vector& param) + { + T A=get_element(param,0); + T gamma=get_element(param,1); + return A*pow(x,gamma); + } + + private: + std::string do_to_string()const + { + return "Simple power law model\n" + "y=A*x^gamma\n"; + } + }; +}; + + + +#endif +//EOF diff --git a/models/poly1d.hpp b/models/poly1d.hpp new file mode 100644 index 0000000..a8c994b --- /dev/null +++ b/models/poly1d.hpp @@ -0,0 +1,67 @@ +#ifndef POLY_MODEL_H_ +#define POLY_MODEL_H_ +#include +#include +#include +#include + +namespace opt_utilities +{ + template + class poly1d + :public model,std::string> + { + private: + model >* do_clone()const + { + return new poly1d(*this); + } + public: + poly1d() + { + assert(n>=0); + for(int i=0;i<=n;++i) + { + std::ostringstream ostr; + ostr<<"a"<push_param_info(param_info >(ostr.str().c_str(),1)); + } + + } + + public: + T do_eval(const T& x,const std::vector& param) + { + // return x*get_element(param,0)+get_element(param,1); + T result(0); + for(int i=0;i<=n;++i) + { + T xn(1); + for(int j=0;j +#include + +namespace opt_utilities +{ + template + class pow_model + :public model + { + private: + model* do_clone()const + { + return new pow_model(*this); + } + private: + pow_model() + { + } + + private: + model* pm1; + typename value_type_trait::value_type idx; + + public: + pow_model(const model& m1, + const typename value_type_trait::value_type& index) + :pm1(m1.clone()),idx(index) + { + int np1=m1.get_num_params(); + + for(int i=0;i p(m1.get_param_info(i)); + //param_info p1(p.get_name(),p.get_default_value()); + this->push_param_info(p); + } + } + + pow_model(const pow_model& rhs) + :pm1(NULL),idx(0) + { + int np1(0); + if(rhs.pm1) + { + pm1=rhs.pm1->clone(); + np1=rhs.pm1->get_num_params(); + for(int i=0;i p(rhs.pm1->get_param_info(i)); + param_info p1(p.get_name()+"1",p.get_default_value()); + this->push_param_info(p1); + } + } + idx=rhs.idx; + } + + pow_model& operator=(const pow_model& rhs) + { + if(this==&rhs) + { + return *this; + } + if(!pm1) + { + //delete pm1; + pm1->destroy(); + } + + int np1(0); + if(rhs.pm1) + { + pm1=rhs.pm1->clone(); + np1=rhs.pm1->get_num_params(); + for(int i=0;i p(rhs.pm1->get_param_info(i)); + // param_info p1(p.get_name()+"1",p.get_default_value()); + this->push_param_info(p); + } + } + idx=rhs.idx; + + return *this; + } + + ~pow_model() + { + if(!pm1) + { + //delete pm1; + pm1->destroy(); + } + } + + public: + Ty do_eval(const Tx& x,const Tp& param) + { + if(!pm1) + { + throw opt_exception("incomplete model!"); + } + + return std::pow(pm1->eval(x,param),idx); + } + }; + + template + pow_model pow(const model& m1, + const typename value_type_trait::value_type& idx) + { + return pow_model(m1,idx); + } +}; + + + +#endif +//EOF diff --git a/models/strmodel1d.cc b/models/strmodel1d.cc new file mode 100644 index 0000000..df3cd40 --- /dev/null +++ b/models/strmodel1d.cc @@ -0,0 +1,82 @@ +#include "strmodel1d.hpp" + +using namespace mu; +using namespace std; +using namespace opt_utilities; + +strmodel1d* strmodel1d::do_clone()const +{ + return new strmodel1d(*this); +} + +strmodel1d::strmodel1d() +{ + set_buildin_fun(); +} + +strmodel1d::strmodel1d(const strmodel1d& rhs) + :expr(rhs.expr), + par_names(rhs.par_names), + var_name(rhs.var_name), + par_vec(rhs.par_vec) +{ + set_buildin_fun(); + set_expr(expr,par_names,var_name); +} + +strmodel1d& strmodel1d::operator=(const strmodel1d& rhs) +{ + set_buildin_fun(); + expr=rhs.expr; + par_names=rhs.par_names; + var_name=rhs.var_name; + par_vec=rhs.par_vec; + set_expr(expr,par_names,var_name); + return *this; +} + +void strmodel1d::set_buildin_fun() +{ + mp.DefineFun("sin",sin); + mp.DefineFun("cos",cos); + mp.DefineFun("exp",exp); + mp.DefineFun("tan",tan); + mp.DefineFun("log",log); +} + + +void strmodel1d::set_expr(const string& _expr, + const std::vector& _par_names, + const std::string& _var_name) +{ + expr=_expr; + par_names=_par_names; + var_name=_var_name; + this->clear_param_info(); + par_vec.resize(par_names.size()); + mp.ClearVar(); + // mp.ClearFun(); + for(int i=0;ipush_param_info(param_info >(par_names[i],0)); + } + mp.DefineVar(var_name.c_str(),&x); + mp.SetExpr(expr.c_str()); +} + + +double strmodel1d::do_eval(const double& _x,const vector& p) +{ + for(int i=0;i +#include +#include +#include +#include +#include +#include + +class strmodel1d + :public opt_utilities::model,std::string> +{ +private: + mu::Parser mp; + strmodel1d* do_clone()const; + std::vector par_vec; + std::vector par_names; + std::string expr; + std::string var_name; + double x; + void set_buildin_fun(); +public: + double do_eval(const double& x,const std::vector& p); + strmodel1d(); + strmodel1d(const strmodel1d& rhs); + strmodel1d& operator=(const strmodel1d& rhs); + + + void set_expr(const std::string& _expr, + const std::vector& _par_names, + const std::string& _var_name); + +}; + + + +#endif +//EOF diff --git a/models/vecn.hpp b/models/vecn.hpp new file mode 100644 index 0000000..cac1436 --- /dev/null +++ b/models/vecn.hpp @@ -0,0 +1,62 @@ +#ifndef VECN_HPP +#define VECN_HPP +#include +namespace opt_utilities +{ + template + class vecn + { + public: + T data[n]; + public: + T& operator[](int i) + { + return data[i]; + } + + const T& operator[](int i)const + { + return data[i]; + } + + vecn() + { + for(int i=0;i + std::istream& operator>>(std::istream& is,vecn& p) + { + for(int i=0;i>p[i]; + // std::cout< + std::ostream& operator<<(std::ostream& os,const vecn& p) + { + os<<'['; + for(int i=0;i \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2006 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#include "muParser.h" + +#include +#include +#include + +/** \brief Pi (what else?). */ +#define PARSER_CONST_PI 3.141592653589793238462643 + +/** \brief The eulerian number. */ +#define PARSER_CONST_E 2.718281828459045235360287 + +using namespace std; + + +/** \brief Namespace for mathematical applications. */ +namespace mu +{ + +//--------------------------------------------------------------------------- +// Trigonometric function +value_type Parser::Sin(value_type v) { return sin(v); } +value_type Parser::Cos(value_type v) { return cos(v); } +value_type Parser::Tan(value_type v) { return tan(v); } +value_type Parser::ASin(value_type v) { return asin(v); } +value_type Parser::ACos(value_type v) { return acos(v); } +value_type Parser::ATan(value_type v) { return atan(v); } +value_type Parser::Sinh(value_type v) { return sinh(v); } +value_type Parser::Cosh(value_type v) { return cosh(v); } +value_type Parser::Tanh(value_type v) { return tanh(v); } +value_type Parser::ASinh(value_type v) { return log(v + sqrt(v * v + 1)); } +value_type Parser::ACosh(value_type v) { return log(v + sqrt(v * v - 1)); } +value_type Parser::ATanh(value_type v) { return ((value_type)0.5 * log((1 + v) / (1 - v))); } + +//--------------------------------------------------------------------------- +// Logarithm functions +value_type Parser::Log2(value_type v) { return log(v)/log((value_type)2); } // Logarithm base 2 +value_type Parser::Log10(value_type v) { return log10(v); } // Logarithm base 10 +value_type Parser::Ln(value_type v) { return log(v); } // Logarithm base e (natural logarithm) + +//--------------------------------------------------------------------------- +// misc +value_type Parser::Exp(value_type v) { return exp(v); } +value_type Parser::Abs(value_type v) { return fabs(v); } +value_type Parser::Sqrt(value_type v) { return sqrt(v); } +value_type Parser::Rint(value_type v) { return floor(v + (value_type)0.5); } +value_type Parser::Sign(value_type v) { return (value_type)((v<0) ? -1 : (v>0) ? 1 : 0); } + +//--------------------------------------------------------------------------- +// Conditional (if then else) +value_type Parser::Ite(value_type v1, value_type v2, value_type v3) { return (v1==1) ? v2 : v3; } + +//--------------------------------------------------------------------------- +// Unary operator Callbacks: Infix operators +value_type Parser::UnaryMinus(value_type v) { return -v; } + +//--------------------------------------------------------------------------- +// Functions with variable number of arguments +// sum +value_type Parser::Sum(const value_type *a_afArg, int a_iArgc) +{ + if (!a_iArgc) + throw exception_type(_T("too few arguments for function sum.")); + + value_type fRes=0; + for (int i=0; i> fVal; + int iEnd = stream.tellg(); // Position after reading +#endif + + if (iEnd==-1) + return false; + + a_iPos += iEnd; + a_fVal = fVal; + return true; +} + +//--------------------------------------------------------------------------- +/** \brief Constructor. + + Call ParserBase class constructor and trigger Function, Operator and Constant initialization. +*/ +Parser::Parser() + :ParserBase() + ,m_fEpsilon((value_type)1e-7) +{ + AddValIdent(IsVal); + + InitCharSets(); + InitFun(); + InitConst(); + InitOprt(); +} + +//--------------------------------------------------------------------------- +/** Define the character sets. */ +void Parser::InitCharSets() +{ + DefineNameChars( _T("0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") ); + DefineOprtChars( _T("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-*^/?<>=#!$%&|~'_") ); + DefineInfixOprtChars( _T("/+-*^?<>=#!$%&|~'_") ); +} + +//--------------------------------------------------------------------------- +/** \brief Initialize the default functions. */ +void Parser::InitFun() +{ + // trigonometric functions + DefineFun(_T("sin"), Sin); + DefineFun(_T("cos"), Cos); + DefineFun(_T("tan"), Tan); + // arcus functions + DefineFun(_T("asin"), ASin); + DefineFun(_T("acos"), ACos); + DefineFun(_T("atan"), ATan); + // hyperbolic functions + DefineFun(_T("sinh"), Sinh); + DefineFun(_T("cosh"), Cosh); + DefineFun(_T("tanh"), Tanh); + // arcus hyperbolic functions + DefineFun(_T("asinh"), ASinh); + DefineFun(_T("acosh"), ACosh); + DefineFun(_T("atanh"), ATanh); + // Logarithm functions + DefineFun(_T("log2"), Log2); + DefineFun(_T("log10"), Log10); + DefineFun(_T("log"), Log10); + DefineFun(_T("ln"), Ln); + // misc + DefineFun(_T("exp"), Exp); + DefineFun(_T("sqrt"), Sqrt); + DefineFun(_T("sign"), Sign); + DefineFun(_T("rint"), Rint); + DefineFun(_T("abs"), Abs); + DefineFun(_T("if"), Ite); + // Functions with variable number of arguments + DefineFun(_T("sum"), Sum); + DefineFun(_T("avg"), Avg); + DefineFun(_T("min"), Min); + DefineFun(_T("max"), Max); +} + +//--------------------------------------------------------------------------- +/** \brief Initialize operators. */ +void Parser::InitConst() +{ + DefineConst(_T("_pi"), (value_type)PARSER_CONST_PI); + DefineConst(_T("_e"), (value_type)PARSER_CONST_E); +} + +//--------------------------------------------------------------------------- +/** \brief Initialize operators. */ +void Parser::InitOprt() +{ + DefineInfixOprt(_T("-"), UnaryMinus); +} + +//--------------------------------------------------------------------------- +/** \brief Numerically differentiate with regard to a variable. */ +value_type Parser::Diff(value_type *a_Var, value_type a_fPos) const +{ + assert(m_fEpsilon); + value_type fEpsilon( (a_fPos==0) ? (value_type)1e-10 : m_fEpsilon * a_fPos ), + fRes(0), fBuf(*a_Var), f[4] = {0,0,0,0}; + + *a_Var = a_fPos+2*fEpsilon; f[0] = Eval(); + *a_Var = a_fPos+1*fEpsilon; f[1] = Eval(); + *a_Var = a_fPos-1*fEpsilon; f[2] = Eval(); + *a_Var = a_fPos-2*fEpsilon; f[3] = Eval(); + *a_Var = fBuf; // restore variable + + fRes = (-f[0] + 8*f[1] - 8*f[2] + f[3]) / (12*fEpsilon); + return fRes; +} + +} // namespace mu diff --git a/muparser/muParser.h b/muparser/muParser.h new file mode 100644 index 0000000..5aff62d --- /dev/null +++ b/muparser/muParser.h @@ -0,0 +1,104 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2006 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#ifndef MU_PARSER_H +#define MU_PARSER_H + +#include "muParserBase.h" +#include + + +namespace mu +{ + +/** \brief Mathematical expressions parser (reference implementation). + + Standard implementation of the mathematical expressions parser. + Can be used as a reference implementation for subclassing the parser. + + + (C) 2004-2006 Ingo Berg
+ ingo_berg(at)gmx.de +
+*/ +class Parser : public ParserBase +{ +private: + // Trigonometric functions + static value_type Sin(value_type); + static value_type Cos(value_type); + static value_type Tan(value_type); + // arcus functions + static value_type ASin(value_type); + static value_type ACos(value_type); + static value_type ATan(value_type); + // hyperbolic functions + static value_type Sinh(value_type); + static value_type Cosh(value_type); + static value_type Tanh(value_type); + // arcus hyperbolic functions + static value_type ASinh(value_type); + static value_type ACosh(value_type); + static value_type ATanh(value_type); + // Logarithm functions + static value_type Log2(value_type); // Logarithm Base 2 + static value_type Log10(value_type); // Logarithm Base 10 + static value_type Ln(value_type); // Logarithm Base e (natural logarithm) + // misc + static value_type Exp(value_type); + static value_type Abs(value_type); + static value_type Sqrt(value_type); + static value_type Rint(value_type); + static value_type Sign(value_type); + static value_type Ite(value_type, value_type, value_type); + + // Prefix operators + // !!! Unary Minus is a MUST if you want to use negative signs !!! + static value_type UnaryMinus(value_type); + + // Functions with variable number of arguments + static value_type Sum(const value_type*, int); // sum + static value_type Avg(const value_type*, int); // mean value + static value_type Min(const value_type*, int); // minimum + static value_type Max(const value_type*, int); // maximum + + static bool IsVal(const char_type *a_szExpr, int &a_iPos, value_type &a_fVal); + + value_type m_fEpsilon; ///< Epsilon used for numerical differentiation. + +public: + Parser(); + + virtual void InitCharSets(); + virtual void InitFun(); + virtual void InitConst(); + virtual void InitOprt(); + + value_type Diff(value_type *a_Var, value_type a_fPos) const; +}; + +} // namespace mu + +#endif + diff --git a/muparser/muParserBase.cpp b/muparser/muParserBase.cpp new file mode 100644 index 0000000..e81e53e --- /dev/null +++ b/muparser/muParserBase.cpp @@ -0,0 +1,1364 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2006 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "muParser.h" + +#include +#include +#include +#include +#include + +using namespace std; + + +namespace mu +{ + +//------------------------------------------------------------------------------ +/** \brief Identifiers for built in binary operators. + + When defining custom binary operators with #AddOprt(...) make sure not to choose + names conflicting with these definitions. +*/ +const char_type* ParserBase::c_DefaultOprt[] = +{ + _T("<="), _T(">="), _T("!="), + _T("=="), _T("<"), _T(">"), + _T("+"), _T("-"), _T("*"), + _T("/"), _T("^"), _T("and"), + _T("or"), _T("xor"), _T("="), + _T("("), _T(")"), _T(","), 0 +}; + +//------------------------------------------------------------------------------ +/** \brief Constructor. + \param a_szFormula the formula to interpret. + \throw ParserException if a_szFormula is null. +*/ +ParserBase::ParserBase() + :m_pParseFormula(&ParserBase::ParseString) + ,m_pCmdCode(0) + ,m_vByteCode() + ,m_vStringBuf() + ,m_pTokenReader() + ,m_FunDef() + ,m_PostOprtDef() + ,m_InfixOprtDef() + ,m_OprtDef() + ,m_ConstDef() + ,m_StrVarDef() + ,m_VarDef() + ,m_bOptimize(true) + ,m_bUseByteCode(true) + ,m_bBuiltInOp(true) + ,m_sNameChars() + ,m_sOprtChars() + ,m_sInfixOprtChars() +{ + InitTokenReader(); +} + +//--------------------------------------------------------------------------- +/** \brief Copy constructor. + + Implemented by calling Assign(a_Parser) +*/ +ParserBase::ParserBase(const ParserBase &a_Parser) + :m_pParseFormula(&ParserBase::ParseString) + ,m_pCmdCode(0) + ,m_vByteCode() + ,m_vStringBuf() + ,m_pTokenReader() + ,m_FunDef() + ,m_PostOprtDef() + ,m_InfixOprtDef() + ,m_OprtDef() + ,m_ConstDef() + ,m_StrVarDef() + ,m_VarDef() + ,m_bOptimize(true) + ,m_bUseByteCode(true) + ,m_bBuiltInOp(true) +{ + m_pTokenReader.reset(new token_reader_type(this)); + Assign(a_Parser); +} + +//--------------------------------------------------------------------------- +/** \brief Assignement operator. + + Implemented by calling Assign(a_Parser). Self assignement is suppressed. + \param a_Parser Object to copy to this. + \return *this + \throw nothrow +*/ +ParserBase& ParserBase::operator=(const ParserBase &a_Parser) +{ + Assign(a_Parser); + return *this; +} + +//--------------------------------------------------------------------------- +/** \brief Copy state of a parser object to this. + + Clears Variables and Functions of this parser. + Copies the states of all internal variables. + Resets parse function to string parse mode. + + \param a_Parser the source object. +*/ +void ParserBase::Assign(const ParserBase &a_Parser) +{ + if (&a_Parser==this) + return; + + // Don't copy bytecode instead cause the parser to create new bytecode + // by resetting the parse function. + ReInit(); + + m_ConstDef = a_Parser.m_ConstDef; // Copy user define constants + m_VarDef = a_Parser.m_VarDef; // Copy user defined variables + m_bOptimize = a_Parser.m_bOptimize; + m_bUseByteCode = a_Parser.m_bUseByteCode; + m_bBuiltInOp = a_Parser.m_bBuiltInOp; + m_vStringBuf = a_Parser.m_vStringBuf; + m_pTokenReader.reset(a_Parser.m_pTokenReader->Clone(this)); + m_StrVarDef = a_Parser.m_StrVarDef; + m_vStringVarBuf = a_Parser.m_vStringVarBuf; + + // Copy function and operator callbacks + m_FunDef = a_Parser.m_FunDef; // Copy function definitions + m_PostOprtDef = a_Parser.m_PostOprtDef; // post value unary operators + m_InfixOprtDef = a_Parser.m_InfixOprtDef; // unary operators for infix notation + + m_sNameChars = a_Parser.m_sNameChars; + m_sOprtChars = a_Parser.m_sOprtChars; + m_sInfixOprtChars = a_Parser.m_sInfixOprtChars; +} + +//--------------------------------------------------------------------------- +/** \brief Initialize the token reader. + + Create new token reader object and submit pointers to function, operator, + constant and variable definitions. + + \post m_pTokenReader.get()!=0 + \throw nothrow +*/ +void ParserBase::InitTokenReader() +{ + m_pTokenReader.reset(new token_reader_type(this)); +} + +//--------------------------------------------------------------------------- +/** \brief Reset parser to string parsing mode and clear internal buffers. + + Clear bytecode, reset the token reader. + \throw nothrow +*/ +void ParserBase::ReInit() const +{ + m_pParseFormula = &ParserBase::ParseString; + m_vStringBuf.clear(); + m_vByteCode.clear(); + m_pTokenReader->ReInit(); +} + +//--------------------------------------------------------------------------- +void ParserBase::AddValIdent(identfun_type a_pCallback) +{ + m_pTokenReader->AddValIdent(a_pCallback); +} + +//--------------------------------------------------------------------------- +void ParserBase::SetVarFactory(facfun_type a_pFactory, void *pUserData) +{ + m_pTokenReader->SetVarCreator(a_pFactory, pUserData); +} + +//--------------------------------------------------------------------------- +/** \brief Add a function or operator callback to the parser. +*/ +void ParserBase::AddCallback( const string_type &a_strName, + const ParserCallback &a_Callback, + funmap_type &a_Storage, + const char_type *a_szCharSet ) +{ + if (a_Callback.GetAddr()==0) + Error(ecINVALID_FUN_PTR); + + const funmap_type *pFunMap = &a_Storage; + + // Check for conflicting operator or function names + if ( pFunMap!=&m_FunDef && m_FunDef.find(a_strName)!=m_FunDef.end() ) + Error(ecNAME_CONFLICT); + + if ( pFunMap!=&m_PostOprtDef && m_PostOprtDef.find(a_strName)!=m_PostOprtDef.end() ) + Error(ecNAME_CONFLICT); + + if ( pFunMap!=&m_InfixOprtDef && pFunMap!=&m_OprtDef && m_InfixOprtDef.find(a_strName)!=m_InfixOprtDef.end() ) + Error(ecNAME_CONFLICT); + + if ( pFunMap!=&m_InfixOprtDef && pFunMap!=&m_OprtDef && m_OprtDef.find(a_strName)!=m_OprtDef.end() ) + Error(ecNAME_CONFLICT); + + CheckName(a_strName, a_szCharSet); + a_Storage[a_strName] = a_Callback; + ReInit(); +} + +//--------------------------------------------------------------------------- +/** \brief Check if a name contains invalid characters. + + \throw ParserException if the name contains invalid charakters. +*/ +void ParserBase::CheckName(const string_type &a_sName, + const string_type &a_szCharSet) const +{ + if ( !a_sName.length() || + (a_sName.find_first_not_of(a_szCharSet)!=string_type::npos) || + (a_sName[0]>='0' && a_sName[0]<='9')) + { + Error(ecINVALID_NAME); + } +} + +//--------------------------------------------------------------------------- +/** \brief Set the formula. + Triggers first time calculation thus the creation of the bytecode and + scanning of used variables. + + \param a_strFormula Formula as string_type + \throw ParserException in case of syntax errors. +*/ +void ParserBase::SetExpr(const string_type &a_sExpr) +{ + // 20060222: Bugfix for Borland-Kylix: + // adding a space to the expression will keep Borlands KYLIX from going wild + // when calling tellg on a stringstream created from the expression after + // reading a value at the end of an expression. (mu::Parser::IsVal function) + // (tellg returns -1 otherwise causing the parser to ignore the value) + string_type sBuf(a_sExpr + _T(" ") ); + m_pTokenReader->SetFormula(sBuf); + ReInit(); +} + +//--------------------------------------------------------------------------- +/** \brief Add a user defined operator. + \post Will reset the Parser to string parsing mode. +*/ +void ParserBase::DefinePostfixOprt(const string_type &a_sName, + fun_type1 a_pFun, + bool a_bAllowOpt) +{ + AddCallback( a_sName, + ParserCallback(a_pFun, a_bAllowOpt, prPOSTFIX, cmOPRT_POSTFIX), + m_PostOprtDef, + ValidOprtChars() ); +} + +//--------------------------------------------------------------------------- +/** \brief Add a user defined operator. + \post Will reset the Parser to string parsing mode. + \param a_sName [in] operator Identifier + \param a_pFun [in] Operator callback function + \param a_iPrec [in] Operator Precedence (default=prSIGN) + \param a_bAllowOpt [in] True if operator is volatile (default=false) + + \sa EPrec +*/ +void ParserBase::DefineInfixOprt(const string_type &a_sName, + fun_type1 a_pFun, + int a_iPrec, + bool a_bAllowOpt) +{ + AddCallback( a_sName, + ParserCallback(a_pFun, a_bAllowOpt, a_iPrec, cmOPRT_INFIX), + m_InfixOprtDef, + ValidOprtChars() ); +} + +//--------------------------------------------------------------------------- +void ParserBase::DefineOprt( const string_type &a_sName, + fun_type2 a_pFun, + unsigned a_iPrec, + bool a_bAllowOpt ) +{ + // Check for conflicts with built in operator names + for (int i=0; m_bBuiltInOp && iIgnoreUndefVar(true); + ParseString(); // implicitely create or update the map with the + // used variables stored in the token reader if not already done + m_pTokenReader->IgnoreUndefVar(false); + } + catch(exception_type &e) + { + m_pTokenReader->IgnoreUndefVar(false); + throw e; + } + + // Make sure to stay in string parse mode, dont call ReInit() + // because it deletes the array with the used variables + m_pParseFormula = &ParserBase::ParseString; + + return m_pTokenReader->GetUsedVar(); +} + +//--------------------------------------------------------------------------- +/** \brief Return a map containing the used variables only. */ +const varmap_type& ParserBase::GetVar() const +{ + return m_VarDef; +} + +//--------------------------------------------------------------------------- +/** \brief Return a map containing all parser constants. */ +const valmap_type& ParserBase::GetConst() const +{ + return m_ConstDef; +} + +//--------------------------------------------------------------------------- +/** \brief Return prototypes of all parser functions. + + The return type is a map of the public type #funmap_type containing the prototype + definitions for all numerical parser functions. String functions are not part of + this map. The Prototype definition is encapsulated in objects of the class FunProt + one per parser function each associated with function names via a map construct. + \return #m_FunDef + \sa FunProt + \throw nothrow +*/ +const funmap_type& ParserBase::GetFunDef() const +{ + return m_FunDef; +} + +//--------------------------------------------------------------------------- +/** \brief Retrieve the formula. */ +const string_type& ParserBase::GetExpr() const +{ + return m_pTokenReader->GetFormula(); +} + +//--------------------------------------------------------------------------- +ParserBase::token_type ParserBase::ApplyNumFunc( const token_type &a_FunTok, + const std::vector &a_vArg) const +{ + token_type valTok; + int iArgCount = (unsigned)a_vArg.size(); + void *pFunc = a_FunTok.GetFuncAddr(); + assert(pFunc); + + // Collect the function arguments from the value stack + switch(a_FunTok.GetArgCount()) + { + case -1: + // Function with variable argument count + // copy arguments into a vector + { + /** \todo remove the unnecessary argument vector by changing order in stArg. */ + std::vector vArg; + for (int i=0; i &a_vArg) const +{ + if (a_vArg.back().GetCode()!=cmSTRING) + Error(ecSTRING_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString()); + + token_type valTok; + int iArgCount = (unsigned)a_vArg.size(); + void *pFunc = a_FunTok.GetFuncAddr(); + assert(pFunc); + + try + { + // Collect the function arguments from the value stack + switch(a_FunTok.GetArgCount()) + { + case 0: valTok.SetVal( ((strfun_type1)pFunc)(a_vArg[0].GetAsString().c_str()) ); break; + case 1: valTok.SetVal( ((strfun_type2)pFunc)(a_vArg[1].GetAsString().c_str(), + a_vArg[0].GetVal()) ); break; + case 2: valTok.SetVal( ((strfun_type3)pFunc)(a_vArg[2].GetAsString().c_str(), + a_vArg[1].GetVal(), + a_vArg[0].GetVal()) ); break; + default: Error(ecINTERNAL_ERROR); + } + } + catch(ParserError& /*e*/) + { + Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString()); + } + + // Find out if the result will depend on a variable + /** \todo remove this loop, put content in the loop that takes the argument values. + + (Attention: SetVal will reset Flags.) + */ + bool bVolatile = a_FunTok.IsFlagSet(token_type::flVOLATILE); + for (int i=0; (bVolatile==false) && (i &a_stOpt, + ParserStack &a_stVal, + int a_iArgCount) const +{ + assert(m_pTokenReader.get()); + + // Operator stack empty or does not contain tokens with callback functions + if (a_stOpt.empty() || a_stOpt.top().GetFuncAddr()==0 ) + return; + + token_type funTok = a_stOpt.pop(); + assert(funTok.GetFuncAddr()); + + // Binary operators must rely on their internal operator number + // since counting of operators relies on commas for function arguments + // binary operators do not have commas in their expression + int iArgCount = ( funTok.GetCode()==cmOPRT_BIN ) ? funTok.GetArgCount() : a_iArgCount; + + if (funTok.GetArgCount()>0 && iArgCount>funTok.GetArgCount()) + Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos()-1, funTok.GetAsString()); + + if ( funTok.GetCode()!=cmOPRT_BIN && iArgCountGetPos()-1, funTok.GetAsString()); + + if ( funTok.GetCode()==cmFUNC_STR && iArgCount>funTok.GetArgCount() ) + Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos()-1, funTok.GetAsString()); + + // Collect the numeric function arguments from the value stack and store them + // in a vector + std::vector stArg; + for (int i=0; iGetPos(), funTok.GetAsString()); + } + + // for string functions add the string argument + if (funTok.GetCode()==cmFUNC_STR) + { + stArg.push_back( a_stVal.pop() ); + if ( stArg.back().GetType()==tpSTR && funTok.GetType()!=tpSTR ) + Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), funTok.GetAsString()); + } + + // String functions accept only one parameter + if (funTok.GetType()==tpSTR) + { + token_type token( ApplyStrFunc(funTok, stArg) ); + a_stVal.push( token ); + } + else + { + token_type token( ApplyNumFunc(funTok, stArg) ); + a_stVal.push( token ); + } +/* +#ifdef __BORLANDC__ + // Borland C++ Compiler does not support taking references on + // unnamed temporaries + if (funTok.GetType()==tpSTR) + { + ParserToken pt( ApplyStrFunc(funTok, stArg.back()) ); + a_stVal.push(pt); + } + else + { + ParserToken pt( ApplyNumFunc(funTok, stArg) ); + a_stVal.push(pt); + } +#else + // String functions accept only one parameter + a_stVal.push( (funTok.GetType()==tpSTR) ? ApplyStrFunc(funTok, stArg) : + ApplyNumFunc(funTok, stArg) ); +#endif // __BORLANDC__ +*/ +} + +//--------------------------------------------------------------------------- +void ParserBase::ApplyBinOprt( ParserStack &a_stOpt, + ParserStack &a_stVal) const +{ + assert(a_stOpt.size()); + + // user defined binary operator + if (a_stOpt.top().GetCode()==cmOPRT_BIN) + { + ApplyFunc(a_stOpt, a_stVal, 2); + } + else + { + // internal binary operator + MUP_ASSERT(a_stVal.size()>=2); + + token_type valTok1 = a_stVal.pop(), + valTok2 = a_stVal.pop(), + optTok = a_stOpt.pop(), + resTok; + + if ( valTok1.GetType()!=valTok2.GetType() || + (valTok1.GetType()==tpSTR && valTok2.GetType()==tpSTR) ) + Error(ecOPRT_TYPE_CONFLICT, m_pTokenReader->GetPos(), optTok.GetAsString()); + + value_type x = valTok2.GetVal(), + y = valTok1.GetVal(); + + switch (optTok.GetCode()) + { + // built in binary operators + case cmAND: resTok.SetVal( (int)x & (int)y ); break; + case cmOR: resTok.SetVal( (int)x | (int)y ); break; + case cmXOR: resTok.SetVal( (int)x ^ (int)y ); break; + case cmLT: resTok.SetVal( x < y ); break; + case cmGT: resTok.SetVal( x > y ); break; + case cmLE: resTok.SetVal( x <= y ); break; + case cmGE: resTok.SetVal( x >= y ); break; + case cmNEQ: resTok.SetVal( x != y ); break; + case cmEQ: resTok.SetVal( x == y ); break; + case cmADD: resTok.SetVal( x + y ); break; + case cmSUB: resTok.SetVal( x - y ); break; + case cmMUL: resTok.SetVal( x * y ); break; + case cmDIV: resTok.SetVal( x / y ); break; + case cmPOW: resTok.SetVal(pow(x, y)); break; + + case cmASSIGN: + // The assignement operator needs special treatment + // it uses a different format when stored in the bytecode! + { + if (valTok2.GetCode()!=cmVAR) + Error(ecINTERNAL_ERROR, 7); + + value_type *pVar = valTok2.GetVar(); + resTok.SetVal( *pVar = y ); + a_stVal.push( resTok ); + + m_vByteCode.AddAssignOp(pVar); + return; // we must return since the following + // stuff does not apply + } + + default: Error(ecINTERNAL_ERROR, 8); + } + + // Create the bytecode entries + if (!m_bOptimize) + { + // Optimization flag is not set + m_vByteCode.AddOp(optTok.GetCode()); + } + else if ( valTok1.IsFlagSet(token_type::flVOLATILE) || + valTok2.IsFlagSet(token_type::flVOLATILE) ) + { + // Optimization flag is not set, but one of the value + // depends on a variable + m_vByteCode.AddOp(optTok.GetCode()); + resTok.AddFlags(token_type::flVOLATILE); + } + else + { + // operator call can be optimized; If optimization is possible + // the two previous tokens must be value tokens / they will be removed + // and replaced with the result of the pending operation. + m_vByteCode.RemoveValEntries(2); + m_vByteCode.AddVal(resTok.GetVal()); + } + + a_stVal.push( resTok ); + } +} + +//--------------------------------------------------------------------------- +/** \brief Parse the command code. + + Command code contains precalculated stack positions of the values and the + associated operators. + The Stack is filled beginning from index one the value at index zero is + not used at all. + + \sa ParseString(), ParseValue() +*/ +value_type ParserBase::ParseCmdCode() const +{ +#if defined(_MSC_VER) + #pragma warning( disable : 4312 ) +#endif + + value_type Stack[99]; + ECmdCode iCode; + bytecode_type idx(0); + int i(0); + + __start: + + idx = m_pCmdCode[i]; + iCode = (ECmdCode)m_pCmdCode[i+1]; + i += 2; + +#ifdef _DEBUG + if (idx>=99) + throw exception_type(ecGENERIC, _T(""), m_pTokenReader->GetFormula(), -1); +#endif + + switch (iCode) + { + // built in binary operators + case cmAND: Stack[idx] = (int)Stack[idx] & (int)Stack[idx+1]; goto __start; + case cmOR: Stack[idx] = (int)Stack[idx] | (int)Stack[idx+1]; goto __start; + case cmXOR: Stack[idx] = (int)Stack[idx] ^ (int)Stack[idx+1]; goto __start; + case cmLE: Stack[idx] = Stack[idx] <= Stack[idx+1]; goto __start; + case cmGE: Stack[idx] = Stack[idx] >= Stack[idx+1]; goto __start; + case cmNEQ: Stack[idx] = Stack[idx] != Stack[idx+1]; goto __start; + case cmEQ: Stack[idx] = Stack[idx] == Stack[idx+1]; goto __start; + case cmLT: Stack[idx] = Stack[idx] < Stack[idx+1]; goto __start; + case cmGT: Stack[idx] = Stack[idx] > Stack[idx+1]; goto __start; + case cmADD: Stack[idx] += Stack[1+idx]; goto __start; + case cmSUB: Stack[idx] -= Stack[1+idx]; goto __start; + case cmMUL: Stack[idx] *= Stack[1+idx]; goto __start; + case cmDIV: Stack[idx] /= Stack[1+idx]; goto __start; + case cmPOW: Stack[idx] = pow(Stack[idx], Stack[1+idx]); goto __start; + + // Assignement needs special treatment + case cmASSIGN: + { + // next is a pointer to the target + value_type **pDest = (value_type**)(&m_pCmdCode[i]); + + // advance index according to pointer size + i += m_vByteCode.GetPtrSize(); + // assign the value + Stack[idx] = **pDest = Stack[idx+1]; + } + goto __start; + + // user defined binary operators + case cmOPRT_BIN: + Stack[idx] = (**(fun_type2**)(&m_pCmdCode[i]))(Stack[idx], Stack[idx+1]); + ++i; + goto __start; + + // variable tokens + case cmVAR: + Stack[idx] = **(value_type**)(&m_pCmdCode[i]); + i += m_vByteCode.GetValSize(); + goto __start; + + // value tokens + case cmVAL: + Stack[idx] = *(value_type*)(&m_pCmdCode[i]); + i += m_vByteCode.GetValSize(); + goto __start; + + // Next is treatment of string functions + case cmFUNC_STR: + { + // The function argument count + int iArgCount = (int)m_pCmdCode[ i++ ]; + + // The index of the string argument in the string table + int iIdxStack = (int)m_pCmdCode[ i++ ]; + MUP_ASSERT( iIdxStack>=0 && iIdxStack<(int)m_vStringBuf.size() ); + + switch(iArgCount) // switch according to argument count + { + case 0: Stack[idx] = (*(strfun_type1*)(&m_pCmdCode[i]))(m_vStringBuf[iIdxStack].c_str()); break; + case 1: Stack[idx] = (*(strfun_type2*)(&m_pCmdCode[i]))(m_vStringBuf[iIdxStack].c_str(), Stack[idx]); break; + case 2: Stack[idx] = (*(strfun_type3*)(&m_pCmdCode[i]))(m_vStringBuf[iIdxStack].c_str(), Stack[idx], Stack[idx+1]); break; + } + i += m_vByteCode.GetPtrSize(); + } + goto __start; + + // Next is treatment of numeric functions + case cmFUNC: + { + int iArgCount = (int)m_pCmdCode[i++]; + + switch(iArgCount) // switch according to argument count + { + case 1: Stack[idx] = (*(fun_type1*)(&m_pCmdCode[i]))(Stack[idx]); break; + case 2: Stack[idx] = (*(fun_type2*)(&m_pCmdCode[i]))(Stack[idx], Stack[idx+1]); break; + case 3: Stack[idx] = (*(fun_type3*)(&m_pCmdCode[i]))(Stack[idx], Stack[idx+1], Stack[idx+2]); break; + case 4: Stack[idx] = (*(fun_type4*)(&m_pCmdCode[i]))(Stack[idx], Stack[idx+1], Stack[idx+2], Stack[idx+3]); break; + case 5: Stack[idx] = (*(fun_type5*)(&m_pCmdCode[i]))(Stack[idx], Stack[idx+1], Stack[idx+2], Stack[idx+3], Stack[idx+4]); break; + default: + if (iArgCount>0) // function with variable arguments store the number as a negative value + Error(ecINTERNAL_ERROR, 1); + + Stack[idx] =(*(multfun_type*)(&m_pCmdCode[i]))(&Stack[idx], -iArgCount); + break; + } + i += m_vByteCode.GetPtrSize(); + } + goto __start; + + case cmEND: + return Stack[1]; + + default: + Error(ecINTERNAL_ERROR, 2); + return 0; + } + +#if defined(_MSC_VER) + #pragma warning( default : 4312 ) +#endif +} + +//--------------------------------------------------------------------------- +/** \brief Return result for constant functions. + + Seems pointless, but for parser functions that are made up of only a value, which occur + in real world applications, this speeds up things by removing the parser overhead almost + completely. +*/ +value_type ParserBase::ParseValue() const +{ + return *(value_type*)(&m_pCmdCode[2]); +} + +//--------------------------------------------------------------------------- +/** \brief One of the two main parse functions. + + Parse expression from input string. Perform syntax checking and create bytecode. + After parsing the string and creating the bytecode the function pointer + #m_pParseFormula will be changed to the second parse routine the uses bytecode instead of string parsing. + + \sa ParseCmdCode(), ParseValue() +*/ +value_type ParserBase::ParseString() const +{ +#if defined(_MSC_VER) + #pragma warning( disable : 4311 ) +#endif + if (!m_pTokenReader->GetFormula().length()) + Error(ecUNEXPECTED_EOF, 0); + + ParserStack stOpt, stVal; + ParserStack stArgCount; + token_type opta, opt; // for storing operators + token_type val, tval; // for storing value + string_type strBuf; // buffer for string function arguments + + ReInit(); + + for(;;) + { + opt = m_pTokenReader->ReadNextToken(); + + switch (opt.GetCode()) + { + // + // Next three are different kind of value entries + // + case cmSTRING: + opt.SetIdx((int)m_vStringBuf.size()); // Assign buffer index to token + stVal.push(opt); + m_vStringBuf.push_back(opt.GetAsString()); // Store string in internal buffer + break; + + case cmVAR: + stVal.push(opt); + m_vByteCode.AddVar( static_cast(opt.GetVar()) ); + break; + + case cmVAL: + stVal.push(opt); + m_vByteCode.AddVal( opt.GetVal() ); + break; + + case cmCOMMA: + if (stArgCount.empty()) + Error(ecUNEXPECTED_COMMA, m_pTokenReader->GetPos()); + ++stArgCount.top(); // Record number of arguments + // fall through... + case cmEND: + case cmBC: + { + while ( stOpt.size() && stOpt.top().GetCode() != cmBO) + { + if (stOpt.top().GetCode()==cmOPRT_INFIX) + ApplyFunc(stOpt, stVal, 1); // infix operator + else + ApplyBinOprt(stOpt, stVal); + } + + // 20060218 infix operator treatment moved here + if (stOpt.size() && stOpt.top().GetCode()==cmOPRT_INFIX) + ApplyFunc(stOpt, stVal, 1); // infix operator + + if ( opt.GetCode()!=cmBC || stOpt.size()==0 || stOpt.top().GetCode()!=cmBO ) + break; + + // if opt is ")" and opta is "(" the bracket has been evaluated, now its time to check + // if there is either a function or a sign pending + // neither the opening nor the closing bracket will be pushed back to + // the operator stack + // Check if a function is standing in front of the opening bracket, + // if yes evaluate it afterwards check for infix operators + assert(stArgCount.size()); + int iArgCount = stArgCount.pop(); + + stOpt.pop(); // Take opening bracket from stack + + if (iArgCount>1 && ( stOpt.size()==0 || + (stOpt.top().GetCode()!=cmFUNC && + stOpt.top().GetCode()!=cmFUNC_STR) ) ) + Error(ecUNEXPECTED_ARG, m_pTokenReader->GetPos()); + + if (stOpt.size() && stOpt.top().GetCode()!=cmOPRT_INFIX) + ApplyFunc(stOpt, stVal, iArgCount); + } // if bracket content is evaluated + break; + + // + // Next are the binary operator entries + // + case cmAND: // built in binary operators + case cmOR: + case cmXOR: + case cmLT: + case cmGT: + case cmLE: + case cmGE: + case cmNEQ: + case cmEQ: + case cmADD: + case cmSUB: + case cmMUL: + case cmDIV: + case cmPOW: + case cmASSIGN: + case cmOPRT_BIN: + // A binary operator (user defined or built in) has been found. + while ( stOpt.size() && stOpt.top().GetCode() != cmBO) + { + if (GetOprtPri(stOpt.top()) < GetOprtPri(opt)) + break; + + if (stOpt.top().GetCode()==cmOPRT_INFIX) + ApplyFunc(stOpt, stVal, 1); // infix operator + else + ApplyBinOprt(stOpt, stVal); + } // while ( ... ) + + // The operator can't be evaluated right now, push back to the operator stack + stOpt.push(opt); + break; + + // + // Last section contains functions and operators implicitely mapped to functions + // + case cmBO: + stArgCount.push( (stOpt.size() && stOpt.top().GetCode()==cmFUNC_STR) ? 0 : 1 ); + stOpt.push(opt); + break; + + case cmFUNC_STR: + case cmFUNC: + case cmOPRT_INFIX: + stOpt.push(opt); + break; + + case cmOPRT_POSTFIX: + stOpt.push(opt); + ApplyFunc(stOpt, stVal, 1); // this is the postfix operator + break; + + default: Error(ecINTERNAL_ERROR, 3); + } // end of switch operator-token + + if ( opt.GetCode() == cmEND ) + { + m_vByteCode.Finalize(); + break; + } + +#if defined(MUP_DUMP_STACK) + StackDump(stVal, stOpt); + m_vByteCode.AsciiDump(); +#endif + } // while (true) + + // Store pointer to start of bytecode + m_pCmdCode = m_vByteCode.GetRawData(); + +#if defined(MUP_DUMP_CMDCODE) + m_vByteCode.AsciiDump(); +#endif + + // get the last value (= final result) from the stack + if (stVal.size()!=1) + Error(ecEMPTY_EXPRESSION); + + if (stVal.top().GetType()!=tpDBL) + Error(ecSTR_RESULT); + + // no error, so change the function pointer for the main parse routine + value_type fVal = stVal.top().GetVal(); // Result from String parsing + + if (m_bUseByteCode) + { + m_pParseFormula = (m_pCmdCode[1]==cmVAL && m_pCmdCode[6]==cmEND) ? + &ParserBase::ParseValue : + &ParserBase::ParseCmdCode; + } + + return fVal; + +#if defined(_MSC_VER) + #pragma warning( default : 4311 ) +#endif +} + + +//--------------------------------------------------------------------------- +/** \brief Create an error containing the parse error position. + + This function will create an Parser Exception object containing the error text and + its position. + + \param a_iErrc [in] The error code of type #EErrorCodes. + \param a_iPos [in] The position where the error was detected. + \param a_strTok [in] The token string representation associated with the error. + \throw ParserException always throws thats the only purpose of this function. +*/ +void ParserBase::Error(EErrorCodes a_iErrc, int a_iPos, const string_type &a_sTok) const +{ + throw exception_type(a_iErrc, a_sTok, m_pTokenReader->GetFormula(), a_iPos); +} + +//------------------------------------------------------------------------------ +/** \brief Clear all user defined variables. + + Resets the parser to string parsing mode by calling #ReInit. + \throw nothrow +*/ +void ParserBase::ClearVar() +{ + m_VarDef.clear(); + ReInit(); +} + +//------------------------------------------------------------------------------ +/** \brief Remove a variable from internal storage. + +Removes a variable if it exists. If the Variable does not exist nothing will be done. + +\throw nothrow +*/ +void ParserBase::RemoveVar(const string_type &a_strVarName) +{ + varmap_type::iterator item = m_VarDef.find(a_strVarName); + if (item!=m_VarDef.end()) + { + m_VarDef.erase(item); + ReInit(); + } +} + +//------------------------------------------------------------------------------ +/** \brief Clear the formula. + +Clear the formula and existing bytecode. + +\post Resets the parser to string parsing mode. +\throw nothrow +*/ +void ParserBase::ClearFormula() +{ + m_vByteCode.clear(); + m_pCmdCode = 0; + m_pTokenReader->SetFormula(_T("")); + ReInit(); +} + +//------------------------------------------------------------------------------ +/** \brief Clear all functions. + \post Resets the parser to string parsing mode. + \throw nothrow +*/ +void ParserBase::ClearFun() +{ + m_FunDef.clear(); + ReInit(); +} + +//------------------------------------------------------------------------------ +/** \brief Clear all user defined constants. + + Both numeric and string constants will be removed from the internal storage. + \post Resets the parser to string parsing mode. + \throw nothrow +*/ +void ParserBase::ClearConst() +{ + m_ConstDef.clear(); + m_StrVarDef.clear(); + ReInit(); +} + +//------------------------------------------------------------------------------ +/** \brief Clear all user defined postfix operators. + \post Resets the parser to string parsing mode. + \throw nothrow +*/ +void ParserBase::ClearPostfixOprt() +{ + m_PostOprtDef.clear(); + ReInit(); +} + +//------------------------------------------------------------------------------ +/** \brief Clear all user defined binary operators. + \post Resets the parser to string parsing mode. + \throw nothrow +*/ +void ParserBase::ClearOprt() +{ + m_OprtDef.clear(); + ReInit(); +} + +//------------------------------------------------------------------------------ +/** \brief Clear the user defined Prefix operators. + \post Resets the parser to string parser mode. + \throw nothrow +*/ +void ParserBase::ClearInfixOprt() +{ + m_InfixOprtDef.clear(); + ReInit(); +} + +//------------------------------------------------------------------------------ +/** \brief Enable or disable the formula optimization feature. + \post Resets the parser to string parser mode. + \throw nothrow +*/ +void ParserBase::EnableOptimizer(bool a_bIsOn) +{ + m_bOptimize = a_bIsOn; + ReInit(); +} + +//------------------------------------------------------------------------------ +/** \brief Enable or disable parsing from Bytecode. + + \attention There is no reason to disable bytecode. It will + drastically decrease parsing speed. +*/ +void ParserBase::EnableByteCode(bool a_bIsOn) +{ + m_bUseByteCode = a_bIsOn; + if (!a_bIsOn) + ReInit(); +} + +//------------------------------------------------------------------------------ +/** \brief Enable or disable the built in binary operators. + \throw nothrow + \sa m_bBuiltInOp, ReInit() + + If you disable the built in binary operators there will be no binary operators + defined. Thus you must add them manually one by one. It is not possible to + disable built in operators selectively. This function will Reinitialize the + parser by calling ReInit(). +*/ +void ParserBase::EnableBuiltInOprt(bool a_bIsOn) +{ + m_bBuiltInOp = a_bIsOn; + ReInit(); +} + +//------------------------------------------------------------------------------ +/** \brief Query status of built in variables. + \return #m_bBuiltInOp; true if built in operators are enabled. + \throw nothrow +*/ +bool ParserBase::HasBuiltInOprt() const +{ + return m_bBuiltInOp; +} + +#if defined(MUP_DUMP_STACK) | defined(MUP_DUMP_CMDCODE) + +//------------------------------------------------------------------------------ +/** \brief Dump stack content. + + This function is used for debugging only. +*/ +void ParserBase::StackDump( const ParserStack &a_stVal, + const ParserStack &a_stOprt ) const +{ + ParserStack stOprt(a_stOprt), + stVal(a_stVal); + + mu::console() << _T("\nValue stack:\n"); + while ( !stVal.empty() ) + { + token_type val = stVal.pop(); + if (val.GetType()==tpSTR) + mu::console() << _T(" \"") << val.GetAsString() << _T("\" "); + else + mu::console() << _T(" ") << val.GetVal() << _T(" "); + } + mu::console() << "\nOperator stack:\n"; + + while ( !stOprt.empty() ) + { + if (stOprt.top().GetCode()<=cmASSIGN) + { + mu::console() << _T("OPRT_INTRNL \"") + << ParserBase::c_DefaultOprt[stOprt.top().GetCode()] + << _T("\" \n"); + } + else + { + switch(stOprt.top().GetCode()) + { + case cmVAR: mu::console() << _T("VAR\n"); break; + case cmVAL: mu::console() << _T("VAL\n"); break; + case cmFUNC: mu::console() << _T("FUNC_NUM \"") + << stOprt.top().GetAsString() + << _T("\"\n"); break; + case cmOPRT_INFIX: mu::console() << _T("OPRT_INFIX \"") + << stOprt.top().GetAsString() + << _T("\"\n"); break; + case cmOPRT_BIN: mu::console() << _T("OPRT_BIN \"") + << stOprt.top().GetAsString() + << _T("\"\n"); break; + case cmFUNC_STR: mu::console() << _T("FUNC_STR\n"); break; + case cmEND: mu::console() << _T("END\n"); break; + case cmUNKNOWN: mu::console() << _T("UNKNOWN\n"); break; + case cmBO: mu::console() << _T("BRACKET \"(\"\n"); break; + case cmBC: mu::console() << _T("BRACKET \")\"\n"); break; + default: mu::console() << stOprt.top().GetType() << _T(" "); break; + } + } + stOprt.pop(); + } + + mu::console() << dec << endl; +} + +#endif // defined(MUP_DUMP_STACK) | defined(MUP_DUMP_CMDCODE) + +} // namespace mu + + diff --git a/muparser/muParserBase.h b/muparser/muParserBase.h new file mode 100644 index 0000000..c4cc433 --- /dev/null +++ b/muparser/muParserBase.h @@ -0,0 +1,324 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2006 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#ifndef MU_PARSER_BASE_H +#define MU_PARSER_BASE_H + +#include +#include +#include +#include +#include + +#include "muParserDef.h" +#include "muParserStack.h" +#include "muParserTokenReader.h" +#include "muParserBytecode.h" +#include "muParserError.h" + + +namespace mu +{ + +/** \brief Mathematical expressions parser (base parser engine). + + Version 1.27 (20061201) + + This is the implementation of a bytecode based mathematical expressions parser. + The formula will be parsed from string and converted into a bytecode. + Future calculations will be done with the bytecode instead the formula string + resulting in a significant performance increase. + Complementary to a set of internally implemented functions the parser is able to handle + user defined functions and variables. + + \author (C) 2004-2006 Ingo Berg +*/ +class ParserBase +{ +friend class ParserTokenReader; + +private: + typedef value_type (ParserBase::*ParseFunction)() const; + typedef ParserToken token_type; + typedef std::vector stringbuf_type; + typedef ParserTokenReader token_reader_type; + + static const char_type *c_DefaultOprt[]; + + public: + /** \brief Type of the error class. + + Included for backwards compatibility. + */ + typedef ParserError exception_type; + + ParserBase(); + ParserBase( const ParserBase &a_Parser ); + ParserBase& operator=(const ParserBase &a_Parser); + + //--------------------------------------------------------------------------- + /** \brief Destructor. (trivial) + + \throw nothrow + */ + virtual ~ParserBase() + {} + + //--------------------------------------------------------------------------- + /** \brief Calculate the result. + + A note on const correctness: + I consider it important that Calc is a const function. + Due to caching operations Calc changes only the state of internal variables with one exception + m_UsedVar this is reset during string parsing and accessible from the outside. Instead of making + Calc non const GetUsedVar is non const because it explicitely calls Eval() forcing this update. + + \pre A formula must be set. + \pre Variables must have been set (if needed) + + \sa #m_pParseFormula + \return The evaluation result + \throw ParseException if no Formula is set or in case of any other error related to the formula. + */ + inline value_type Eval() const + { + return (this->*m_pParseFormula)(); + } + + void SetExpr(const string_type &a_sExpr); + void SetVarFactory(facfun_type a_pFactory, void *pUserData = NULL); + + void EnableOptimizer(bool a_bIsOn=true); + void EnableByteCode(bool a_bIsOn=true); + void EnableBuiltInOprt(bool a_bIsOn=true); + + bool HasBuiltInOprt() const; + void AddValIdent(identfun_type a_pCallback); + +#define MUP_DEFINE_FUNC(TYPE) \ + inline void DefineFun(const string_type &a_strName, TYPE a_pFun, bool a_bAllowOpt = true) \ + { \ + AddCallback( a_strName, ParserCallback(a_pFun, a_bAllowOpt), \ + m_FunDef, ValidNameChars() ); \ + } + + MUP_DEFINE_FUNC(fun_type1) + MUP_DEFINE_FUNC(fun_type2) + MUP_DEFINE_FUNC(fun_type3) + MUP_DEFINE_FUNC(fun_type4) + MUP_DEFINE_FUNC(fun_type5) + MUP_DEFINE_FUNC(multfun_type) + MUP_DEFINE_FUNC(strfun_type1) + MUP_DEFINE_FUNC(strfun_type2) + MUP_DEFINE_FUNC(strfun_type3) +#undef MUP_DEFINE_FUNC + + void DefineOprt(const string_type &a_strName, fun_type2 a_pFun, unsigned a_iPri=0, bool a_bAllowOpt = false); + void DefineConst(const string_type &a_sName, value_type a_fVal); + void DefineStrConst(const string_type &a_sName, const string_type &a_strVal); + void DefineVar(const string_type &a_sName, value_type *a_fVar); + void DefinePostfixOprt(const string_type &a_strFun, fun_type1 a_pOprt, bool a_bAllowOpt=true); + void DefineInfixOprt(const string_type &a_strName, fun_type1 a_pOprt, int a_iPrec=prINFIX, bool a_bAllowOpt=true); + + // Clear user defined variables, constants or functions + void ClearVar(); + void ClearFun(); + void ClearConst(); + void ClearInfixOprt(); + void ClearPostfixOprt(); + void ClearOprt(); + + void RemoveVar(const string_type &a_strVarName); + const varmap_type& GetUsedVar() const; + const varmap_type& GetVar() const; + const valmap_type& GetConst() const; + const string_type& GetExpr() const; + const funmap_type& GetFunDef() const; + + //--------------------------------------------------------------------------- + /** \brief Return the strings of all Operator identifiers. + + GetOprt is a const function returning a pinter to an array of const char pointers. + + \return Returns a pointer to the c_DefaultOprt array of const char *. + \throw nothrow + */ + const char_type ** GetOprtDef() const + { + return (const char_type **)(&c_DefaultOprt[0]); + } + + //--------------------------------------------------------------------------- + /** \brief Define the set of valid characters to be used in names of + functions, variables, constants. + */ + void DefineNameChars(const char_type *a_szCharset) + { + m_sNameChars = a_szCharset; + } + + //--------------------------------------------------------------------------- + /** \brief Define the set of valid characters to be used in names of + binary operators and postfix operators. + */ + void DefineOprtChars(const char_type *a_szCharset) + { + m_sOprtChars = a_szCharset; + } + + //--------------------------------------------------------------------------- + /** \brief Define the set of valid characters to be used in names of + infix operators. + */ + void DefineInfixOprtChars(const char_type *a_szCharset) + { + m_sInfixOprtChars = a_szCharset; + } + + //--------------------------------------------------------------------------- + /** \brief Virtual function that defines the characters allowed in name identifiers. + \sa #ValidOprtChars, #ValidPrefixOprtChars + */ + const char_type* ValidNameChars() const + { + assert(m_sNameChars.size()); + return m_sNameChars.c_str(); + } + + //--------------------------------------------------------------------------- + /** \brief Virtual function that defines the characters allowed in operator definitions. + \sa #ValidNameChars, #ValidPrefixOprtChars + */ + const char_type* ValidOprtChars() const + { + assert(m_sOprtChars.size()); + return m_sOprtChars.c_str(); + } + + //--------------------------------------------------------------------------- + /** \brief Virtual function that defines the characters allowed in infix operator definitions. + \sa #ValidNameChars, #ValidOprtChars + */ + const char_type* ValidInfixOprtChars() const + { + assert(m_sInfixOprtChars.size()); + return m_sInfixOprtChars.c_str(); + } + + void Error( EErrorCodes a_iErrc, + int a_iPos = (int)mu::string_type::npos, + const string_type &a_strTok = string_type() ) const; + + protected: + + //--------------------------------------------------------------------------- + /** \brief Initialize user defined functions. + + Calls the virtual functions InitFun(), InitConst() and InitOprt(). + */ + void Init() + { + InitCharSets(); + InitFun(); + InitConst(); + InitOprt(); + } + + //--------------------------------------------------------------------------- + virtual void InitCharSets() = 0; + virtual void InitFun() = 0; + virtual void InitConst() = 0; + virtual void InitOprt() = 0; + + private: + void Assign(const ParserBase &a_Parser); + void InitTokenReader(); + void ReInit() const; + + void AddCallback( const string_type &a_strName, + const ParserCallback &a_Callback, + funmap_type &a_Storage, + const char_type *a_szCharSet ); + + void ApplyBinOprt(ParserStack &a_stOpt, + ParserStack &a_stVal) const; + + void ApplyFunc(ParserStack &a_stOpt, + ParserStack &a_stVal, + int iArgCount) const; + + token_type ApplyNumFunc(const token_type &a_FunTok, + const std::vector &a_vArg) const; + + token_type ApplyStrFunc(const token_type &a_FunTok, + const std::vector &a_vArg) const; + + int GetOprtPri(const token_type &a_Tok) const; + + value_type ParseString() const; + value_type ParseCmdCode() const; + value_type ParseValue() const; + + void ClearFormula(); + void CheckName(const string_type &a_strName, const string_type &a_CharSet) const; + +#if defined(MUP_DUMP_STACK) | defined(MUP_DUMP_CMDCODE) + void StackDump(const ParserStack &a_stVal, + const ParserStack &a_stOprt) const; +#endif + + /** \brief Pointer to the parser function. + + Eval() calls the function whose address is stored there. + */ + mutable ParseFunction m_pParseFormula; + mutable const ParserByteCode::map_type *m_pCmdCode; ///< Formula converted to bytecode, points to the data of the bytecode class. + mutable ParserByteCode m_vByteCode; ///< The Bytecode class. + mutable stringbuf_type m_vStringBuf; ///< String buffer, used for storing string function arguments + stringbuf_type m_vStringVarBuf; + + /** \brief Managed pointer to the token reader object. */ + std::auto_ptr m_pTokenReader; + + funmap_type m_FunDef; ///< Map of function names and pointers. + funmap_type m_PostOprtDef; ///< Postfix operator callbacks + funmap_type m_InfixOprtDef; ///< unary infix operator. + funmap_type m_OprtDef; ///< Binary operator callbacks + valmap_type m_ConstDef; ///< user constants. + strmap_type m_StrVarDef; ///< user defined string constants + varmap_type m_VarDef; ///< user defind variables. + + bool m_bOptimize; ///< Flag that indicates if the optimizer is on or off. + bool m_bUseByteCode; ///< Flag that indicates if bytecode parsing is on or off. + bool m_bBuiltInOp; ///< Flag that can be used for switching built in operators on and off + + string_type m_sNameChars; ///< Charset for names + string_type m_sOprtChars; ///< Charset for postfix/ binary operator tokens + string_type m_sInfixOprtChars; ///< Charset for infix operator tokens +}; + +} // namespace mu + +#endif + diff --git a/muparser/muParserBytecode.cpp b/muparser/muParserBytecode.cpp new file mode 100644 index 0000000..7c8db24 --- /dev/null +++ b/muparser/muParserBytecode.cpp @@ -0,0 +1,396 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2006 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "muParserBytecode.h" + +#include +#include +#include +#include +#include + +#include "muParserDef.h" +#include "muParserError.h" +#include "muParserToken.h" + + +namespace mu +{ + + //--------------------------------------------------------------------------- + /** \brief Bytecode default constructor. + + \pre [assert] sizeof(value_type)>=sizeof(map_type) + \pre [assert] sizeof(value_type*)>=sizeof(map_type) + */ + ParserByteCode::ParserByteCode() + :m_iStackPos(0) + ,m_vBase() + ,mc_iSizeVal( sizeof(value_type) / sizeof(map_type) ) + ,mc_iSizePtr( std::max( (int)sizeof(value_type*) / + (int)sizeof(map_type), 1 ) ) + ,mc_iSizeValEntry( 2 + mc_iSizeVal) + { + m_vBase.reserve(1000); + assert( sizeof(value_type)>=sizeof(map_type) ); + } + + //--------------------------------------------------------------------------- + /** \brief Destructor (trivial).*/ + ParserByteCode::~ParserByteCode() + {} + + //--------------------------------------------------------------------------- + /** \brief Copy constructor. + + Implemented in Terms of Assign(const ParserByteCode &a_ByteCode) + */ + ParserByteCode::ParserByteCode(const ParserByteCode &a_ByteCode) + :mc_iSizeVal( sizeof(value_type)/sizeof(map_type) ) + ,mc_iSizePtr( sizeof(value_type*) / sizeof(map_type) ) + ,mc_iSizeValEntry( 2 + mc_iSizeVal) + { + Assign(a_ByteCode); + } + + //--------------------------------------------------------------------------- + /** \brief Assignment operator. + + Implemented in Terms of Assign(const ParserByteCode &a_ByteCode) + */ + ParserByteCode& ParserByteCode::operator=(const ParserByteCode &a_ByteCode) + { + Assign(a_ByteCode); + return *this; + } + + //--------------------------------------------------------------------------- + /** \brief Store an address in bytecode. + + \param a_pAddr Address to be stored. + \throw nothrow + */ + void ParserByteCode::StorePtr(void *a_pAddr) + { + #if defined(_MSC_VER) + #pragma warning( disable : 4311 ) + #endif + + // demo code for packing / unpacking pointers into bytecode +// void *ptr(NULL); +// double **pVal; +// double fVal; +// map_type dbg[2]; +// dbg[0] = *( reinterpret_cast(&a_pAddr) ), +// dbg[1] = *( reinterpret_cast(&a_pAddr) + 1 ); +// Version 1: +// *( (map_type*)&ptr+0) = dbg[0]; +// *( (map_type*)&ptr+1) = dbg[1]; +// Version 2: +// memcpy(&ptr, dbg, sizeof(dbg)); +// Version 3: +// pVal = (double**)dbg; +// fVal = **(double**)dbg; + + for (int i=0; i(&a_pAddr) + i ) ); + } + + #if defined(_MSC_VER) + #pragma warning( default : 4311 ) + #endif + } + + //--------------------------------------------------------------------------- + /** \brief Copy state of another object to this. + + \throw nowthrow + */ + void ParserByteCode::Assign(const ParserByteCode &a_ByteCode) + { + if (this==&a_ByteCode) + return; + + m_iStackPos = a_ByteCode.m_iStackPos; + m_vBase = a_ByteCode.m_vBase; + } + + //--------------------------------------------------------------------------- + /** \brief Add a Variable pointer to bytecode. + \param a_pVar Pointer to be added. + \throw nothrow + */ + void ParserByteCode::AddVar(value_type *a_pVar) + { + m_vBase.push_back( ++m_iStackPos ); + m_vBase.push_back( cmVAR ); + + StorePtr(a_pVar); + + int iSize = GetValSize()-GetPtrSize(); + assert(iSize>=0); + + // Make sure variable entries have the same size like value entries. + // (necessary for optimization; fill with zeros) + for (int i=0; i +
  • value array position of the value
  • +
  • the operator code according to ParserToken::cmVAL
  • +
  • the value stored in #mc_iSizeVal number of bytecode entries.
  • + + + \param a_pVal Value to be added. + \throw nothrow + */ + void ParserByteCode::AddVal(value_type a_fVal) + { + m_vBase.push_back( ++m_iStackPos ); + m_vBase.push_back( cmVAL ); + + for (int i=0; i(&a_fVal) + i) ); + } + + //--------------------------------------------------------------------------- + /** \brief Add an operator identifier to bytecode. + + Operator entries in byte code consist of: +
      +
    • value array position of the result
    • +
    • the operator code according to ParserToken::ECmdCode
    • +
    + + \sa ParserToken::ECmdCode + */ + void ParserByteCode::AddOp(ECmdCode a_Oprt) + { + m_vBase.push_back(--m_iStackPos); + m_vBase.push_back(a_Oprt); + } + + //--------------------------------------------------------------------------- + /** \brief Add an assignement operator + + Operator entries in byte code consist of: +
      +
    • cmASSIGN code
    • +
    • the pointer of the destination variable
    • +
    + + \sa ParserToken::ECmdCode + */ + void ParserByteCode::AddAssignOp(value_type *a_pVar) + { + m_vBase.push_back(--m_iStackPos); + m_vBase.push_back(cmASSIGN); + StorePtr(a_pVar); + } + + //--------------------------------------------------------------------------- + /** \brief Add function to bytecode. + + \param a_iArgc Number of arguments, negative numbers indicate multiarg functions. + \param a_pFun Pointer to function callback. + */ + void ParserByteCode::AddFun(void *a_pFun, int a_iArgc) + { + if (a_iArgc>=0) + { + m_iStackPos = m_iStackPos - a_iArgc + 1; + } + else + { + m_iStackPos = m_iStackPos + a_iArgc + 1; + } + + m_vBase.push_back(m_iStackPos); + m_vBase.push_back(cmFUNC); + m_vBase.push_back(a_iArgc); + + StorePtr(a_pFun); + } + + //--------------------------------------------------------------------------- + /** \brief Add Strung function entry to the parser bytecode. + \throw nothrow + + A string function entry consists of the stack position of the return value, + followed by a cmSTRFUNC code, the function pointer and an index into the + string buffer maintained by the parser. + */ + void ParserByteCode::AddStrFun(void *a_pFun, int a_iArgc, int a_iIdx) + { + m_iStackPos = m_iStackPos - a_iArgc + 1; + m_vBase.push_back(m_iStackPos); + m_vBase.push_back(cmFUNC_STR); + m_vBase.push_back(a_iArgc); + m_vBase.push_back(a_iIdx); + + StorePtr(a_pFun); + } + + //--------------------------------------------------------------------------- + /** \brief Add end marker to bytecode. + + \throw nothrow + */ + void ParserByteCode::Finalize() + { + // yes we need the end code three times!! (I forgot why) + m_vBase.push_back(cmEND); + m_vBase.push_back(cmEND); + m_vBase.push_back(cmEND); + + // shrink bytecode vector to fit + storage_type(m_vBase).swap(m_vBase); + } + + //--------------------------------------------------------------------------- + /** \brief Get Pointer to bytecode data storage. */ + const ParserByteCode::map_type* ParserByteCode::GetRawData() const + { + assert(m_vBase.size()); + return &m_vBase[0]; + } + + //--------------------------------------------------------------------------- + /** \brief Delete the bytecode. + + \throw nothrow + + The name of this function is a violation of my own coding guidelines + but this way it's more in line with the STL functions thus more + intuitive. + */ + void ParserByteCode::clear() + { + m_vBase.clear(); + m_iStackPos = 0; + } + + //--------------------------------------------------------------------------- + /** \brief Remove a value number of entries from the bytecode. + + \attention Currently I don't test if the entries are really value entries. + */ + void ParserByteCode::RemoveValEntries(unsigned a_iNumber) + { + unsigned iSize = a_iNumber * mc_iSizeValEntry; + assert( m_vBase.size() >= iSize ); + m_vBase.resize(m_vBase.size()-iSize); + + assert(m_iStackPos >= a_iNumber); + m_iStackPos -= (a_iNumber); + } + + //--------------------------------------------------------------------------- + /** \brief Dump bytecode (for debugging only!). */ + void ParserByteCode::AsciiDump() + { + if (!m_vBase.size()) + { + std::cout << "No bytecode available\n"; + return; + } + + std::cout << "Entries:" << (int)m_vBase.size() + << " (ValSize:" << mc_iSizeVal + << " entries, PtrSize:" << mc_iSizePtr + << " entries, MapSize:" << sizeof(map_type) + << " byte)\n"; + int i = 0; + + while ( m_vBase[i] != cmEND && i<(int)m_vBase.size()) + { + std::cout << "IDX[" << m_vBase[i++] << "]\t"; + switch (m_vBase[i]) + { + case cmVAL: std::cout << "VAL "; ++i; + std::cout << "[" << *( reinterpret_cast(&m_vBase[i]) ) << "]\n"; + i += mc_iSizeVal; + break; + + case cmVAR: std::cout << "VAR "; ++i; + std::cout << "[ADDR: 0x" << std::hex << *(value_type**)&m_vBase[i] << "]\n"; + i += mc_iSizePtr; + + // Variable entries have the same size like value entries + // the remaining spave must be skipped + i+= std::max(mc_iSizeVal - mc_iSizePtr, 0); + break; + + case cmFUNC: + std::cout << "CALL\t"; ++i; + std::cout << "[ARG:" << std::dec << m_vBase[i] << "]"; ++i; + std::cout << "[ADDR: 0x" << std::hex << *(value_type**)&m_vBase[i] << "]\n"; + i += mc_iSizePtr; + break; + + case cmFUNC_STR: + std::cout << "CALL STRFUNC\t"; ++i; + std::cout << "[ARG:" << std::dec << m_vBase[i] << "]"; ++i; + std::cout << "[IDX:" << std::dec << m_vBase[i] << "]"; ++i; + std::cout << "[ADDR: 0x" << *(value_type**)&m_vBase[i] << "]\n"; + i += mc_iSizePtr; + break; + + case cmLT: std::cout << "LT\n"; ++i; break; + case cmGT: std::cout << "GT\n"; ++i; break; + case cmLE: std::cout << "LE\n"; ++i; break; + case cmGE: std::cout << "GE\n"; ++i; break; + case cmEQ: std::cout << "EQ\n"; ++i; break; + case cmNEQ: std::cout << "NEQ\n"; ++i; break; + case cmADD: std::cout << "ADD\n"; ++i; break; + case cmAND: std::cout << "AND\n"; ++i; break; + case cmOR: std::cout << "OR\n"; ++i; break; + case cmXOR: std::cout << "XOR\n"; ++i; break; + case cmSUB: std::cout << "SUB\n"; ++i; break; + case cmMUL: std::cout << "MUL\n"; ++i; break; + case cmDIV: std::cout << "DIV\n"; ++i; break; + case cmPOW: std::cout << "POW\n"; ++i; break; + + case cmASSIGN: + std::cout << "ASSIGN\t"; ++i; + std::cout << "[ADDR: 0x" << *(value_type**)&m_vBase[i] << "]\n"; + i += mc_iSizePtr; + break; + + default: std::cout << "(unknown code: " << m_vBase[i] << ")\n"; + ++i; + break; + } // switch cmdCode + } // while bytecode + + std::cout << "END" << std::endl; + } +} // namespace mu diff --git a/muparser/muParserBytecode.h b/muparser/muParserBytecode.h new file mode 100644 index 0000000..d425990 --- /dev/null +++ b/muparser/muParserBytecode.h @@ -0,0 +1,148 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2006 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#ifndef MU_PARSER_BYTECODE_H +#define MU_PARSER_BYTECODE_H + +#include +#include +#include +#include + +#include "muParserDef.h" +#include "muParserError.h" +#include "muParserToken.h" + + +namespace mu +{ + + +/** \brief Bytecode implementation of the Math Parser. + + The bytecode contains the formula converted to revers polish notation stored in a continious + memory area. Associated with this data are operator codes, variable pointers, constant + values and function pointers. Those are necessary in order to calculate the result. + All those data items will be casted to the underlying datatype of the bytecode. + + \author (C) 2004, 2005 Ingo Berg +*/ +class ParserByteCode +{ +public: + /** \brief Underlying type of the container. + + The bytecode is a vector of this type containing control codes, + values and pointers. Values and pointer will be casted to this + type before their storage. + */ + typedef bytecode_type map_type; + +private: + + /** \brief Token type for internal use only. */ + typedef ParserToken token_type; + + /** \brief Core type of the bytecode. */ + typedef std::vector storage_type; + + /** \brief Position in the Calculation array. */ + unsigned m_iStackPos; + + /** \brief Core type of the bytecode. */ + storage_type m_vBase; + + /** \brief Size of a value entry in the bytecode, relative to TMapType size. */ + const int mc_iSizeVal; + + /** \brief Size of a pointer, relative to size of underlying TMapType. + + \attention The size is related to the size of TMapType not bytes! + */ + const int mc_iSizePtr; + + /** \brief A value entry requires that much entires in the bytecode. + + Value entry consists of: +
      +
    • One entry for Stack index
    • +
    • One entry for Token identifier
    • +
    • mc_iSizeVal entries for the value
    • +
        + + \sa AddVal(TBaseData a_fVal) + */ + const int mc_iSizeValEntry; + + void StorePtr(void *a_pAddr); + +public: + ParserByteCode(); + ~ParserByteCode(); + ParserByteCode(const ParserByteCode &a_ByteCode); + ParserByteCode& operator=(const ParserByteCode &a_ByteCode); + void Assign(const ParserByteCode &a_ByteCode); + + void AddVar(value_type *a_pVar); + void AddVal(value_type a_fVal); + void AddOp(ECmdCode a_Oprt); + void AddAssignOp(value_type *a_pVar); + void AddFun(void *a_pFun, int a_iArgc); + void AddStrFun(void *a_pFun, int a_iArgc, int a_iIdx); + + void Finalize(); + void clear(); + const map_type* GetRawData() const; + + /** \brief Return size of a value entry. + + That many bytecode entries are necessary to store a value. + + \sa mc_iSizeVal + */ + unsigned GetValSize() const + { + return mc_iSizeVal; + } + + /** \brief Return size of a pointer entry. + + That many bytecode entries are necessary to store a pointer. + + \sa mc_iSizePtr + */ + unsigned GetPtrSize() const + { + return mc_iSizePtr; + } + + void RemoveValEntries(unsigned a_iNumber); + void AsciiDump(); +}; + +} // namespace mu + +#endif + + diff --git a/muparser/muParserCallback.cpp b/muparser/muParserCallback.cpp new file mode 100644 index 0000000..1312ad7 --- /dev/null +++ b/muparser/muParserCallback.cpp @@ -0,0 +1,198 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2006 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "muParserCallback.h" + + +namespace mu +{ + + ParserCallback::ParserCallback(fun_type1 a_pFun, bool a_bAllowOpti, int a_iPrec, ECmdCode a_iCode) + :m_pFun((void*)a_pFun) + ,m_iArgc(1) + ,m_iPri(a_iPrec) + ,m_iCode(a_iCode) + ,m_iType(tpDBL) + ,m_bAllowOpti(a_bAllowOpti) + {} + + + ParserCallback::ParserCallback( fun_type2 a_pFun, bool a_bAllowOpti, int a_iPrec, ECmdCode a_iCode) + :m_pFun((void*)a_pFun) + ,m_iArgc(2) + ,m_iPri(a_iPrec) + ,m_iCode(a_iCode) + ,m_iType(tpDBL) + ,m_bAllowOpti(a_bAllowOpti) + {} + + + ParserCallback::ParserCallback(fun_type3 a_pFun, bool a_bAllowOpti) + :m_pFun((void*)a_pFun) + ,m_iArgc(3) + ,m_iPri(-1) + ,m_iCode(cmFUNC) + ,m_iType(tpDBL) + ,m_bAllowOpti(a_bAllowOpti) + {} + + + ParserCallback::ParserCallback(fun_type4 a_pFun, bool a_bAllowOpti) + :m_pFun((void*)a_pFun) + ,m_iArgc(4) + ,m_iPri(-1) + ,m_iCode(cmFUNC) + ,m_iType(tpDBL) + ,m_bAllowOpti(a_bAllowOpti) + {} + + ParserCallback::ParserCallback(fun_type5 a_pFun, bool a_bAllowOpti) + :m_pFun((void*)a_pFun) + ,m_iArgc(5) + ,m_iPri(-1) + ,m_iCode(cmFUNC) + ,m_iType(tpDBL) + ,m_bAllowOpti(a_bAllowOpti) + {} + + ParserCallback::ParserCallback(multfun_type a_pFun, bool a_bAllowOpti) + :m_pFun((void*)a_pFun) + ,m_iArgc(-1) + ,m_iPri(-1) + ,m_iCode(cmFUNC) + ,m_iType(tpDBL) + ,m_bAllowOpti(a_bAllowOpti) + {} + + ParserCallback::ParserCallback(strfun_type1 a_pFun, bool a_bAllowOpti) + :m_pFun((void*)a_pFun) + ,m_iArgc(0) + ,m_iPri(-1) + ,m_iCode(cmFUNC_STR) + ,m_iType(tpSTR) + ,m_bAllowOpti(a_bAllowOpti) + {} + + ParserCallback::ParserCallback(strfun_type2 a_pFun, bool a_bAllowOpti) + :m_pFun((void*)a_pFun) + ,m_iArgc(1) + ,m_iPri(-1) + ,m_iCode(cmFUNC_STR) + ,m_iType(tpSTR) + ,m_bAllowOpti(a_bAllowOpti) + {} + + ParserCallback::ParserCallback(strfun_type3 a_pFun, bool a_bAllowOpti) + :m_pFun((void*)a_pFun) + ,m_iArgc(2) + ,m_iPri(-1) + ,m_iCode(cmFUNC_STR) + ,m_iType(tpSTR) + ,m_bAllowOpti(a_bAllowOpti) + {} + + /** \brief Default constructor. + + \throw nothrow + */ + ParserCallback::ParserCallback() + :m_pFun(0) + ,m_iArgc(0) + ,m_iCode(cmUNKNOWN) + ,m_iType(tpVOID) + ,m_bAllowOpti(0) + {} + + /** \brief Copy constructor. + + \throw nothrow + */ + ParserCallback::ParserCallback(const ParserCallback &a_Fun) + { + m_pFun = a_Fun.m_pFun; + m_iArgc = a_Fun.m_iArgc; + m_bAllowOpti = a_Fun.m_bAllowOpti; + m_iCode = a_Fun.m_iCode; + m_iType = a_Fun.m_iType; + m_iPri = a_Fun.m_iPri; + } + + /** \brief Clone this instance and return a pointer to the new instance. */ + ParserCallback* ParserCallback::Clone() const + { + return new ParserCallback(*this); + } + + + /** \brief Return tru if the function is conservative. + + Conservative functions return always the same result for the same argument. + \throw nothrow + */ + bool ParserCallback::IsOptimizable() const + { + return m_bAllowOpti; + } + + /** \brief Get the callback address for the parser function. + + The type of the address is void. It needs to be recasted according to the + argument number to the right type. + + \throw nothrow + \return #pFun + */ + void* ParserCallback::GetAddr() const + { + return m_pFun; + } + + /** \brief Return the callback code. */ + ECmdCode ParserCallback::GetCode() const + { + return m_iCode; + } + + + ETypeCode ParserCallback::GetType() const + { + return m_iType; + } + + /** \brief Return the operator priority. + + Only valid if the callback token is an operator token (binary or infix). + */ + int ParserCallback::GetPri() const + { + return m_iPri; + } + + /** \brief Returns the number of function Arguments. */ + int ParserCallback::GetArgc() const + { + return m_iArgc; + } +} // namespace mu diff --git a/muparser/muParserCallback.h b/muparser/muParserCallback.h new file mode 100644 index 0000000..9fecddb --- /dev/null +++ b/muparser/muParserCallback.h @@ -0,0 +1,94 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2006 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef MU_PARSER_CALLBACK_H +#define MU_PARSER_CALLBACK_H + +#include "muParserDef.h" + + +namespace mu +{ + +/** \brief Encapsulation of prototypes for a numerical parser function. + + Encapsulates the prototyp for numerical parser functions. The class + stores the number of arguments for parser functions as well + as additional flags indication the function is non optimizeable. + The pointer to the callback function pointer is stored as void* + and needs to be casted according to the argument count. + Negative argument counts indicate a parser function with a variable number + of arguments. + This class is not used for string function prototyping. + + \author (C) 2004-2006 Ingo Berg +*/ +class ParserCallback +{ +public: + ParserCallback(fun_type1 a_pFun, bool a_bAllowOpti, int a_iPrec = -1, ECmdCode a_iCode=cmFUNC); + ParserCallback(fun_type2 a_pFun, bool a_bAllowOpti, int a_iPrec = -1, ECmdCode a_iCode=cmFUNC); + ParserCallback(fun_type3 a_pFun, bool a_bAllowOpti); + ParserCallback(fun_type4 a_pFun, bool a_bAllowOpti); + ParserCallback(fun_type5 a_pFun, bool a_bAllowOpti); + ParserCallback(multfun_type a_pFun, bool a_bAllowOpti); + ParserCallback(strfun_type1 a_pFun, bool a_bAllowOpti); + ParserCallback(strfun_type2 a_pFun, bool a_bAllowOpti); + ParserCallback(strfun_type3 a_pFun, bool a_bAllowOpti); + ParserCallback(); + ParserCallback(const ParserCallback &a_Fun); + + ParserCallback* Clone() const; + + bool IsOptimizable() const; + void* GetAddr() const; + ECmdCode GetCode() const; + ETypeCode GetType() const; + int GetPri() const; + int GetArgc() const; + +private: + void *m_pFun; ///< Pointer to the callback function, casted to void + + /** \brief Number of numeric function arguments + + This number is negative for functions with variable number of arguments. in this cases + they represent the actual number of arguments found. + */ + int m_iArgc; + int m_iPri; ///< Valid only for binary and infix operators; Operator precedence. + ECmdCode m_iCode; + ETypeCode m_iType; + bool m_bAllowOpti; ///< Flag indication optimizeability +}; + +//------------------------------------------------------------------------------ +/** \brief Container for Callback objects. */ +typedef std::map funmap_type; + +} // namespace mu + +#endif + diff --git a/muparser/muParserDLL.cpp b/muparser/muParserDLL.cpp new file mode 100644 index 0000000..0f85cb7 --- /dev/null +++ b/muparser/muParserDLL.cpp @@ -0,0 +1,657 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2006 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + + +#if defined(MUPARSER_DLL) && defined(_WIN32) + +#include "muParserDLL.h" +#include "muParser.h" +#include "muParserError.h" + + +#define MU_PARSER_TRY \ + try \ + { + +#define MU_PARSER_CATCH \ + } \ + catch(exception_type &e) \ + { \ + g_bError = true; \ + g_ParserError = e; \ + if (g_pErrHandler) \ + g_pErrHandler(); \ + } \ + catch(...) \ + { \ + g_bError = true; \ + g_ParserError = exception_type(mu::ecINTERNAL_ERROR); \ + if (g_pErrHandler) \ + g_pErrHandler(); \ + } + +//--------------------------------------------------------------------------- +typedef mu::ParserBase::exception_type exception_type; +typedef mu::ParserBase* parser_type; + +#if !defined(_UNICODE) + typedef std::string string_type; +#else + typedef std::wstring string_type; +#endif + +typedef string_type::value_type char_type; + +//--------------------------------------------------------------------------- +// +// +// unexported variables +// +// +//--------------------------------------------------------------------------- + +/** \brief The last exception that was caught. +*/ +exception_type g_ParserError; +errhandler_type g_pErrHandler; + +//--------------------------------------------------------------------------- +/** \brief Flags indicating an error occured. +*/ +bool g_bError; + +//--------------------------------------------------------------------------- +// +// +// unexported functions +// +// +//--------------------------------------------------------------------------- + +parser_type GetPtr(parser_handle a_hParser) +{ + return static_cast(a_hParser); +} + +//--------------------------------------------------------------------------- +/** \brief DLL entry point. +*/ +BOOL APIENTRY DllMain( HANDLE /*hModule*/, DWORD ul_reason_for_call, LPVOID /*lpReserved*/ ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + g_pErrHandler = 0; + g_bError = false; + break; + + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + + return TRUE; +} + +//--------------------------------------------------------------------------- +// +// +// exported functions +// +// +//--------------------------------------------------------------------------- + +MU_PARSER_API void mupSetErrorHandler(errhandler_type a_pHandler) +{ + g_pErrHandler = a_pHandler; +} + +//--------------------------------------------------------------------------- +MU_PARSER_API void mupSetVarFactory(parser_handle a_hParser, facfun_type a_pFactory, void *pUserData) +{ + parser_type p(GetPtr(a_hParser)); + p->SetVarFactory(a_pFactory, pUserData); +} + +//--------------------------------------------------------------------------- +/** \brief Create a new Parser instance and return its handle. +*/ +MU_PARSER_API parser_handle mupInit() +{ + return (void*)(new mu::Parser()); +} + +//--------------------------------------------------------------------------- +/** \brief Release the parser instance related with a parser handle. +*/ +MU_PARSER_API void mupRelease(parser_handle a_hParser) +{ + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + delete p; + MU_PARSER_CATCH +} + +//--------------------------------------------------------------------------- +/** \brief Evaluate the expression. +*/ +MU_PARSER_API double mupEval(parser_handle a_hParser) +{ + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + return p->Eval(); + MU_PARSER_CATCH + + return 0; +} + +//--------------------------------------------------------------------------- +MU_PARSER_API void mupSetExpr(parser_handle a_hParser, const char *a_szExpr) +{ + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + p->SetExpr(a_szExpr); + MU_PARSER_CATCH +} + +//--------------------------------------------------------------------------- +MU_PARSER_API void mupRemoveVar(parser_handle a_hParser, const char *a_szName) +{ + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + p->RemoveVar( string_type(a_szName) ); + MU_PARSER_CATCH +} + +//--------------------------------------------------------------------------- +/** \brief Release all parser variables. + \param a_hParser Handle to the parser instance. +*/ +MU_PARSER_API void mupClearVar(parser_handle a_hParser) +{ + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + p->ClearVar(); + MU_PARSER_CATCH +} + +//--------------------------------------------------------------------------- +/** \brief Release all parser variables. + \param a_hParser Handle to the parser instance. +*/ +MU_PARSER_API void mupClearConst(parser_handle a_hParser) +{ + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + p->ClearConst(); + MU_PARSER_CATCH +} + +//--------------------------------------------------------------------------- +/** \brief Clear all user defined operators. + \param a_hParser Handle to the parser instance. +*/ +MU_PARSER_API void mupClearOprt(parser_handle a_hParser) +{ + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + p->ClearOprt(); + MU_PARSER_CATCH +} + +//--------------------------------------------------------------------------- +MU_PARSER_API void mupDefineFun1(parser_handle a_hParser, const char *a_szName, fun_type1 a_pFun, bool a_bAllowOpt) +{ + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + p->DefineFun(a_szName, a_pFun, a_bAllowOpt); + MU_PARSER_CATCH +} + +//--------------------------------------------------------------------------- +MU_PARSER_API void mupDefineFun2(parser_handle a_hParser, const char *a_szName, fun_type2 a_pFun, bool a_bAllowOpt) +{ + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + p->DefineFun(a_szName, a_pFun, a_bAllowOpt); + MU_PARSER_CATCH +} + +//--------------------------------------------------------------------------- +MU_PARSER_API void mupDefineFun3(parser_handle a_hParser, const char *a_szName, fun_type3 a_pFun, bool a_bAllowOpt) +{ + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + p->DefineFun(a_szName, a_pFun, a_bAllowOpt); + MU_PARSER_CATCH +} + +//--------------------------------------------------------------------------- +MU_PARSER_API void mupDefineFun4(parser_handle a_hParser, const char *a_szName, fun_type4 a_pFun, bool a_bAllowOpt) +{ + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + p->DefineFun(a_szName, a_pFun, a_bAllowOpt); + MU_PARSER_CATCH +} + +//--------------------------------------------------------------------------- +MU_PARSER_API void mupDefineFun5(parser_handle a_hParser, const char *a_szName, fun_type5 a_pFun, bool a_bAllowOpt) +{ + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + p->DefineFun(a_szName, a_pFun, a_bAllowOpt); + MU_PARSER_CATCH +} + +//--------------------------------------------------------------------------- +MU_PARSER_API void mupDefineStrFun1(parser_handle a_hParser, const char *a_szName, strfun_type1 a_pFun, bool a_bAllowOpt) +{ + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + p->DefineFun(a_szName, a_pFun, a_bAllowOpt); + MU_PARSER_CATCH +} + +//--------------------------------------------------------------------------- +MU_PARSER_API void mupDefineStrFun2(parser_handle a_hParser, const char *a_szName, strfun_type2 a_pFun, bool a_bAllowOpt) +{ + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + p->DefineFun(a_szName, a_pFun, a_bAllowOpt); + MU_PARSER_CATCH +} + +//--------------------------------------------------------------------------- +MU_PARSER_API void mupDefineStrFun3(parser_handle a_hParser, const char *a_szName, strfun_type3 a_pFun, bool a_bAllowOpt) +{ + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + p->DefineFun(a_szName, a_pFun, a_bAllowOpt); + MU_PARSER_CATCH +} + +//--------------------------------------------------------------------------- +MU_PARSER_API void mupDefineMultFun(parser_handle a_hParser, const char *a_szName, multfun_type a_pFun, bool a_bAllowOpt) +{ + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + p->DefineFun(a_szName, a_pFun, a_bAllowOpt); + MU_PARSER_CATCH +} + +//--------------------------------------------------------------------------- +MU_PARSER_API void mupDefineOprt(parser_handle a_hParser, const char *a_szName, fun_type2 a_pFun, int a_iPri, bool a_bAllowOpt) +{ + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + p->DefineOprt(a_szName, a_pFun, a_iPri, a_bAllowOpt); + MU_PARSER_CATCH +} + +//--------------------------------------------------------------------------- +MU_PARSER_API void mupDefineVar(parser_handle a_hParser, const char *a_szName, double *a_pVar) +{ + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + p->DefineVar(a_szName, a_pVar); + MU_PARSER_CATCH +} + +//--------------------------------------------------------------------------- +MU_PARSER_API void mupDefineConst(parser_handle a_hParser, const char *a_szName, double a_fVal) +{ + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + p->DefineConst(a_szName, a_fVal); + MU_PARSER_CATCH +} + +//--------------------------------------------------------------------------- +MU_PARSER_API void mupDefineStrConst(parser_handle a_hParser, const char *a_szName, const char *a_szVal) +{ + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + p->DefineStrConst(a_szName, a_szVal); + MU_PARSER_CATCH +} + +//--------------------------------------------------------------------------- +MU_PARSER_API const char* mupGetExpr(parser_handle a_hParser) +{ + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + return p->GetExpr().c_str(); + MU_PARSER_CATCH + + return ""; +} + +//--------------------------------------------------------------------------- +MU_PARSER_API void mupDefinePostfixOprt(parser_handle a_hParser, + const char *a_szName, + fun_type1 a_pOprt, + bool a_bAllowOpt) +{ + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + p->DefinePostfixOprt(a_szName, a_pOprt, a_bAllowOpt); + MU_PARSER_CATCH +} + +//--------------------------------------------------------------------------- +MU_PARSER_API void mupDefineInfixOprt(parser_handle a_hParser, + const char *a_szName, + fun_type1 a_pOprt, + bool a_bAllowOpt) +{ + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + p->DefineInfixOprt(a_szName, a_pOprt, a_bAllowOpt); + MU_PARSER_CATCH +} + +// Define character sets for identifiers +//--------------------------------------------------------------------------- +MU_PARSER_API void mupDefineNameChars(parser_handle a_hParser, const char *a_szCharset) +{ + parser_type p(GetPtr(a_hParser)); + p->DefineNameChars(a_szCharset); +} + +//--------------------------------------------------------------------------- +MU_PARSER_API void mupDefineOprtChars(parser_handle a_hParser, const char *a_szCharset) +{ + parser_type p(GetPtr(a_hParser)); + p->DefineOprtChars(a_szCharset); +} + +//--------------------------------------------------------------------------- +MU_PARSER_API void mupDefineInfixOprtChars(parser_handle a_hParser, const char *a_szCharset) +{ + parser_type p(GetPtr(a_hParser)); + p->DefineInfixOprtChars(a_szCharset); +} + +//--------------------------------------------------------------------------- +/** \brief Get the number of variables defined in the parser. + \param a_hParser [in] Must be a valid parser handle. + \return The number of used variables. + \sa mupGetExprVar +*/ +MU_PARSER_API int mupGetVarNum(parser_handle a_hParser) +{ + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + const mu::varmap_type VarMap = p->GetVar(); + return (int)VarMap.size(); + MU_PARSER_CATCH + + return 0; // never reached +} + +//--------------------------------------------------------------------------- +/** \brief Return a variable that is used in an expression. + + Prior to calling this function call mupGetExprVarNum in order to get the + number of variables in the expression. If the parameter a_iVar is greater + than the number of variables both a_szName and a_pVar will be set to zero. + As a side effect this function will trigger an internal calculation of the + expression undefined variables will be set to zero during this calculation. + During the calculation user defined callback functions present in the expression + will be called, this is unavoidable. + + \param a_hParser [in] A valid parser handle. + \param a_iVar [in] The index of the variable to return. + \param a_szName [out] Pointer to the variable name. + \param a_pVar [out] Pointer to the variable. + \throw nothrow +*/ +MU_PARSER_API void mupGetVar(parser_handle a_hParser, unsigned a_iVar, const char **a_szName, double **a_pVar) +{ + // A static buffer is needed for the name since i cant return the + // pointer from the map. + static char szName[1024]; + + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + const mu::varmap_type VarMap = p->GetVar(); + + if (a_iVar>=VarMap.size()) + { + *a_szName = 0; + *a_pVar = 0; + return; + } + mu::varmap_type::const_iterator item; + + item = VarMap.begin(); + for (unsigned i=0; ifirst.c_str(), sizeof(szName)); + szName[sizeof(szName)-1] = 0; + + *a_szName = &szName[0]; + *a_pVar = item->second; + return; + + MU_PARSER_CATCH + + *a_szName = 0; + *a_pVar = 0; +} + +//--------------------------------------------------------------------------- +/** \brief Get the number of variables used in the expression currently set in the parser. + \param a_hParser [in] Must be a valid parser handle. + \return The number of used variables. + \sa mupGetExprVar +*/ +MU_PARSER_API int mupGetExprVarNum(parser_handle a_hParser) +{ + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + const mu::varmap_type VarMap = p->GetUsedVar(); + return (int)VarMap.size(); + MU_PARSER_CATCH + + return 0; // never reached +} + +//--------------------------------------------------------------------------- +/** \brief Return a variable that is used in an expression. + + Prior to calling this function call mupGetExprVarNum in order to get the + number of variables in the expression. If the parameter a_iVar is greater + than the number of variables both a_szName and a_pVar will be set to zero. + As a side effect this function will trigger an internal calculation of the + expression undefined variables will be set to zero during this calculation. + During the calculation user defined callback functions present in the expression + will be called, this is unavoidable. + + \param a_hParser [in] A valid parser handle. + \param a_iVar [in] The index of the variable to return. + \param a_szName [out] Pointer to the variable name. + \param a_pVar [out] Pointer to the variable. + \throw nothrow +*/ +MU_PARSER_API void mupGetExprVar(parser_handle a_hParser, unsigned a_iVar, const char **a_szName, double **a_pVar) +{ + // A static buffer is needed for the name since i cant return the + // pointer from the map. + static char szName[1024]; + + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + const mu::varmap_type VarMap = p->GetUsedVar(); + + if (a_iVar>=VarMap.size()) + { + *a_szName = 0; + *a_pVar = 0; + return; + } + mu::varmap_type::const_iterator item; + + item = VarMap.begin(); + for (unsigned i=0; ifirst.c_str(), sizeof(szName)); + szName[sizeof(szName)-1] = 0; + + *a_szName = &szName[0]; + *a_pVar = item->second; + return; + + MU_PARSER_CATCH + + *a_szName = 0; + *a_pVar = 0; +} + +//--------------------------------------------------------------------------- +/** \brief Return the number of constants defined in a parser. */ +MU_PARSER_API int mupGetConstNum(parser_handle a_hParser) +{ + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + const mu::valmap_type ValMap = p->GetConst(); + return (int)ValMap.size(); + MU_PARSER_CATCH + + return 0; // never reached +} + +//--------------------------------------------------------------------------- +/** \brief Retrieve name and value of a single parser constant. + \param a_hParser [in] a valid parser handle + \param a_iVar [in] Index of the constant to query + \param a_pszName [out] pointer to a null terminated string with the constant name + \param [out] The constant value +*/ +MU_PARSER_API void mupGetConst(parser_handle a_hParser, unsigned a_iVar, + const char **a_pszName, double &a_fVal) +{ + // A static buffer is needed for the name since i cant return the + // pointer from the map. + static char szName[1024]; + + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + const mu::valmap_type ValMap = p->GetConst(); + + if (a_iVar>=ValMap.size()) + { + *a_pszName = 0; + a_fVal = 0; + return; + } + + mu::valmap_type::const_iterator item; + item = ValMap.begin(); + for (unsigned i=0; ifirst.c_str(), sizeof(szName)); + szName[sizeof(szName)-1] = 0; + + *a_pszName = &szName[0]; + a_fVal = item->second; + return; + + MU_PARSER_CATCH + + *a_pszName = 0; + a_fVal = 0; +} + +//--------------------------------------------------------------------------- +/** \brief Add a custom value regognition function. +*/ +MU_PARSER_API void mupAddValIdent(parser_handle a_hParser, identfun_type a_pFun) +{ + MU_PARSER_TRY + parser_type p(GetPtr(a_hParser)); + p->AddValIdent(a_pFun); + MU_PARSER_CATCH +} + +//--------------------------------------------------------------------------- +/** \brief Query if an error occured. + + After querying the internal error bit will be reset. So a consecutive call + will return false. +*/ +MU_PARSER_API bool mupError() +{ + bool bError(g_bError); + g_bError = false; + return bError; +} + +//--------------------------------------------------------------------------- +/** \brief Reset the internal error flag. +*/ +MU_PARSER_API void mupErrorReset() +{ + g_bError = false; +} + +//--------------------------------------------------------------------------- +/** \brief Return the message associated with the last error. +*/ +MU_PARSER_API const char* mupGetErrorMsg() +{ + return g_ParserError.GetMsg().c_str(); +} + +//--------------------------------------------------------------------------- +/** \brief Return the message associated with the last error. +*/ +MU_PARSER_API const char* mupGetErrorToken() +{ + return g_ParserError.GetToken().c_str(); +} + +//--------------------------------------------------------------------------- +/** \brief Return the code associated with the last error. +*/ +MU_PARSER_API int mupGetErrorCode() +{ + return g_ParserError.GetCode(); +} + +//--------------------------------------------------------------------------- +/** \brief Return the postion associated with the last error. */ +MU_PARSER_API int mupGetErrorPos() +{ + return (int)g_ParserError.GetPos(); +} + + +#endif // MUPARSER_DLL diff --git a/muparser/muParserDLL.h b/muparser/muParserDLL.h new file mode 100644 index 0000000..20e2db8 --- /dev/null +++ b/muparser/muParserDLL.h @@ -0,0 +1,123 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2006 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +// Folgender ifdef-Block ist die Standardmethode zum Erstellen von Makros, die das Exportieren +// aus einer DLL vereinfachen. Alle Dateien in der DLL werden mit dem MUPARSERLIB_EXPORTS-Symbol +// kompiliert, das in der Befehlszeile definiert wurde. Das Symbol darf nicht für ein Projekt definiert werden, +// das diese DLL verwendet. Alle anderen Projekte, deren Quelldateien diese Datei beinhalten, erkennen +// MUPARSERLIB_API-Funktionen als aus einer DLL importiert, während die DLL mit diesem Makro +// definierte Symbole als exportiert ansieht. +#ifndef MU_PARSER_DLL_H +#define MU_PARSER_DLL_H + +#ifdef MUPARSERLIB_EXPORTS +#define MU_PARSER_API __declspec(dllexport) +#else +#define MU_PARSER_API __declspec(dllimport) +#endif + + +#define WIN32_LEAN_AND_MEAN +#include + +typedef void* parser_handle; +typedef double (*fun_type1)(double); +typedef double (*fun_type2)(double, double); +typedef double (*fun_type3)(double, double, double); +typedef double (*fun_type4)(double, double, double, double); +typedef double (*fun_type5)(double, double, double, double, double); +typedef double (*multfun_type)(const double*, int); +typedef double (*strfun_type1)(const char*); +typedef double (*strfun_type2)(const char*, double); +typedef double (*strfun_type3)(const char*, double, double); +typedef void (*errhandler_type)(); +typedef double* (*facfun_type)(const char*, void *); +typedef bool (*identfun_type)(const char*, int&, double&); + +extern "C" +{ + +// Basic operations / initialization +MU_PARSER_API parser_handle mupInit(); +MU_PARSER_API void mupRelease(parser_handle a_hParser); +MU_PARSER_API const char* mupGetExpr(parser_handle a_hParser); +MU_PARSER_API void mupSetExpr(parser_handle a_hParser, const char *a_szExpr); +MU_PARSER_API void mupSetErrorHandler(errhandler_type a_pErrHandler); +MU_PARSER_API void mupSetVarFactory(parser_handle a_hParser, facfun_type a_pFactory, void *pUserData); + +MU_PARSER_API double mupEval(parser_handle a_hParser); + +// Defining callbacks / variables / constants +MU_PARSER_API void mupDefineFun1(parser_handle a_hParser, const char *a_szName, fun_type1 a_pFun, bool a_bAllowOpt = true); +MU_PARSER_API void mupDefineFun2(parser_handle a_hParser, const char *a_szName, fun_type2 a_pFun, bool a_bAllowOpt = true); +MU_PARSER_API void mupDefineFun3(parser_handle a_hParser, const char *a_szName, fun_type3 a_pFun, bool a_bAllowOpt = true); +MU_PARSER_API void mupDefineFun4(parser_handle a_hParser, const char *a_szName, fun_type4 a_pFun, bool a_bAllowOpt = true); +MU_PARSER_API void mupDefineFun5(parser_handle a_hParser, const char *a_szName, fun_type5 a_pFun, bool a_bAllowOpt = true); +// string functions +MU_PARSER_API void mupDefineStrFun1(parser_handle a_hParser, const char *a_szName, strfun_type1 a_pFun, bool a_bAllowOpt = true); +MU_PARSER_API void mupDefineStrFun2(parser_handle a_hParser, const char *a_szName, strfun_type2 a_pFun, bool a_bAllowOpt = true); +MU_PARSER_API void mupDefineStrFun3(parser_handle a_hParser, const char *a_szName, strfun_type3 a_pFun, bool a_bAllowOpt = true); + +MU_PARSER_API void mupDefineMultFun(parser_handle a_hParser, const char *a_szName, multfun_type a_pFun, bool a_bAllowOpt = true); +MU_PARSER_API void mupDefineOprt(parser_handle a_hParser, const char *a_szName, fun_type2 a_pFun, int a_iPri = 0, bool a_bAllowOpt = true); +MU_PARSER_API void mupDefineConst(parser_handle a_hParser, const char *a_szName, double a_fVal); +MU_PARSER_API void mupDefineStrConst(parser_handle a_hParser, const char *a_szName, const char *a_sVal); +MU_PARSER_API void mupDefineVar(parser_handle a_hParser, const char *a_szName, double *a_fVar); +MU_PARSER_API void mupDefinePostfixOprt(parser_handle a_hParser, const char *a_szName, fun_type1 a_pOprt, bool a_bAllowOpt = true); +MU_PARSER_API void mupDefineInfixOprt(parser_handle a_hParser, const char *a_szName, fun_type1 a_pOprt, bool a_bAllowOpt=true); + +// Define character sets for identifiers +MU_PARSER_API void mupDefineNameChars(parser_handle a_hParser, const char *a_szCharset); +MU_PARSER_API void mupDefineOprtChars(parser_handle a_hParser, const char *a_szCharset); +MU_PARSER_API void mupDefineInfixOprtChars(parser_handle a_hParser, const char *a_szCharset); + +// Remove all / single variables +MU_PARSER_API void mupRemoveVar(parser_handle a_hParser, const char *a_szName); +MU_PARSER_API void mupClearVar(parser_handle a_hParser); +MU_PARSER_API void mupClearConst(parser_handle a_hParser); +MU_PARSER_API void mupClearOprt(parser_handle a_hParser); + +// Querying variables / expression variables / constants +MU_PARSER_API int mupGetExprVarNum(parser_handle a_hParser); +MU_PARSER_API int mupGetVarNum(parser_handle a_hParser); +MU_PARSER_API int mupGetConstNum(parser_handle a_hParser); +MU_PARSER_API void mupGetExprVar(parser_handle a_hParser, unsigned a_iVar, const char **a_pszName, double **a_pVar); +MU_PARSER_API void mupGetVar(parser_handle a_hParser, unsigned a_iVar, const char **a_pszName, double **a_pVar); +MU_PARSER_API void mupGetConst(parser_handle a_hParser, unsigned a_iVar, const char **a_pszName, double &a_pVar); + +// Add value recognition callbacks +MU_PARSER_API void mupAddValIdent(parser_handle a_hParser, identfun_type); + +// Error handling +MU_PARSER_API bool mupError(); +MU_PARSER_API void mupErrorReset(); +MU_PARSER_API const char* mupGetErrorMsg(); +MU_PARSER_API int mupGetErrorCode(); +MU_PARSER_API int mupGetErrorPos(); +MU_PARSER_API const char* mupGetErrorToken(); + +} // extern "C" + +#endif diff --git a/muparser/muParserDef.h b/muparser/muParserDef.h new file mode 100644 index 0000000..164b882 --- /dev/null +++ b/muparser/muParserDef.h @@ -0,0 +1,239 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2006 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#ifndef MUP_DEF_H +#define MUP_DEF_H + +#include +#include +#include +#include + +#include "muParserFixes.h" + +/** \brief Define the base datatype for values. + + This datatype must be a built in value type. You can not use custom classes. + It has been tested with float, double and long double types, int should + work as well. +*/ +#define MUP_BASETYPE double + + +/** \brief Definition of the basic bytecode datatype. */ +#define MUP_BYTECODE_TYPE long + +/** \brief Maybe I use this for unicode support later. */ +#if defined(_UNICODE) + /** \brief Definition of the basic parser string type. */ + #define MUP_STRING_TYPE std::wstring + + #if !defined(_T) + #define _T(x) L##x + #endif // not defined _T +#else + #ifndef _T + #define _T + #endif + + /** \brief Definition of the basic parser string type. */ + #define MUP_STRING_TYPE std::string +#endif + +#if defined(_DEBUG) + /** \brief Debug macro to force an abortion of the programm with a certain message. + */ + #define MUP_FAIL(MSG) \ + bool MSG=false; \ + assert(MSG); + + #ifndef _UNICODE + /** \brief An assertion that does not kill the program. + + This macro is neutralised in UNICODE builds. It's + too difficult to translate. + */ + #define MUP_ASSERT(COND) \ + if (!(COND)) \ + { \ + stringstream_type ss; \ + ss << "Assertion \""#COND"\" failed: " \ + << __FILE__ << " line " \ + << __LINE__ << "."; \ + throw ParserError( ss.str() ); \ + } + #else + #define MUP_ASSERT(COND) + #endif // _UNICODE +#else + #define MUP_FAIL(MSG) + #define MUP_ASSERT(COND) +#endif + +//------------------------------------------------------------------------------ +// +// do not change anything beyond this point... +// +// !!! This section is devoted to macros that are used for debugging +// !!! or for features that are not fully implemented yet. +// +//#define MUP_DUMP_STACK +//#define MUP_DUMP_CMDCODE + + +namespace mu +{ +#if defined(_UNICODE) + + //------------------------------------------------------------------------------ + /** \brief Encapsulate wcout. */ + inline std::wostream& console() + { + return std::wcout; + } + + /** \brief Encapsulate cin. */ + inline std::wistream& console_in() + { + return std::wcin; + } + +#else + + /** \brief Encapsulate cout. */ + inline std::ostream& console() + { + return std::cout; + } + + /** \brief Encapsulate cin. */ + inline std::istream& console_in() + { + return std::cin; + } + +#endif + + //------------------------------------------------------------------------------ + /** \brief Bytecode values. + + \attention The order of the operator entries must match the order in ParserBase::c_DefaultOprt! + */ + enum ECmdCode + { + // The following are codes for built in binary operators + // apart from built in operators the user has the opportunity to + // add user defined operators. + cmLE = 0, ///< Operator item: less or equal + cmGE = 1, ///< Operator item: greater or equal + cmNEQ = 2, ///< Operator item: not equal + cmEQ = 3, ///< Operator item: equals + cmLT = 4, ///< Operator item: less than + cmGT = 5, ///< Operator item: greater than + cmADD = 6, ///< Operator item: add + cmSUB = 7, ///< Operator item: subtract + cmMUL = 8, ///< Operator item: multiply + cmDIV = 9, ///< Operator item: division + cmPOW = 10, ///< Operator item: y to the power of ... + cmAND = 11, ///< Operator item: logical and + cmOR = 12, ///< Operator item: logical or + cmXOR = 13, ///< Operator item: logical xor + cmASSIGN = 14, ///< Operator item: Assignment operator + cmBO = 15, ///< Operator item: opening bracket + cmBC = 16, ///< Operator item: closing bracket + cmCOMMA = 17, ///< Operator item: comma + cmVAR = 18, ///< variable item + cmSTRVAR = 19, + cmVAL = 20, ///< value item + + cmFUNC = 21, ///< Code for a function item + cmFUNC_STR = 22, ///< Code for a function with a string parameter + + cmSTRING = 23, ///< Code for a string token + cmOPRT_BIN = 24, ///< user defined binary operator + cmOPRT_POSTFIX = 25, ///< code for postfix operators + cmOPRT_INFIX = 26, ///< code for infix operators + cmEND = 27, ///< end of formula + cmUNKNOWN = 28 ///< uninitialized item + }; + + //------------------------------------------------------------------------------ + /** \brief Types internally used by the parser. + */ + enum ETypeCode + { + tpSTR = 0, ///> String type (Function arguments and constants only, no string variables) + tpDBL = 1, ///> Floating point variables + tpVOID = 2 ///> Undefined type. + }; + + //------------------------------------------------------------------------------ + /** \brief Parser operator precedence values. */ + enum EPrec + { + // binary operators + prLOGIC = 1, ///> logic operators + prCMP = 2, ///> comparsion operators + prADD_SUB = 3, ///> addition + prMUL_DIV = 4, ///> multiplication/division + prPOW = 5, ///> power operator priority (highest) + + // infix operators + prINFIX = 4, ///> Signs have a higher priority than ADD_SUB, but lower than power operator + prPOSTFIX = 4 ///> Postfix operator priority (currently unused) + }; + + //------------------------------------------------------------------------------ + // basic types + typedef MUP_BASETYPE value_type; + typedef MUP_STRING_TYPE string_type; + typedef MUP_BYTECODE_TYPE bytecode_type; + typedef string_type::value_type char_type; + typedef std::basic_stringstream, + std::allocator > stringstream_type; + + // Data container types + typedef std::map varmap_type; + typedef std::map valmap_type; + typedef std::map strmap_type; + + // Parser callbacks + typedef value_type (*fun_type1)(value_type); + typedef value_type (*fun_type2)(value_type, value_type); + typedef value_type (*fun_type3)(value_type, value_type, value_type); + typedef value_type (*fun_type4)(value_type, value_type, value_type, value_type); + typedef value_type (*fun_type5)(value_type, value_type, value_type, value_type, value_type); + typedef value_type (*multfun_type)(const value_type*, int); + typedef value_type (*strfun_type1)(const char_type*); + typedef value_type (*strfun_type2)(const char_type*, value_type); + typedef value_type (*strfun_type3)(const char_type*, value_type, value_type); + + // Parser utility callback functions (unrelated to the math callbacks) + typedef bool (*identfun_type)(const char_type*, int&, value_type&); + typedef value_type* (*facfun_type)(const char_type*, void*); +} // end fo namespace + +#endif + diff --git a/muparser/muParserError.cpp b/muparser/muParserError.cpp new file mode 100644 index 0000000..237f529 --- /dev/null +++ b/muparser/muParserError.cpp @@ -0,0 +1,300 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2006 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#include "muParserError.h" + + +namespace mu +{ + const ParserErrorMsg ParserErrorMsg::m_Instance; + + //------------------------------------------------------------------------------ + const ParserErrorMsg& ParserErrorMsg::Instance() + { + return m_Instance; + } + + //------------------------------------------------------------------------------ + string_type ParserErrorMsg::operator[](unsigned a_iIdx) const + { + return (a_iIdx \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2006 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef MU_PARSER_ERROR_H +#define MU_PARSER_ERROR_H + +#include +#include +#include +#include +#include +#include + +#include "muParserDef.h" + + +namespace mu +{ + +/** \brief Error codes. */ +enum EErrorCodes +{ + // Formula syntax errors + ecUNEXPECTED_OPERATOR = 0, ///< Unexpected binary operator found + ecUNASSIGNABLE_TOKEN = 1, ///< Token cant be identified. + ecUNEXPECTED_EOF = 2, ///< Unexpected end of formula. (Example: "2+sin(") + ecUNEXPECTED_COMMA = 3, ///< An unexpected comma has been found. (Example: "1,23") + ecUNEXPECTED_ARG = 4, ///< An unexpected argument has been found + ecUNEXPECTED_VAL = 5, ///< An unexpected value token has been found + ecUNEXPECTED_VAR = 6, ///< An unexpected variable token has been found + ecUNEXPECTED_PARENS = 7, ///< Unexpected Parenthesis, opening or closing + ecUNEXPECTED_STR = 8, ///< A string has been found at an inapropriate position + ecSTRING_EXPECTED = 9, ///< A string function has been called with a different type of argument + ecVAL_EXPECTED = 10, ///< A numerical function has been called with a non value type of argument + ecMISSING_PARENS = 11, ///< Missing parens. (Example: "3*sin(3") + ecUNEXPECTED_FUN = 12, ///< Unexpected function found. (Example: "sin(8)cos(9)") + ecUNTERMINATED_STRING = 13, ///< unterminated string constant. (Example: "3*valueof("hello)") + ecTOO_MANY_PARAMS = 14, ///< Too many function parameters + ecTOO_FEW_PARAMS = 15, ///< Too few function parameters. (Example: "ite(1<2,2)") + ecOPRT_TYPE_CONFLICT = 16, ///< binary operators may only be applied to value items of the same type + ecSTR_RESULT = 17, ///< result is a string + + // Invalid Parser input Parameters + ecINVALID_NAME = 18, ///< Invalid function, variable or constant name. + ecBUILTIN_OVERLOAD = 19, ///< Trying to overload builtin operator + ecINVALID_FUN_PTR = 20, ///< Invalid callback function pointer + ecINVALID_VAR_PTR = 21, ///< Invalid variable pointer + ecEMPTY_EXPRESSION = 22, ///< The Expression is empty + ecNAME_CONFLICT = 23, ///< Name conflict + ecOPT_PRI = 24, ///< Invalid operator priority + // + ecDOMAIN_ERROR = 25, ///< catch division by zero, sqrt(-1), log(0) (currently unused) + ecDIV_BY_ZERO = 26, ///< Division by zero (currently unused) + ecGENERIC = 27, ///< Generic error + + // internal errors + ecINTERNAL_ERROR = 28, ///< Internal error of any kind. + + // The last two are special entries + ecCOUNT, ///< This is no error code, It just stores just the total number of error codes + ecUNDEFINED = -1 ///< Undefined message, placeholder to detect unassigned error messages +}; + +//--------------------------------------------------------------------------- +class ParserErrorMsg +{ +public: + typedef ParserErrorMsg self_type; + + ParserErrorMsg& operator=(const ParserErrorMsg &); + ParserErrorMsg(const ParserErrorMsg&); + ParserErrorMsg(); + + ~ParserErrorMsg(); + + static const ParserErrorMsg& Instance(); + string_type operator[](unsigned a_iIdx) const; + +private: + std::vector m_vErrMsg; + static const self_type m_Instance; +}; + +//--------------------------------------------------------------------------- +/** \brief Error class of the parser. + + Part of the math parser package. + + \author Ingo Berg +*/ +/* final */ class ParserError +{ +private: + //------------------------------------------------------------------------------ + /** \brief Replace all ocuurences of a substring with another string. */ + void ReplaceSubString( string_type &strSource, + const string_type &strFind, + const string_type &strReplaceWith); + void Reset(); + +public: + ParserError(); + explicit ParserError(EErrorCodes a_iErrc); + explicit ParserError(const string_type &sMsg); + ParserError( EErrorCodes a_iErrc, + const string_type &sTok, + const string_type &sFormula = string_type(_T("(formula is not available)")), + int a_iPos = -1); + ParserError( EErrorCodes a_iErrc, + int a_iPos, + const string_type &sTok); + ParserError( const char_type *a_szMsg, + int a_iPos = -1, + const string_type &sTok = string_type()); + ParserError(const ParserError &a_Obj); + ParserError& operator=(const ParserError &a_Obj); + ~ParserError(); + + void SetFormula(const string_type &a_strFormula); + const string_type& GetExpr() const; + const string_type& GetMsg() const; + std::size_t GetPos() const; + const string_type& GetToken() const; + EErrorCodes GetCode() const; + +private: + string_type m_strMsg; ///< The message string + string_type m_strFormula; ///< Formula string + string_type m_strTok; ///< Token related with the error + int m_iPos; ///< Formula position related to the error + EErrorCodes m_iErrc; ///< Error code + const ParserErrorMsg &m_ErrMsg; +}; + +} // namespace mu + +#endif + diff --git a/muparser/muParserFixes.h b/muparser/muParserFixes.h new file mode 100644 index 0000000..02ca007 --- /dev/null +++ b/muparser/muParserFixes.h @@ -0,0 +1,196 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2006 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef MU_PARSER_FIXES_H +#define MU_PARSER_FIXES_H + +// +// Compatibility fixes +// + +//--------------------------------------------------------------------------- +// +// Intel Compiler +// +//--------------------------------------------------------------------------- + +#ifdef __INTEL_COMPILER + +// remark #981: operands are evaluated in unspecified order +// disabled -> completely pointless if the functions do not have side effects +// +#pragma warning(disable:981) + +// remark #383: value copied to temporary, reference to temporary used +#pragma warning(disable:383) + +// remark #1572: floating-point equality and inequality comparisons are unreliable +// disabled -> everyone knows it, the parser passes this problem +// deliberately to the user +#pragma warning(disable:1572) + +#endif + + +//--------------------------------------------------------------------------- +// +// MSVC6 +// +//--------------------------------------------------------------------------- + + +#if _MSC_VER==1200 + +/** \brief Macro to replace the MSVC6 auto_ptr with the _my_auto_ptr class. + + Hijack auto_ptr and replace it with a version that actually does + what an auto_ptr normally does. If you use std::auto_ptr in your other code + it might either explode or work much better. The original crap created + by Microsoft, called auto_ptr and bundled with MSVC6 is not standard compliant. +*/ +#define auto_ptr _my_auto_ptr + +// This is another stupidity that needs to be undone in order to de-pollute +// the global namespace! +#undef min +#undef max + + +namespace std +{ + typedef ::size_t size_t; + + //--------------------------------------------------------------------------- + /** \brief MSVC6 fix: Dummy function to put rand into namespace std. + + This is a hack for MSVC6 only. It's dirty, it's ugly and it works, provided + inlining is enabled. Necessary because I will not pollute or change my + code in order to adopt it to MSVC6 interpretation of how C++ should look like! + */ + inline int rand(void) + { + return ::rand(); + } + + //--------------------------------------------------------------------------- + /** \brief MSVC6 fix: Dummy function to put strlen into namespace std. + + This is a hack for MSVC6 only. It's dirty, it's ugly and it works, provided + inlining is enabled. Necessary because I will not pollute or change my + code in order to adopt it to MSVC6 interpretation of how C++ should look like! + */ + inline size_t strlen(const char *szMsg) + { + return ::strlen(szMsg); + } + + //--------------------------------------------------------------------------- + /** \brief MSVC6 fix: Dummy function to put strncmp into namespace std. + + This is a hack for MSVC6 only. It's dirty, it's ugly and it works, provided + inlining is enabled. Necessary because I will not pollute or change my + code in order to adopt it to MSVC6 interpretation of how C++ should look like! + */ + inline int strncmp(const char *a, const char *b, size_t len) + { + return ::strncmp(a,b,len); + } + + //--------------------------------------------------------------------------- + template + T max(T a, T b) + { + return (a>b) ? a : b; + } + + //--------------------------------------------------------------------------- + template + T min(T a, T b) + { + return (a + class _my_auto_ptr + { + public: + typedef _Ty element_type; + + explicit _my_auto_ptr(_Ty *_Ptr = 0) + :_Myptr(_Ptr) + {} + + _my_auto_ptr(_my_auto_ptr<_Ty>& _Right) + :_Myptr(_Right.release()) + {} + + template + operator _my_auto_ptr<_Other>() + { + return (_my_auto_ptr<_Other>(*this)); + } + + template + _my_auto_ptr<_Ty>& operator=(_my_auto_ptr<_Other>& _Right) + { + reset(_Right.release()); + return (*this); + } + + ~auto_ptr() { delete _Myptr; } + _Ty& operator*() const { return (*_Myptr); } + _Ty *operator->() const { return (&**this); } + _Ty *get() const { return (_Myptr); } + + _Ty *release() + { + _Ty *_Tmp = _Myptr; + _Myptr = 0; + return (_Tmp); + } + + void reset(_Ty* _Ptr = 0) + { + if (_Ptr != _Myptr) + delete _Myptr; + _Myptr = _Ptr; + } + + private: + _Ty *_Myptr; + }; // class _my_auto_ptr +} // namespace std + +#endif // Microsoft Visual Studio Version 6.0 + +#endif // include guard + + diff --git a/muparser/muParserInt.cpp b/muparser/muParserInt.cpp new file mode 100644 index 0000000..1b072bc --- /dev/null +++ b/muparser/muParserInt.cpp @@ -0,0 +1,264 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2006 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "muParserInt.h" + +#include +#include +#include + +using namespace std; + + +/** \brief Namespace for mathematical applications. */ +namespace mu +{ + +value_type ParserInt::Abs(value_type v) { return Round(fabs(v)); } +value_type ParserInt::Sign(value_type v) { return (Round(v)<0) ? -1 : (Round(v)>0) ? 1 : 0; } +value_type ParserInt::Ite(value_type v1, + value_type v2, + value_type v3) { return (Round(v1)==1) ? Round(v2) : Round(v3); } +value_type ParserInt::Add(value_type v1, value_type v2) { return Round(v1) + Round(v2); } +value_type ParserInt::Sub(value_type v1, value_type v2) { return Round(v1) - Round(v2); } +value_type ParserInt::Mul(value_type v1, value_type v2) { return Round(v1) * Round(v2); } +value_type ParserInt::Div(value_type v1, value_type v2) { return Round(v1) / Round(v2); } +value_type ParserInt::Mod(value_type v1, value_type v2) { return Round(v1) % Round(v2); } +value_type ParserInt::Shr(value_type v1, value_type v2) { return Round(v1) >> Round(v2); } +value_type ParserInt::Shl(value_type v1, value_type v2) { return Round(v1) << Round(v2); } +value_type ParserInt::LogAnd(value_type v1, value_type v2) { return Round(v1) & Round(v2); } +value_type ParserInt::LogOr(value_type v1, value_type v2) { return Round(v1) | Round(v2); } +value_type ParserInt::LogXor(value_type v1, value_type v2) { return Round(v1) ^ Round(v2); } +value_type ParserInt::And(value_type v1, value_type v2) { return Round(v1) && Round(v2); } +value_type ParserInt::Or(value_type v1, value_type v2) { return Round(v1) || Round(v2); } +value_type ParserInt::Less(value_type v1, value_type v2) { return Round(v1) < Round(v2); } +value_type ParserInt::Greater(value_type v1, value_type v2) { return Round(v1) > Round(v2); } +value_type ParserInt::LessEq(value_type v1, value_type v2) { return Round(v1) <= Round(v2); } +value_type ParserInt::GreaterEq(value_type v1, value_type v2) { return Round(v1) >= Round(v2); } +value_type ParserInt::Equal(value_type v1, value_type v2) { return Round(v1) == Round(v2); } +value_type ParserInt::NotEqual(value_type v1, value_type v2) { return Round(v1) != Round(v2); } +value_type ParserInt::Not(value_type v) { return !Round(v); } + +//--------------------------------------------------------------------------- +// Unary operator Callbacks: Infix operators +value_type ParserInt::UnaryMinus(value_type v) +{ + return -Round(v); +} + +//--------------------------------------------------------------------------- +value_type ParserInt::Sum(const value_type* a_afArg, int a_iArgc) +{ + if (!a_iArgc) + throw ParserError(_T("too few arguments for function sum.")); + + value_type fRes=0; + for (int i=0; i> iVal; + int iEnd = stream.tellg(); // Position after reading + + if (iEnd==-1) + return false; + + a_iPos += iEnd; + a_fVal = (value_type)iVal; + return true; +} + +//--------------------------------------------------------------------------- +bool ParserInt::IsHexVal(const char_type *a_szExpr, int &a_iPos, value_type &a_fVal) +{ + if (a_szExpr[0]!='$') + return false; + + unsigned iVal(0); + +// New code based on streams for UNICODE compliance: + stringstream_type::pos_type nPos(0); + stringstream_type ss(a_szExpr+1); + ss >> std::hex >> iVal; + nPos = ss.tellg(); + + if (nPos==(stringstream_type::pos_type)0) + return false; + + a_iPos += 1 + nPos; + +/* + // original code based on sscanf. Working but not UNICODE compliant! + int iLen(0); + if (sscanf(a_szExpr+1, "%x%n", &iVal, &iLen)==0) + return false; + + a_iPos += iLen+1; +*/ + + a_fVal = iVal; + return true; +} + +//--------------------------------------------------------------------------- +bool ParserInt::IsBinVal(const char_type *a_szExpr, int &a_iPos, value_type &a_fVal) +{ + if (a_szExpr[0]!='#') + return false; + + unsigned iVal(0), + iBits(sizeof(iVal)*8), + i(0); + + for (i=0; (a_szExpr[i+1]=='0' || a_szExpr[i+1]=='1') && i> (iBits-i) ); + a_iPos += i+1; + + return true; +} + +//--------------------------------------------------------------------------- +/** \brief Constructor. + + Call ParserBase class constructor and trigger Function, Operator and Constant initialization. +*/ +ParserInt::ParserInt() +:ParserBase() +{ + AddValIdent(IsVal); + AddValIdent(IsHexVal); + AddValIdent(IsBinVal); + + InitCharSets(); + InitFun(); + InitOprt(); +} + +//--------------------------------------------------------------------------- +void ParserInt::InitConst() +{ +} + +//--------------------------------------------------------------------------- +void ParserInt::InitCharSets() +{ + DefineNameChars( _T("0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") ); + DefineOprtChars( _T("+-*^/?<>=!%&|~'_") ); + DefineInfixOprtChars( _T("/+-*^?<>=!%&|~'_") ); +} + +//--------------------------------------------------------------------------- +/** \brief Initialize the default functions. */ +void ParserInt::InitFun() +{ + DefineFun( _T("sign"), Sign); + DefineFun( _T("abs"), Abs); + DefineFun( _T("if"), Ite); + DefineFun( _T("sum"), Sum); + DefineFun( _T("min"), Min); + DefineFun( _T("max"), Max); +} + +//--------------------------------------------------------------------------- +/** \brief Initialize operators. */ +void ParserInt::InitOprt() +{ + // disable all built in operators, not all of them usefull for integer numbers + // (they don't do rounding of values) + EnableBuiltInOprt(false); + + // Disable all built in operators, they wont work with integer numbers + // since they are designed for floating point numbers + DefineInfixOprt( _T("-"), UnaryMinus); + DefineInfixOprt( _T("!"), Not); + + DefineOprt( _T("&"), LogAnd, prLOGIC); + DefineOprt( _T("|"), LogOr, prLOGIC); + DefineOprt( _T("^"), LogXor, prLOGIC); + DefineOprt( _T("&&"), And, prLOGIC); + DefineOprt( _T("||"), Or, prLOGIC); + + DefineOprt( _T("<"), Less, prCMP); + DefineOprt( _T(">"), Greater, prCMP); + DefineOprt( _T("<="), LessEq, prCMP); + DefineOprt( _T(">="), GreaterEq, prCMP); + DefineOprt( _T("=="), Equal, prCMP); + DefineOprt( _T("!="), NotEqual, prCMP); + + DefineOprt( _T("+"), Add, prADD_SUB); + DefineOprt( _T("-"), Sub, prADD_SUB); + + DefineOprt( _T("*"), Mul, prMUL_DIV); + DefineOprt( _T("/"), Div, prMUL_DIV); + DefineOprt( _T("%"), Mod, prMUL_DIV); + + DefineOprt( _T(">>"), Shr, prMUL_DIV+1); + DefineOprt( _T("<<"), Shl, prMUL_DIV+1); +} + +} // namespace mu diff --git a/muparser/muParserInt.h b/muparser/muParserInt.h new file mode 100644 index 0000000..008792d --- /dev/null +++ b/muparser/muParserInt.h @@ -0,0 +1,93 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2006 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef MU_PARSER_INT_H +#define MU_PARSER_INT_H + +#include "muParserBase.h" +#include + + +namespace mu +{ + +/** \brief Mathematical expressions parser. + + This version of the parser handles only integer numbers. It disables the built in operators thus it is + slower than muParser. Integer values are stored in the double value_type and converted if needed. +*/ +class ParserInt : public ParserBase +{ +private: + static int Round(value_type v) { return (int)(v + ((v>=0) ? 0.5 : -0.5) ); }; + + static value_type Abs(value_type); + static value_type Sign(value_type); + static value_type Ite(value_type, value_type, value_type); + // !! The unary Minus is a MUST, otherwise you cant use negative signs !! + static value_type UnaryMinus(value_type); + // Functions with variable number of arguments + static value_type Sum(const value_type* a_afArg, int a_iArgc); // sum + static value_type Min(const value_type* a_afArg, int a_iArgc); // minimum + static value_type Max(const value_type* a_afArg, int a_iArgc); // maximum + // binary operator callbacks + static value_type Add(value_type v1, value_type v2); + static value_type Sub(value_type v1, value_type v2); + static value_type Mul(value_type v1, value_type v2); + static value_type Div(value_type v1, value_type v2); + static value_type Mod(value_type v1, value_type v2); + static value_type Shr(value_type v1, value_type v2); + static value_type Shl(value_type v1, value_type v2); + static value_type LogAnd(value_type v1, value_type v2); + static value_type LogOr(value_type v1, value_type v2); + static value_type LogXor(value_type v1, value_type v2); + static value_type And(value_type v1, value_type v2); + static value_type Or(value_type v1, value_type v2); + static value_type Xor(value_type v1, value_type v2); + static value_type Less(value_type v1, value_type v2); + static value_type Greater(value_type v1, value_type v2); + static value_type LessEq(value_type v1, value_type v2); + static value_type GreaterEq(value_type v1, value_type v2); + static value_type Equal(value_type v1, value_type v2); + static value_type NotEqual(value_type v1, value_type v2); + static value_type Not(value_type v1); + + static bool IsHexVal(const char_type *a_szExpr, int &a_iPos, value_type &a_iVal); + static bool IsBinVal(const char_type *a_szExpr, int &a_iPos, value_type &a_iVal); + static bool IsVal(const char_type *a_szExpr, int &a_iPos, value_type &a_iVal); + +public: + ParserInt(); + + virtual void InitFun(); + virtual void InitOprt(); + virtual void InitConst(); + virtual void InitCharSets(); +}; + +} // namespace mu + +#endif + diff --git a/muparser/muParserStack.h b/muparser/muParserStack.h new file mode 100644 index 0000000..e035582 --- /dev/null +++ b/muparser/muParserStack.h @@ -0,0 +1,120 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2006 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef MU_PARSER_STACK_H +#define MU_PARSER_STACK_H + +#include +#include +#include +#include + +#include "muParserError.h" +#include "muParserToken.h" + + +namespace mu +{ + + /** \brief Parser stack implementation. + + Stack implementation based on a std::stack. The behaviour of pop() had been + slightly changed in order to get an error code if the stack is empty. + The stack is used within the Parser both as a value stack and as an operator stack. + + \author (C) 2004, 2005 Ingo Berg + */ + template + class ParserStack + { + private: + /** \brief Type of the underlying stack implementation. */ + typedef std::stack > impl_type; + impl_type m_Stack; + + public: + + //--------------------------------------------------------------------------- + ParserStack() + :m_Stack() + {} + + //--------------------------------------------------------------------------- + virtual ~ParserStack() + {} + + //--------------------------------------------------------------------------- + /** \brief Pop a value from the stack. + + Unlike the standard implementation this function will return the value that + is going to be taken from the stack. + + \throw ParserException in case the stack is empty. + \sa pop(int &a_iErrc) + */ + TValueType pop() + { + if (empty()) + throw ParserError( _T("stack is empty.") ); + + TValueType el = top(); + m_Stack.pop(); + return el; + } + + /** \brief Push an object into the stack. + + \param a_Val object to push into the stack. + \throw nothrow + */ + void push(const TValueType& a_Val) + { + m_Stack.push(a_Val); + } + + /** \brief Return the number of stored elements. */ + unsigned size() const + { + return (unsigned)m_Stack.size(); + } + + /** \brief Returns true if stack is empty false otherwise. */ + bool empty() const + { + return m_Stack.size()==0; + } + + /** \brief Return reference to the top object in the stack. + + The top object is the one pushed most recently. + */ + TValueType& top() + { + return m_Stack.top(); + } + }; +} // namespace MathUtils + +#endif diff --git a/muparser/muParserTest.cpp b/muparser/muParserTest.cpp new file mode 100644 index 0000000..eed6cc4 --- /dev/null +++ b/muparser/muParserTest.cpp @@ -0,0 +1,1125 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2006 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "muParserTest.h" + +#include +#include +#include + +#define PARSER_CONST_PI 3.141592653589793238462643 +#define PARSER_CONST_E 2.718281828459045235360287 + +using namespace std; + + +namespace mu +{ + namespace Test + { + int ParserTester::c_iCount = 0; + + //--------------------------------------------------------------------------- + ParserTester::ParserTester() + :m_vTestFun() + { + AddTest(&ParserTester::TestNames); + AddTest(&ParserTester::TestSyntax); + AddTest(&ParserTester::TestPostFix); + AddTest(&ParserTester::TestInfixOprt); + AddTest(&ParserTester::TestVarConst); + AddTest(&ParserTester::TestVolatile); + AddTest(&ParserTester::TestMultiArg); + AddTest(&ParserTester::TestFormula); + AddTest(&ParserTester::TestInterface); + AddTest(&ParserTester::TestBinOprt); + AddTest(&ParserTester::TestException); + AddTest(&ParserTester::TestStrArg); + + ParserTester::c_iCount = 0; + } + + //--------------------------------------------------------------------------- + int ParserTester::TestInterface() + { + int iStat = 0; + mu::console() << _T("testing member functions..."); + + // Test RemoveVar + value_type afVal[3] = {1,2,3}; + Parser p; + + try + { + p.DefineVar( _T("a"), &afVal[0]); + p.DefineVar( _T("b"), &afVal[1]); + p.DefineVar( _T("c"), &afVal[2]); + p.SetExpr( _T("a+b+c") ); + p.Eval(); + } + catch(...) + { + iStat += 1; // this is not supposed to happen + } + + try + { + p.RemoveVar( _T("c") ); + p.Eval(); + iStat += 1; // not supposed to reach this, nonexisting variable "c" deleted... + } + catch(...) + { + // failure is expected... + } + + if (iStat==0) + mu::console() << _T("passed") << endl; + else + mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; + + return iStat; + } + + //--------------------------------------------------------------------------- + int ParserTester::TestStrArg() + { + int iStat = 0; + mu::console() << _T("testing string arguments..."); + + iStat += EqnTest(_T("valueof(\"aaa\")+valueof(\"bbb\") "), 246, true); + iStat += EqnTest(_T("2*(valueof(\"aaa\")-23)+valueof(\"bbb\")"), 323, true); + // use in expressions with variables + iStat += EqnTest(_T("a*(atof(\"10\")-b)"), 8, true); + iStat += EqnTest(_T("a-(atof(\"10\")*b)"), -19, true); + // string + numeric arguments + iStat += EqnTest(_T("strfun1(\"100\")"), 100, true); + iStat += EqnTest(_T("strfun2(\"100\",1)"), 101, true); + iStat += EqnTest(_T("strfun3(\"99\",1,2)"), 102, true); + + if (iStat==0) + mu::console() << _T("passed") << endl; + else + mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; + + return iStat; + } + + //--------------------------------------------------------------------------- + int ParserTester::TestBinOprt() + { + int iStat = 0; + mu::console() << _T("testing binary operators..."); + + // built in operators + // xor operator + iStat += EqnTest(_T("1 xor 2"), 3, true); + iStat += EqnTest(_T("a xor b"), 3, true); // with a=1 and b=2 + iStat += EqnTest(_T("1 xor 2 xor 3"), 0, true); + iStat += EqnTest(_T("a xor b xor 3"), 0, true); // with a=1 and b=2 + iStat += EqnTest(_T("a xor b xor c"), 0, true); // with a=1 and b=2 + iStat += EqnTest(_T("(1 xor 2) xor 3"), 0, true); + iStat += EqnTest(_T("(a xor b) xor c"), 0, true); // with a=1 and b=2 + iStat += EqnTest(_T("(a) xor (b) xor c"), 0, true); // with a=1 and b=2 + iStat += EqnTest(_T("1 or 2"), 3, true); + iStat += EqnTest(_T("a or b"), 3, true); // with a=1 and b=2 + + // Assignement operator + iStat += EqnTest(_T("a = b"), 2, true); + iStat += EqnTest(_T("a = sin(b)"), 0.909297, true); + iStat += EqnTest(_T("a = 1+sin(b)"), 1.909297, true); + + // Test user defined binary operators + iStat += EqnTestInt(_T("1 | 2"), 3, true); + iStat += EqnTestInt(_T("1 || 2"), 1, true); + iStat += EqnTestInt(_T("123 & 456"), 72, true); + iStat += EqnTestInt(_T("(123 & 456) % 10"), 2, true); + iStat += EqnTestInt(_T("1 && 0"), 0, true); + iStat += EqnTestInt(_T("123 && 456"), 1, true); + iStat += EqnTestInt(_T("1 << 3"), 8, true); + iStat += EqnTestInt(_T("8 >> 3"), 1, true); + iStat += EqnTestInt(_T("10 ^ 10"), 0, true); + iStat += EqnTestInt(_T("10 * 10 ^ 99"), 7, true); + iStat += EqnTestInt(_T("9 / 4"), 2, true); + iStat += EqnTestInt(_T("9 % 4"), 1, true); + iStat += EqnTestInt(_T("if(5%2,1,0)"), 1, true); + iStat += EqnTestInt(_T("if(4%2,1,0)"), 0, true); + iStat += EqnTestInt(_T("-10+1"), -9, true); + iStat += EqnTestInt(_T("1+2*3"), 7, true); + iStat += EqnTestInt(_T("const1 != const2"), 1, true); + iStat += EqnTestInt(_T("const1 != const2"), 0, false); + iStat += EqnTestInt(_T("const1 == const2"), 0, true); + iStat += EqnTestInt(_T("const1 == 1"), 1, true); + iStat += EqnTestInt(_T("10*(const1 == 1)"), 10, true); + iStat += EqnTestInt(_T("2*(const1 | const2)"), 6, true); + iStat += EqnTestInt(_T("2*(const1 | const2)"), 7, false); + iStat += EqnTestInt(_T("const1 < const2"), 1, true); + iStat += EqnTestInt(_T("const2 > const1"), 1, true); + iStat += EqnTestInt(_T("const1 <= 1"), 1, true); + iStat += EqnTestInt(_T("const2 >= 2"), 1, true); + iStat += EqnTestInt(_T("2*(const1 + const2)"), 6, true); + iStat += EqnTestInt(_T("2*(const1 - const2)"), -2, true); + + iStat += EqnTestInt(_T("a != b"), 1, true); + iStat += EqnTestInt(_T("a != b"), 0, false); + iStat += EqnTestInt(_T("a == b"), 0, true); + iStat += EqnTestInt(_T("a == 1"), 1, true); + iStat += EqnTestInt(_T("10*(a == 1)"), 10, true); + iStat += EqnTestInt(_T("2*(a | b)"), 6, true); + iStat += EqnTestInt(_T("2*(a | b)"), 7, false); + iStat += EqnTestInt(_T("a < b"), 1, true); + iStat += EqnTestInt(_T("b > a"), 1, true); + iStat += EqnTestInt(_T("a <= 1"), 1, true); + iStat += EqnTestInt(_T("b >= 2"), 1, true); + iStat += EqnTestInt(_T("2*(a + b)"), 6, true); + iStat += EqnTestInt(_T("2*(a - b)"), -2, true); + iStat += EqnTestInt(_T("a + (a << b)"), 5, true); + iStat += EqnTestInt(_T("-2^2"), -4, true); +// incorrect: '^' is yor here, not power +// iStat += EqnTestInt("-(1+2)^2", -9, true); +// iStat += EqnTestInt("-1^3", -1, true); + + // Test precedence + // a=1, b=2, c=3 + iStat += EqnTestInt(_T("a + b * c"), 7, true); + iStat += EqnTestInt(_T("a * b + c"), 5, true); + iStat += EqnTestInt(_T("a10"), 0, true); + iStat += EqnTestInt(_T("a"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("?<"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("**"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("xor"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("and"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("or"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("not"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("!"), f1of1) + // Binary operator + // The following must fail with builtin operators activated + // p.EnableBuiltInOp(true); -> this is the default + PARSER_THROWCHECK(Oprt, false, _T("+"), f1of2) + PARSER_THROWCHECK(Oprt, false, _T("-"), f1of2) + PARSER_THROWCHECK(Oprt, false, _T("*"), f1of2) + PARSER_THROWCHECK(Oprt, false, _T("/"), f1of2) + // without activated built in operators it should work + p.EnableBuiltInOprt(false); + PARSER_THROWCHECK(Oprt, true, _T("+"), f1of2) + PARSER_THROWCHECK(Oprt, true, _T("-"), f1of2) + PARSER_THROWCHECK(Oprt, true, _T("*"), f1of2) + PARSER_THROWCHECK(Oprt, true, _T("/"), f1of2) + #undef PARSER_THROWCHECK + + if (iStat==0) + mu::console() << _T("passed") << endl; + else + mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; + + return iStat; + } + + //--------------------------------------------------------------------------- + int ParserTester::TestSyntax() + { + int iStat = 0; + mu::console() << _T("testing syntax engine..."); + + iStat += EqnTest(_T("(1+ 2*a)"), 3, true); // Spaces within formula + iStat += EqnTest(_T("(2+"), 0, false); // missing closing bracket + iStat += EqnTest(_T("2++4"), 0, false); // unexpected operator + iStat += EqnTest(_T("2+-4"), 0, false); // unexpected operator + iStat += EqnTest(_T("(2+)"), 0, false); // unexpected closing bracket + iStat += EqnTest(_T("--2"), 0, false); // double sign + iStat += EqnTest(_T("ksdfj"), 0, false); // unknown token + iStat += EqnTest(_T("()"), 0, false); // empty bracket + iStat += EqnTest(_T("sin(cos)"), 0, false); // unexpected function + iStat += EqnTest(_T("5t6"), 0, false); // unknown token + iStat += EqnTest(_T("5 t 6"), 0, false); // unknown token + iStat += EqnTest(_T("8*"), 0, false); // unexpected end of formula + iStat += EqnTest(_T(",3"), 0, false); // unexpected comma + iStat += EqnTest(_T("3,5"), 0, false); // unexpected comma + iStat += EqnTest(_T("sin(8,8)"), 0, false); // too many function args + iStat += EqnTest(_T("(7,8)"), 0, false); // too many function args + iStat += EqnTest(_T("sin)"), 0, false); // unexpected closing bracket + iStat += EqnTest(_T("a)"), 0, false); // unexpected closing bracket + iStat += EqnTest(_T("pi)"), 0, false); // unexpected closing bracket + iStat += EqnTest(_T("sin(())"), 0, false); // unexpected closing bracket + iStat += EqnTest(_T("sin()"), 0, false); // unexpected closing bracket + + if (iStat==0) + mu::console() << _T("passed") << endl; + else + mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; + + return iStat; + } + + //--------------------------------------------------------------------------- + int ParserTester::TestVarConst() + { + int iStat = 0; + mu::console() << _T("testing variable/constant name recognition..."); + + // distinguish constants with same basename + iStat += EqnTest( _T("const"), 1, true); + iStat += EqnTest( _T("const1"), 2, true); + iStat += EqnTest( _T("const2"), 3, true); + iStat += EqnTest( _T("2*const"), 2, true); + iStat += EqnTest( _T("2*const1"), 4, true); + iStat += EqnTest( _T("2*const2"), 6, true); + iStat += EqnTest( _T("2*const+1"), 3, true); + iStat += EqnTest( _T("2*const1+1"), 5, true); + iStat += EqnTest( _T("2*const2+1"), 7, true); + iStat += EqnTest( _T("const"), 0, false); + iStat += EqnTest( _T("const1"), 0, false); + iStat += EqnTest( _T("const2"), 0, false); + + // distinguish variables with same basename + iStat += EqnTest( _T("a"), 1, true); + iStat += EqnTest( _T("aa"), 2, true); + iStat += EqnTest( _T("2*a"), 2, true); + iStat += EqnTest( _T("2*aa"), 4, true); + iStat += EqnTest( _T("2*a-1"), 1, true); + iStat += EqnTest( _T("2*aa-1"), 3, true); + + // Finally test querying of used variables + try + { + int idx; + mu::Parser p; + mu::value_type vVarVal[] = { 1, 2, 3, 4, 5}; + p.DefineVar( _T("a"), &vVarVal[0]); + p.DefineVar( _T("b"), &vVarVal[1]); + p.DefineVar( _T("c"), &vVarVal[2]); + p.DefineVar( _T("d"), &vVarVal[3]); + p.DefineVar( _T("e"), &vVarVal[4]); + + // Test lookup of defined variables + // 4 used variables + p.SetExpr( _T("a+b+c+d") ); + mu::varmap_type UsedVar = p.GetUsedVar(); + int iCount = (int)UsedVar.size(); + if (iCount!=4) throw false; + + mu::varmap_type::const_iterator item = UsedVar.begin(); + for (idx=0; item!=UsedVar.end(); ++item) + { + if (&vVarVal[idx++]!=item->second) + throw false; + } + + // Test lookup of undefined variables + p.SetExpr( _T("undef1+undef2+undef3") ); + UsedVar = p.GetUsedVar(); + iCount = (int)UsedVar.size(); + if (iCount!=3) throw false; + + for (item = UsedVar.begin(); item!=UsedVar.end(); ++item) + { + if (item->second!=0) + throw false; // all pointers to undefined variables must be null + } + + // 1 used variables + p.SetExpr( _T("a+b") ); + UsedVar = p.GetUsedVar(); + iCount = (int)UsedVar.size(); + if (iCount!=2) throw false; + item = UsedVar.begin(); + for (idx=0; item!=UsedVar.end(); ++item) + if (&vVarVal[idx++]!=item->second) throw false; + + } + catch(...) + { + iStat += 1; + } + + if (iStat==0) + mu::console() << _T("passed") << endl; + else + mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; + + return iStat; + } + + //--------------------------------------------------------------------------- + int ParserTester::TestMultiArg() + { + int iStat = 0; + mu::console() << _T("testing multiarg functions..."); + + // picking the right argument + iStat += EqnTest( _T("f1of1(1)"), 1, true); + iStat += EqnTest( _T("f1of2(1, 2)"), 1, true); + iStat += EqnTest( _T("f2of2(1, 2)"), 2, true); + iStat += EqnTest( _T("f1of3(1, 2, 3)"), 1, true); + iStat += EqnTest( _T("f2of3(1, 2, 3)"), 2, true); + iStat += EqnTest( _T("f3of3(1, 2, 3)"), 3, true); + iStat += EqnTest( _T("f1of4(1, 2, 3, 4)"), 1, true); + iStat += EqnTest( _T("f2of4(1, 2, 3, 4)"), 2, true); + iStat += EqnTest( _T("f3of4(1, 2, 3, 4)"), 3, true); + iStat += EqnTest( _T("f4of4(1, 2, 3, 4)"), 4, true); + iStat += EqnTest( _T("f1of5(1, 2, 3, 4, 5)"), 1, true); + iStat += EqnTest( _T("f2of5(1, 2, 3, 4, 5)"), 2, true); + iStat += EqnTest( _T("f3of5(1, 2, 3, 4, 5)"), 3, true); + iStat += EqnTest( _T("f4of5(1, 2, 3, 4, 5)"), 4, true); + iStat += EqnTest( _T("f5of5(1, 2, 3, 4, 5)"), 5, true); + // Too few arguments / Too many arguments + iStat += EqnTest( _T("f1of1(1,2)"), 0, false); + iStat += EqnTest( _T("f1of1()"), 0, false); + iStat += EqnTest( _T("f1of2(1, 2, 3)"), 0, false); + iStat += EqnTest( _T("f1of2(1)"), 0, false); + iStat += EqnTest( _T("f1of3(1, 2, 3, 4)"), 0, false); + iStat += EqnTest( _T("f1of3(1)"), 0, false); + iStat += EqnTest( _T("f1of4(1, 2, 3, 4, 5)"), 0, false); + iStat += EqnTest( _T("f1of4(1)"), 0, false); + iStat += EqnTest( _T("(1,2,3)"), 0, false); + iStat += EqnTest( _T("1,2,3"), 0, false); + iStat += EqnTest( _T("(1*a,2,3)"), 0, false); + iStat += EqnTest( _T("1,2*a,3"), 0, false); + + // correct calculation of arguments + iStat += EqnTest( _T("min(a, 1)"), 1, true); + iStat += EqnTest( _T("min(3*2, 1)"), 1, true); + iStat += EqnTest( _T("min(3*2, 1)"), 6, false); + // correct calculation of arguments + iStat += EqnTest( _T("min(3*a+1, 1)"), 1, true); + iStat += EqnTest( _T("max(3*a+1, 1)"), 4, true); + iStat += EqnTest( _T("max(3*a+1, 1)*2"), 8, true); + iStat += EqnTest( _T("2*max(3*a+1, 1)+2"), 10, true); + + // functions with Variable argument count + iStat += EqnTest( _T("sum(1,2,3)"), 6, true); + iStat += EqnTest( _T("2*sum(1,2,3)"), 12, true); + iStat += EqnTest( _T("2*sum(1,2,3)+2"), 14, true); + iStat += EqnTest( _T("2*sum(-1,2,3)+2"), 10, true); + iStat += EqnTest( _T("2*sum(-1,2,-(-a))+2"), 6, true); + iStat += EqnTest( _T("2*sum(-1,10,-a)+2"), 18, true); + iStat += EqnTest( _T("2*sum(1,2,3)*2"), 24, true); + iStat += EqnTest( _T("sum(1,-max(1,2),3)*2"), 4, true); + iStat += EqnTest( _T("sum(1*3, 4, a+2)"), 10, true); + iStat += EqnTest( _T("sum(1*3, 2*sum(1,2,2), a+2)"), 16, true); + iStat += EqnTest( _T("sum(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2)"), 24, true); + + // some failures + iStat += EqnTest( _T("sum()"), 0, false); + iStat += EqnTest( _T("sum(,)"), 0, false); + iStat += EqnTest( _T("sum(1,2,)"), 0, false); + iStat += EqnTest( _T("sum(,1,2)"), 0, false); + + if (iStat==0) + mu::console() << _T("passed") << endl; + else + mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; + + return iStat; + } + + + //--------------------------------------------------------------------------- + int ParserTester::TestInfixOprt() + { + int iStat = 0; + mu::console() << "testing infix operators..."; + + iStat += EqnTest( _T("-1"), -1, true); + iStat += EqnTest( _T("-(-1)"), 1, true); + iStat += EqnTest( _T("-(-1)*2"), 2, true); + iStat += EqnTest( _T("-(-2)*sqrt(4)"), 4, true); + iStat += EqnTest( _T("-a"), -1, true); + iStat += EqnTest( _T("-(a)"), -1, true); + iStat += EqnTest( _T("-(-a)"), 1, true); + iStat += EqnTest( _T("-(-a)*2"), 2, true); + iStat += EqnTest( _T("-(8)"), -8, true); + iStat += EqnTest( _T("-8"), -8, true); + iStat += EqnTest( _T("-(2+1)"), -3, true); + iStat += EqnTest( _T("-(f1of1(1+2*3)+1*2)"), -9, true); + iStat += EqnTest( _T("-(-f1of1(1+2*3)+1*2)"), 5, true); + iStat += EqnTest( _T("-sin(8)"), -0.989358, true); + iStat += EqnTest( _T("3-(-a)"), 4, true); + iStat += EqnTest( _T("3--a"), 4, true); + + // Postfix / infix priorities + iStat += EqnTest( _T("~2#"), 8, true); + iStat += EqnTest( _T("~f1of1(2)#"), 8, true); + iStat += EqnTest( _T("~(b)#"), 8, true); + iStat += EqnTest( _T("(~b)#"), 12, true); + iStat += EqnTest( _T("~(2#)"), 8, true); + iStat += EqnTest( _T("~(f1of1(2)#)"), 8, true); + // + iStat += EqnTest( _T("-2^2"),-4, true); + iStat += EqnTest( _T("-(a+b)^2"),-9, true); + iStat += EqnTest( _T("(-3)^2"),9, true); + iStat += EqnTest( _T("-(-2^2)"),4, true); + iStat += EqnTest( _T("3+-3^2"),-6, true); + // The following assumes use of sqr as postfix operator ("?") together + // tiwth a sign operator of low priority: + iStat += EqnTest( _T("-2?"), -4, true); + iStat += EqnTest( _T("-(1+1)?"),-4, true); + iStat += EqnTest( _T("2+-(1+1)?"),-2, true); + iStat += EqnTest( _T("2+-2?"), -2, true); + // This is the classic behaviour of the infix sign operator (here: "$") which is + // now deprecated: + iStat += EqnTest( _T("$2^2"),4, true); + iStat += EqnTest( _T("$(a+b)^2"),9, true); + iStat += EqnTest( _T("($3)^2"),9, true); + iStat += EqnTest( _T("$($2^2)"),-4, true); + iStat += EqnTest( _T("3+$3^2"),12, true); + + if (iStat==0) + mu::console() << _T("passed") << endl; + else + mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; + + return iStat; + } + + + //--------------------------------------------------------------------------- + int ParserTester::TestPostFix() + { + int iStat = 0; + mu::console() << _T("testing postfix operators..."); + + // application + iStat += EqnTest( _T("3m+5"), 5.003, true); + iStat += EqnTest( _T("1000m"), 1, true); + iStat += EqnTest( _T("1000 m"), 1, true); + iStat += EqnTest( _T("(a)m"), 1e-3, true); + iStat += EqnTest( _T("-(a)m"), -1e-3, true); + iStat += EqnTest( _T("-2m"), -2e-3, true); + iStat += EqnTest( _T("f1of1(1000)m"), 1, true); + iStat += EqnTest( _T("-f1of1(1000)m"), -1, true); + iStat += EqnTest( _T("-f1of1(-1000)m"), 1, true); + iStat += EqnTest( _T("f4of4(0,0,0,1000)m"), 1, true); + iStat += EqnTest( _T("2+(a*1000)m"), 3, true); + // some incorrect results + iStat += EqnTest( _T("1000m"), 0.1, false); + iStat += EqnTest( _T("(a)m"), 2, false); + // failure due to syntax checking + iStat += EqnTest( _T("a m"), 0, false); + iStat += EqnTest( _T("4 + m"), 0, false); + iStat += EqnTest( _T("m4"), 0, false); + iStat += EqnTest( _T("sin(m)"), 0, false); + iStat += EqnTest( _T("m m"), 0, false); + iStat += EqnTest( _T("m(8)"), 0, false); + iStat += EqnTest( _T("4,m"), 0, false); + iStat += EqnTest( _T("-m"), 0, false); + iStat += EqnTest( _T("2(-m)"), 0, false); + iStat += EqnTest( _T("2(m)"), 0, false); + + if (iStat==0) + mu::console() << _T("passed") << endl; + else + mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; + + return iStat; + } + + //--------------------------------------------------------------------------- + /** \brief Test volatile (nonoptimizeable functions). */ + int ParserTester::TestVolatile() + { + int iStat = 0; + mu::console() << "testing volatile/nonvolatile functions..."; + + // First test with volatile flag turned on + try + { + mu::Parser p; + p.DefineFun( _T("rnd"), Rnd, false); + p.DefineFun( _T("valueof"), RndWithString, false); + + // 1st test, compare results from sucessive calculations + p.SetExpr( _T("3+rnd(8)") ); + if (p.Eval()==p.Eval()) iStat += 1; + + // 2nd test, force bytecode creation, compare two results both + // calculated from bytecode + p.SetExpr( _T("3+rnd(8)") ); + p.Eval(); //<- Force bytecode creation + if (p.Eval()==p.Eval()) iStat += 1; + + p.SetExpr( _T("3*rnd(8)+3") ); + p.Eval(); //<- Force bytecode creation + if (p.Eval()==p.Eval()) iStat += 1; + + p.SetExpr( _T("10+3*sin(rnd(8))-1") ); + p.Eval(); //<- Force bytecode creation + if (p.Eval()==p.Eval()) iStat += 1; + + p.SetExpr( _T("3+rnd(rnd(8))*2") ); + p.Eval(); //<- Force bytecode creation + if (p.Eval()==p.Eval()) iStat += 1; + + p.SetExpr( _T("valueof(\"Das ist ein Test\")") ); + p.Eval(); //<- Force bytecode creation + if (p.Eval()==p.Eval()) iStat += 1; + } + catch(Parser::exception_type &e) + { + mu::console() << _T("\n ") << e.GetExpr() << _T(" : ") << e.GetMsg(); + iStat += 1; + } + + // Second test with volatile flag turned off + try + { + mu::Parser p; + p.DefineFun( _T("rnd"), Rnd); + p.DefineFun( _T("valueof"), RndWithString); + + // compare string parsing with bytecode + p.SetExpr( _T("3+rnd(8)") ); + if (p.Eval()!=p.Eval()) iStat += 1; + + p.SetExpr( _T("3+rnd(8)") ); + p.Eval(); //<- Force bytecode creation + if (p.Eval()!=p.Eval()) iStat += 1; + + p.SetExpr( _T("3*rnd(8)+3") ); + p.Eval(); //<- Force bytecode creation + if (p.Eval()!=p.Eval()) iStat += 1; + + p.SetExpr( _T("10+3*sin(rnd(8))-1") ); + p.Eval(); //<- Force bytecode creation + if (p.Eval()!=p.Eval()) iStat += 1; + + p.SetExpr( _T("3+rnd(rnd(8))*2") ); + p.Eval(); //<- Force bytecode creation + if (p.Eval()!=p.Eval()) iStat += 1; + } + catch(Parser::exception_type &e) + { + mu::console() << _T("\n ") << e.GetExpr() << _T(" : ") << e.GetMsg(); + iStat += 1; + } + + if (iStat==0) + mu::console() << _T("passed") << endl; + else + mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; + + return iStat; + } + + //--------------------------------------------------------------------------- + int ParserTester::TestFormula() + { + int iStat = 0; + mu::console() << _T("testing sample formulas..."); + + // operator precedencs + iStat += EqnTest( _T("1+2-3*4/5^6"), 2.99923, true); + iStat += EqnTest( _T("1^2/3*4-5+6"), 2.3333, true); + iStat += EqnTest( _T("1+2*3"), 7, true); + iStat += EqnTest( _T("1+2*3"), 7, true); + iStat += EqnTest( _T("(1+2)*3"), 9, true); + iStat += EqnTest( _T("(1+2)*(-3)"), -9, true); + iStat += EqnTest( _T("2/4"), 0.5, true); + + iStat += EqnTest( _T("exp(ln(7))"), 7, true); + iStat += EqnTest( _T("e^ln(7)"), 7, true); + iStat += EqnTest( _T("e^(ln(7))"), 7, true); + iStat += EqnTest( _T("(e^(ln(7)))"), 7, true); + iStat += EqnTest( _T("1-(e^(ln(7)))"), -6, true); + iStat += EqnTest( _T("2*(e^(ln(7)))"), 14, true); + iStat += EqnTest( _T("10^log(5)"), 5, true); + iStat += EqnTest( _T("10^log10(5)"), 5, true); + iStat += EqnTest( _T("2^log2(4)"), 4, true); + iStat += EqnTest( _T("-(sin(0)+1)"), -1, true); + iStat += EqnTest( _T("-(2^1.1)"), -2.14354692, true); + + iStat += EqnTest( _T("(cos(2.41)/b)"), -0.372056, true); + +#if !defined(_UNICODE) + // I can't translate the following two tests to unicode without loosing + // readability. + + // long formula (Reference: Matlab) + iStat += EqnTest( + "(((-9))-e/(((((((pi-(((-7)+(-3)/4/e))))/(((-5))-2)-((pi+(-0))*(sqrt((e+e))*(-8))*(((-pi)+(-pi)-(-9)*(6*5))" + "/(-e)-e))/2)/((((sqrt(2/(-e)+6)-(4-2))+((5/(-2))/(1*(-pi)+3))/8)*pi*((pi/((-2)/(-6)*1*(-1))*(-6)+(-e)))))/" + "((e+(-2)+(-e)*((((-3)*9+(-e)))+(-9)))))))-((((e-7+(((5/pi-(3/1+pi)))))/e)/(-5))/(sqrt((((((1+(-7))))+((((-" + "e)*(-e)))-8))*(-5)/((-e)))*(-6)-((((((-2)-(-9)-(-e)-1)/3))))/(sqrt((8+(e-((-6))+(9*(-9))))*(((3+2-8))*(7+6" + "+(-5))+((0/(-e)*(-pi))+7)))+(((((-e)/e/e)+((-6)*5)*e+(3+(-5)/pi))))+pi))/sqrt((((9))+((((pi))-8+2))+pi))/e" + "*4)*((-5)/(((-pi))*(sqrt(e)))))-(((((((-e)*(e)-pi))/4+(pi)*(-9)))))))+(-pi)", -12.23016549, true); + + // long formula (Reference: Matlab) + iStat += EqnTest( + "(atan(sin((((((((((((((((pi/cos((a/((((0.53-b)-pi)*e)/b))))+2.51)+a)-0.54)/0.98)+b)*b)+e)/a)+b)+a)+b)+pi)/e" + ")+a)))*2.77)", -2.16995656, true); +#endif + + // long formula (Reference: Matlab) + iStat += EqnTest( _T("1+2-3*4/5^6*(2*(1-5+(3*7^9)*(4+6*7-3)))+12"), -7995810.09926, true); + + if (iStat==0) + mu::console() << _T("passed") << endl; + else + mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; + + return iStat; + } + + + //--------------------------------------------------------------------------- + int ParserTester::TestException() + { + int iStat = 0; + mu::console() << _T("testing error codes..."); + + iStat += ThrowTest(_T("3+"), ecUNEXPECTED_EOF); + iStat += ThrowTest(_T("3+)"), ecUNEXPECTED_PARENS); + iStat += ThrowTest(_T("sin(3,4)"), ecTOO_MANY_PARAMS); + iStat += ThrowTest(_T("3,4"), ecUNEXPECTED_COMMA); + iStat += ThrowTest(_T("if(3)"), ecTOO_FEW_PARAMS); + iStat += ThrowTest(_T("(1+2"), ecMISSING_PARENS); + iStat += ThrowTest(_T("sin(3)3"), ecUNEXPECTED_VAL); + iStat += ThrowTest(_T("sin(3)xyz"), ecUNASSIGNABLE_TOKEN); + iStat += ThrowTest(_T("sin(3)cos(3)"), ecUNEXPECTED_FUN); + + // String function related + iStat += ThrowTest( _T("valueof(\"xxx\")"), 999, false); + iStat += ThrowTest( _T("valueof()"), ecUNEXPECTED_PARENS); + iStat += ThrowTest( _T("1+valueof(\"abc\""), ecMISSING_PARENS); + iStat += ThrowTest( _T("valueof(\"abc\""), ecMISSING_PARENS); + iStat += ThrowTest( _T("valueof(\"abc"), ecUNTERMINATED_STRING); + iStat += ThrowTest( _T("valueof(\"abc\",3)"), ecTOO_MANY_PARAMS); + iStat += ThrowTest( _T("valueof(3)"), ecSTRING_EXPECTED); + iStat += ThrowTest( _T("sin(\"abc\")"), ecVAL_EXPECTED); + iStat += ThrowTest( _T("valueof(\"\\\"abc\\\"\")"), 999, false); + iStat += ThrowTest( _T("\"hello world\""), ecSTR_RESULT); + iStat += ThrowTest( _T("(\"hello world\")"), ecSTR_RESULT); + iStat += ThrowTest( _T("\"abcd\"+100"), ecOPRT_TYPE_CONFLICT); + iStat += ThrowTest( _T("\"a\"+\"b\""), ecOPRT_TYPE_CONFLICT); + iStat += ThrowTest( _T("strfun1(\"100\",3)"), ecTOO_MANY_PARAMS); + iStat += ThrowTest( _T("strfun2(\"100\",3,5)"), ecTOO_MANY_PARAMS); + iStat += ThrowTest( _T("strfun3(\"100\",3,5,6)"), ecTOO_MANY_PARAMS); + iStat += ThrowTest( _T("strfun2(\"100\")"), ecTOO_FEW_PARAMS); + iStat += ThrowTest( _T("strfun3(\"100\",6)"), ecTOO_FEW_PARAMS); + iStat += ThrowTest( _T("strfun2(1,1)"), ecSTRING_EXPECTED); + iStat += ThrowTest( _T("strfun2(a,1)"), ecSTRING_EXPECTED); + iStat += ThrowTest( _T("strfun2(1,1,1)"), ecTOO_MANY_PARAMS); + iStat += ThrowTest( _T("strfun2(a,1,1)"), ecTOO_MANY_PARAMS); + iStat += ThrowTest( _T("strfun3(1,2,3)"), ecSTRING_EXPECTED); + iStat += ThrowTest( _T("strfun3(1, \"100\",3)"), ecSTRING_EXPECTED); + iStat += ThrowTest( _T("strfun3(\"1\", \"100\",3)"), ecVAL_EXPECTED); + iStat += ThrowTest( _T("strfun3(\"1\", 3, \"100\")"), ecVAL_EXPECTED); + iStat += ThrowTest( _T("strfun3(\"1\", \"100\", \"100\", \"100\")"), ecTOO_MANY_PARAMS); + + // assignement operator +// iStat += ThrowTest("maxspec=0", 0, false); + iStat += ThrowTest( _T("3=4"), ecUNEXPECTED_OPERATOR); + iStat += ThrowTest( _T("sin(8)=4"), ecUNEXPECTED_OPERATOR); + iStat += ThrowTest( _T("\"test\"=a"), ecUNEXPECTED_OPERATOR); + iStat += ThrowTest( _T("sin=9"), ecUNEXPECTED_OPERATOR); + iStat += ThrowTest( _T("(8)=5"), ecUNEXPECTED_OPERATOR); + iStat += ThrowTest( _T("(a)=5"), ecUNEXPECTED_OPERATOR); + iStat += ThrowTest( _T("a=\"tttt\""), ecOPRT_TYPE_CONFLICT); + + if (iStat==0) + mu::console() << _T("passed") << endl; + else + mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; + + return iStat; + } + + + //--------------------------------------------------------------------------- + void ParserTester::AddTest(testfun_type a_pFun) + { + m_vTestFun.push_back(a_pFun); + } + + //--------------------------------------------------------------------------- + void ParserTester::Run() + { + int iStat = 0; + try + { + for (int i=0; i<(int)m_vTestFun.size(); ++i) + iStat += (this->*m_vTestFun[i])(); + } + catch(Parser::exception_type &e) + { + mu::console() << "\n" << e.GetMsg() << endl; + mu::console() << e.GetToken() << endl; + Abort(); + } + catch(std::exception &e) + { + mu::console() << e.what() << endl; + Abort(); + } + catch(...) + { + mu::console() << "Internal error"; + Abort(); + } + + if (iStat==0) + { + mu::console() << "Test passed (" << ParserTester::c_iCount << " expressions)" << endl; + } + else + { + mu::console() << "Test failed with " << iStat + << " errors (" << ParserTester::c_iCount + << " expressions)" << endl; + } + ParserTester::c_iCount = 0; + } + + + //--------------------------------------------------------------------------- + int ParserTester::ThrowTest(const string_type &a_str, int a_iErrc, bool a_bFail) + { + ParserTester::c_iCount++; + + try + { + double fVal=0; + Parser p; + + p.DefineVar( _T("a"), &fVal); + p.DefineFun( _T("valueof"), ValueOf); + p.DefineFun( _T("strfun1"), StrFun1); + p.DefineFun( _T("strfun2"), StrFun2); + p.DefineFun( _T("strfun3"), StrFun3); + p.SetExpr(a_str); + p.Eval(); + } + catch(Parser::exception_type &e) + { + // output the formula in case of an failed test + if (a_bFail==true && a_iErrc!=e.GetCode() ) + { + mu::console() << _T("\n ") + << _T("Expression: ") << a_str + << _T(" Code:") << e.GetCode() + << _T(" Expected:") << a_iErrc; + } + + return (a_iErrc==e.GetCode()) ? 0 : 1; + } + + // if a_bFail==false no exception is expected + bool bRet((a_bFail==false) ? 0 : 1); + if (bRet==1) + { + mu::console() << _T("\n ") + << _T("Expression: ") << a_str + << _T(" did evaluate; Expected error:") << a_iErrc; + } + + return bRet; + } + + //--------------------------------------------------------------------------- + /** \brief Evaluate a tet expression. + + \return 1 in case of a failure, 0 otherwise. + */ + int ParserTester::EqnTest(const string_type &a_str, double a_fRes, bool a_fPass) + { + ParserTester::c_iCount++; + int iRet(0); + + try + { + Parser *p1, p2, p3; // three parser objects + // they will be used for testing copy and assihnment operators + // p1 is a pointer since i'm going to delete it in order to test if + // parsers after copy construction still refer to members of it. + // !! If this is the case this function will crash !! + + p1 = new mu::Parser(); + // Add constants + p1->DefineConst( _T("pi"), (value_type)PARSER_CONST_PI); + p1->DefineConst( _T("e"), (value_type)PARSER_CONST_E); + p1->DefineConst( _T("const"), 1); + p1->DefineConst( _T("const1"), 2); + p1->DefineConst( _T("const2"), 3); + // variables + value_type vVarVal[] = { 1, 2, 3, -2}; + p1->DefineVar( _T("a"), &vVarVal[0]); + p1->DefineVar( _T("aa"), &vVarVal[1]); + p1->DefineVar( _T("b"), &vVarVal[1]); + p1->DefineVar( _T("c"), &vVarVal[2]); + p1->DefineVar( _T("d"), &vVarVal[3]); + // functions + p1->DefineFun( _T("f1of1"), f1of1); // one parameter + p1->DefineFun( _T("f1of2"), f1of2); // two parameter + p1->DefineFun( _T("f2of2"), f2of2); + p1->DefineFun( _T("f1of3"), f1of3); // three parameter + p1->DefineFun( _T("f2of3"), f2of3); + p1->DefineFun( _T("f3of3"), f3of3); + p1->DefineFun( _T("f1of4"), f1of4); // four parameter + p1->DefineFun( _T("f2of4"), f2of4); + p1->DefineFun( _T("f3of4"), f3of4); + p1->DefineFun( _T("f4of4"), f4of4); + p1->DefineFun( _T("f1of5"), f1of5); // five parameter + p1->DefineFun( _T("f2of5"), f2of5); + p1->DefineFun( _T("f3of5"), f3of5); + p1->DefineFun( _T("f4of5"), f4of5); + p1->DefineFun( _T("f5of5"), f5of5); + // sample functions + p1->DefineFun( _T("min"), Min); + p1->DefineFun( _T("max"), Max); + p1->DefineFun( _T("sum"), Sum); + p1->DefineFun( _T("valueof"), ValueOf); + p1->DefineFun( _T("atof"), StrToFloat); + p1->DefineFun( _T("strfun1"), StrFun1); + p1->DefineFun( _T("strfun2"), StrFun2); + p1->DefineFun( _T("strfun3"), StrFun3); + + // infix / postfix operator + // (identifiers used here do not have any meaning or make any sense at all) + p1->DefineInfixOprt( _T("$"), sign, prPOW+1); // sign with high priority + p1->DefineInfixOprt( _T("~"), plus2); // high priority + p1->DefinePostfixOprt( _T("m"), Milli); + p1->DefinePostfixOprt( _T("#"), times3); + p1->DefinePostfixOprt( _T("?"), sqr); // + p1->SetExpr(a_str); + + // Test bytecode integrity + // String parsing and bytecode parsing must yield the same result + value_type fVal[4] = {-999, -998, -997, -996}; // initially should be different + fVal[0] = p1->Eval(); // result from stringparsing + fVal[1] = p1->Eval(); // result from bytecode + if (fVal[0]!=fVal[1]) + throw Parser::exception_type( _T("Bytecode corrupt.") ); + + // Test copy and assignement operators + try + { + // Test copy constructor + std::vector vParser; + vParser.push_back(*p1); + mu::Parser p2 = vParser[0]; // take parser from vector + + // destroy the originals from p2 + vParser.clear(); // delete the vector + delete p1; // delete the original + p1 = 0; + + fVal[2] = p2.Eval(); + + // Test assignement operator + // additionally disable Optimizer this time + mu::Parser p3; + p3 = p2; + p3.EnableOptimizer(false); + fVal[3] = p3.Eval(); + } + catch(std::exception &e) + { + mu::console() << _T("\n ") << e.what() << _T("\n"); + } + + // limited floating point accuracy requires the following test + bool bCloseEnough(true); + for (int i=0; i<4; ++i) + { + bCloseEnough &= (fabs(a_fRes-fVal[i]) <= fabs(fVal[i]*0.0001)); + } + + iRet = ((bCloseEnough && a_fPass) || (!bCloseEnough && !a_fPass)) ? 0 : 1; + if (iRet==1) + { + mu::console() << "\n fail: " << a_str.c_str() + << " (incorrect result; expected: " << a_fRes + << " ;calculated: " << fVal[0]<< ")."; + } + } + catch(Parser::exception_type &e) + { + if (a_fPass) + { + mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.GetMsg() << _T(")"); + return 1; + } + } + catch(std::exception &e) + { + mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.what() << _T(")"); + return 1; // always return a failure since this exception is not expected + } + catch(...) + { + mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)"); + return 1; // exceptions other than ParserException are not allowed + } + + return iRet; + } + + //--------------------------------------------------------------------------- + int ParserTester::EqnTestInt(const string_type &a_str, double a_fRes, bool a_fPass) + { + ParserTester::c_iCount++; + + value_type vVarVal[] = {1, 2, 3}; // variable values + value_type fVal[2] = {-99, -999}; // results: initially should be different + int iRet(0); + + try + { + ParserInt p; + p.DefineConst( _T("const1"), 1); + p.DefineConst( _T("const2"), 2); + p.DefineVar( _T("a"), &vVarVal[0]); + p.DefineVar( _T("b"), &vVarVal[1]); + p.DefineVar( _T("c"), &vVarVal[2]); + + p.SetExpr(a_str); + fVal[0] = p.Eval(); // result from stringparsing + fVal[1] = p.Eval(); // result from bytecode + + if (fVal[0]!=fVal[1]) + throw Parser::exception_type( _T("Bytecode corrupt.") ); + + iRet = ( (a_fRes==fVal[0] && a_fPass) || + (a_fRes!=fVal[0] && !a_fPass) ) ? 0 : 1; + if (iRet==1) + { + mu::console() << _T("\n fail: ") << a_str.c_str() + << _T(" (incorrect result; expected: ") << a_fRes + << _T(" ;calculated: ") << fVal[0]<< _T(")."); + } + } + catch(Parser::exception_type &e) + { + if (a_fPass) + mu::console() << _T("\n ") << e.GetExpr() << _T(" : ") << e.GetMsg(); + } + catch(...) + { + mu::console() << "\n fail: " << a_str.c_str() << " (unexpected exception)"; + return 1; // exceptions other than ParserException are not allowed + } + + return iRet; + } + + //--------------------------------------------------------------------------- + /** \brief Internal error in test class Test is going to be aborted. */ + void ParserTester::Abort() const + { + mu::console() << _T("Test failed (internal error in test class)") << endl; + while (!getchar()); + exit(-1); + } + } // namespace test +} // namespace mu + + + diff --git a/muparser/muParserTest.h b/muparser/muParserTest.h new file mode 100644 index 0000000..fe9bfdd --- /dev/null +++ b/muparser/muParserTest.h @@ -0,0 +1,176 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2006 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef MU_PARSER_TEST_H +#define MU_PARSER_TEST_H + +#include +#include // for accumulate +#include "muParser.h" +#include "muParserInt.h" + + +namespace mu +{ + /** \brief Namespace for test cases. */ + namespace Test + { + //------------------------------------------------------------------------------ + /** \brief Test cases for unit testing. + + (C) 2004-2006 Ingo Berg + */ + class ParserTester // final + { + private: + // Multiarg callbacks + static value_type f1of1(value_type v) { return v;}; + + static value_type f1of2(value_type v, value_type ) {return v;}; + static value_type f2of2(value_type , value_type v) {return v;}; + + static value_type f1of3(value_type v, value_type , value_type ) {return v;}; + static value_type f2of3(value_type , value_type v, value_type ) {return v;}; + static value_type f3of3(value_type , value_type , value_type v) {return v;}; + + static value_type f1of4(value_type v, value_type, value_type , value_type ) {return v;} + static value_type f2of4(value_type , value_type v, value_type , value_type ) {return v;} + static value_type f3of4(value_type , value_type, value_type v, value_type ) {return v;} + static value_type f4of4(value_type , value_type, value_type , value_type v) {return v;} + + static value_type f1of5(value_type v, value_type, value_type , value_type , value_type ) { return v; } + static value_type f2of5(value_type , value_type v, value_type , value_type , value_type ) { return v; } + static value_type f3of5(value_type , value_type, value_type v, value_type , value_type ) { return v; } + static value_type f4of5(value_type , value_type, value_type , value_type v, value_type ) { return v; } + static value_type f5of5(value_type , value_type, value_type , value_type , value_type v) { return v; } + + static value_type Min(value_type a_fVal1, value_type a_fVal2) { return (a_fVal1a_fVal2) ? a_fVal1 : a_fVal2; } + + static value_type plus2(value_type v1) { return v1+2; } + static value_type times3(value_type v1) { return v1*3; } + static value_type sqr(value_type v1) { return v1*v1; } + + static value_type sign(value_type v) { return -v; } + + static value_type Sum(const value_type* a_afArg, int a_iArgc) + { + if (!a_iArgc) + throw mu::Parser::exception_type( _T("too few arguments for function sum.") ); + + value_type fRes=0; + for (int i=0; i> val; + return val; + } + + static value_type StrFun2(const char_type* v1, value_type v2) + { + int val(0); + stringstream_type(v1) >> val; + return val + v2; + } + + static value_type StrFun3(const char_type* v1, value_type v2, value_type v3) + { + int val(0); + stringstream_type(v1) >> val; + return val + v2 + v3; + } + + static value_type StrToFloat(const char_type* a_szMsg) + { + double val(0); + stringstream_type(a_szMsg) >> val; + return val; + +// using namespace std; // atof is for some compilers in std for some not... +// return atof(a_szMsg); + } + + // postfix operator callback + static value_type Milli(value_type v) { return v/(value_type)1e3; } + + static int c_iCount; + + int TestNames(); + int TestSyntax(); + int TestMultiArg(); + int TestVolatile(); + int TestPostFix(); + int TestFormula(); + int TestInfixOprt(); + int TestBinOprt(); + int TestVarConst(); + int TestInterface(); + int TestException(); + int TestStrArg(); + + void Abort() const; + + public: + typedef int (ParserTester::*testfun_type)(); + + ParserTester(); + void Run(); + + private: + std::vector m_vTestFun; + void AddTest(testfun_type a_pFun); + + // Test Double Parser + int EqnTest(const string_type& a_str, double a_fRes, bool a_fPass); + int ThrowTest(const string_type& a_str, int a_iErrc, bool a_bFail = true); + + // Test Int Parser + int EqnTestInt(const string_type& a_str, double a_fRes, bool a_fPass); + }; + } // namespace Test +} // namespace mu + +#endif + + diff --git a/muparser/muParserToken.h b/muparser/muParserToken.h new file mode 100644 index 0000000..b4c7e54 --- /dev/null +++ b/muparser/muParserToken.h @@ -0,0 +1,464 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2006 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef MU_PARSER_TOKEN_H +#define MU_PARSER_TOKEN_H + +#include +#include +#include +#include +#include + +#include "muParserError.h" +#include "muParserCallback.h" + + +namespace mu +{ + +/** \brief Encapsulation of the data for a single formula token. + + Formula token implementation. Part of the Math Parser Package. + Formula tokens can be either one of the following: +
          +
        • value
        • +
        • variable
        • +
        • function with numerical arguments
        • +
        • functions with a string as argument
        • +
        • prefix operators
        • +
        • infix operators
        • +
        • binary operator
        • +
        + + \author (C) 2004 Ingo Berg +*/ +template +class ParserToken +{ +public: + /** \brief Additional token flags. */ + enum ETokFlags + { + flVOLATILE = 1 ///< Mark a token that depends on a variable or a function that is not conservative + }; + +private: + ECmdCode m_iCode; ///< Type of the token; The token type is a constant of type #ECmdCode. + ETypeCode m_iType; + void *m_pTok; ///< Stores Token pointer; not applicable for all tokens + int m_iFlags; ///< Additional flags for the token. + int m_iIdx; ///< An otional index to an external buffer storing the token data + TString m_strTok; ///< Token string + TString m_strVal; ///< Value for string variables + value_type m_fVal; + std::auto_ptr m_pCallback; + +public: + + //--------------------------------------------------------------------------- + /** \brief Constructor (default). + + Sets token to an neutral state of type cmUNKNOWN. + \throw nothrow + \sa ECmdCode + */ + ParserToken() + :m_iCode(cmUNKNOWN) + ,m_iType(tpVOID) + ,m_pTok(0) + ,m_iFlags(0) + ,m_iIdx(-1) + ,m_strTok() + ,m_pCallback() + {} + + //------------------------------------------------------------------------------ + /** \brief Create token from another one. + + Implemented by calling Assign(...) + \throw nothrow + \post m_iType==cmUNKNOWN + \sa #Assign + */ + ParserToken(const ParserToken &a_Tok) + { + Assign(a_Tok); + } + + //------------------------------------------------------------------------------ + /** \brief Assignement operator. + + Copy token state from another token and return this. + Implemented by calling Assign(...). + \throw nothrow + */ + ParserToken& operator=(const ParserToken &a_Tok) + { + Assign(a_Tok); + return *this; + } + + //------------------------------------------------------------------------------ + /** \brief Copy token information from argument. + + \throw nothrow + */ + void Assign(const ParserToken &a_Tok) + { + m_iCode = a_Tok.m_iCode; + m_pTok = a_Tok.m_pTok; + m_iFlags = a_Tok.m_iFlags; + m_strTok = a_Tok.m_strTok; + m_iIdx = a_Tok.m_iIdx; + m_strVal = a_Tok.m_strVal; + m_iType = a_Tok.m_iType; + m_fVal = a_Tok.m_fVal; + // create new callback object if a_Tok has one + m_pCallback.reset(a_Tok.m_pCallback.get() ? a_Tok.m_pCallback->Clone() : 0); + } + + //------------------------------------------------------------------------------ + /** \brief Add additional flags to the token. + + Flags are currently used to mark volatile (non optimizeable) functions. + \sa m_iFlags, ETokFlags + */ + void AddFlags(int a_iFlags) + { + m_iFlags |= a_iFlags; + } + + //------------------------------------------------------------------------------ + /** \brief Check if a certain flag ist set. + + \throw nothrow + */ + bool IsFlagSet(int a_iFlags) const + { + #if defined(_MSC_VER) + #pragma warning( disable : 4800 ) + #endif + + return (bool)(m_iFlags & a_iFlags); + + #if defined(_MSC_VER) + #pragma warning( default : 4800 ) // int: Variable set to boolean value (may degrade performance) + #endif + } + + //------------------------------------------------------------------------------ + /** \brief Assign a token type. + + Token may not be of type value, variable or function. Those have seperate set functions. + + \pre [assert] a_iType!=cmVAR + \pre [assert] a_iType!=cmVAL + \pre [assert] a_iType!=cmFUNC + \post m_fVal = 0 + \post m_pTok = 0 + */ + ParserToken& Set(ECmdCode a_iType, const TString &a_strTok=TString()) + { + // The following types cant be set this way, they have special Set functions + assert(a_iType!=cmVAR); + assert(a_iType!=cmVAL); + assert(a_iType!=cmFUNC); + + m_iCode = a_iType; + m_iType = tpVOID; + m_pTok = 0; + m_iFlags = 0; + m_strTok = a_strTok; + m_iIdx = -1; + + return *this; + } + + //------------------------------------------------------------------------------ + /** \brief Set Callback type. */ + ParserToken& Set(const ParserCallback &a_pCallback, const TString &a_sTok) + { + assert(a_pCallback.GetAddr()); + + m_iCode = a_pCallback.GetCode(); + m_iType = tpVOID; + m_strTok = a_sTok; + m_pCallback.reset(new ParserCallback(a_pCallback)); + + m_pTok = 0; + m_iFlags = 0; + m_iIdx = -1; + + if (!m_pCallback->IsOptimizable()) + AddFlags(flVOLATILE); + + return *this; + } + + //------------------------------------------------------------------------------ + /** \brief Make this token a value token. + + Member variables not necessary for value tokens will be invalidated. + \throw nothrow + */ + ParserToken& SetVal(TBase a_fVal, const TString &a_strTok=TString()) + { + m_iCode = cmVAL; + m_iType = tpDBL; + m_fVal = a_fVal; + m_iFlags = 0; + m_strTok = a_strTok; + m_iIdx = -1; + + m_pTok = 0; + m_pCallback.reset(0); + + return *this; + } + + //------------------------------------------------------------------------------ + /** \brief make this token a variable token. + + Member variables not necessary for variable tokens will be invalidated. + \throw nothrow + */ + ParserToken& SetVar(TBase *a_pVar, const TString &a_strTok) + { + m_iCode = cmVAR; + m_iType = tpDBL; + m_iFlags = 0; + m_strTok = a_strTok; + m_iIdx = -1; + m_pTok = (void*)a_pVar; + m_pCallback.reset(0); + + AddFlags(ParserToken::flVOLATILE); + return *this; + } + + //------------------------------------------------------------------------------ + /** \brief Make this token a variable token. + + Member variables not necessary for variable tokens will be invalidated. + \throw nothrow + */ + ParserToken& SetString(const TString &a_strTok, std::size_t a_iSize) + { + m_iCode = cmSTRING; // cmSTRVAR; + m_iType = tpSTR; + m_iFlags = 0; + m_strTok = a_strTok; + m_iIdx = static_cast(a_iSize); + + m_pTok = 0; + m_pCallback.reset(0); + + AddFlags(ParserToken::flVOLATILE); + return *this; + } + + //------------------------------------------------------------------------------ + /** \brief Make token a string token. + + String tokens are used to store the value of string function arguments. + \param a_strTok the string content. + \post #m_iType==cmSTRING, #m_strTok==a_strTok + \throw nothrow + */ + ParserToken& SetString(const string_type &a_strTok) + { + m_iCode = cmSTRING; + m_iType = tpSTR; + m_iFlags = 0; + m_iIdx = -1; + + m_pTok = 0; + m_pCallback.reset(0); + + m_strTok = a_strTok; + + return *this; + } + + //------------------------------------------------------------------------------ + /** \brief Set an index associated with the token related data. + + In cmSTRFUNC - This is the index to a string table in the main parser. + \param a_iIdx The index the string function result will take in the bytecode parser. + \throw exception_type if #a_iIdx<0 or #m_iType!=cmSTRING + */ + void SetIdx(int a_iIdx) + { + if (m_iCode!=cmSTRING || a_iIdx<0) + throw ParserError(ecINTERNAL_ERROR); + + m_iIdx = a_iIdx; + } + + //------------------------------------------------------------------------------ + /** \brief Return Index associated with the token related data. + + In cmSTRFUNC - This is the index to a string table in the main parser. + + \throw exception_type if #m_iIdx<0 or #m_iType!=cmSTRING + \return The index the result will take in the Bytecode calculatin array (#m_iIdx). + */ + int GetIdx() const + { + if (m_iIdx<0 || m_iCode!=cmSTRING ) + throw ParserError(ecINTERNAL_ERROR); + + return m_iIdx; + } + + //------------------------------------------------------------------------------ + /** \brief Return the token type. + + \return #m_iType + \throw nothrow + */ + ECmdCode GetCode() const + { + if (m_pCallback.get()) + { + return m_pCallback->GetCode(); + } + else + { + return m_iCode; + } + } + + //------------------------------------------------------------------------------ + ETypeCode GetType() const + { + if (m_pCallback.get()) + { + return m_pCallback->GetType(); + } + else + { + return m_iType; + } + } + + //------------------------------------------------------------------------------ + int GetPri() const + { + if ( !m_pCallback.get()) + throw ParserError(ecINTERNAL_ERROR); + + if ( m_pCallback->GetCode()!=cmOPRT_BIN && m_pCallback->GetCode()!=cmOPRT_INFIX) + throw ParserError(ecINTERNAL_ERROR); + + return m_pCallback->GetPri(); + } + + //------------------------------------------------------------------------------ + /** \brief Return the address of the callback function assoziated with + function and operator tokens. + + \return The pointer stored in #m_pTok. + \throw exception_type if token type is non of: +
          +
        • cmFUNC
        • +
        • cmSTRFUNC
        • +
        • cmPOSTOP
        • +
        • cmINFIXOP
        • +
        • cmOPRT_BIN
        • +
        + \sa ECmdCode + */ + void* GetFuncAddr() const + { + return (m_pCallback.get()) ? m_pCallback->GetAddr() : 0; + } + + //------------------------------------------------------------------------------ + /** \biref Get value of the token. + + Only applicable to variable and value tokens. + \throw exception_type if token is no value/variable token. + */ + TBase GetVal() const + { + switch (m_iCode) + { + case cmVAL: return m_fVal; + case cmVAR: return *((TBase*)m_pTok); + default: throw ParserError(ecVAL_EXPECTED); + } + } + + //------------------------------------------------------------------------------ + /** \brief Get address of a variable token. + + Valid only if m_iType==CmdVar. + \throw exception_type if token is no variable token. + */ + TBase* GetVar() const + { + if (m_iCode!=cmVAR) + throw ParserError(ecINTERNAL_ERROR); + + return (TBase*)m_pTok; + } + + //------------------------------------------------------------------------------ + /** \brief Return the number of function arguments. + + Valid only if m_iType==CmdFUNC. + */ + int GetArgCount() const + { + assert(m_pCallback.get()); + + if (!m_pCallback->GetAddr()) + throw ParserError(ecINTERNAL_ERROR); + + return m_pCallback->GetArgc(); + } + + //------------------------------------------------------------------------------ + /** \brief Return the token identifier. + + If #m_iType is cmSTRING the token identifier is the value of the string argument + for a string function. + \return #m_strTok + \throw nothrow + \sa m_strTok + */ + const TString& GetAsString() const + { + return m_strTok; + } +}; + +} // namespace mu + +#endif + + diff --git a/muparser/muParserTokenReader.cpp b/muparser/muParserTokenReader.cpp new file mode 100644 index 0000000..99c0a0a --- /dev/null +++ b/muparser/muParserTokenReader.cpp @@ -0,0 +1,822 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2006 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include +#include + +#include "muParserTokenReader.h" +#include "muParserBase.h" + + +namespace mu +{ + + // Forward declaration + class ParserBase; + + //--------------------------------------------------------------------------- + /** \brief Copy constructor. + + \sa Assign + \throw nothrow + */ + ParserTokenReader::ParserTokenReader(const ParserTokenReader &a_Reader) + { + Assign(a_Reader); + } + + //--------------------------------------------------------------------------- + /** \brief Assignement operator. + + Self assignement will be suppressed otherwise #Assign is called. + + \param a_Reader Object to copy to this token reader. + \throw nothrow + */ + ParserTokenReader& ParserTokenReader::operator=(const ParserTokenReader &a_Reader) + { + if (&a_Reader!=this) + Assign(a_Reader); + + return *this; + } + + //--------------------------------------------------------------------------- + /** \brief Assign state of a token reader to this token reader. + + \param a_Reader Object from which the state should be copied. + \throw nothrow + */ + void ParserTokenReader::Assign(const ParserTokenReader &a_Reader) + { + m_pParser = a_Reader.m_pParser; + m_strFormula = a_Reader.m_strFormula; + m_iPos = a_Reader.m_iPos; + m_iSynFlags = a_Reader.m_iSynFlags; + + m_UsedVar = a_Reader.m_UsedVar; + m_pFunDef = a_Reader.m_pFunDef; + m_pConstDef = a_Reader.m_pConstDef; + m_pVarDef = a_Reader.m_pVarDef; + m_pStrVarDef = a_Reader.m_pStrVarDef; + m_pPostOprtDef = a_Reader.m_pPostOprtDef; + m_pInfixOprtDef = a_Reader.m_pInfixOprtDef; + m_pOprtDef = a_Reader.m_pOprtDef; + m_bIgnoreUndefVar = a_Reader.m_bIgnoreUndefVar; + m_vIdentFun = a_Reader.m_vIdentFun; + m_pFactory = a_Reader.m_pFactory; + m_pFactoryData = a_Reader.m_pFactoryData; + m_iBrackets = a_Reader.m_iBrackets; + } + + //--------------------------------------------------------------------------- + /** \brief Constructor. + + Create a Token reader and bind it to a parser object. + + \pre [assert] a_pParser may not be NULL + \post #m_pParser==a_pParser + \param a_pParent Parent parser object of the token reader. + */ + ParserTokenReader::ParserTokenReader(ParserBase *a_pParent) + :m_pParser(a_pParent) + ,m_strFormula() + ,m_iPos(0) + ,m_iSynFlags(0) + ,m_bIgnoreUndefVar(false) + ,m_pFunDef(NULL) + ,m_pPostOprtDef(NULL) + ,m_pInfixOprtDef(NULL) + ,m_pOprtDef(NULL) + ,m_pConstDef(NULL) + ,m_pStrVarDef(NULL) + ,m_pVarDef(NULL) + ,m_pFactory(NULL) + ,m_pFactoryData(NULL) + ,m_vIdentFun() + ,m_UsedVar() + ,m_fZero(0) + ,m_iBrackets(0) + { + assert(m_pParser); + SetParent(m_pParser); + } + + //--------------------------------------------------------------------------- + /** \brief Destructor (trivial). + + \throw nothrow + */ + ParserTokenReader::~ParserTokenReader() + {} + + //--------------------------------------------------------------------------- + /** \brief Create instance of a ParserTokenReader identical with this + and return its pointer. + + This is a factory method the calling function must take care of the object destruction. + + \return A new ParserTokenReader object. + \throw nothrow + */ + ParserTokenReader* ParserTokenReader::Clone(ParserBase *a_pParent) const + { + std::auto_ptr ptr(new ParserTokenReader(*this)); + ptr->SetParent(a_pParent); + return ptr.release(); + } + + //--------------------------------------------------------------------------- + void ParserTokenReader::AddValIdent(identfun_type a_pCallback) + { + m_vIdentFun.push_back(a_pCallback); + } + + //--------------------------------------------------------------------------- + void ParserTokenReader::SetVarCreator(facfun_type a_pFactory, void *pUserData) + { + m_pFactory = a_pFactory; + m_pFactoryData = pUserData; + } + + //--------------------------------------------------------------------------- + /** \brief Return the current position of the token reader in the formula string. + + \return #m_iPos + \throw nothrow + */ + int ParserTokenReader::GetPos() const + { + return m_iPos; + } + + //--------------------------------------------------------------------------- + /** \brief Return a reference to the formula. + + \return #m_strFormula + \throw nothrow + */ + const string_type& ParserTokenReader::GetFormula() const + { + return m_strFormula; + } + + //--------------------------------------------------------------------------- + /** \brief Return a map containing the used variables only. */ + const varmap_type& ParserTokenReader::GetUsedVar() const + { + return m_UsedVar; + } + + //--------------------------------------------------------------------------- + /** \brief Initialize the token Reader. + + Sets the formula position index to zero and set Syntax flags to default for initial formula parsing. + \pre [assert] triggered if a_szFormula==0 + */ + void ParserTokenReader::SetFormula(const string_type &a_strFormula) + { + m_strFormula = a_strFormula; + ReInit(); + } + + //--------------------------------------------------------------------------- + void ParserTokenReader::SetDefs( const funmap_type *a_pFunDef, + const funmap_type *a_pOprtDef, + const funmap_type *a_pInfixOprtDef, + const funmap_type *a_pPostOprtDef, + varmap_type *a_pVarDef, + const strmap_type *a_pStrVarDef, + const valmap_type *a_pConstDef ) + { + m_pFunDef = a_pFunDef; + m_pOprtDef = a_pOprtDef; + m_pInfixOprtDef = a_pInfixOprtDef; + m_pPostOprtDef = a_pPostOprtDef; + m_pVarDef = a_pVarDef; + m_pStrVarDef = a_pStrVarDef; + m_pConstDef = a_pConstDef; + } + + //--------------------------------------------------------------------------- + /** \brief Set Flag that contronls behaviour in case of undefined variables beeing found. + + If true, the parser does not throw an exception if an undefined variable is found. + otherwise it does. This variable is used internally only! + It supresses a "undefined variable" exception in GetUsedVar(). + Those function should return a complete list of variables including + those the are not defined by the time of it's call. + */ + void ParserTokenReader::IgnoreUndefVar(bool bIgnore) + { + m_bIgnoreUndefVar = bIgnore; + } + + //--------------------------------------------------------------------------- + /** \brief Reset the token reader to the start of the formula. + + The syntax flags will be reset to a value appropriate for the + start of a formula. + \post #m_iPos==0, #m_iSynFlags = noOPT | noBC | noPOSTOP | noSTR + \throw nothrow + \sa ESynCodes + */ + void ParserTokenReader::ReInit() + { + m_iPos = 0; + m_iSynFlags = noOPT | noBC | noPOSTOP | noASSIGN; + m_iBrackets = 0; + m_UsedVar.clear(); + } + + //--------------------------------------------------------------------------- + /** \brief Read the next token from the string. */ + ParserTokenReader::token_type ParserTokenReader::ReadNextToken() + { + assert(m_pParser); + + std::stack FunArgs; + const char_type *szFormula = m_strFormula.c_str(); + token_type tok; + + while (szFormula[m_iPos]==' ') + ++m_iPos; + + if ( IsEOF(tok) ) return tok; // Check for end of formula + if ( IsOprt(tok) ) return tok; // Check for user defined binary operator + if ( IsBuiltIn(tok) ) return tok; // Check built in operators / tokens + if ( IsFunTok(tok) ) return tok; // Check for function token + if ( IsValTok(tok) ) return tok; // Check for values / constant tokens + if ( IsVarTok(tok) ) return tok; // Check for variable tokens + if ( IsStrVarTok(tok) ) return tok; // Check for string variables + if ( IsString(tok) ) return tok; // Check for String tokens + if ( IsInfixOpTok(tok) ) return tok; // Check for unary operators + if ( IsPostOpTok(tok) ) return tok; // Check for unary operators + + // Check String for undefined variable token. Done only if a + // flag is set indicating to ignore undefined variables. + // This is a way to conditionally avoid an error if + // undefined variables occur. + // The GetUsedVar function must supress the error for + // undefined variables in order to collect all variable + // names including the undefined ones. + if ( (m_bIgnoreUndefVar || m_pFactory) && IsUndefVarTok(tok) ) return tok; + + // Check for unknown token + // + // !!! From this point on there is no exit without an exception possible... + // + string_type strTok; + int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); + if (iEnd!=m_iPos) + Error(ecUNASSIGNABLE_TOKEN, m_iPos, strTok); + + Error(ecUNASSIGNABLE_TOKEN, m_iPos, m_strFormula.substr(m_iPos)); + return token_type(); // never reached + } + + //--------------------------------------------------------------------------- + void ParserTokenReader::SetParent(ParserBase *a_pParent) + { + m_pParser = a_pParent; + m_pFunDef = &a_pParent->m_FunDef; + m_pOprtDef = &a_pParent->m_OprtDef; + m_pInfixOprtDef = &a_pParent->m_InfixOprtDef; + m_pPostOprtDef = &a_pParent->m_PostOprtDef; + m_pVarDef = &a_pParent->m_VarDef; + m_pStrVarDef = &a_pParent->m_StrVarDef; + m_pConstDef = &a_pParent->m_ConstDef; + } + + //--------------------------------------------------------------------------- + /** \brief Extract all characters that belong to a certain charset. + + \param a_szCharSet [in] Const char array of the characters allowed in the token. + \param a_strTok [out] The string that consists entirely of characters listed in a_szCharSet. + \param a_iPos [in] Position in the string from where to start reading. + \return The Position of the first character not listed in a_szCharSet. + \throw nothrow + */ + int ParserTokenReader::ExtractToken( const char_type *a_szCharSet, + string_type &a_sTok, int a_iPos ) const + { + int iEnd = (int)m_strFormula.find_first_not_of(a_szCharSet, a_iPos); + + if (iEnd==(int)string_type::npos) + iEnd = (int)m_strFormula.length(); + + a_sTok = string_type( m_strFormula.begin()+a_iPos, m_strFormula.begin()+iEnd); + a_iPos = iEnd; + return iEnd; + } + + //--------------------------------------------------------------------------- + /** \brief Check if a built in operator or other token can be found + \param a_Tok [out] Operator token if one is found. This can either be a binary operator or an infix operator token. + \return true if an operator token has been found. + */ + bool ParserTokenReader::IsBuiltIn(token_type &a_Tok) + { + const char_type **pOprtDef = m_pParser->GetOprtDef(); + const char_type* szFormula = m_strFormula.c_str(); + + // Compare token with function and operator strings + // check string for operator/function + for (int i=0; pOprtDef[i]; i++) + { +#if !defined _UNICODE + std::size_t len = std::strlen( pOprtDef[i] ); + if ( !std::strncmp(&szFormula[m_iPos], pOprtDef[i], len) ) +#else + // this would work for both UNICODE and char but it's so god damn ugly!! + // apart from this this cant be fast + std::size_t len( std::char_traits::length(pOprtDef[i]) ); + if ( string_type(pOprtDef[i]) == string_type(szFormula + m_iPos, szFormula + m_iPos + len) ) +#endif + { + switch(i) + { + case cmAND: + case cmOR: + case cmXOR: + case cmLT: + case cmGT: + case cmLE: + case cmGE: + case cmNEQ: + case cmEQ: + case cmADD: + case cmSUB: + case cmMUL: + case cmDIV: + case cmPOW: + case cmASSIGN: + // The assignement operator need special treatment + if (i==cmASSIGN && m_iSynFlags & noASSIGN) + Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]); + + if (!m_pParser->HasBuiltInOprt()) continue; + if (m_iSynFlags & noOPT) + { + // Maybe its an infix operator not an operator + // Both operator types can share characters in + // their identifiers + if ( IsInfixOpTok(a_Tok) ) + return true; + + Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]); + } + + m_iSynFlags = noBC | noOPT | noCOMMA | noPOSTOP | noASSIGN; + m_iSynFlags |= ( (i != cmEND) && ( i != cmBC) ) ? noEND : 0; + break; + + case cmCOMMA: + if (m_iSynFlags & noCOMMA) + Error(ecUNEXPECTED_COMMA, m_iPos, pOprtDef[i]); + + m_iSynFlags = noBC | noOPT | noEND | noCOMMA | noPOSTOP | noASSIGN; + break; + + case cmBO: + if (m_iSynFlags & noBO) + Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]); + + m_iSynFlags = noBC | noOPT | noEND | noCOMMA | noPOSTOP | noASSIGN; + ++m_iBrackets; + break; + + case cmBC: + if (m_iSynFlags & noBC) + Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]); + + m_iSynFlags = noBO | noVAR | noVAL | noFUN | noINFIXOP | noSTR | noASSIGN; + + if (--m_iBrackets<0) + Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]); + break; + + default: // The operator is listed in c_DefaultOprt, but not here. This is a bad thing... + Error(ecINTERNAL_ERROR); + } // switch operator id + + m_iPos += (int)len; + a_Tok.Set( (ECmdCode)i, pOprtDef[i] ); + return true; + } // if operator string found + } // end of for all operator strings + + return false; + } + + //--------------------------------------------------------------------------- + /** \brief Check for End of Formula. + + \return true if an end of formula is found false otherwise. + \param a_Tok [out] If an eof is found the corresponding token will be stored there. + \throw nothrow + \sa IsOprt, IsFunTok, IsStrFunTok, IsValTok, IsVarTok, IsString, IsInfixOpTok, IsPostOpTok + */ + bool ParserTokenReader::IsEOF(token_type &a_Tok) + { + const char_type* szFormula = m_strFormula.c_str(); + + // check for EOF + if ( !szFormula[m_iPos] || szFormula[m_iPos] == '\n') + { + if ( m_iSynFlags & noEND ) + Error(ecUNEXPECTED_EOF, m_iPos); + + if (m_iBrackets>0) + Error(ecMISSING_PARENS, m_iPos, _T(")")); + + m_iSynFlags = 0; + a_Tok.Set(cmEND); + return true; + } + + return false; + } + + //--------------------------------------------------------------------------- + /** \brief Check if a string position contains a unary infix operator. + \return true if a function token has been found false otherwise. + */ + bool ParserTokenReader::IsInfixOpTok(token_type &a_Tok) + { + string_type sTok; + int iEnd = ExtractToken(m_pParser->ValidInfixOprtChars(), sTok, m_iPos); + if (iEnd==m_iPos) + return false; + + funmap_type::const_iterator item = m_pInfixOprtDef->find(sTok); + if (item==m_pInfixOprtDef->end()) + return false; + + a_Tok.Set(item->second, sTok); + m_iPos = (int)iEnd; + + if (m_iSynFlags & noINFIXOP) + Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); + + m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN; + return true; + } + + //--------------------------------------------------------------------------- + /** \brief Check whether the token at a given position is a function token. + \param a_Tok [out] If a value token is found it will be placed here. + \throw ParserException if Syntaxflags do not allow a function at a_iPos + \return true if a function token has been found false otherwise. + \pre [assert] m_pParser!=0 + */ + bool ParserTokenReader::IsFunTok(token_type &a_Tok) + { + string_type strTok; + int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); + if (iEnd==m_iPos) + return false; + + funmap_type::const_iterator item = m_pFunDef->find(strTok); + if (item==m_pFunDef->end()) + return false; + + a_Tok.Set(item->second, strTok); + + m_iPos = (int)iEnd; + if (m_iSynFlags & noFUN) + Error(ecUNEXPECTED_FUN, m_iPos-(int)a_Tok.GetAsString().length(), a_Tok.GetAsString()); + + m_iSynFlags = noANY ^ noBO; + return true; + } + + //--------------------------------------------------------------------------- + /** \brief Check if a string position contains a binary operator. + \param a_Tok [out] Operator token if one is found. This can either be a binary operator or an infix operator token. + \return true if an operator token has been found. + */ + bool ParserTokenReader::IsOprt(token_type &a_Tok) + { + string_type strTok; + int iEnd = ExtractToken(m_pParser->ValidOprtChars(), strTok, m_iPos); + if (iEnd==m_iPos) + return false; + + funmap_type::const_iterator item = m_pOprtDef->find(strTok); + if (item==m_pOprtDef->end()) + return false; + + a_Tok.Set(item->second, strTok); + + if (m_iSynFlags & noOPT) + { + // An operator was found but is not expected to occur at + // this position of the formula, maybe it is an infix + // operator, not a binary operator. Both operator types + // can share characters in their identifiers. + if ( IsInfixOpTok(a_Tok) ) return true; + // nope, no infix operator + Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); + } + + m_iPos = (int)iEnd; + m_iSynFlags = noBC | noOPT | noCOMMA | noPOSTOP | noEND | noBC | noASSIGN; + return true; + } + + //--------------------------------------------------------------------------- + /** \brief Check if a string position contains a unary post value operator. */ + bool ParserTokenReader::IsPostOpTok(token_type &a_Tok) + { + // Tricky problem with equations like "3m+5": + // m is a postfix operator, + is a valid sign for postfix operators and + // for binary operators parser detects "m+" as operator string and + // finds no matching postfix operator. + // + // This is a special case so this routine slightly differs from the other + // token readers. + + // Test if there could be a postfix operator + string_type sTok; + int iEnd = ExtractToken(m_pParser->ValidOprtChars(), sTok, m_iPos); + if (iEnd==m_iPos) + return false; + + // iteraterate over all postfix operator strings + funmap_type::const_iterator item = m_pPostOprtDef->begin(); + for (item=m_pPostOprtDef->begin(); item!=m_pPostOprtDef->end(); ++item) + { + if (sTok.find(item->first)!=0) + continue; + + a_Tok.Set(item->second, sTok); + m_iPos += (int)item->first.length(); + + if (m_iSynFlags & noPOSTOP) + Error(ecUNEXPECTED_OPERATOR, m_iPos-(int)item->first.length(), item->first); + + m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noSTR | noASSIGN; + return true; + } + + return false; + } + + //--------------------------------------------------------------------------- + /** \brief Check whether the token at a given position is a value token. + + Value tokens are either values or constants. + + \param a_Tok [out] If a value token is found it will be placed here. + \return true if a value token has been found. + */ + bool ParserTokenReader::IsValTok(token_type &a_Tok) + { + assert(m_pConstDef); + assert(m_pParser); + + #if defined(_MSC_VER) + #pragma warning( disable : 4244 ) + #endif + + string_type strTok; + value_type fVal(0); + int iEnd(0); + + // 2.) Check for user defined constant + // Read everything that could be a constant name + iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); + if (iEnd!=m_iPos) + { + valmap_type::const_iterator item = m_pConstDef->find(strTok); + if (item!=m_pConstDef->end()) + { + m_iPos = iEnd; + a_Tok.SetVal(item->second, strTok); + + if (m_iSynFlags & noVAL) + Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok); + + m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; + return true; + } + } + + // 3.call the value recognition functions provided by the user + // Call user defined value recognition functions + std::vector::const_iterator item = m_vIdentFun.begin(); + for (item = m_vIdentFun.begin(); item!=m_vIdentFun.end(); ++item) + { + int iStart = m_iPos; + if ( (*item)(m_strFormula.c_str() + m_iPos, m_iPos, fVal) ) + { + strTok.assign(m_strFormula.c_str(), iStart, m_iPos); + if (m_iSynFlags & noVAL) + Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok); + + a_Tok.SetVal(fVal, strTok); + m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; + return true; + } + } + + return false; + + #if defined(_MSC_VER) + #pragma warning( default : 4244 ) + #endif + } + + //--------------------------------------------------------------------------- + /** \brief Check wheter a token at a given position is a variable token. + \param a_Tok [out] If a variable token has been found it will be placed here. + \return true if a variable token has been found. + */ + bool ParserTokenReader::IsVarTok(token_type &a_Tok) + { + if (!m_pVarDef->size()) + return false; + + string_type strTok; + int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); + if (iEnd==m_iPos) + return false; + + varmap_type::const_iterator item = m_pVarDef->find(strTok); + if (item==m_pVarDef->end()) + return false; + + if (m_iSynFlags & noVAR) + Error(ecUNEXPECTED_VAR, m_iPos, strTok); + + m_iPos = iEnd; + a_Tok.SetVar(item->second, strTok); + m_UsedVar[item->first] = item->second; // Add variable to used-var-list + + m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noINFIXOP | noSTR; + return true; + } + + //--------------------------------------------------------------------------- + bool ParserTokenReader::IsStrVarTok(token_type &a_Tok) + { + if (!m_pStrVarDef || !m_pStrVarDef->size()) + return false; + + string_type strTok; + int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); + if (iEnd==m_iPos) + return false; + + strmap_type::const_iterator item = m_pStrVarDef->find(strTok); + if (item==m_pStrVarDef->end()) + return false; + + if (m_iSynFlags & noSTR) + Error(ecUNEXPECTED_VAR, m_iPos, strTok); + + m_iPos = iEnd; + if (!m_pParser->m_vStringVarBuf.size()) + Error(ecINTERNAL_ERROR); + + a_Tok.SetString(m_pParser->m_vStringVarBuf[item->second], m_pParser->m_vStringVarBuf.size() ); + + m_iSynFlags = m_iSynFlags = noANY ^ ( noBC | noOPT | noEND | noCOMMA); + return true; + } + + //--------------------------------------------------------------------------- + /** \brief Check wheter a token at a given position is an undefined variable. + + \param a_Tok [out] If a variable tom_pParser->m_vStringBufken has been found it will be placed here. + \return true if a variable token has been found. + \throw nothrow + */ + bool ParserTokenReader::IsUndefVarTok(token_type &a_Tok) + { + string_type strTok; + int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); + if (iEnd==m_iPos) + return false; + + if (m_iSynFlags & noVAR) + { + // 20061021 added token string strTok instead of a_Tok.GetAsString() as the + // token identifier. + Error(ecUNEXPECTED_VAR, m_iPos - (int)a_Tok.GetAsString().length(), strTok); + } + + // If a factory is available implicitely create new variables + if (m_pFactory) + { + value_type *fVar = m_pFactory(strTok.c_str(), m_pFactoryData); + a_Tok.SetVar(fVar, strTok ); + + // Do not use m_pParser->DefineVar( strTok, fVar ); + // in order to define the new variable, it will clear the + // m_UsedVar array which will kill previousely defined variables + // from the list + // This is safe because the new variable can never override an existing one + // because they are checked first! + (*m_pVarDef)[strTok] = fVar; + m_UsedVar[strTok] = fVar; // Add variable to used-var-list + } + else + { + a_Tok.SetVar((value_type*)&m_fZero, strTok); + m_UsedVar[strTok] = 0; // Add variable to used-var-list + } + + m_iPos = iEnd; + + // Call the variable factory in order to let it define a new parser variable + m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noINFIXOP | noSTR; + return true; + } + + //--------------------------------------------------------------------------- + /** \brief Check wheter a token at a given position is a string. + + \param a_Tok [out] If a variable token has been found it will be placed here. + \return true if a string token has been found. + \sa IsOprt, IsFunTok, IsStrFunTok, IsValTok, IsVarTok, IsEOF, IsInfixOpTok, IsPostOpTok + \throw nothrow + */ + bool ParserTokenReader::IsString(token_type &a_Tok) + { + if (m_strFormula[m_iPos]!='"') + return false; + + string_type strBuf(&m_strFormula[m_iPos+1]); + std::size_t iEnd(0), iSkip(0); + + // parser over escaped '\"' end replace them with '"' + for(iEnd=(int)strBuf.find( _T("\"") ); iEnd!=string_type::npos; iEnd=(int)strBuf.find( _T("\""), iEnd)) + { + if (strBuf[iEnd-1]!='\\') break; + strBuf.replace(iEnd-1, 2, _T("\"") ); + iSkip++; + } + + if (iEnd==string_type::npos) + Error(ecUNTERMINATED_STRING, m_iPos, _T("\"") ); + + string_type strTok(strBuf.begin(), strBuf.begin()+iEnd); + + if (m_iSynFlags & noSTR) + Error(ecUNEXPECTED_STR, m_iPos, strTok); + + m_pParser->m_vStringBuf.push_back(strTok); // Store string in internal buffer + a_Tok.SetString(strTok, m_pParser->m_vStringBuf.size()); + + m_iPos += (int)strTok.length() + 2 + (int)iSkip; // +2 wg Anführungszeichen; +iSkip für entfernte escape zeichen + m_iSynFlags = m_iSynFlags = noANY ^ ( noCOMMA | noBC | noOPT | noEND ); + + return true; + } + + //--------------------------------------------------------------------------- + /** \brief Create an error containing the parse error position. + + This function will create an Parser Exception object containing the error text and its position. + + \param a_iErrc [in] The error code of type #EErrorCodes. + \param a_iPos [in] The position where the error was detected. + \param a_strTok [in] The token string representation associated with the error. + \throw ParserException always throws thats the only purpose of this function. + */ + void ParserTokenReader::Error( EErrorCodes a_iErrc, + int a_iPos, + const string_type &a_sTok) const + { + m_pParser->Error(a_iErrc, a_iPos, a_sTok); + } +} // namespace mu + diff --git a/muparser/muParserTokenReader.h b/muparser/muParserTokenReader.h new file mode 100644 index 0000000..122586e --- /dev/null +++ b/muparser/muParserTokenReader.h @@ -0,0 +1,156 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2006 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef MU_PARSER_TOKEN_READER_H +#define MU_PARSER_TOKEN_READER_H + +#include +#include +#include +#include +#include +#include +#include + +#include "muParserDef.h" +#include "muParserToken.h" + + +namespace mu +{ + + // Forward declaration + class ParserBase; + + /** \brief Token reader for the ParserBase class. + + */ + class ParserTokenReader + { + private: + typedef ParserToken token_type; + + private: + ParserBase *m_pParser; + string_type m_strFormula; + int m_iPos; + int m_iSynFlags; + bool m_bIgnoreUndefVar; + + const funmap_type *m_pFunDef; + const funmap_type *m_pPostOprtDef; + const funmap_type *m_pInfixOprtDef; + const funmap_type *m_pOprtDef; + const valmap_type *m_pConstDef; + const strmap_type *m_pStrVarDef; + varmap_type *m_pVarDef; ///< The only non const pointer to parser internals + facfun_type m_pFactory; + void *m_pFactoryData; + std::vector m_vIdentFun; ///< Value token identification function + varmap_type m_UsedVar; + value_type m_fZero; ///< Dummy value of zero, referenced by undefined variables + int m_iBrackets; + + // + // private Functions + // + private: + + /** \brief Syntax codes. + + The syntax codes control the syntax check done during the first time parsing of + the expression string. They are flags that indicate which tokens are allowed next + if certain tokens are identified. + */ + enum ESynCodes + { + noBO = 1 << 0, ///< to avoid i.e. "cos(7)(" + noBC = 1 << 1, ///< to avoid i.e. "sin)" or "()" + noVAL = 1 << 2, ///< to avoid i.e. "tan 2" or "sin(8)3.14" + noVAR = 1 << 3, ///< to avoid i.e. "sin a" or "sin(8)a" + noCOMMA = 1 << 4, ///< to avoid i.e. ",," or "+," ... + noFUN = 1 << 5, ///< to avoid i.e. "sqrt cos" or "(1)sin" + noOPT = 1 << 6, ///< to avoid i.e. "(+)" + noPOSTOP = 1 << 7, ///< to avoid i.e. "(5!!)" "sin!" + noINFIXOP = 1 << 8, ///< to avoid i.e. "++4" "!!4" + noEND = 1 << 9, ///< to avoid unexpected end of formula + noSTR = 1 << 10, ///< to block numeric arguments on string functions + noASSIGN = 1 << 11, ///< to block assignement to constant i.e. "4=7" + noANY = ~0 ///< All of he above flags set + }; + + ParserTokenReader(const ParserTokenReader &a_Reader); + ParserTokenReader& operator=(const ParserTokenReader &a_Reader); + void Assign(const ParserTokenReader &a_Reader); + + public: + ParserTokenReader(ParserBase *a_pParent); + ~ParserTokenReader(); + ParserTokenReader* Clone(ParserBase *a_pParent) const; + + void AddValIdent(identfun_type a_pCallback); + void SetVarCreator(facfun_type a_pFactory, void *pUserData); + int GetPos() const; + const string_type& GetFormula() const; + const varmap_type& GetUsedVar() const; + void SetFormula(const string_type &a_strFormula); + void SetDefs( const funmap_type *a_pFunDef, + const funmap_type *a_pOprtDef, + const funmap_type *a_pInfixOprtDef, + const funmap_type *a_pPostOprtDef, + varmap_type *a_pVarDef, + const strmap_type *a_pStrVarDef, + const valmap_type *a_pConstDef ); + void IgnoreUndefVar(bool bIgnore); + void ReInit(); + token_type ReadNextToken(); + + // + // private functions + // + private: + + void SetParent(ParserBase *a_pParent); + int ExtractToken( const char_type *a_szCharSet, + string_type &a_strTok, int a_iPos ) const; + bool IsBuiltIn(token_type &a_Tok); + bool IsEOF(token_type &a_Tok); + bool IsInfixOpTok(token_type &a_Tok); + bool IsFunTok(token_type &a_Tok); + bool IsPostOpTok(token_type &a_Tok); + bool IsOprt(token_type &a_Tok); + bool IsValTok(token_type &a_Tok); + bool IsVarTok(token_type &a_Tok); + bool IsStrVarTok(token_type &a_Tok); + bool IsUndefVarTok(token_type &a_Tok); + bool IsString(token_type &a_Tok); + void Error( EErrorCodes a_iErrc, int a_iPos = -1, + const string_type &a_sTok = string_type() ) const; + }; +} // namespace mu + +#endif + + diff --git a/run_me b/run_me new file mode 100755 index 0000000..a920e69 --- /dev/null +++ b/run_me @@ -0,0 +1,5 @@ +#!/bin/sh + +echo "To run the program: type ./optcli" +echo "To re-build the program, type: make clean;make" + diff --git a/samples/a b/samples/a new file mode 100755 index 0000000..b8b8e8c Binary files /dev/null and b/samples/a differ diff --git a/samples/a.cc b/samples/a.cc new file mode 100644 index 0000000..1cf92df --- /dev/null +++ b/samples/a.cc @@ -0,0 +1,36 @@ +#include +#include +#include +using namespace std; + +double powerlaw(double x) +{ + return 5*pow(x,-1.1); +} + +double bpl(double x) +{ + double x_b=5; + double f_b=10; + double gamma1=-0.8; + double gamma2=-1.5; + if(x>x>>x1>>x2>>y>>y1>>y2) + { + cout< +#include +#include +#include +using std::cerr;using std::endl; + +namespace opt_utilities +{ + template + class chisq + :public statistic + { + private: + bool verb; + int n; + + + statistic* do_clone()const + { + // return const_cast*>(this); + return new chisq(*this); + } + public: + void verbose(bool v) + { + verb=v; + } + public: + chisq() + :verb(false) + {} + + + + Ts do_eval(const Tp& p) + { + Ts result(0); + for(int i=(this->datas()).size()-1;i>=0;--i) + { + Ty chi=(this->datas().get_data(i).get_y()-eval_model(this->datas().get_data(i).get_x(),p))/this->datas().get_data(i).get_y_upper_err(); + result+=chi*chi; + + } + if(verb) + { + n++; + if(n%10==0) + { + + cerr< + class chisq,double,std::string> + :public statistic ,double,std::string> + { + public: + typedef double Ty; + typedef double Tx; + typedef std::vector Tp; + typedef double Ts; + typedef std::string Tstr; + private: + bool verb; + int n; + + statistic* do_clone()const + { + // return const_cast*>(this); + return new chisq(*this); + } + + + public: + void verbose(bool v) + { + verb=v; + } + public: + chisq() + :verb(false) + {} + + + + Ty do_eval(const Tp& p) + { + Ty result(0); + for(int i=(this->datas()).size()-1;i>=0;--i) + { + +#ifdef HAVE_X_ERROR + Tx x1=this->datas().get_data(i).get_x()-this->datas().get_data(i).get_x_lower_err(); + Tx x2=this->datas().get_data(i).get_x()+this->datas().get_data(i).get_x_upper_err(); + Ty errx=(eval_model(x1,p)-eval_model(x2,p))/2; + //Ty errx=0; +#else + Ty errx=0; +#endif + + Ty y_model=eval_model(this->datas().get_data(i).get_x(),p); + Ty y_obs=this->datas().get_data(i).get_y(); + Ty y_err; + + if(y_model>y_obs) + { + y_err=this->datas().get_data(i).get_y_upper_err(); + } + else + { + y_err=this->datas().get_data(i).get_y_lower_err(); + } + + Ty chi=(y_obs-y_model)/std::sqrt(y_err*y_err+errx*errx); + + // Ty chi=(this->datas().get_data(i).get_y()-eval_model(this->datas().get_data(i).get_x(),p)); + // cerr<datas()[i].x,p)<datas()[i].y_upper_err<datas()[i].x<<"\t"<datas()[i].y<<"\t"<datas()[i].x,p)< +#include + +using std::cout;using std::endl; +namespace opt_utilities +{ + template + class cstat_poisson + :public statistic + { + private: + bool verb; + int n; + + Ty lnfrac(Ty y)const + { + return y*log(y)-y; + } + + public: + void verbose(bool v) + { + verb=v; + } + public: + + statistic* do_clone()const + { + // return const_cast*>(this); + return new cstat_poisson(*this); + } + + Ts do_eval(const Tp& p) + { + Ts result(0); + for(int i=(this->datas()).size()-1;i>=0;--i) + { + Ty model_y=eval_model(this->datas().get_data(i).get_x(),p); + result+=model_y-this->datas().get_data(i).get_y()*log(model_y)+lnfrac(this->datas().get_data(i).get_y()); + } + + if(verb) + { + n++; + if(n%10==0) + { + cout<p_fitter->get_dof()<<"\t"; + for(int i=0;i + +using namespace blitz; + +#include + +namespace opt_utilities +{ + template + void set_element(blitz::Array& x,size_t i,TX v) + { + x(i)=v; + } + + + inline const double& get_element(const blitz::Array& x,size_t i) + { + return x(i); + } + + inline size_t get_size(const Array& x) + { + return x.extent(0); + } + + inline void resize(Array& x,size_t s) + { + x.resize(s); + } + + inline Array& opt_eq(Array& lhs, const Array& rhs) + { + lhs.resize(rhs.extent(0)); + lhs=rhs.copy(); + return lhs; + } + + template <> + class value_type_trait > + { + public: + typedef double value_type; + }; + + template <> + class value_type_trait > + { + public: + typedef double value_type; + }; +} + +#include +#include +#include +#include +#include +#include +using namespace std; +#include +#include +#include +//#include "gmpxx.h" +using namespace std; +//using namespace opt_utilities; +using namespace blitz; + +class foo + :public opt_utilities::func_obj > +{ + typedef blitz::Array pT; + double do_eval(const pT& x) + { + return x(0)*x(0)+x(1)*x(1); + } + + foo* do_clone()const + { + return new foo(*this); + } +}; + +class lin1d + :public opt_utilities::model > +{ +private: + opt_utilities::model >* do_clone()const + { + return new lin1d(*this); + } +public: + lin1d() + { + this->push_param_info(opt_utilities::param_info >("k",1)); + this->push_param_info(opt_utilities::param_info >("b",0)); + } + +public: + double do_eval(const double& x,const Array& param) + { + return x*opt_utilities::get_element(param,(size_t)0)+opt_utilities::get_element(param,(size_t)1); + } + +private: + std::string do_to_string()const + { + return "linear model\n" + "y=k*x+b\n"; + } +}; + + + +int main() +{ + opt_utilities::fitter,double> f; + //opt_utilities::optimizer > opt; + opt_utilities::powell_method > pm; + f.set_method(pm); + + Array a(2); + a=2,4; + + opt_utilities::default_data_set ds; + + for(double x=0;x<10;x+=.1) + { + opt_utilities::data d; + d.set_x(x); + d.set_x_lower_err(0); + d.set_x_upper_err(0); + d.set_y(x*3+4); + d.set_y_lower_err(.1); + d.set_y_upper_err(.1); + ds.push_back(d); + } + f.load_data(ds); + f.set_model(lin1d()); + f.set_statistic(opt_utilities::chisq,double>()); + cout< +#include +//#include "gmpxx.h" +#include "strmodel1d.hpp" +using namespace std; +using namespace opt_utilities; + +class foo + :public func_obj > +{ +public: + double do_eval(const vector& p) + { + // cout<<"p0="< > op; + powell_method > pw; + gsl_simplex > gs; + + op.set_func_obj(foo()); + op.set_opt_method(gs); + vector p1(2); + p1[0]=1; + p1[1]=1; + op.set_start_point(p1); + + vector p=op.optimize(); + cout< >; + minex_func.params = (void *)&f; + + s = gsl_multimin_fminimizer_alloc (T, 2); + gsl_multimin_fminimizer_set (s, &minex_func, x, ss); + + do + { + iter++; + status = gsl_multimin_fminimizer_iterate(s); + + if (status) + break; + + size = gsl_multimin_fminimizer_size (s); + status = gsl_multimin_test_size (size, 1e-2); + + if (status == GSL_SUCCESS) + { + printf ("converged to minimum at\n"); + } + + printf ("%5d %10.3e %10.3ef f() = %7.3f size = %.3f\n", + iter, + gsl_vector_get (s->x, 0), + gsl_vector_get (s->x, 1), + s->fval, size); + } + while (status == GSL_CONTINUE && iter < 100); + + /* + foo f; + gsl_vector_set (x, 0, 0.0); + gsl_vector_set (x, 1, 0.0); + cout<<"fdsa "; + cout< >(x,(void*)&f)< +#include +#include +#include +#include + +namespace opt_utilities +{ + template + class opt_types + { + public: + typedef fitter fitter; + typedef chisq chisq; + typedef powell_method powell_method; + typedef model model; + typedef default_data_set data_set; + }; + + typedef opt_types,double,std::string> dopt; +} + + + + +#endif +//EOF diff --git a/version_ctrl.cc b/version_ctrl.cc new file mode 100644 index 0000000..97781ad --- /dev/null +++ b/version_ctrl.cc @@ -0,0 +1,18 @@ +#include +using namespace std; +class cprt +{ +public: + cprt() + { + cerr<<"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"<