以前、ソルバーが VBA を介してモデルにバイナリ制約を追加しないという問題がありました...私は (ほとんど) その問題を解決しました。しかし今、私は新しい問題を抱えています。まず、問題のあるコードの関連セクションを投稿させてください。これは Excel 2007 で実行されていることに注意してください。
'build string of ByChange cells and set up cascading constraints
by_change_string = ""
For i = 1 To j - 1
If Len(by_change_string) > 0 Then 'there are already some elements in the string, so we might start with a comma
If Not (Right(by_change_string, 1) = ",") Then 'make sure the last character isn't already a comma
by_change_string = by_change_string & ","
End If
End If
current_status = Sheets("Buyback Risk Area").Range("C1").Offset(i).Value
Select Case current_status
Case "Y" 'risk area is currently yellow, so green transition is available
by_change_string = by_change_string & "$E$" & i + 1
solverok setcell:="$B$" & j + 4, MaxMinVal:=2, ValueOf:="0", ByChange:=by_change_string
'add binary constraints
solveradd cellref:="$E$" & i + 1, relation:=5, formulatext:="binary"
Case "O" 'risk area is currently orange, so green and yellow transitions are available
by_change_string = by_change_string & "$E$" & i + 1 & ",$G$" & i + 1
solverok setcell:="$B$" & j + 4, MaxMinVal:=2, ValueOf:="0", ByChange:=by_change_string
'add cascading constraints
solveradd cellref:="$E$" & i + 1, relation:=1, formulatext:="$G$" & i + 1 'says E <= G, which means you can't select green unless you've already selected yellow
'add binary constraints
solveradd cellref:="$E$" & i + 1, relation:=5, formulatext:="binary"' solveradd cellref:="$G$" & i + 1, relation:=5, formulatext:="binary"
Case "R" 'risk area is currently red, so green, yellow, and orange transitions are available
by_change_string = by_change_string & "$E$" & i + 1 & ",$G$" & i + 1 & ",$I$" & i + 1
'solverok setcell:="$B$" & j + 4, MaxMinVal:=2, ValueOf:="0", ByChange:=by_change_string
'add cascading constraints
solveradd cellref:="$E$" & i + 1, relation:=1, formulatext:="$G$" & i + 1 'says E <= G, which means you can't select green unless you've already selected yellow
solveradd cellref:="$G$" & i + 1, relation:=1, formulatext:="$I$" & i + 1 'says G <= I, which means you can't select yellow unless you've already selected orange
'add binary constraints
solveradd cellref:="$E$" & i + 1, relation:=5, formulatext:="binary"
solveradd cellref:="$G$" & i + 1, relation:=5, formulatext:="binary"
solveradd cellref:="$I$" & i + 1, relation:=5, formulatext:="binary"
Case "B" 'risk area is black, so green, yellow, orange and red transitions are avaailable
by_change_string = by_change_string & "$E$" & i + 1 & ",$G$" & i + 1 & ",$I$" & i + 1 & ",$K$" & i + 1
solverok setcell:="$B$" & j + 4, MaxMinVal:=2, ValueOf:="0", ByChange:=by_change_string
'add cascading constraints
solveradd cellref:="$E$" & i + 1, relation:=1, formulatext:="$G$" & i + 1 'says E <= G, which means you can't select green unless you've already selected yellow
solveradd cellref:="$G$" & i + 1, relation:=1, formulatext:="$I$" & i + 1 'says G <= I, which means you can't select yellow unless you've already selected orange
solveradd cellref:="$I$" & i + 1, relation:=1, formulatext:="$K$" & i + 1 'says K <= M, which means you can't select orange unless you've already selected red
'add binary constraints
solveradd cellref:="$E$" & i + 1, relation:=5, formulatext:="binary"
solveradd cellref:="$G$" & i + 1, relation:=5, formulatext:="binary"
solveradd cellref:="$I$" & i + 1, relation:=5, formulatext:="binary"
solveradd cellref:="$K$" & i + 1, relation:=5, formulatext:="binary"
End Select
Next i
'buyback amount constraint
solveradd cellref:="$O$" & j + 1, relation:=1, formulatext:="$B$" & j + 2
'set target cell
solverok setcell:="$B$" & j + 4, MaxMinVal:=2, ValueOf:="0", ByChange:=by_change_string
'set binary constraints
'binary_array = Split(by_change_string, ",")
'For i = 0 To UBound(binary_array)
' solveradd cellref:=Range(binary_array(i)), relation:=5, formulatext:="binary"
'Next i
Application.ScreenUpdating = True
SolverSolve userFinish:=False
ここでの基本的な考え方は、シートをループしてデータを調べ (実行ごとに変化します)、適切なモデルを構築することです。
文字列 by_change_string には、変化するすべての変数のセル アドレスが含まれており、すべてバイナリです。そのため、コードがスプレッドシートの各行を調べると、その行のどのセルがモデルで考慮できるかが判断され、それらが文字列に追加されます。
成長する by_change_string での solverok への複数の呼び出しは、バイナリ制約がモデルに追加されていなかった以前の問題を解決しようとする試みです。<= 制約はすべてありましたが、バイナリ制約はありませんでした。モデルに追加されるまで、変数をバイナリに制約できないようです。以前は、by_change_string を構築するループが完了した後、単一の solverok ステートメントしかありませんでしたが、そのように実行すると、すべての <= 制約が取得され、バイナリー制約はまったく取得されませんでした。
このコードをテスト シートで実行すると、結果のモデルには (セルを変更することにより) 136 個の決定変数が含まれるはずです。確認したところ、by_change_string には実際に 136 個のアドレスが含まれています。しかし、ソルバー ダイアログ ボックスを見ると、最初の 41 個しかありません。デバッグ モードで実行全体をステップ実行し、反復ごとに solverok が呼び出されるのを見ましたが、何らかの理由で変更セルによる最初の 41 個しかありません。 . そして、物事がうまくいかないデータの行について特別なことは何もありません...それは、選択されたケースの1つの最初のインスタンスなどではありません...
ソルバーがこの省略されたモデルで実行されると、最適であるというガベージ ソリューションが返されます。最終的な目的関数の値が最初の目的関数の値と同じになるように、基本的にすべてを同じに保ちます。
それで、私は別のことを試しました...下部にコメントアウトされたコードブロックがあることに気付くでしょう:
'set binary constraints
'binary_array = Split(by_change_string, ",")
'For i = 0 To UBound(binary_array)
' solveradd cellref:=Range(binary_array(i)), relation:=5, formulatext:="binary"
'Next i
ここでのアイデアは、選択したケースからすべての solverok および solveradd ステートメントを取得することにより、物事をより効率的にすることでした。最後の solverok ステートメントの後まで待機することで、すべての変数がモデルに含まれるようになったので、by_change_string をステップ実行して、それらのそれぞれをバイナリ変数にすることができます。そうすれば、1 つの solverok ステートメントのみが必要になり、一部のケースですべての solveradd を取り除くことができます。そのため、選択したケースでそれらのソルベロクとソルブラッドをすべてコメントアウトし、マクロを再度実行しました。ソルバーから出力が得られません。実行後にソルバー ダイアログを見ると、ターゲット セルとセルを変更するフィールドの両方が空白になっています。あたかも最後のソルバーロックステートメントが一度も実行されなかったかのようです。
それで、私はすべてのソルバーロックのコメントを外してみましたが、コメントアウトされたバイナリ変数のためにソルバールドを残しました。最初の 41 個の決定変数のみを取得することに戻ります。二項制約を設定するためのループは機能しましたが、ソルバーはモデルに変数を取得していません。
私はこの時点でかなり困惑しています。何か案は?