DDSL: Digital Dynamic Simulation Library for C/C++,based on Graph Theory

このソフトウェアはGNU Lesser General Public Licenseに従って再配布できます。
ソースコード等はGitHubから全てをダウンロードできます。
Copylight (c) 2020 Shigeo Kobayashi. All rights reserved.
[==>English]
概要フラグ(属性)関数一覧参考

DDSL(Digital Dynamic Simulation Library for C/C++,based on Graph Theory) は動的(静的)な数値シミュレーション用の C/C++ ライブラリーです。
DDSL は静的シミュレーション用にNewton法(非線形連立方程式解法)を、動的シミュレーション用に常微分方程式解法 Euler法、Backward Euler法、Runge-Kutta法を実装しています。もっとも、これらの解法をユーザーが直接呼び出すことはありません。グラフ理論(グラフ処理)を活用して自動的に計算順序、代数連立方程式(非線形)、常微分方程式をDDSLが組み立てて解くことが出来ます(グラフ理論については文献等を参照)。

概要

DDS_PROCESSORDDS_VARIABLE
DDSLを利用するにはプロセッサー(
DDS_PROCESSOR)と複数の変数(DDS_VARIABLE)を定義する必要があります。
プロセッサー(DDS_PROCESSOR)は全ての変数(DDS_VARIABLE)を管理し、代数方程式や常微分方程式等を組み立てた後に解きます。

重要なのは計算して欲しい変数にDDS_FLAG_REQUIREDフラグを設定することです(後述)。DDSLはDDS_FLAG_REQUIREDフラグの付いた変数を計算するため、計算順序の決定等、すべてを自動的に処理して計算を実行します(以下の例参照)。

DDS_PROCESSOR と DDS_VARIABLE は c の struct へのポインターで ddsl.h で定義されています。

※: プログラミングには ddsl.h をソースプログラムに include してから適切なライブラリーをリンクしてください。
※: DDSが提供する関数などの名前は "DDS_" や "Dds" で始まります。

DDS_PROCESSOR

DDS_PROCESSORの定義:
    DDS_PROCESSOR p;
    int e = DdsCreateProcessor(&p,10);
    if(e!=0) printf("DdsCreateProcessor() returned an error\n");
DdsCreateProcessor(&p,10) は DDS_PROCESSOR に必要なメモリーを確保して、そのアドレスを p にセットします。第二引数 10 は p が管理できる変数の個数を指定します。これは後に必要なら自動的に拡大されます。 DdsCreateProcessor() は正常終了すれば 0 を、エラーの場合はゼロ以外を返します(具体的な戻り値は ddsl.h を参照)。

※:DdsCreateProcessor() は自動的に二つの組み込み変数(動的シミュレーション用の時間と積分時間刻み) timestep を用意します。

DDS_VARIABLE の簡単な静的計算例

変数(DDS_VARIABLE)は値(double),フラグ/属性(unsigned int)を持ち、右辺変数(以後 RHSV と表記)と変数の値を計算するための関数(ポインター)を必要なら持つことが出来ます。
※: 変数の値を変更するのはDDSLでユーザーは関数内で他の変数を含めて変更してはいけません。
定義:
上流: y = f(u,v,w)、この場合 u,v,w は y の上流
下流: x = f(y)、 x は y の下流に位置します。
全ての変数はプロセッサー(DDS_PROCESSOR)に、以下の様に、登録する必要があります。
    DDS_PROCESSOR p;
    DDS_VARIABLE y,x1,x2;
    DdsCreateProcessor(&p,10);
    DdsAddVariableV(p,&x1, "x1", DDS_FLAG_SET, 1.0, NULL,0); /* Register x1 to p. */
    DdsAddVariableV(p,&x2, "x2", DDS_FLAG_SET, 2.0, NULL,0);
    DdsAddVariableV(p,&y,  "y",  DDS_FLAG_REQUIRED, 0.0, CompY,2,x1,x2);
    DdsCompileGraph(p, 0); /* Check relations and determine computation order. */
    DdsComputeStatic(p);   /* Compute variable's value according to defined(by DdsCompileGraph()) order. */
    printf("Value: y=%lf x1=%lf x2=%lf\n",DdsGetValue(y),DdsGetValue(x1),DdsGetValue(x2));
    /* ==> Value: y=0.718282 x1=1.000000 x2=2.000000 */
    DdsDeleteProcessor(&p);
   double CompY(DDS_PROCESSOR p, DDS_VARIABLE y)
   {
	DDS_VARIABLE x1 = DdsGetRHSV(y, 0);
	DDS_VARIABLE x2 = DdsGetRHSV(y, 1);
	double xv1 = DdsGetValue(x1);
	double xv2 = DdsGetValue(x2);
	return exp(xv1)-xv2;
   }
※:例では簡略のため関数の戻り値をチェックしていませんが、本来エラーかどうかチェックすべきです。

DdsAddVariableV(p,&y, "y", DDS_FLAG_REQUIRED, 0.0, CompY,2,x1,x2)
は変数(DDS_VARIABLE)のメモリーを確保して、それを y にセットします。さらに y をプロセッサー p に登録します。
さらに DdsAddVariableV() はフラグ DDS_FLAG_REQUIRED、値 0.0、y の値を計算する関数ポインター CompY、RHSV x1,x2(2 は RHSV x1、x2 の個数), を y にセットします。
※: この例では y のRHSV(右辺変数) x1 、 x2 は y が p に登録される前に既に登録されています。そうでない場合、DdsCompileGraph(p, 0)を呼び出す前に RHSV を再設定する必要があります(次例)。

フラグ DDS_FLAG_REQUIRED は最終的に値を知りたい変数に付与します。

DdsAddVariableV(p,&x1, "x1", DDS_FLAG_SET, 1.0, NULL,0)
x1 と x2 に設定したDDS_FLAG_SETフラグは定数指定です。従って設定した値 (1.0 、 2.0) は不変で、例え x1 と x2 に値を計算する関数や RHSV が定義されていても無視されます。

DdsCompileGraph(p, 0) は変数関係をチェックした後、計算順序等、計算に必要なすべてを準備します。そして DdsComputeStatic(p) が求められている y を計算します。

例は冗長に見えますが、代わりに柔軟性が得られます。
例えば、フラグを以下の様に変更すると:

    DdsAddVariableV(p,&x1, "x1", DDS_FLAG_REQUIRED, 1.0, NULL,0);
    DdsAddVariableV(p,&y,  "y",  DDS_FLAG_TARGETED, 0.0, CompY,2,x1,x2);
    /* ==> Value: y=0.000000 x1=0.693148 x2=2.000000 */
DDS_FLAG_TARGETED は y の値を計算の結果(従属変数)として 0.0 にしたいという意味になります。 そのために x1 が独立変数として(DDS_FLAG_SET のフラグは外されています)、 y を 0.0 にするために計算されることになります。 指定に応じて、 DDSL は自動的に非線形方程式(通常は連立)を組み立てて y の値を計算します。

※: DdsAddVariableV() の後でもフラグは自由に変更できます。

非定常・定常を含む動的例題(DDS_FLAG_INTEGRATED 、DDS_STEADY_STATE)

以下の例は常微分方程式による積分例です。最後に 定常状態 を代数的に一気に計算します。
	/* dy/dt = A(C-y) + B */
	/* dy/dt(inf)==>0.0, y = (AC+B)/A  */
	/* Steady state y = 5.0 */
	DDS_PROCESSOR p;
	DDS_VARIABLE y, dydt, A,B,C, time, step;
	DDS_VARIABLE* pVs, *pVr;
	int i,j,nv, nr;
	DdsCreateProcessor(&p, 10);
	DdsAddVariableV(p, &A, "A", DDS_FLAG_SET, 1.0, NULL, 0);
	DdsAddVariableV(p, &B, "B", DDS_FLAG_SET, 2.0, NULL, 0);
	DdsAddVariableV(p, &C, "C", DDS_FLAG_SET, 3.0, NULL, 0);
	DdsAddVariableV(p, &y, "y", DDS_FLAG_REQUIRED|DDS_FLAG_INTEGRATED, 1.0, NULL,1, &dydt);
	DdsAddVariableV(p, &dydt, "dy/dt", DDS_FLAG_REQUIRED, 0.0, CompDYDT, 4,&A,&B,&C,&y);
	time = DdsTime(p);
	step = DdsStep(p);
	pVs = DdsGetVariables(&nv, p);
	for (i = 0; i < nv; ++i) {
		pVr = DdsGetRhsvs(&nr, pVs[i]);
		for (j = 0; j < nr; ++j) {
			pVr[j] = *((DDS_VARIABLE*)pVr[j]);
		}
	}
	DdsSetValue(step, 0.1);
	DdsCompileGraph(p, 0);
	for (i = 0; i < 11; ++i) {
		DdsComputeDynamic(p,0);
		printf("Dynamic:Time=%lf dydt=%lf y=%lf\n",
			DdsGetValue(time), DdsGetValue(dydt), DdsGetValue(y));
	}
	DdsCompileGraph(p, DDS_STEADY_STATE);
	DdsComputeStatic(p);
	printf("Steady :Time=%lf dydt=%lf y=%lf\n",
		DdsGetValue(time), DdsGetValue(dydt), DdsGetValue(y));
	DdsDeleteProcessor(&p);
double CompDYDT(DDS_PROCESSOR p, DDS_VARIABLE y)
{
	DDS_VARIABLE A = DdsGetRHSV(y, 0);
	DDS_VARIABLE B = DdsGetRHSV(y, 1);
	DDS_VARIABLE C = DdsGetRHSV(y, 2);
	DDS_VARIABLE Y = DdsGetRHSV(y, 3);
	double AV = DdsGetValue(A);
	double BV = DdsGetValue(B);
	double CV = DdsGetValue(C);
	double yv = DdsGetValue(Y);
	return AV*(CV-yv)+BV;
}

/* Computation results 
Dynamic:Time=0.000000 dydt=4.000000 y=1.000000
Dynamic:Time=0.100000 dydt=3.619000 y=1.380650
Dynamic:Time=0.200000 dydt=3.274607 y=1.725071
Dynamic:Time=0.300000 dydt=2.962992 y=2.036717
Dynamic:Time=0.400000 dydt=2.681031 y=2.318706
Dynamic:Time=0.500000 dydt=2.425901 y=2.573860
Dynamic:Time=0.600000 dydt=2.195050 y=2.804734
Dynamic:Time=0.700000 dydt=1.986167 y=3.013638
Dynamic:Time=0.800000 dydt=1.797161 y=3.202662
Dynamic:Time=0.900000 dydt=1.626141 y=3.373699
Dynamic:Time=1.000000 dydt=1.471396 y=3.528459
Steady :Time=1.000000 dydt=0.000000 y=5.000000
*/
全ての変数は(もちろん全ての RHSVも) DdsCompileGraph() を呼び出す前にプロセッサーに登録されていなければなりません。 しかし、ループ等の問題で DdsAddVariableV() 呼び出し時点で RHSV を全て登録するのは困難な時があります。
この場合、RHSV 定義時はポインターを仮に登録して、後に以下の様に登録し直す方法があります。
以下はその例です(上記例から抜粋)。
	pVs = DdsGetVariables(&nv, p);
	for (i = 0; i < nv; ++i) {
		pVr = DdsGetRhsvs(&nr, pVs[i]);
		for (j = 0; j < nr; ++j) {
			pVr[j] = *((DDS_VARIABLE*)pVr[j]);
		}
	}
※: この時の RHSV はポインター DdsAddVariableV(p, &dydt, "dy/dt", DDS_FLAG_REQUIRED, 0.0, CompDYDT, 4,&A,&B,&C,&y)).
※: DdsAddVariableV() は与えられた RHSV を格納するだけでチェックしません(NULL も指定可)。

DdsAddVariableV(p, &y, "y", DDS_FLAG_REQUIRED|DDS_FLAG_INTEGRATED, 1.0, NULL,1, &dydt)
y の登録で DDS_FLAG_INTEGRATED フラグは y が dydt を積分して(常微分方程式を解いて)計算されることを意味します(dydt は y の時間微分)。
左図の様に y 以外の変数は特定の時間平面上で計算されます。一方 y は時間刻み毎に過去(dT前)の dydt から計算されます(Euler法)。
DdsComputeDynamic(p,0) は DDS_FLAG_INTEGRATED 変数を 1 ステップ分だけ積分します。その後、変化した y の値に対応させるために DdsComputeStatic(p) を内部的に呼び出します。

※: DDSL は DdsCompileGraph(p, DDS_STEADY_STATE) と呼び出すことで定常状態 を一気に計算することが出来ます。
※: y(=DDS_FLAG_INTEGRATED:<I>) は下流の変数からは定数(=DDS_FLAG_SET:<S>)の様に見えます(参照:フラグ)。
※: 以降、詳細に説明します。

ユーザーがすること:

前例の様に、大体、以下のような順序で以下の関数を呼び出します:
  1. DdsCreateProcessor()...プロセッサーの作成
  2. DdsAddVariableV()
    DdsAddVariableA()...変数(y)を作成しプロセッサーに登録。同時に変数の値(初期値)、右辺変数(RHSV)の定義、y の値を計算する関数のセット、さらに、y のフラグG(属性)をセットします。 フラグは計算順序や連立方程式等の組み立てに決定的な役割を持ちます。
  3. DdsCompileGraph()... 変数や因果関係のチェック後、計算順序など計算実行の全てを準備します。
  4. DdsComputeStatic() or
    DdsComputeDynamic()... DdsCompileGraph()が組み立てた計算を実行します。
  5. DdsDeleteProcessor()... プロセッサーと個々の変数が確保したメモリーを開放します。

DDSL の機能:

DDSL は以下の処理を実行します:
  1. 直接的・間接的に、 DDS_FLAG_REQUIRED の変数計算に寄与しない変数を計算から除外する。
  2. ループの検出: 即ち y=f(y)、のような式は y2 = y1 - f(y1), y2 ==>0.0 の様に変形して解きます。
  3. 必要なら非線形連立方程式を組み立て(解き)ます。
  4. 計算される変数の計算順序を組み立て(解き)ます。
  5. 与えられた常微分方程式を解きます。
  6. 必要なら定常状態を常微分方程式から代数方程式に変換して解きます。
これらを DDSL がどのように実現するのか以降に詳述します。

フラグ(属性)

ユーザーフラグシステムフラグブロック三角分解
変数のフラグ(属性)(ddsl.hで定義されています)は最も重要な部分です。変数はユーザフラグとシステムフラグの2つの 32-bit unsigned int フラグを持ちます。ユーザーフラグはユーザーが設定します。DDSL がユーザフラグを設定・変更することはありません。個々のフラグは 32-bit のうちの 1-bit で set(1) または reset(0) されます。 DDSL はユーザフラグをチェックした後に、正しければシステムフラグ領域にコピーします。その後、処理に応じてシステムフラグを追加・変更します。
二つ以上のユーザーフラグを以下の様に | で連結して指定することが出来ます。

    DdsAddVariableV(p,&x2, "x2", DDS_FLAG_SET|DDS_FLAG_VOLATILE, 2.0, NULL,0);
または

    DdsSetUserFlag(x2,DDS_FLAG_SET|DDS_FLAG_VOLATILE);

ユーザーフラグ:

DDS_FLAG_REQUIREDDDS_FLAG_SETDDS_FLAG_TARGETEDDDS_FLAG_INTEGRATED
DDS_FLAG_VOLATILEDDS_FLAG_DIVISIBLEDDS_FLAG_NON_DIVISIBLE
※: ユーザーフラグは 32-ビット unsigned int 中の下位 12-ビットを使用します。従って、残り、上位 20-ビット はユーザが自由に使用できます(DDSL はユーザーフラグの上位 20-ビット を参照しません)。

ユーザーフラグ(記法)
DDS_FLAG_REQUIRED (<R>)0x00000001
もっとも重要な、このフラグは最終的に値を知りたい変数に付与します。DDSLは<R>変数を計算するために計算順序を含めてすべてを準備・処理します。
もし <R> 変数が無ければ計算は何も実行されません。

DDS_FLAG_SET (<S>)0x00000002
<S> は定数指定です。
<S> が指定されると、例え値を計算する関数や右辺変数が定義されていても全ては無視され、値が計算されることはなくなります。
この指定がされると(右辺変数が定義されていた場合、無視されることにより)連結成分が分割される場合があります。
※:連結成分(connected component) とは直接・間接的に連結された変数のグループのことです。

DDS_FLAG_TARGETED (<T>)0x00000004
<T> は計算結果として指定した値になることを強制する指定です。
従って、<T>(従属変数)を指定した値にするため、自由に値を変更できる独立変数(<F>、DDSLが検出)が上流に存在することが必要になります。 <F>変数は値を自由に変更できるので右辺変数(RHSV)を持たず、<S>でもありません。 <T> 変数を指定した値にするためには方程式(一般に非線形連立)を解く必要があります。

連立方程式の解の存在条件(DDSLがチェックします):

y<T> = f(x<F>)

  1. 従属変数 y (=<T>) の数と独立変数 x (=<F>) の数は一致する必要があります(同一連結成分上で)。
  2. <F> から <T> に到達する独立したルートが存在する必要があります。 (<F> と <T> の一対一対応)。
※: 計算前の<F> 変数の値は初期値となります。
※: 一般に N 個の <T> (N個の <F>) は N 次元の連立方程式(可能なら小さくできます。)になります。

※: 下流の変数から見れば <T> は <S> に見えます。
※: この指定の結果、連結成分が分割されることがあります。


上図は、2個の <F> と2個の <T> が接続しているので、2次元の連立方程式に見えます。 しかし、途中で一本のルートになっていて2個の「独立した」ルートがないので、計算するまでもなく解は存在しません(計算前にDDSLがチェックします)。

DDS_FLAG_DIVISIBLE (<D>)0x00000020
<D>は分割候補指定です。
左辺変数 (y とします) が直接・間接的に右辺変数となること( y = f(y) )はループとなります。 この場合、y を次の様に分割( y ==> y1 , y2 )してループ上の変数を計算する必要があります。 y1 は <F>) になり、y2 は <T>) となり、以下の様に処理されます。
y2 = y1 - f(y1)
y2==>0.0
y1 は <F>、 y2 は <T> であると同時に両者とも <DD> となります。

DDSL は自動的にループを検出して上記の処理を実行します。
どのループ上の変数も分割の対象になり得ます。 従って、ユーザは初期値の与えやすさなどを考慮して、分割の候補を <D>(DDS_FLAG_DIVISIBLE) フラグで指定することが出来ます。 DDSL は <D> フラグ変数を優先して分割します。しかし、複数のループに関係する変数があれば、そちらが優先されるので常に <D> 変数が分割されるとは限りません。 実際に分割された変数にはシステムフラグ DDS_SFLAG_DIVIDED(<DD>) が付与されます。

※: <D> が常に分割されるとは限りません。
※: y1 は元の y と同じです。新規に作成される変数 y2 は名前として yの名前+'+' となります。

DDS_FLAG_NON_DIVISIBLE (<N>)0x00000040
<N> 指定は、上記 <D> 指定とは逆に、分割してほしくない変数に付与します。ただ、上記 <D> 指定と同じ理由で分割されないとは限りません。

DDS_FLAG_INTEGRATED (<I>)0x00000008
<I> は積分指定です。右辺変数は一つで(
<DR>)(つまり、時間微分)と見なされます。 積分は常微分方程式を解くことになります。 左辺変数を計算するための関数ポインターは、常微分方程式解法が実装されているために、指定する必要はありません(Euler法、Backward Euler法、そしてRunge-Kutta法)。

定常状態の直接計算:

もし、存在するなら、積分を続ければ定常状態にいつかは達するはずです。しかし、多分、計算はかなりの量になります。

DDSL は以下の様に定常状態を代数的に直接計算することが出来ます。

  1. <I> を <F> 変数に変更する
  2. 時間微分変数 <DR> を値 0.0 (時間変化無し==>つまり定常状態)の <T> に変更する。
  3. 上記方程式(非線形連立)を解くことで、 時間微分変数 <DR> をゼロにする <I> 変数を直接計算します。
参照: DdsCompileGraph(p,DDS_STEADY_STATE)
DDS_FLAG_VOLATILE (<V>)0x00000010
<V> フラグは <S> または <T> 変数にのみ付与することが出来ます。
<V> は値が不確定(時間依存)であり、DDSL は値を管理できないことを意味します。値を管理するのはユーザー自身。

ブロック三角分解

非線形連立方程式(y=f(x) ==>0.0)を Newton 法で解く場合は Jacobian 行列(一次微分行列)を計算する必要があります。
y(x+dx) = y(x)+J*dx ==> 0.0 ,
よって dx = -J-1*y(x),
ここで J は Jacobian 行列(=dy/dx), y,x,そして dx はベクトル,さらに x+dx は繰り返し計算の次の近似値。
J や J-1 の計算は時に大規模になり得ます。
DDSL は、可能なら、J をより小さいサイズの連続した行列に分解(ブロック三角分解)します。
左図では 大きな J を計算せず (1)、(2)、そして (3) の順に(行と列を入れ換えることで)計算することが出来ます。
※:DDSL は数値微分機能を実装しているので Jacobian 行列用の計算式を用意する必要はありません。

システムフラグ:

DDS_SFLAG_ALIVEDDS_SFLAG_FREEDDS_SFLAG_DIVIDEDDDS_SFLAG_DERIVATIVE
DDS_SFLAG_ERRORDDS_COMPUTED_ONCEDDS_COMPUTED_EVERY_TIMEDDS_COMPUTED_ANY_TIME

DDSL はユーザーフラグをチェックして、それが正しければユーザーフラグをシステムフラグ領域にコピーします。 その後、処理に応じてシステムフラグ領域には各種のフラグが追加・変更・削除されます。 以下、代表的なシステムフラグの説明です。

システムフラグ (記法)
DDS_SFLAG_ALIVE (<AL>)0x00001000
直接・間接的に
<R>変数の計算に寄与する変数にこのフラグ(<AL>)が付与されます。
また、 <AL> ではない変数(<R>変数の計算に全く寄与しない変数)は計算から除外されます。

DDS_SFLAG_FREE (<F>)0x00002000
DDSL は右辺変数(RHSV)を持たず<S>でもない変数を見つけ、<F> フラグを付与します。
<F> 変数は自由に値を変更できるので、その値を決定するためには、方程式(通常非線形連立)を解く必要があります。 つまり、予め設定された値になる必要のある従属変数(
<T>)が下流に存在する必要があります。

連立方程式の解の存在条件:

DDS_SFLAG_DIVIDED (<DD>)0x00004000
DDSL はループを検出してループ上の1変数を分割します
分割の結果、一個の変数が自動的に作成・追加されます。
分割前の変数は、そのまま <F> に変更されます。新規に作成された変数は <T> になります。 どちらも、同時に <DD> 変数となります。

DDS_SFLAG_DERIVATIVE (<DR>)0x00008000
<DR>は<I>変数の右辺変数です。 つまり、 <I> 変数の微分変数となり。
定常状態計算では値 0.0 の<T> 変数に変更されます(同時に <I> 変数は <F> に変更されます)。

DDS_SFLAG_ERROR (<ER>)0x00010000
ユーザフラグの組み合わせなどにエラーがあった場合、エラーのあった変数にこのフラグがセットされます。

DDS_COMPUTED_ONCE (<1T>)0x00020000
最初に一度だけ計算される変数に設定されるフラグです。
つまり、直接・間接的に(
<V>ではない)<S> や <T> だけから計算される変数です。
<1T> 変数の値は一度計算されたら以後変更されることはありません。
※: 参照:DdsGetVariableSequence()

DDS_COMPUTED_EVERY_TIME (<ET>)0x00040000
<ET> 変数は <I> から <DR> に至るルート上にある変数で、積分計算毎に毎回計算される変数です。
※: 参照:
DdsGetVariableSequence()

DDS_COMPUTED_ANY_TIME (<AT>)0x00080000
<AT> 変数は積分計算には含まれない(<ET> 変数ではない)が時間依存である変数にセットされます。
<AT> 変数の値が必要な場合は、
DdsComputeStatic()DdsComputeDynamic()後に呼び出す必要があります。
※: 参照:DdsGetVariableSequence()

関数一覧

プロセッサー基本関数変数基本関数補助関数低レベル関数
DdsCreateProcessor
DdsDeleteProcessor
DdsAddVariableV
DdsAddVariableA
DdsCompileGraph
DdsComputeStatic
DdsComputeDynamic
DdsGetVariables
DdsTime
DdsStep
DdsGetVariableSequence
DdsSetErrorHandler
DdsGetErrorHandler
DdsGetVariableName
DdsGetValue
DdsSetValue
DdsGetRhsvs
DdsSetRHSV
DdsGetRHSV
DdsGetUserFlag
DdsSetUserFlag
DdsGetSystemFlag
DdsSetUserFlagOn
DdsSetUserFlagOff
DdsGetEPS
DdsSetEPS
DdsGetMaxIterations
DdsSetMaxIterations
DdsGetProcessorUserPTR
DdsSetProcessorUserPTR
DdsGetVariableUserPTR
DdsSetVariableUserPTR
DdsCheckVariable
DdsDbgPrintF
DdsGetVariableNext
DdsGetVariableIndex
DdsGetVariableScore
DdsSieveVariable
DdsDivideLoop
DdsCheckRouteFT
DdsBuildSequence

戻り値関数名(引数...)
intDdsCreateProcessor(DDS_PROCESSOR* p, int nv)
DdsCreateProcessor() は DDS_PROCESSOR (本体は struct で ddsl.h で定義) のメモリーを確保して、そのポインターを第1引数のプロセッサー p にセットします。
第2引数 nvp が最初に保持できる変数の最大値です。ただし、この値は必要に応じて自動的に拡大されます。
※: 戻り値 0 は正常終了。ゼロ以外はエラーコード。 各エラーコードの値は ddsl.h を参照。

voidDdsDeleteProcessor(DDS_PROCESSOR* p)
DdsDeleteProcessor() は確保したメモリーを全て解法し、さらに p 自身の領域も解放してから p にNULLを設定します。

intDdsAddVariableV(DDS_PROCESSOR p,DDS_VARIABLE *pv,const char *name,unsigned int f,double val, ComputeVal func,int nr,...)
DdsAddVariableV() は DDS_VARIABLE(本体は struct で ddsl.h で定義) のメモリーを確保してから、そのポインターを pv にセットします。
さらに作成した変数をプロセッサー p に登録します。

[引数の説明]

※: 最後の nr 個の右辺変数はこの時点では何でも構いません(NULL可)。
※: 戻り値 0 は正常終了。ゼロ以外はエラーコード。 各エラーコードの値は ddsl.h を参照。

intDdsAddVariableA(DDS_PROCESSOR p, DDS_VARIABLE* pv, const char* name, unsigned int f, double val, ComputeVal func, int nr, DDS_VARIABLE* rhsvs)
DdsAddVariableA() は最後の右辺変数指定が nr 個の要素を持つ変数配列である以外は
DdsAddVariableV() と同じです。
※: 戻り値 0 は正常終了。ゼロ以外はエラーコード。 各エラーコードの値は ddsl.h を参照。

intDdsCompileGraph(DDS_PROCESSOR p,int method)
DdsCompileGraph() は以下の(低レベル)関数を順に呼び出し、計算前の全てを準備します。

  1. DdsSieveVariable(p)... ユーザ-フラグを、チェック後、システムフラグにコピー。さらに <AL> を選別します。
  2. DdsDivideLoop(p)... ループを検出後、<DD>変数を分割します。
  3. DdsCheckRouteFT(p)...は <F> と <T> の 1 対 1 ルート対応、を確認後 ブロック三角化分解を実行します。
  4. DdsBuildSequence(p)... 各変数の計算順序を決定します。
DdsCompileGraph() は計算順序決定の際に全ての変数を以下の 3 つのグループに分類します(DdsBuildSequence(p))。 引数 method は 0(デフォルト:DDS_I_RUNGE_KUTTA)、または以下の一つ: 計算順序は上記3種類の指定に従って変化します。
※: 戻り値 0 は正常終了。ゼロ以外はエラーコード。 各エラーコードの値は ddsl.h を参照。

intDdsComputeStatic(DDS_PROCESSOR p)
DdsComputeStatic() は特定時間平面上の変数値を計算します。変数値計算に非線形連立方程式が含まれていれば Newton 方で解きます。
※: 戻り値 0 は正常終了。ゼロ以外はエラーコード。 各エラーコードの値は ddsl.h を参照。

intDdsComputeDynamic(DDS_PROCESSOR p,int method)
DdsComputeDynamic() は常微分方程式の 1 ステップ 分を計算します(時間を1ステップ 分進めます)。
計算は以下の順に実行されます:

  1. 最初に必要なら DdsComputeStatic() を呼び出し、時間 t(=current time) の時の全変数値を計算します。
  2. 次に、例えば <I> を y(t) とすると dt 時間後の値 y(t+dt) を常微分方程式を解くことで計算します。t は 現在時刻、 dt は 積分時間刻みです。
  3. さらに現在時刻を t + dt として、変化した y(t+dt) に影響される全変数を DdsComputeStatic() を呼び出すことで計算します(参照:DdsGetVariableSequence(p,DDS_COMPUTED_EVERY_TIME))。
method は 0(デフォルト)、または DDS_I_EULER か DDS_I_RUNGE_KUTTA を指定します。
DDS_I_EULER または DDS_I_RUNGE_KUTTA は、 DdsCompileGraph() にどちらかを指定した場合のみ可能です( DDS_I_EULER と DDS_I_RUNGE_KUTTA は相互に交換可能です)。
※: 時間(t) は自動的に 時間刻み (予め設定されている必要があります)分更新されます。
※: 戻り値 0 は正常終了。ゼロ以外はエラーコード。 各エラーコードの値は ddsl.h を参照。

ErrHandlerDdsGetErrorHandler(DDS_PROCESSOR p)
DdsGetErrorHandler() はプロセッサー p に登録されているエラーハンドラー(ErrorHandler)を返します。
ユーザーはこのエラーハンドラーを利用してエラー時の情報を得ることが出来ます(参照:ddsl.h)。

voidDdsSetErrorHandler(DDS_PROCESSOR p, ErrHandler handler)
DdsSetErrorHandler() はエラーハンドラー ErrorHandler(handler)をプロセッサー p に登録します。
ユーザーはこのエラーハンドラーを利用してエラー時の情報を得ることが出来ます(参照:ddsl.h)。

DDS_VARIABLEDdsTime(DDS_PROCESSOR p)
DdsTime() は組み込みの時間変数(名前は "#TIME" )を返します。
時間の初期値は 0.0、
DdsComputeDynamic() によって1時間刻み分進められます。

DDS_VARIABLEDdsStep(DDS_PROCESSOR p)
DdsStep() は組み込みの時間刻み変数(名前は "#STEP" )を返します。
初期値は 0.0 です。従って時間を進めるには、
DdsComputeDynamic()を呼び出す前に、適切な値を設定する必要があります(参照: DdsSetValue())。

unsigned intDdsGetUserFlag(DDS_VARIABLE v)
DdsGetUserFlag() はすべての
ユーザーフラグ(32-ビット)を返します。

unsigned intDdsSetUserFlag(DDS_VARIABLE v,unsigned int f)
DdsSetUserFlag() はすべての
ユーザーフラグ(32-ビット)を指定した f と置き換えて、 f を返します。

unsigned intDdsGetSystemFlag(DDS_VARIABLE v)
DdsGetSystemFlag() はすべての
システムフラグ(32-ビット)を返します。

unsigned intDdsSetUserFlagOn(DDS_VARIABLE v, unsigned int f)
DdsSetUserFlagOn() は以下の様にユーザーフラグ(F)を、指定された f のオン(1)になっている部分のみを 1 に設定します。戻り値は結果の F となります。
F |= f

unsigned intDdsSetUserFlagOff(DDS_VARIABLE v, unsigned int f)
DdsSetUserFlagOff() は以下の様にユーザーフラグ(F)を、指定された f のオン(1)になっている部分のみを 0 に設定します。戻り値は結果の F となります。
F &= ~(f)

DDS_VARIABLE*DdsGetVariables(int* nv, DDS_PROCESSOR p)
DdsGetVariables() はプロセッサー p に登録された変数配列を返します。 nv は配列のサイズがセットされます。

void*DdsGetVariableUserPTR(DDS_VARIABLE v)
DdsGetVariableUserPTR() は変数 v に登録されているユーザーポインター(任意)を返します。 ユーザーポインターの使用方法はユーザー次第です。DDS がこのポインターを参照することはありません。

voidDdsSetVariableUserPTR(DDS_VARIABLE v, void* val)
DdsSetVariableUserPTR() はユーザーポインター(任意)val を変数 v に登録ます。 ユーザーポインターの使用方法はユーザー次第です。DDS がこのポインターを参照することはありません。

const char*DdsGetVariableName(DDS_VARIABLE v)
DdsGetVariableName() は変数 v の名前を返します。

doubleDdsGetValue(DDS_VARIABLE v)
DdsGetValue() は変数 y の値を返します。

doubleDdsSetValue(DDS_VARIABLE v,double val)
DdsSetValue() は変数 y の値を val に設定します。

DDS_VARIABLE*DdsGetRhsvs(int* nr, DDS_VARIABLE v)
DdsGetRhsvs() は変数 v の右辺変数(RHSV)配列を返します。 nr には右辺変数の数(配列サイズ)がセットされます。

intDdsSetRHSV(DDS_VARIABLE v, int i, DDS_VARIABLE rv)
DdsSetRHSV() は変数 v の右辺変数配列の i 番目の要素を rv に置き換えます。

DDS_VARIABLEDdsGetRHSV(DDS_VARIABLE v, int i)
DdsGetRHSV() は変数 v の右辺変数配列の i 番目の要素を返します。

DDS_VARIABLEDdsGetVariableSequence(DDS_PROCESSOR p, unsigned int seq)
DDS は
DdsCompileGraph() で各変数の計算順序を決定します。
DDS(DdsCompileGraph()) はさらに計算される変数を以下の3グループに分割します。 各グループは先頭から最終まで計算順序に従ったリンクリストで繋がっています(最終変数の次は NULL となります)。

  1. DDS_COMPUTED_ONCE ... 最初に一度計算しか計算されない変数グループです。
  2. DDS_COMPUTED_EVERY_TIME ... 各積分ステップ毎、毎回計算される変数グループです。
  3. DDS_COMPUTED_ANY_TIME ... 時間に依存しているもののDdsComputeDynamic()呼び出し後に、必要なら DdsComputeStatic() 呼び出しで計算される変数グループです。
上記変数は以下の様に列挙できます(引数 seq は上記3グループの一つを指定します):

  DDS_VARIABLE v = DdsGetVariableSequence(p,DDS_COMPUTED_ONCE);
  /* The order of variables computed at DDS_COMPUTED_ONCE */
  while(v != NULL) {
     printf(" Name=%s\n",DdsGetVariableName(v));
     v = DdsGetVariableNext(v);
  }
doubleDdsGetEPS(DDS_PROCESSOR p)
DdsGetEPS() は非線形連立方程式の収束判定定数を返します。

doubleDdsSetEPS(DDS_PROCESSOR p, double eps)
DdsSetEPS() は非線形連立方程式の収束判定定数(eps)を設定します。

intDdsGetMaxIterations(DDS_PROCESSOR p)
DdsGetMaxIterations() は非線形連立方程式の最大繰返し回数を返します。

intDdsSetMaxIterations(DDS_PROCESSOR p, int max)
DdsSetMaxIterations() は非線形連立方程式の最大繰返し回数を max に設定します。

void*DdsGetProcessorUserPTR(DDS_PROCESSOR p)
DdsGetProcessorUserPTR() はプロセッサーに登録されたユーザーポインター(任意)を返します。 ユーザーポインターの使用方法はユーザー次第です。DDS がこのポインターを参照することはありません。

voidDdsSetProcessorUserPTR(DDS_PROCESSOR p,void* val)
DdsSetProcessorUserPTR() はユーザーポインター(任意)val をプロセッサー p に登録ます。 ユーザーポインターの使用方法はユーザー次第です。DDS がこのポインターを参照することはありません。

intDdsCheckVariable(DDS_PROCESSOR p, DDS_VARIABLE hv)
DdsCheckVariable() はプロセッサー p に登録された変数のユーザーフラグ等をチェックします。
もし、何らかのエラーが検出されればゼロ以外の値を返すとともに、エラーのあった変数のシステムフラグには
DDS_SFLAG_ERROR が設定されます。

voidDdsDbgPrintF(FILE* f, const char* title, DDS_PROCESSOR p)
DdsDbgPrintF() は全変数の情報を title と共に FILE* f に出力します。 出力情報などの詳細は ddsl.cpp を参照してください。

DDS_VARIABLEDdsGetVariableNext(DDS_VARIABLE v)
DdsGetVariableNext() は各変数が内部に保有するリンク(処理段階に応じて変化します)'NEXT' を返します。
詳細は ddsl.cpp を参照してください。

intDdsGetVariableIndex(DDS_VARIABLE v)
DdsGetVariableIndex() は各変数が内部に保有するインデックス(処理段階に応じて変化します)'INDEX' を返します。
詳細は ddsl.cpp を参照してください。

intDdsGetVariableScore(DDS_VARIABLE v)
DdsGetVariableScore() は各変数が内部に保有するスコアー(処理段階に応じて変化します)'SCORE' を返します。
詳細は ddsl.cpp を参照してください。

intDdsSieveVariable(DDS_PROCESSOR p)
低レベル関数、詳細は
DdsCompileGraph() のソースコードを参照してください。

intDdsDivideLoop(DDS_PROCESSOR p)
低レベル関数、詳細は
DdsCompileGraph() のソースコードを参照してください。

intDdsCheckRouteFT(DDS_PROCESSOR p)
低レベル関数、詳細は
DdsCompileGraph() のソースコードを参照してください。

intDdsBuildSequence(DDS_PROCESSOR p)
低レベル関数、詳細は
DdsCompileGraph() のソースコードを参照してください。


参照論文等:

小林 茂雄 2021-6-10

このソフトウェアを偉大なお二人(故人)に捧げます。天才プログラマー、かつての上司、恒川純吉氏と大数学者の伊理正夫先生。そしてこのソフトウェアは私が、短い期間でしたが、お二人と共に仕事が出来た栄誉の証明でもあります。