[英]VBA not adding elements to a Solver model
早些時候我遇到了一個問題,即求解器沒有通過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的循環完成之后,過去只有一個resolverok語句,但是當我這樣做時,我得到了所有<=約束,但沒有二進制約束。
當此代碼在我的測試表上運行時,生成的模型應具有136個決策變量(通過更改單元格)。 我已經檢查了,by_change_string實際上確實有136個地址。 但是,當我在“求解器”對話框中查看時,只有第一個41。我已經在調試模式下逐步執行了整個執行過程,看到它在每次迭代后都調用了solverok,但是由於某種原因,只有第一個41 by change cell存在。 出現錯誤的那一行數據沒有什么特別的...這並不是選擇情況之一或某些情況的第一個實例...
當求解器在此縮寫模型上運行時,它返回一個認為最佳的垃圾解決方案。 基本上,所有內容都相同,因此最終目標函數值與起始目標函數值相同。
因此,然后我嘗試了其他操作...您會在底部注意到注釋掉的代碼塊:
'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並將每個變量設為二進制變量。 這樣,您只需要一個solverok語句,就可以擺脫選擇情況下的所有Solvedradd。 因此,我在選擇的情況下注釋掉了所有那些solverok和solveradd,然后再次運行宏。 我沒有得到求解器的輸出。 運行后查看求解器對話框時,目標單元格和“通過更改單元格”字段均為空白。 好像最后一個solverok語句從未運行過。
因此,我嘗試取消對所有Solvedrok的注釋,但將二進制變量的Solvedradd注釋掉。 我回過頭來只獲得前41個決策變量。 設置二進制約束的循環確實起作用,但是Solvedradd並沒有將變量引入模型中。
在這一點上我很困惑。 有任何想法嗎?
正如我所假設的:
“求解器”在“通過更改單元格”參數中最多允許255個字符。 如果您不相信我,請嘗試手動添加所需的單元格。 您將無法執行此操作。
您可以通過求解器的最大非連續范圍為51(假設每個組只有1個單元格,格式$A$1,
帶有1個字母1個數字2個美元符號和1個逗號)。 如果嘗試手動添加更多內容,它將刪除所有先前的選擇。 大概只要滿足長度限制,使用代碼進行操作就將忽略所有內容。
老實說,我從未使用過求解器,也不知道如何通過代碼訪問它。 無論如何,您都在嘗試使其無法執行的操作。
現在,不僅可以告訴您它行不通,還可以解決(但我認為令人討厭)。 如果必須做您正在做的事情,這就是我會嘗試的方法。 將重要的值復制到工作簿中的另一個位置,並將它們彼此相鄰設置,以便您可以將它們作為連續范圍傳遞。 求解程序運行后,將您的值放回應放置的位置。
編輯: 此求解器的有限文檔可能有些過時,但它指出以下內容:
在“通過更改單元格”編輯框中輸入模型決策變量。 Excel允許輸入一個所謂的多重選擇,該選擇包含多達16個范圍(矩形,行或列或單個單元格),以逗號分隔。
這意味着您只能有16個不連續的范圍到規划求解,並希望它能起作用。
Daniel Cook似乎對問題的原因是正確的。 我會提出一個不同的解決方法。 創建一個包含所有非連續范圍的命名范圍,並將by_change_string設置為表示該命名范圍的字符串。
我想補充這些答案:
資料來源:我剛剛在Excel 2013中嘗試了這些解決方案
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.