2

以前、ソルバーが 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 個の決定変数のみを取得することに戻ります。二項制約を設定するためのループは機能しましたが、ソルバーはモデルに変数を取得していません。

私はこの時点でかなり困惑しています。何か案は?

4

3 に答える 3

2

私が仮定したように:

ソルバーでは、[セルを変更する] パラメーターに最大 255 文字しか使用できません。信じられない場合は、必要なセルを手動で追加してみてください。あなたはそれをすることができなくなります。

ソルバーに渡すことができる非連続範囲の最大値は 51 です (各グループが$A$1,、1 文字 1 数字 2 ドル記号 1 コンマのような形式の 1 つのセルのみであると仮定します)。さらに手動で追加しようとすると、以前の選択がすべて削除されます。おそらくコードでそれを行うと、長さの制約を満たすとすべてが無視されます。

正直なところ、私はソルバーを使用したことがなく、コードからアクセスする方法もわかりません。とにかく、あなたはそれができないことをさせようとしています。

うまくいかないことを伝えるだけでなく、可能な (私の意見では不快ですが) 回避策を次に示します。これは、あなたがしていることをしなければならない場合に私が試みることです。重要な値をワークブックの別の場所にコピーし、連続した範囲として渡すことができるように並べて設定します。ソルバーが実行されたら、値を本来あるべき場所に戻します。

編集:ソルバーに関するこの限定的なドキュメントは少し古くなっている可能性がありますが、次のように記載されています。

モデル決定変数は、[セルを変更する] 編集ボックスに入力されます。Excel では、コンマで区切られた最大 16 個の範囲 (四角形、行または列、または単一のセル) で構成される、いわゆる複数選択を入力できます。

これは、ソルバーに対して 16 個の非連続範囲しか持たず、それが機能することを期待できることを意味します。

于 2012-12-22T04:43:19.333 に答える