我过去经常使用ExprTk库,以便进一步处理用 C 语言使用 Mathematica(包含数学表达式)生成的大型输出文件。直到现在,我专门使用这个库来处理产生 type 值的表达式,<double>
例如该库通过定义类型完美地工作
typedef exprtk::symbol_table<double> symbol_table_t;
typedef exprtk::expression<double> expression_t;
typedef exprtk::parser<double> parser_t;
并将“一切”存储在结构中
struct readInExpression
{
double a, b;
symbol_table_t symbol_table;
expression_t expression;
};
读取包含变量以及用户定义函数的a
文本b
文件
double my_function(double a, double b) {
return a+b;
}
可以通过以下方式实现
void readInFromFile(readInExpression* f, parser_t* p) {
std::string file = "xyz.txt";
std::ifstream ifs(file);
std::string content( (std::istreambuf_iterator<char>(ifs) ),
(std::istreambuf_iterator<char>() ) );
f->symbol_table.add_variable("a",f->a);
f->symbol_table.add_variable("b",f->b);
f->symbol_table.add_function("my_function",my_function);
f->expression.register_symbol_table(f->symbol_table);
p->compile(content,f->expression);
}
然后可以评估读入表达式的任意值,a
并b
使用
double evaluateFile(readInExpression* f, double a, double b) {
f->a = a;
f->b = b;
return f->expression.value();
}
最近,我在尝试处理包含复数和返回类型复数值的函数的文本文件时遇到了问题std::complex<double>
。更具体地说,我有一个.txt
包含表单表达式的文件
2*m*A0(m*m) + Complex(1.0,2.0)*B0(M*M,0.0,m*m)
其中A0(a)
和B0(a,b,c)
是由高能物理中(张量)环积分的 Passarino-Veltman 约简产生的标量环积分。这些可以在 C 中使用LoopTools进行数值计算,需要注意的是,它们对 、 和 的某些值采用a
复b
数值c
。在上面的 typedef 中简单地替换<double>
bystd::complex<double>
会在编译时引发大量错误。我不确定 ExprTk 库是否能够处理复数——我知道它不能处理自定义类,但据我了解,它应该能够处理本机数据类型(正如我在这里找到的那样, ExprTk 至少能够处理向量,但是考虑到我需要处理的表达式的复杂性,我认为不可能以某种方式以向量的形式重写所有内容,特别是由于代数与复数和向量)。请注意,我也不能将表达式分成实部和虚部,因为我必须针对变量的许多不同值评估表达式。
尽管我之前在文本文件中处理过复数和提到的函数A0(a)
,B0(a,b,c)
但我通过简单地.txt
在 C 中包含文件来解决这个问题,使用#include "xyz.txt"
,在相应的函数中实现,但是,考虑到手头的文本文件的大小,这似乎是不可能的(如果我尝试这样做,编译器会抛出错误)。
有人知道 ExprTk 是否以及如何处理复数?(非常感谢 MWE。)如果不是这样,这里的任何人都可以建议一个不同的数学解析器,它对用户友好并且可以处理 type 的复数std::complex<double>
,同时允许定义自己返回的自定义函数如此复杂的价值观?
一个 MWE:
/************/
/* Includes */
/************/
#include <iostream> // Input and Output on the console
#include <fstream> // Input and Output to files
#include <string> // In order to work with strings -- needed to loop through the Mathematica output files
#include "exprtk.hpp" // Parser to evaluate string expressions as mathematical/arithmetic input
#include <math.h> // Simple Math Stuff
#include <gsl/gsl_math.h> // GSL math stuff
#include <complex> // Complex Numbers
/**********/
/* Parser */
/**********/
// Type definitions for the parser
typedef exprtk::symbol_table<double> symbol_table_t; // (%)
typedef exprtk::expression<double> expression_t; // (%)
typedef exprtk::parser<double> parser_t; // (%)
/* This struct is used to store certain information of the Mathematica files in
order to later evaluate them for different variables with the parser library. */
struct readInExpression
{
double a,b; // (%)
symbol_table_t symbol_table;
// Instantiate expression
expression_t expression;
};
/* Global variable where the read-in file/parser is stored. */
readInExpression file;
parser_t parser;
/*******************/
/* Custom function */
/*******************/
double my_function(double a, double b) {
return a+b;
}
/***********************************/
/* Converting Mathematica Notation */
/***********************************/
/* Mathematica prints complex numbers as Complex(x,y), so we need a function to convert to C++ standard. */
std::complex<double> Complex(double a, double b) { // (%)
std::complex<double> c(a,b);
return c;
}
/************************************/
/* Processing the Mathematica Files */
/************************************/
double evaluateFileDoubleValuedInclude(double a, double b) {
return
#include "xyz.txt"
;
}
std::complex<double> evaluateFileComplexValuedInclude(double a, double b) {
return
#include "xyzC.txt"
;
}
void readInFromFile(readInExpression* f, parser_t* p) {
std::string file = "xyz.txt"; // (%)
std::ifstream ifs(file);
std::string content( (std::istreambuf_iterator<char>(ifs) ),
(std::istreambuf_iterator<char>() ) );
// Register variables with the symbol_table
f->symbol_table.add_variable("a",f->a);
f->symbol_table.add_variable("b",f->b);
// Add custom functions to the evaluation list (see definition above)
f->symbol_table.add_function("my_function",my_function); // (%)
// f->symbol_table.add_function("Complex",Complex); // (%)
// Register symbol_table to instantiated expression
f->expression.register_symbol_table(f->symbol_table);
// Compile the expression with the instantiate parser
p->compile(content,f->expression);
}
std::complex<double> evaluateFile(readInExpression* f, double a, double b) { // (%)
// Set the values of the struct to the input values
f->a = a;
f->b = b;
// Evaluate the result for the upper values
return f->expression.value();
}
int main() {
exprtk::symbol_table<std::complex<double> > st1; // Works
exprtk::expression<std::complex<double> > e1; // Works
// exprtk::parser<std::complex<double> > p1; // Throws an error
double a = 2.0;
double b = 3.0;
std::cout << "Evaluating the text file containing only double-valued functions via the #include method: \n" << evaluateFileDoubleValuedInclude(a,b) << "\n \n";
std::cout << "Evaluating the text file containing complex-valued functions via the #include method: \n" << evaluateFileComplexValuedInclude(a,b) << "\n \n";
readInFromFile(&file,&parser);
std::cout<< "Evaluating either the double-valued or the complex-valued file [see the necessary changes tagged with (%)]:\n" << evaluateFile(&file,a,b) << "\n";
return 0;
}
xyz.txt
a + b * my_function(a,b)
xyzC.txt
2.0*Complex(a,b) + 3.0*a
要让 MWE 工作,请将exprtk.hpp
文件放在您编译的同一文件夹中。
请注意,evaluateFile(...)
函数的返回类型可以是 /is std::complex<double>
,即使只返回双值类型。// (%)
尝试复值文件时,标记为的行可能会发生变化xyzC.txt
。
实例化exprtk::parser<std::complex<double> >
投掷(等等)
./exprtk.hpp:1587:10: error: no matching function for call to 'abs_impl'
exprtk_define_unary_function(abs )
而所有其他需要的类型似乎都没有抱怨 type std::complex<double>
。