2015/10/14

Recent entries from same category

  1. RapidJSON や simdjson よりも速いC言語から使えるJSONライブラリ「yyjson」
  2. コメントも扱える高機能な C++ 向け JSON パーサ「jsoncpp」
  3. C++ で flask ライクなウェブサーバ「clask」書いた。
  4. C++ 用 SQLite3 ORM 「sqlite_orm」が便利。
  5. zsh で PATH に相対パスを含んだ場合にコマンドが補完できないのは意図的かどうか。

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*xoptimize により 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です。

Posted at by