数理最適化セミナーのご案内

5.3 ドライバ

 ではこのモデルを解く汎用のC++プログラムを準備しましょう.それはプロジェクトに追加されている

driver.cpp

というファイルで,knapsackSolveという名前の手続きです.このルーチンのインタフェースは入力として,ナップサック問題のモデルの

Parameter a(index = i);
Parameter b;
Parameter c(index = i);

に相当するデータ(aargbargcarg)を与えると

Variable x(index = i);

に相当する変数値(xarg)と目的関数(farg)を返すというものです.ドライバのこのインタフェースは問題に特化して調整できるので,より柔軟なコード作成が可能になります.

#include "knapsack.h"   // インクルード宣言
//
//  ナップサック問題の求解
//       
//
int knapsackSolve(int narg // 問題のサイズ
       ,double* aarg  // 係数a
       ,double barg   // 係数b
       ,double* carg  // 係数c
       ,double* xarg  // 解ベクトル( x )
       ,double* farg  // 目的関数
       )
{
  // 初期化
  SimpleInitialize();
  { // SimpleInitialize()のコールの後は{を付ける
    // 値転送用のオブジェクト
    Set S;
    Element i(set = S);
    Parameter b;
    Parameter c(index = i), a(index = i);

    // C配列を初期化用のデータに与える.
    b = barg; // スカラはそのまま代入
    c.readD(narg, carg); // 配列からSIMPLEのオブジェクトへの設定
    a.readD(narg, aarg); // 配列からSIMPLEのオブジェクトへの設定

    //
    // knapsack問題の求解
    //
    System_knapsack knap(c, a, b);

    int len;
    int* ind;
    double* knapx;
    knap.x.val.dump(len, ind, knapx); 
    // knapsack問題のxをCの配列であるknapxに設定

    // 解を戻り配列に設定
    int it;
    for (it = 0; it < len; ++it) {
      xarg[it] = knapx[it];
    }
    *farg = result.optValue; 
    // 目的関数値を取る簡単な方法(asDouble()でも可能)

    // 不要な領域の破壊
    delete [] ind;
    delete [] knapx;
  } // SimpleClearBuffer()のコールの前を}で閉じる.
    // 終了処理
    SimpleClearBuffer();
    return result.errorCode; // エラーコードを返す.
}

 SimpleInitialize()SimpleClearBuffer()はC++SIMPLEを利用した処理の最初と最後に必ず必要なコールです.実装上の理由により,SimpleInitializeのコールより後と,SimpleClearBuffer()のコールより前は{ }でくくる必要があります.SIMPLEのオブジェクト(SetElement)の宣言は,この{ }の中で行います.SimpleInitializeをコールせずにSIMPLEのオブジェクトを宣言して利用した場合,あるいはこの{}の外でSIMPLEのオブジェクトを宣言すると実行時エラーとなります.

 手続きの中ほどでSystem_knapsackというクラスのオブジェクトknapを宣言していますが,これがknapsack.smpというモデル記述に対応するクラスのオブジェクトの宣言です.このプログラムの先頭の

#include "knapsack.h"

がこのモデル定義を含むファイルで,モデルknapsackに対応するクラスを利用する場合には必ずインクルードする必要があります.

 一般にNAME.smpなるモデルにはSystem_NAMEというクラスが対応します.クラスの定義ファイルNAME.hにはSystem_NAMEの定義が書かれています.そのため,System_NAMEを使用する際には必ずNAME.hのインクルードが必要になります.

 クラス宣言の中でSIMPLEオブジェクトをrequiredというキーワード付きで

// knapsack.smpの中
Parameter c(index = i, required);
Parameter a(index = i, required);
Parameter b(required);

のように宣言しているので,呼び出し側の手続きで同様に宣言した受け渡し用のオブジェクト

// driver.cppの中
Set S;
Element i(set = S);
Parameter b;
Parameter c(index = i), a(index = i);

b = barg; // スカラはそのまま代入
c.readD(narg, cary); // 配列はreadDを用いる.
a.readD(narg, aary); // 配列はreadDを用いる.

として値を設定,システムオブジェクトknapの宣言の際に

System_knapsack knap(c, a, b); // knapsack問題の求解

のように渡しています(この引数にはモデル中,requiredというキーワード付きで宣言したオブジェクトが出現順に並びます).


 

 

上に戻る