liboctave + C++で可能なことを増やすために

octaveMatlab には劣るかもしれないが,かなり多くのことができる.それらのうち, liboctave で実装されているものはもちろん C++ から利用できるのだが,そうでないもの,例えばスクリプトやDLDなどによって提供されているものについても, C++ から利用できる場合がある.そのための力技テクニックを紹介する.
liboctave に関するドキュメントはとても少ない.よって liboctave で可能なことを増やすためには,どうしてもコードを読み,場合によっては改変する必要がある.

情報源

octaveマニュアルを C++ のために読む

octaveは liboctave+C++ で書かれているから,octaveマニュアルに書かれていることは,すべて C++ 上で実現できる. octave で利用できる関数が, C++ ではどのように実装されているかを探す方法を述べておこう.

octaveがデフォルトで使える関数は次の4つのうちいずれかの形式で提供されており,関数の説明箇所でどの形式かが明記されている.

[Function File]
The function described is defned using Octave commands stored in a text file. See Section 11.7 [Function Files], page 113.
[Built-in Function]
The function described is written in a language like C++, C, or Fortran, and is part of the compiled Octave binary.
[Loadable Function]
The function described is written in a language like C++, C, or Fortran. On systems that support dynamic linking of user-supplied functions, it may be automatically linked while Octave is running, but only if it is needed. See Appendix A [Dynami-cally Linked Functions], page 441.
[Mapping Function]
The function described works element-by-element for matrix and vector arguments.

[octaveマニュアル p.21 から抜粋]

この情報をもとにしてC++で使いたい関数を調べ,利用する. octaveソースコードを調べるので, octave のソースをどこかに展開しておく必要がある.以下では octave-src-dir は, octave のソースディレクトリを指すものとする.

[Function File] の利用

基本的に, octave-src-dir/scripts に"関数名.m"というファイル名で置かれている.このスクリプトliboctave+C++ に翻訳する という力技で,C++から利用できるようになる.ちなみに octaveスクリプトC++ のソースに自動翻訳するプログラムも存在するようだが,信頼性は低いようだ.

[Built-in Function] の利用

基本的に octave-src-dir/src/data.cc で定義されている.例えば columns というビルトイン関数は, data.cc で

  01302 DEFUN (columns, args, ,
  01303   "-*- texinfo -*-\n\
  01304 @deftypefn {Built-in Function} {} columns (@var{a})\n\
  01305 Return the number of columns of @var{a}.\n\
  01306 @seealso{size, numel, rows, length, isscalar, isvector, and ismatrix}\n\
  01307 @end deftypefn")
  01308 {
  01309   octave_value retval;
  01310
  01311   if (args.length () == 1)
  01312     retval = args(0).columns ();
  01313   else
  01314     print_usage ();
  01315
  01316   return retval;
  01317 }

のように定義されている.前半6行は octave に関数を提供するためのマクロ,残りが関数の中身である. octave_value retval は関数の戻り値で, args(0) は関数の最初の引数(行列)である. retval = args(0).columns (); で,行列の列数を retval に代入していることがわかる.

このように, data.cc からビルトイン関数の定義場所を探して,それを C++ 向けに少し書き直せば,比較的容易に C++ からビルトイン関数が利用できるようになる.

[Loadable Function] の利用

これは「C++ で記述した関数を octave から利用する」方法によって提供されている関数である.この提供方法はビルトイン関数とほとんど同じで,既に C++ で実装されているため,容易に書き直せるだろう.これらの関数は octave-src-dir/src/DLD-FUNCTIONS に置かれていて,多くの関数が 関数名.cc で定義されている.

[Mapping Function] の利用

多くの関数が octave-src-dir/src/mappers.cc で定義されているようだ.例えば octave の isspace は mappers.cc で

  00103 static int
  00104 xisspace (int c)
  00105 {
  00106   return isspace (c);
  00107 }
  00511   DEFUN_MAPPER (isspace, xisspace, 0, 0, 0, 0, 0, 0.0, 0.0, 0, 0,
  00512     "-*- texinfo -*-\n\
  00513 @deftypefn {Mapping Function} {} isspace (@var{s})\n\
  00514 Return 1 for whitespace characters (space, formfeed, newline,\n\
  00515 carriage return, tab, and vertical tab).\n\
  00516 @end deftypefn");

のように定義されている.前半は xisspace というC++の関数を定義しており,後半は octave の isspace を C++ の xisspace にマップしていると考えられる.

見つからない場合

ほとんどの関数のC++による実装が上記の探し方で見つかるはずだが,それでも見つからない場合は,利用したい関数名を octave のソースディレクトリで grep コマンドなどによって調べよう.