NAG関数を使用する

目次

ヘッダファイル

NAG関数を呼ぶには、ヘッダーファイルまたはNAG関数が宣言されているファイルをインクルードする必要があります。

すべてのNAGヘッダファイルを共通で使用する1つのヘッダファイルを下記に示します。通常、このヘッダファイルだけをコードにインクルードします。

#include <OC_nag.h> // 全てに共通のNAGヘッダファイル

1つまたは数個のみのNAG関数が使われている場合、それぞれ個々のNAGヘッダファイルをインクルードすることもできます。例えば、NAG関数 f02abcがコード内で使われている場合、2つの関連ヘッダファイルをインクルードする必要があります。

#include <NAG\nag.h>    // NAG 構造体と型の定義
#include <NAG\nagf02.h> // f02 関数の宣言も含む

エラー構造体

すべてのNAG関数は、NagError構造体へのポインタの1つの引数を取ります。この構造体は、NAG関数の実行が成功したかどうかをテストするために使われます。

下記のサンプルは、NAG関数f02abc がうまく動作するかどうかを示します。

NagError err;                    // エラー構造体を宣言
f02abc(n, mx, n, r, v, n, &err); // NAG f02abc 関数の呼び出し
if( err.code != NE_NOERROR )     // エラーが発生したら
    printf(err.message);         // エラーメッセージを出力

呼び出しが成功したかどうかを知る必要が無ければ、エラー構造体の宣言は必要ありません。そしてNAGERR_DEFAULT マクロが代わりに渡されます。このマクロはNULLポインタです。NAG関数の将来のバージョンとの互換性を確実にするため、エラー構造体無しで操作できるなら、このマクロを使用した方がよいでしょう。

f02abc(n, mx, n, r, v, n, NAGERR_DEFAULT);

コールバック関数

NAGライブラリで、ほとんどのルーチンはコールバック関数を含みます。コールバック関数を定義する前に、関数が呼ばれるときにNAGが期待している戻り型と引数の型を知る必要があります。

例えば、NAG関数 d01ajc は次のようになります。ヘッダファイルnagd01.h で、最初の引数が NAG_D01AJC_FUN f であることが分かります。この引数はコールバック関数です。そして、nag_types.h で、NAG_D01AJC_FUNNAG_D01_FUN の型であることがわかり、以下のように定義されます。

typedef double (NAG_CALL * NAG_D01_FUN)(double);

そして、次のようにコールバック関数を定義します。

double NAG_CALL myFunc(double x)
{
    double result;
    // 'x'で処理
    return result;
}

NAG 関数d01ajc を呼び出すと、上述で定義した myFunc は、最初の引く数として渡されます。

c05adcを呼び出すサンプル

このサンプルは、NAG関数c05adc を呼び出す方法を示し、この4番目の引数がコールバック関数の引数です。NAG_C05ADC_FUN 型のこのコールバック関数は、nag_types.h で定義されます。

typedef double (NAG_CALL * NAG_C05ADC_FUN)(double);

定義から、戻り型と引数の型がdoubleであることが分かります。そして、次のようにコールバック関数を定義できます。

double NAG_CALL myC05ADCfunc(double x)
{
    return exp(-x)-x;
}

以下のコードは、コールバック関数myC05ADCfunc を渡して、関数 c05adc を呼び出す方法を示しています。

double a = 0.0, b = 1.0, x, ftol = 0.0, xtol = 1e-05;
NagError err;

c05adc(a, b, &x, myC05ADCfunc, xtol, ftol, &err);

NAGがOriginからデータを取得

多くのNAG関数は、数値データの配列へのポインタを取ります。Originのワークシートおよび行列シートは、そのデータのポインタを取得できます。このポインタはNAG関数に渡すことができます。Origin Cで、データはDataset または DataRange オブジェクトを使って渡されます。 以下のセクションでは、DatasetおよびDataRangeを使ってワークシートからデータを渡す方法を示しています。DataRangeを使う方法がお勧めです。

Dataset

DatasetがNAG関数で期待されているデータ型であれば、DatasetオブジェクトをNAG関数に渡すことができます。Originワークシート列のデータ型は、デフォルトで文字と数値です。すべてではありませんが、ほとんどのNAG関数に対しては、NAG関数が浮動小数点または整数型のポインタを期待しているので、このデータ型を渡すことができません。

DatasetがNAG関数で期待されているデータ型であることが確実な場合、次のコードはDatasetオブジェクトをNAG関数に渡すのに使うことができます。

// アクティブワークシートへのアクセス
Worksheet wks = Project.ActiveLayer();

// データセットを構築し、wksデータにアクセス
Dataset dsX, dsY;
dsX.Attach(wks, 0);
dsY.Attach(wks, 1);

// NAGの nag_1d_spline_interpolant(e01bac)関数を呼び出し
NagError err;
Nag_Spline spline;
e01bac(m, dsX, dsY, &spline, &err);

DataRange

DataRangeクラスは、仮にワークシート列が文字と数値データ型であったとしても、ワークシートからのデータをvectorに取得するGetDataメソッドを提供します。GetDataメソッドは、欠損値を持つ行を簡単に無視でき、これはNAG関数にデータを渡すときに大変重要です。

DataRangeを使って、OriginからNAG関数にデータを渡すのはより安全で、お勧めです。以下のサンプルで、実際の方法を示しています。

void call_NAG_example()
{
	int i, numPoints = 5;

	// 新しいワークシートページを作成.
	WorksheetPage pg;
	pg.Create("origin");

	// アクティブワークシートにアクセスして2列追加
	Worksheet wks = Project.ActiveLayer();
	// X2列追加
	i = wks.AddCol();
	Column col(wks, i);
	col.SetType(OKDATAOBJ_DESIGNATION_X);
	// Y2列追加
	wks.AddCol();

	// 最初の2列でいくつかの開始XY値を作成
	Dataset dsX, dsY;
	dsX.Attach(wks, 0);
	dsY.Attach(wks, 1);
	for (i = 0; i < numPoints; i++)
	{
		int r = rnd(0) * 10;
		if (r < 1)
			r = 1;
		if (i > 0)
			r += dsX[i - 1];
		dsX.Add(r);
		dsY.Add(rnd(0));
	}

	// データ範囲オブジェクトを作成
	DataRange dr;
	dr.Add(wks, 0, "X");
	dr.Add(wks, 1, "Y");

	// データ範囲を使用してwks からデータをvedtorにコピー
	// このコピーは、欠損値を持つ行を無視
	vector vX1, vY1;
	dr.GetData(DRR_GET_DEPENDENT, 0, NULL, NULL, &vY1, &vX1);

	// NAGを呼び出して係数を計算
	NagError err;
	Nag_Spline spline;
	e01bac(vX1.GetSize(), vX1, vY1, &spline, &err);

	// スプラインの XY 値を取得
	vector vX2, vY2;
	double fit, xarg;
	for (i = 0; i < vX1.GetSize(); i++)
	{
		vX2.Add(vX1[i]);
		vY2.Add(vY1[i]);
		if (i < vX1.GetSize() - 1)
		{
			xarg = (vX1[i] + vX1[i + 1]) * 0.5;
			e02bbc(xarg, &fit, &spline, &err);
			vX2.Add(xarg);
			vY2.Add(fit);
		}
	}

	//NAGで割り当てられたメモリを解放
	NAG_FREE(spline.lamda);
	NAG_FREE(spline.c);

	// ワークシートにスプライン値をコピー
	dsX.Attach(wks, 2);
	dsX = vX2;

	dsY.Attach(wks, 3);
	dsY = vY2;
}

NAG e04関数の呼び出し方法

次のサンプルは、NAG関数nag_opt_simplex_easyを安全に呼び出す方法を示します。結果はファイルに出力します。

#include <OC_nag.h>

#define NULLFN NULL

void text_e04cbc()
{
        double objf;
	double x[2];
	Integer maxcal, n;
        NagError fail; 

	printf("\ne04cbc example: \n");

        maxcal = 100;
	n = 2;
	x[0] = 0.4;
	x[1] = -0.8;
        tolf = sqrt(nag_machine_precision);
	tolx = sqrt(tolf);
	try
	{
		// NAG関数 e04cbc = nag_opt_simplex_easy 呼び出し
		nag_opt_simplex_easy(n, x, &objf, tolf, tolx, funct, NULLFN, maxcal, NAGCOMM_NULL, &fail);  
	}
	catch(int err)
	{
		printf("\nerror = %d\n", err);  // 例外がある場合
	}
	printf("fail->code = %d\n", fail.code);  // エラーコード
	printf("fail->message = %s\n", fail.message);  // エラーメッセージ

        printf("The final function value is %12.4f\n", objf);
	printf("at the point");
	for (int ii = 1; ii <= n; ++ii)
	{
		printf(" %12.4f", x[ii-1]);
	}
	printf("\n");
}

// nag_opt_simplex_easy のコールバック関数
void NAG_CALL funct(Integer n, double* xc, double* objf, Nag_Comm* comm)
{
	*objf = exp(xc[0])*(xc[0]*4.0*(xc[0]+xc[1])+xc[1]*2.0*(xc[1]+1.0)+1.0);
}