mathematicaをLAPACK代わりに使う

一般化固有値問題LAPACKを使って解いているのですが、行列が非対称になったときに
たまに結果が収束しなかったりして困ってました。僕のLAPACKの使い方が駄目なだけかもしれませんが、
倍精度doubleでは駄目かもしれない。ちなみに、単精度(float)は全然話になりません。
4倍精度のlong doubleなるものがあるのですが、今度はLAPACKが対応していない。
4倍精度に対応したMLAPACKや、別の固有値演算パック(Arnoldi法で解くやつ)のARPACKとか
あるようですが、FORTRANで書かれていて、僕の環境ではVCからのコンパイルやリンクの仕方が
意味不明すぎる。

ほとほと困っていたのですが、そういえば職場ではmathematicaが使えて、これで固有値問題
解かせるとちゃんと結果が出る。そこで、これをLAPACK代わりに使えないかと調べたところ、
mathlinkなるもので簡単に使えるようです。
以下に、mathlinkを使った一般化固有値問題を解くコードを置きます。
VCではmathematicaのライブラリとインクルードファイルのパスを通しておいてください。
使い方はinit_kernelでmathematicaカーネルを起動して、solve_generalized_eigen_problemで
カーネル固有値問題を解くようにメッセージを送って,戻ってきた結果を引数にコピーしているだけです。
メッセージ内容を書き換えると、ほかの数値計算にも使えると思います。

//
// mathematicaを使う
//
#include <float.h>
// mathlink読み出し
#include "mathlink.h"

// グローバル変数
MLINK link;
MLENV env;
char *str_S, *str_H;
char *str_in;

// NxN行列データをmathematica形式のテクストデータに変換
void conv_mat2str(char *str, double *A, int N)
{
	int i, j, n, s;
	n = 0;
	s = sprintf(&str[n], "{");
	n += s;
	for(i = 0;i < N;i++){
		s = sprintf(&str[n], "{");
		n += s;
		for(j = 0;j < N;j++){			
			if(j != (N-1))
				s = sprintf(&str[n], "%.18f, ", A[i * N + j]);
			else
				s = sprintf(&str[n], "%.18f}",  A[i * N + j]);
			n += s;
		};//j
		if(i != (N-1))
			s = sprintf(&str[n], ",");
		else
			s = sprintf(&str[n], "}\0");
		n+= s;
	};//i
};

// カーネル起動
void init_kernel()
{
	char *in[] = {
		"-linklaunch",
			"-linkname",
			"\"C:\\Program Files\\Wolfram Research\\Mathematica\\7.0\\MathKernel\" -mathlink",
			""
	};
	int errno;
	env = MLInitialize((char *)0);
	// math kernelを開く
	link = MLOpenArgv(env, in, in + 3, &errno);
	// テンポラリテキストデータワークを適当に確保
	str_S  = new char[30000];
	str_H  = new char[30000];
	str_in = new char[30000];
};

// カーネル閉じる
void close_kernel()
{
	// mathkernelを閉じる
	MLClose(link);
	MLDeinitialize(env);
	//ワーク解放
	delete str_S;
	delete str_H;
	delete str_in;
}

// 一般化固有値問題Hx=λSxを解く(実数値のみ取り出す)
void solve_generalized_eigen_problem(double *H, double *S, int N, double *E)
{
	// 行列データをmathematicaの入力テキストデータに変換
	conv_mat2str(str_S, S, N);
	conv_mat2str(str_H, H, N);
	// methematicaに入力する式作成(※注意:Re[]で無理やり実数化してます)
	// [1] A = Re[Eigensystem[{H, S}]];
	// [2] A[[1]];固有値
	// [3] A[[2]];固有ベクトル
	sprintf(str_in, "A=Re[Eigensystem[{%s, %s}]];A[[1]]\0", str_H, str_S);
    /* math kernelに計算式を送信 */
	MLPutFunction(link, "EvaluatePacket", 1);
    MLPutFunction(link, "ToExpression", 1);
    MLPutString(link, (const char *)str_in);
    MLEndPacket(link);
    /* send the packet */
	MLFlush(link);
	// 結果を受け取る
	int p;
	while ((p = MLNextPacket(link)) && p != RETURNPKT){
		MLNewPacket(link);
	};
	// 結果を変数にコピー
	double *ret;
	long n;
	double *data;
	long *dims;
	char **heads;
	long d;
	// 固有値データを受け取る
	MLGetRealList(link, &ret, &n);
    /* math kernelに計算式を送信 */
	MLPutFunction(link, "EvaluatePacket", 1);
    MLPutFunction(link, "ToExpression", 1);
    MLPutString(link, (const char *)"A[[2]]");
    MLEndPacket(link);
    /* send the packet */
	MLFlush(link);
	// 結果を受け取る
	while ((p = MLNextPacket(link)) && p != RETURNPKT){
		MLNewPacket(link);
	};
	// 固有ベクトルデータ
	MLGetRealArray(link, &data,& dims, &heads, &d);
	// 結果を固有値の小さな順にコピー
	// (mathmaticaでは固有値の絶対値の大きな順で出力されるため)
	int i, j, min_j;
	double min_E;
	for(i = 0;i < N;i++){
		min_E = DBL_MAX;
		for(j = 0;j < N;j++){
			if(min_E > ret[j]){
				min_E = ret[j];
				min_j = j;
			};
		};// j
		memcpy(&H[i * N], &data[min_j * N], sizeof(double) * N);
		memcpy(&E[i], &ret[min_j], sizeof(double));
		ret[min_j] = DBL_MAX;
	};
};