36#include <boost/spirit/home/x3.hpp>
37#include <boost/variant/apply_visitor.hpp>
42namespace x3 = boost::spirit::x3;
58 fFuncNo = assignment.func_number;
59 fAst = assignment.rhs;
101 for (
const auto& op :
fAst.rest) {
122 UInt_t mapSize, UInt_t paramSize)
124 struct CheckVisitor :
public boost::static_visitor<Bool_t>
130 CheckVisitor(UInt_t mapSize, UInt_t paramSize,
PFunction* func)
131 : fMapSize(mapSize), fParamSize(paramSize), fFunc(func) {}
133 Bool_t operator()(
const musrfit::ast::leer&)
const {
return true; }
134 Bool_t operator()(
double)
const {
return true; }
135 Bool_t operator()(
const musrfit::ast::constant&)
const {
return true; }
137 Bool_t operator()(
const musrfit::ast::parameter& p)
const {
138 if (p.number < 1 ||
static_cast<UInt_t
>(p.number) > fParamSize) {
139 std::cerr <<
"**ERROR** Parameter PAR" << p.number <<
" out of range (1-" << fParamSize <<
")" << std::endl;
145 Bool_t operator()(
const musrfit::ast::map_ref& m)
const {
146 if (m.number < 1 ||
static_cast<UInt_t
>(m.number) > fMapSize) {
147 std::cerr <<
"**ERROR** Map MAP" << m.number <<
" out of range (1-" << fMapSize <<
")" << std::endl;
153 Bool_t operator()(
const musrfit::ast::function_call& f)
const {
157 Bool_t operator()(
const musrfit::ast::power_call& p)
const {
166 Bool_t operator()(
const musrfit::ast::expression& expr)
const {
170 for (
const auto& op : expr.rest) {
178 CheckVisitor checker(mapSize, paramSize,
this);
179 return boost::apply_visitor(checker, operand);
203 Double_t result = boost::apply_visitor(evaluator,
fAst.first);
206 for (
const auto& op :
fAst.rest) {
207 Double_t rhs = boost::apply_visitor(evaluator, op.operand_);
209 switch (op.operator_) {
210 case musrfit::ast::op_plus:
213 case musrfit::ast::op_minus:
216 case musrfit::ast::op_times:
219 case musrfit::ast::op_divide:
220 if (std::abs(rhs) > 1.0e-20)
243 bool hasHighPrecOps =
false;
244 for (
const auto& op : expr.rest) {
245 if (op.operator_ == musrfit::ast::op_times || op.operator_ == musrfit::ast::op_divide) {
246 hasHighPrecOps =
true;
252 if (
const musrfit::ast::expression* inner = boost::get<musrfit::ast::expression>(&expr.first)) {
255 bool needsParens =
false;
256 if (hasHighPrecOps && !inner->rest.empty()) {
257 for (
const auto& innerOp : inner->rest) {
258 if (innerOp.operator_ == musrfit::ast::op_plus || innerOp.operator_ == musrfit::ast::op_minus) {
275 for (
const auto& op : expr.rest) {
276 switch (op.operator_) {
277 case musrfit::ast::op_plus: result +=
" + ";
break;
278 case musrfit::ast::op_minus: result +=
" - ";
break;
279 case musrfit::ast::op_times: result +=
" * ";
break;
280 case musrfit::ast::op_divide: result +=
" / ";
break;
284 if (
const musrfit::ast::expression* inner = boost::get<musrfit::ast::expression>(&op.operand_)) {
287 bool needsParens =
false;
288 if ((op.operator_ == musrfit::ast::op_times || op.operator_ == musrfit::ast::op_divide) &&
289 !inner->rest.empty()) {
290 for (
const auto& innerOp : inner->rest) {
291 if (innerOp.operator_ == musrfit::ast::op_plus || innerOp.operator_ == musrfit::ast::op_minus) {
320 struct StringVisitor :
public boost::static_visitor<TString>
323 StringVisitor(
PFunction* func) : fFunc(func) {}
325 TString operator()(
const musrfit::ast::leer&)
const {
return "leer"; }
327 TString operator()(
double val)
const {
328 std::ostringstream oss;
330 return TString(oss.str().c_str());
333 TString operator()(
const musrfit::ast::constant& c)
const {
335 if (c.sign) str =
"-";
337 switch (c.const_type) {
338 case musrfit::ast::constant::pi: str +=
"PI";
break;
339 case musrfit::ast::constant::gamma_mu: str +=
"GAMMA_MU";
break;
340 case musrfit::ast::constant::field: str += (c.sign ?
"B" :
"B");
break;
341 case musrfit::ast::constant::energy: str += (c.sign ?
"EN" :
"EN");
break;
342 case musrfit::ast::constant::temp:
350 TString operator()(
const musrfit::ast::parameter& p)
const {
352 if (p.sign) str =
"-";
358 TString operator()(
const musrfit::ast::map_ref& m)
const {
360 if (m.sign) str =
"-";
366 TString operator()(
const musrfit::ast::function_call& f)
const {
369 case musrfit::ast::fun_cos: str =
"COS";
break;
370 case musrfit::ast::fun_sin: str =
"SIN";
break;
371 case musrfit::ast::fun_tan: str =
"TAN";
break;
372 case musrfit::ast::fun_cosh: str =
"COSH";
break;
373 case musrfit::ast::fun_sinh: str =
"SINH";
break;
374 case musrfit::ast::fun_tanh: str =
"TANH";
break;
375 case musrfit::ast::fun_acos: str =
"ACOS";
break;
376 case musrfit::ast::fun_asin: str =
"ASIN";
break;
377 case musrfit::ast::fun_atan: str =
"ATAN";
break;
378 case musrfit::ast::fun_acosh: str =
"ACOSH";
break;
379 case musrfit::ast::fun_asinh: str =
"ASINH";
break;
380 case musrfit::ast::fun_atanh: str =
"ATANH";
break;
381 case musrfit::ast::fun_log: str =
"LOG";
break;
382 case musrfit::ast::fun_ln: str =
"LN";
break;
383 case musrfit::ast::fun_exp: str =
"EXP";
break;
384 case musrfit::ast::fun_sqrt: str =
"SQRT";
break;
392 TString operator()(
const musrfit::ast::power_call& p)
const {
393 TString str =
"POW(";
401 TString operator()(
const musrfit::ast::expression& expr)
const {
403 if (expr.rest.empty()) {
413 StringVisitor visitor(
this);
414 return boost::apply_visitor(visitor, operand);
455 switch (c.const_type) {
456 case musrfit::ast::constant::pi:
457 val = 3.14159265358979323846;
460 case musrfit::ast::constant::gamma_mu:
464 case musrfit::ast::constant::field:
468 case musrfit::ast::constant::energy:
472 case musrfit::ast::constant::temp:
474 if (c.index >= 0 &&
static_cast<UInt_t
>(c.index) <
fMetaData.fTemp.size()) {
477 std::cerr <<
"**ERROR** Temperature index T" << c.index <<
" out of range" << std::endl;
486 return c.sign ? -val : val;
501 Int_t idx = p.number - 1;
503 if (idx < 0 ||
static_cast<UInt_t
>(idx) >=
fParam.size()) {
504 std::cerr <<
"**ERROR** Parameter PAR" << p.number <<
" out of range during evaluation" << std::endl;
508 Double_t val =
fParam[idx];
509 return p.sign ? -val : val;
524 Int_t mapIdx = m.number - 1;
526 if (mapIdx < 0 ||
static_cast<UInt_t
>(mapIdx) >=
fMap.size()) {
527 std::cerr <<
"**ERROR** Map MAP" << m.number <<
" out of range during evaluation" << std::endl;
531 Int_t paramIdx =
fMap[mapIdx] - 1;
533 if (paramIdx < 0 ||
static_cast<UInt_t
>(paramIdx) >=
fParam.size()) {
534 std::cerr <<
"**ERROR** Mapped parameter out of range during evaluation" << std::endl;
538 Double_t val =
fParam[paramIdx];
539 return m.sign ? -val : val;
555 Double_t arg = boost::apply_visitor(*
this, f.arg.first);
556 for (
const auto& op : f.arg.rest) {
557 Double_t rhs = boost::apply_visitor(*
this, op.operand_);
558 switch (op.operator_) {
559 case musrfit::ast::op_plus: arg += rhs;
break;
560 case musrfit::ast::op_minus: arg -= rhs;
break;
561 case musrfit::ast::op_times: arg *= rhs;
break;
562 case musrfit::ast::op_divide:
563 if (std::abs(rhs) > 1.0e-20) arg /= rhs;
569 Double_t result = 0.0;
571 case musrfit::ast::fun_cos: result = std::cos(arg);
break;
572 case musrfit::ast::fun_sin: result = std::sin(arg);
break;
573 case musrfit::ast::fun_tan: result = std::tan(arg);
break;
574 case musrfit::ast::fun_cosh: result = std::cosh(arg);
break;
575 case musrfit::ast::fun_sinh: result = std::sinh(arg);
break;
576 case musrfit::ast::fun_tanh: result = std::tanh(arg);
break;
577 case musrfit::ast::fun_acos: result = std::acos(arg);
break;
578 case musrfit::ast::fun_asin: result = std::asin(arg);
break;
579 case musrfit::ast::fun_atan: result = std::atan(arg);
break;
580 case musrfit::ast::fun_acosh: result = std::acosh(arg);
break;
581 case musrfit::ast::fun_asinh: result = std::asinh(arg);
break;
582 case musrfit::ast::fun_atanh: result = std::atanh(arg);
break;
583 case musrfit::ast::fun_log: result = std::log10(std::abs(arg));
break;
584 case musrfit::ast::fun_ln: result = std::log(std::abs(arg));
break;
585 case musrfit::ast::fun_exp: result = std::exp(arg);
break;
586 case musrfit::ast::fun_sqrt: result = std::sqrt(std::abs(arg));
break;
587 default: result = 0.0;
606 Double_t base = boost::apply_visitor(*
this, p.base.first);
607 for (
const auto& op : p.base.rest) {
608 Double_t rhs = boost::apply_visitor(*
this, op.operand_);
609 switch (op.operator_) {
610 case musrfit::ast::op_plus: base += rhs;
break;
611 case musrfit::ast::op_minus: base -= rhs;
break;
612 case musrfit::ast::op_times: base *= rhs;
break;
613 case musrfit::ast::op_divide:
614 if (std::abs(rhs) > 1.0e-20) base /= rhs;
620 Double_t exponent = boost::apply_visitor(*
this, p.pow.first);
621 for (
const auto& op : p.pow.rest) {
622 Double_t rhs = boost::apply_visitor(*
this, op.operand_);
623 switch (op.operator_) {
624 case musrfit::ast::op_plus: exponent += rhs;
break;
625 case musrfit::ast::op_minus: exponent -= rhs;
break;
626 case musrfit::ast::op_times: exponent *= rhs;
break;
627 case musrfit::ast::op_divide:
628 if (std::abs(rhs) > 1.0e-20) exponent /= rhs;
633 return std::pow(std::abs(base), exponent);
651 Double_t result = boost::apply_visitor(*
this, e.first);
653 for (
const auto& op : e.rest) {
654 Double_t rhs = boost::apply_visitor(*
this, op.operand_);
655 switch (op.operator_) {
656 case musrfit::ast::op_plus: result += rhs;
break;
657 case musrfit::ast::op_minus: result -= rhs;
break;
658 case musrfit::ast::op_times: result *= rhs;
break;
659 case musrfit::ast::op_divide:
660 if (std::abs(rhs) > 1.0e-20) result /= rhs;
Visitor class for evaluating the AST.
const PMetaData & fMetaData
Double_t operator()(const musrfit::ast::leer &) const
Evaluates a leer (empty) AST node.
const std::vector< Double_t > & fParam
const std::vector< Int_t > & fMap
PMetaData fMetaData
Metadata from experimental data (field, energy, temperature, etc.)
Int_t fFuncNo
Function number extracted from label (x in FUNx)
Bool_t fValid
Validity flag: true if function parsed and initialized successfully.
musrfit::ast::expression fAst
Abstract syntax tree for the expression.
virtual Bool_t CheckMapAndParamRange(UInt_t mapSize, UInt_t paramSize)
Validates that all parameter and map references are within valid ranges.
virtual Bool_t FindAndCheckMapAndParamRange(const musrfit::ast::operand &operand, UInt_t mapSize, UInt_t paramSize)
Recursively validates parameter and map references in the AST.
virtual TString GenerateString(const musrfit::ast::expression &expr)
Generates a human-readable string representation of the AST.
virtual TString GenerateStringOperand(const musrfit::ast::operand &operand)
Generates a string representation of an operand.
TString fFuncString
Formatted, human-readable function representation.
PFunction(const musrfit::ast::assignment &assignment)
Constructor that parses and prepares a function for evaluation.
virtual ~PFunction()
Destructor that cleans up resources.
std::vector< Double_t > fParam
Current fit parameter values for evaluation.
virtual Double_t Eval(std::vector< Double_t > param, PMetaData metaData)
Evaluates the function with given parameters and metadata.
std::vector< Int_t > fMap
Map vector for indirect parameter references.