#include #include #include #include #include /*! \n ヘッセ行列を解く \n 渡される関数は ax^2 + bx の形で入れてください。 @param pHessianMatrix [out] 出来上がったヘッセ行列を入れる。 @param pFirstOrderCoeff [out] 偏微分の結果、定数になる項(一次項の部分) @param pFormula [in] ヘッセ行列の元になる2次式の関数。3次元の場合は(ax^2 + by^2 + cz^2 + dxy + exz + fyz + gx + hy + iz) で9つ必要。 \n 実際は最後の + DIM分は計算には必要ないが、、、。 \n 順番は、基底のみ(DIM-1)、基底の組み合わせ(DIM-2)と入れること。 */ template< const int NUMofDIM > void PartialDifferential( OUT double *pHessianMatrix, OUT double *pFirstOrderCoeff, IN const double *pFormula ) { int uBaseIdx = NUMofDIM * (NUMofDIM+1) / 2; int uBase; // ヘッセ行列の作成 for( int y = 0 ; y= d \n の形で入れるようにしてください。 \n \n 最大化を行うときは、符号と不等号を逆にして \n   目的条件 : -ax^2 - bx \n   制約条件 : -cx <= -d \n とすれば、最大化問題を解くことができます \n @param pMin [out] 最小化時の値 @param pCoeff [out] 最小化時のKKTベクトル @param pTargetFunc [in] 目的関数。3次元の場合は(ax^2 + by^2 + cz^2 + dxy + exz + fyz + gx + hy + iz) で9つ必要。 \n 実際は最後の + DIM分は計算には必要ないが、、、。 \n 順番は、基底のみ(DIM-1)、基底の組み合わせ(DIM-2)と入れること。 @param pConstrainFormula [in] 制約式の定数項以外の部分。DIM が3次元なら3つ必要。(ax + by + cz = d) なら a, b, c の部分 @param pConstant [in] 制約式の定数項の部分。(ax + by + cz = d) なら d の部分 @retval true 最適解が得られた @retval false 最適解は存在しない */ template< const int NUMofDIM, const int NUMofCON > BOOL LemkeAlgorithm( OUT double *pMin, OUT double *pCoeff, IN const double *pTargetFunc, IN const double *pConstrainFormula, IN const double *pConstant ) { static const int NUMofCOMPDIM = NUMofDIM + NUMofCON; double pCompMatrix[NUMofCOMPDIM][NUMofCOMPDIM]; // 相補条件行列 double pCompConstant[NUMofCOMPDIM]; // 相補条件定数項 // 初期化 { double pHessianMatrix[NUMofDIM][NUMofDIM]; // ヘッセ行列 double pFirstOrderCoeff[NUMofDIM]; // 1次項の係数 // ヘッセ行列と一次項の部分を格納する PartialDifferential( (double *)pHessianMatrix, (double *)pFirstOrderCoeff, pTargetFunc ); // 各行列の作成 { double pConstrainMatrix[NUMofCON][NUMofDIM]; // 制約条件行列(制約式の数×次元数 のマトリクス) // 制約条件を行列に格納 for( int y = 0 ; y 1次項の部分 //  | c| -> 定数項の部分 // となるが、ヘシアンが反転したことにより全体が -1 をかける必要があるので、 // |-r| * -1 = | r| // | c| |-c| // となっている。 for( int u = 0 ; u pExtendConst[u] ) uTradeFormula = u; } // 入れ替える { uPastTradeDimension = NUMofCOMPDIM + uTradeFormula; pBasicVariableFlg[uTradeFormula][uPastTradeDimension] = false; pBasicVariableFlg[uTradeFormula][uTradeDimension] = true; double fDiv = double(-1) / pExtendMtx[uTradeFormula][uTradeDimension]; // 行列部分 for( int x = 0 ; x<(NUMofCOMPDIM + NUMofCOMPDIM + 1) ; ++x ) pExtendMtx[uTradeFormula][x] *= fDiv; // 定数項の部分 pExtendConst[uTradeFormula] *= fDiv; } // 各基底式から人為変数を削除する for( int y = 0 ; y 0) && (pExtendConst[y] >= 0)) || ((pExtendMtx[y][uTradeDimension] < 0) && (pExtendConst[y] < 0)) ) continue; fTemp = pExtendConst[y] / -pExtendMtx[y][uTradeDimension]; // 0 より上の制約を加えないと基底が見つからない場合があるので、解は 0 より上とする。 if( (fTemp > DBL_EPSILON) && fMin > fTemp ) { // 非基底変数の対の場合は交換しない fMin = fTemp; uTradeFormula = y; } } // 基底変数が負にならないので、最適解は存在しない if( uTradeFormula == int(~0) ) return false; } // 入れ替える { // 変更前の基底変数の位置を取得する for( int x = 0 ; x<(NUMofCOMPDIM + NUMofCOMPDIM + 1) ; ++x ) { if( !pBasicVariableFlg[uTradeFormula][x] ) continue; uPastTradeDimension = x; break; } // 行列対応変数を基底にする pBasicVariableFlg[uTradeFormula][uPastTradeDimension] = false; pBasicVariableFlg[uTradeFormula][uTradeDimension] = true; // 後の後退代入で単純に置き換えるので、選択された次元の割った後の変数の符号を必ず - に保つ。 double fDiv = double(-1) / pExtendMtx[uTradeFormula][uTradeDimension]; // 行列部分 for( int x = 0 ; x<(NUMofCOMPDIM + NUMofCOMPDIM + 1) ; ++x ) pExtendMtx[uTradeFormula][x] *= fDiv; // 定数項の部分 pExtendConst[uTradeFormula] *= fDiv; } // 選択された次元の変数を各基底式から削除する for( int y = 0 ; y( &fMin, pCoeff, (double *)pTarget, (double *)pConstrain, (double *)pConstant ) ) { printf( "失敗!\n" ); return; } printf( "最小値 = %f\n", fMin ); printf( " 係数 x = %f\n", pCoeff[0] ); printf( " 係数 y = %f\n", pCoeff[1] ); printf( " 係数 z = %f\n", pCoeff[2] ); }