00001
00002
00003
00004 #include "udf.h"
00005 #include "ast.h"
00006
00007 using namespace std;
00008
00009
00010 Function* init_component(const string& func_name, const Tplate::Component& c,
00011 vector<Variable*>& variables, const Settings* settings)
00012 {
00013 assert(c.p);
00014 vector<string> varnames;
00015 v_foreach (VMData, j, c.cargs) {
00016 string var_name;
00017 if (j->single_symbol()) {
00018 int idx = j->code()[1];
00019 var_name = variables[idx]->name;
00020 }
00021 else {
00022 var_name = "_i" + S(variables.size() + 1);
00023 VMData vm = *j;
00024 if (vm.has_op(OP_TILDE))
00025 throw ExecuteError("unexpected `~' in UDF");
00026 Variable *v = make_compound_variable(var_name, &vm, variables);
00027 v->set_var_idx(variables);
00028 variables.push_back(v);
00029 }
00030 varnames.push_back(var_name);
00031 }
00032 Function *func = (*c.p->create)(settings, func_name, c.p, varnames);
00033 func->init();
00034 func->set_var_idx(variables);
00035 return func;
00036 }
00037
00038
00039 CompoundFunction::CompoundFunction(const Settings* settings,
00040 const string &name,
00041 const Tplate::Ptr tp,
00042 const vector<string> &vars)
00043 : Function(settings, name, tp, vars)
00044 {
00045 }
00046
00047 CompoundFunction::~CompoundFunction()
00048 {
00049 purge_all_elements(intern_functions_);
00050 purge_all_elements(intern_variables_);
00051 }
00052
00053 void CompoundFunction::init()
00054 {
00055 Function::init();
00056
00057
00058 for (int j = 0; j != nv(); ++j) {
00059 Variable* var = new Variable(varnames[j], -2);
00060 intern_variables_.push_back(var);
00061 }
00062
00063 v_foreach (Tplate::Component, i, tp_->components) {
00064 string func_name = "_i" + S(intern_functions_.size() + 1);
00065 Function *func = init_component(func_name, *i, intern_variables_,
00066 settings_);
00067 intern_functions_.push_back(func);
00068 }
00069 }
00070
00071 void CompoundFunction::set_var_idx(vector<Variable*> const& variables)
00072 {
00073 VariableUser::set_var_idx(variables);
00074 for (int i = 0; i < nv(); ++i) {
00075 const Variable* orig = variables[get_var_idx(i)];
00076 intern_variables_[i]->set_original(orig);
00077 }
00078 }
00079
00080 void CompoundFunction::more_precomputations()
00081 {
00082 vm_foreach (Variable*, i, intern_variables_)
00083 (*i)->recalculate(intern_variables_, vector<realt>());
00084 vm_foreach (Function*, i, intern_functions_)
00085 (*i)->do_precomputations(intern_variables_);
00086 }
00087
00088 void CompoundFunction::calculate_value_in_range(const vector<realt> &xx,
00089 vector<realt> &yy,
00090 int first, int last) const
00091 {
00092 v_foreach (Function*, i, intern_functions_)
00093 (*i)->calculate_value_in_range(xx, yy, first, last);
00094 }
00095
00096 void CompoundFunction::calculate_value_deriv_in_range(const vector<realt> &xx,
00097 vector<realt> &yy,
00098 vector<realt> &dy_da,
00099 bool in_dx,
00100 int first, int last) const
00101 {
00102 v_foreach (Function*, i, intern_functions_)
00103 (*i)->calculate_value_deriv_in_range(xx, yy, dy_da, in_dx, first, last);
00104 }
00105
00106 string CompoundFunction::get_current_formula(const string& x) const
00107 {
00108 string t;
00109 v_foreach (Function*, i, intern_functions_) {
00110 if (!t.empty())
00111 t += "+";
00112 t += (*i)->get_current_formula(x);
00113 }
00114 return t;
00115 }
00116
00117 bool CompoundFunction::get_center(realt* a) const
00118 {
00119 if (Function::get_center(a))
00120 return true;
00121 vector<Function*> const& ff = intern_functions_;
00122 bool r = ff[0]->get_center(a);
00123 if (!r)
00124 return false;
00125 for (size_t i = 1; i < ff.size(); ++i) {
00126 realt b;
00127 r = ff[i]->get_center(&b);
00128 if (!r || is_neq(*a, b))
00129 return false;
00130 }
00131 return true;
00132 }
00133
00134
00135
00136 bool CompoundFunction::get_height(realt* a) const
00137 {
00138 vector<Function*> const& ff = intern_functions_;
00139 if (ff.size() == 1)
00140 return ff[0]->get_height(a);
00141 realt ctr;
00142 if (!get_center(&ctr))
00143 return false;
00144 realt sum = 0;
00145 for (size_t i = 0; i < ff.size(); ++i) {
00146 if (!ff[i]->get_height(a))
00147 return false;
00148 sum += *a;
00149 }
00150 *a = sum;
00151 return true;
00152 }
00153
00154 bool CompoundFunction::get_fwhm(realt* a) const
00155 {
00156 vector<Function*> const& ff = intern_functions_;
00157 if (ff.size() == 1)
00158 return ff[0]->get_fwhm(a);
00159 return false;
00160 }
00161
00162 bool CompoundFunction::get_area(realt* a) const
00163 {
00164 vector<Function*> const& ff = intern_functions_;
00165 realt sum = 0;
00166 for (size_t i = 0; i < ff.size(); ++i)
00167 if (ff[i]->get_area(a))
00168 sum += *a;
00169 else
00170 return false;
00171 *a = sum;
00172 return true;
00173 }
00174
00175 bool CompoundFunction::get_nonzero_range(double level,
00176 realt& left, realt& right) const
00177 {
00178 vector<Function*> const& ff = intern_functions_;
00179 if (ff.size() == 1)
00180 return ff[0]->get_nonzero_range(level, left, right);
00181 else
00182 return false;
00183 }
00184
00185
00186
00187 CustomFunction::CustomFunction(const Settings* settings,
00188 const string &name,
00189 const Tplate::Ptr tp,
00190 const vector<string> &vars)
00191 : Function(settings, name, tp, vars),
00192
00193 derivatives_(vars.size()+1)
00194 {
00195 }
00196
00197 CustomFunction::~CustomFunction()
00198 {
00199 }
00200
00201 void CustomFunction::set_var_idx(const vector<Variable*>& variables)
00202 {
00203 VariableUser::set_var_idx(variables);
00204
00205 assert(var_idx.size() + 2 == tp_->op_trees.size());
00206
00207
00208 vector<int> symbol_map = range_vector(0, var_idx.size());
00209 vm_.clear_data();
00210 int n = tp_->op_trees.size() - 1;
00211 for (int i = 0; i < n; ++i) {
00212 add_bytecode_from_tree(tp_->op_trees[i], symbol_map, vm_);
00213 vm_.append_code(OP_PUT_DERIV);
00214 vm_.append_code(i);
00215 }
00216 value_offset_ = vm_.code().size();
00217 add_bytecode_from_tree(tp_->op_trees.back(), symbol_map, vm_);
00218 }
00219
00220 void CustomFunction::more_precomputations()
00221 {
00222 substituted_vm_ = vm_;
00223 substituted_vm_.replace_symbols(av_);
00224 }
00225
00226 void CustomFunction::calculate_value_in_range(const vector<realt> &xx,
00227 vector<realt> &yy,
00228 int first, int last) const
00229 {
00230 for (int i = first; i < last; ++i)
00231 yy[i] += run_code_for_custom_func_value(substituted_vm_, xx[i],
00232 value_offset_);
00233 }
00234
00235 void CustomFunction::calculate_value_deriv_in_range(const vector<realt> &xx,
00236 vector<realt> &yy,
00237 vector<realt> &dy_da,
00238 bool in_dx,
00239 int first, int last) const
00240 {
00241 int dyn = dy_da.size() / xx.size();
00242 for (int i = first; i < last; ++i) {
00243 realt y = run_code_for_custom_func(substituted_vm_, xx[i],derivatives_);
00244
00245 if (!in_dx) {
00246 yy[i] += y;
00247 v_foreach (Multi, j, multi_)
00248 dy_da[dyn*i+j->p] += derivatives_[j->n] * j->mult;
00249 dy_da[dyn*i+dyn-1] += derivatives_.back();
00250 }
00251 else {
00252 v_foreach (Multi, j, multi_)
00253 dy_da[dyn*i+j->p] += dy_da[dyn*i+dyn-1]
00254 * derivatives_[j->n] * j->mult;
00255 }
00256 }
00257 }
00258
00259 string CustomFunction::get_bytecode() const
00260 {
00261 const VMData& s = substituted_vm_;
00262 vector<int> der_code(s.code().begin(), s.code().begin() + value_offset_);
00263 vector<int> val_code(s.code().begin() + value_offset_, s.code().end());
00264 return "code with symbols: " + vm2str(vm_)
00265 + "\nderivatives: " + vm2str(der_code, s.numbers())
00266 + "\nvalue: " + vm2str(val_code, s.numbers());
00267 }
00268
00269
00270
00271 SplitFunction::SplitFunction(const Settings* settings,
00272 const string &name,
00273 const Tplate::Ptr tp,
00274 const vector<string> &vars)
00275 : Function(settings, name, tp, vars)
00276 {
00277 }
00278
00279 SplitFunction::~SplitFunction()
00280 {
00281 delete left_;
00282 delete right_;
00283 purge_all_elements(intern_variables_);
00284 }
00285
00286 void SplitFunction::init()
00287 {
00288 Function::init();
00289
00290
00291 for (int j = 0; j != nv(); ++j) {
00292 Variable* var = new Variable(varnames[j], -2);
00293 intern_variables_.push_back(var);
00294 }
00295
00296 left_ = init_component("l", tp_->components[1], intern_variables_,
00297 settings_);
00298 right_ = init_component("r", tp_->components[2], intern_variables_,
00299 settings_);
00300
00301 VMData vm = tp_->components[0].cargs[0];
00302 if (vm.has_op(OP_TILDE))
00303 throw ExecuteError("unexpected `~' in condition in UDF");
00304 Variable *v = make_compound_variable("split", &vm, intern_variables_);
00305 v->set_var_idx(intern_variables_);
00306 intern_variables_.push_back(v);
00307 }
00308
00309 void SplitFunction::set_var_idx(vector<Variable*> const& variables)
00310 {
00311 VariableUser::set_var_idx(variables);
00312 for (int i = 0; i < nv(); ++i) {
00313 const Variable* orig = variables[get_var_idx(i)];
00314 intern_variables_[i]->set_original(orig);
00315 }
00316 }
00317
00318 void SplitFunction::more_precomputations()
00319 {
00320 vm_foreach (Variable*, i, intern_variables_)
00321 (*i)->recalculate(intern_variables_, vector<realt>());
00322 left_->do_precomputations(intern_variables_);
00323 right_->do_precomputations(intern_variables_);
00324 }
00325
00326 void SplitFunction::calculate_value_in_range(const vector<realt> &xx,
00327 vector<realt> &yy,
00328 int first, int last) const
00329 {
00330 realt xsplit = intern_variables_.back()->get_value();
00331 int t = lower_bound(xx.begin(), xx.end(), xsplit) - xx.begin();
00332 left_->calculate_value_in_range(xx, yy, first, t);
00333 right_->calculate_value_in_range(xx, yy, t, last);
00334 }
00335
00336 void SplitFunction::calculate_value_deriv_in_range(const vector<realt> &xx,
00337 vector<realt> &yy,
00338 vector<realt> &dy_da,
00339 bool in_dx,
00340 int first, int last) const
00341 {
00342 realt xsplit = intern_variables_.back()->get_value();
00343 int t = lower_bound(xx.begin(), xx.end(), xsplit) - xx.begin();
00344 left_-> calculate_value_deriv_in_range(xx, yy, dy_da, in_dx, first, t);
00345 right_-> calculate_value_deriv_in_range(xx, yy, dy_da, in_dx, t, last);
00346 }
00347
00348 string SplitFunction::get_current_formula(const string& x) const
00349 {
00350 realt xsplit = intern_variables_.back()->get_value();
00351 return "x < " + S(xsplit) + " ? " + left_->get_current_formula(x)
00352 + " : " + right_->get_current_formula(x);
00353 }
00354
00355 bool SplitFunction::get_height(realt* a) const
00356 {
00357 realt h2;
00358 return left_->get_height(a) && right_->get_height(&h2) && is_eq(*a, h2);
00359 }
00360
00361 bool SplitFunction::get_center(realt* a) const
00362 {
00363 if (Function::get_center(a))
00364 return true;
00365 realt c2;
00366 return left_->get_center(a) && right_->get_center(&c2) && is_eq(*a, c2);
00367 }
00368
00369 bool SplitFunction::get_nonzero_range(double level,
00370 realt& left, realt& right) const
00371 {
00372 realt dummy;
00373 return left_->get_nonzero_range(level, left, dummy) &&
00374 right_->get_nonzero_range(level, dummy, right);
00375 }
00376