R の関数を C# から使う


[note]
[2012-11-09 06:00 追記] この記事は R の内部関数を呼び出す方法について記述しています。 R のスクリプトを C# から呼んだり,その結果を C# で操作したい場合は R.NET をご利用ください。
[/note]

統計解析環境の R に定義されている様々な関数を C# から使えると便利だと感じている人は少なからずいるのではないかと思うのです。 R.dll を介して使うことができるのですが,そのためのクラスを定義するのが面倒なので動的に読み込むと良いです。

public sealed class REngine : LateBoundUnmanagedDll
{
	public string Version
	{
		get
		{
			GetDllVersion getVersion = GetFunction<GetDllVersion>("getDLLVersion");
			return Marshal.PtrToStringAnsi(getVersion());
		}
	}

	public REngine(params string[] args)
		: base("R.dll")
	{
		InitializeEmbeddedR initialize = GetFunction<InitializeEmbeddedR>("Rf_initEmbeddedR");
		initialize(args.Length, args);
	}

	protected override bool ReleaseHandle()
	{
		EndEmbeddedR end = GetFunction<EndEmbeddedR>("Rf_endEmbeddedR");
		end(0);
		return base.ReleaseHandle();
	}

	[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
	private delegate int InitializeEmbeddedR(int argc, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] string[] argv);
	[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
	private delegate void EndEmbeddedR(int fatal);
	[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
	[return: MarshalAs(UnmanagedType.LPStr)]
	private delegate IntPtr GetDllVersion();
}

R.dll は R_HOME\bin に入っているので,ディレクトリを DLL 探索パスに追加して使用します。使いたい関数は R_HOME\include\Rmath.h あたりを探すと見つかると思います。例えばガンマ関数を使いたい場合は Rf_gammafn という関数が見つかります。

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate double Gamma(double x);

REngine.SetDllDirectory(@"X:\path\to\R\R-x.y.z\bin");
using (REngine engine = new REngine())
{
	Console.WriteLine("R version: {0}", engine.Version);
	var gamma = engine.GetFunction<Gamma>("Rf_gammafn");
	Console.WriteLine("Γ(0.5) = {0:F5}", gamma(0.5));
}

更新履歴

[2010-11-19 22:45] Embed のスペルが間違っていた点を修正。 GetDllVersion デリゲートの戻り値の型を IntPtr から string に変更して MarshalAsAttribute をつけた。

[2011-03-11 20:00] GetDllVersion の戻り値の型を IntPtr に戻した。デリゲートに UnmanagedFunctionPointerAttribute をつけた。