Lepton という数式パーサを見つけたので遊んでみた。
Simtk.org: Lepton Mathematical Expression Parser: Overview
Purpose/Synopsis: A small C++ library for parsing, evaluating, differentiating, and analyzing mathem...
https://simtk.org/home/lepton
一般的な数式パーサは expression を token に分解するのみだが、この lepton はもう1歩踏み込んだ処理が行える。
通常の数式は以下の様にパースし実行出来る。
#include <iostream>
#include <string>
#include <map>
#include <Lepton.h>
int
main(int argc, char* argv[]) {
std::map<std::string, double> variables;
variables["x"] = 2.0;
variables["y"] = 3.0;
std::cout << Lepton::Parser::parse("x^y").evaluate(variables) << std::endl;
// 8
return 0;
}
答えは8となる。もちろん定数も扱える。定数は optimize
により実行前に展開される。例えば 2*3*x
は optimize
により 6*x
にコンパイルされる。
#include <iostream>
#include <string>
#include <map>
#include <cmath>
#include <algorithm>
#include <Lepton.h>
#define PI 3.14
int
main(int argc, char* argv[]) {
std::map<std::string, double> constants;
constants["pi"] = PI;
Lepton::ParsedExpression exp = Lepton::Parser::parse("2*pi*x").optimize(constants);
std::cout << exp << std::endl;
// 6.28319*(x) ;
std::map<std::string, double> variables;
variables["x"] = 2;
std::cout << exp.evaluate(variables) << std::endl;
// 12.56
return 0;
}
また変数の参照も扱える。
#include <iostream>
#include <string>
#include <map>
#include <cmath>
#include <algorithm>
#include <Lepton.h>
int
main(int argc, char* argv[]) {
Lepton::CompiledExpression expression =
Lepton::Parser::parse("x+y^2").createCompiledExpression();
double& x = expression.getVariableReference("x");
double& y = expression.getVariableReference("y");
x = 1;
y = 2;
std::cout << expression.evaluate() << std::endl;
// 5
return 0;
}
尚、実行時に変数が解決されていないと例外が発生する様になっている。
さらに関数が定義出来るので sin
を定義してみた。
#include <iostream>
#include <string>
#include <map>
#include <cmath>
#include <algorithm>
#include <Lepton.h>
class SinFunc : public Lepton::CustomFunction {
int getNumArguments() const {
return 1;
}
Lepton::CustomFunction* clone() const {
return new SinFunc();
}
double evaluate(const double* arguments) const {
return std::sin(arguments[0]);
}
double evaluateDerivative(const double* arguments, const int*derivOrder) const {
return evaluate(arguments);
}
};
int
main(int argc, char* argv[]) {
std::map<std::string, Lepton::CustomFunction*> functions;
SinFunc sin_func;
functions["sin"] = &sin_func;
Lepton::ParsedExpression exp = Lepton::Parser::parse("sin(Θ)", functions);
std::map<std::string, double> variables;
variables["Θ"] = 3.14 / 2;
std::cout << exp.evaluate(variables) << std::endl;
// 1
return 0;
}
とても便利そうです。これの文字列が扱える物があれば FizzBuzz とか出来て便利(ではないが)そうと思ってしまい、我ながら駄目な人間だなーと思った。
ライセンスはMITです。