I am new to VBA and have a question.
in Excell, I estimated 3 values by using solver. The objective was set to an exact value, including there were 6 simple constraints.
Now I want to re-estimate these 3 values by only incrementally increasing the objective value (thus constraints stay the same).
I am thinking a using a loop in VBA but I have no idea where to start since I am no Pro in VBA.
can anyone help?
Ciao!
you can make a loop to adapt the target value for the solver via vba. In the vba editor you need to add reference to the solver (menu tools-> references-> check solver).
in the loop i is used to set the target, once the solution is found, the corresponding range B9:D9 is copied as from column F.
Dim i
For i = 1 To 40
SolverOk SetCell:="B21", MaxMinVal:=3, ValueOf:=i, ByChange:="B9:D9", Engine:= _
1, EngineDesc:="GRG Nonlinear"
SolverSolve True
Range("B9:D9").Copy Cells(i, "F")
Next i
Related
I am trying to run an automatic solver over a column of values. Target, reference and constraints cells are all in the same row, and they shift down with the target cell while running the solver throughout the column. The target cell has to be minimized, by changing the reference cell on the same row, under the constrain requiring to keep a third cell (that depends on the reference cell value) greater or equal than a fourth cell. None of the cells contain integers, all of them contain decimal values.
To resume:
Target cell (to be minimized) : P13
Reference cell (changing cell) : L13
Constrain (where M13 depends on L13) : M13 >= F13
all down to row 8795, shifting accordingly all the cells before mentioned.
The solver works fine running it manually row by row, but trying to automatize it in order to avoid 8762 iterations it doesn't respect the constrain. I have tried to remove " ", to add SolverReset and to put the constraint on top of the instructions, but nothing worked well. The code is:
Private Sub CommandButton1_Click()
Dim count As Integer
count = 13
Do While count <= 8795
SolverOk SetCell:=Cells(count, 16), MaxMinVal:=2, ByChange:=Cells(count, 12)
SolverAdd CellRef:=Cells(count, 13), Relation:=3, FormulaText:=Cells(count, 6)
SolverSolve userfinish:=True
count = count + 1
Loop
End Sub
I was trying to change constraint and I have noticed where probably the bug is: after running the code, if I open the solver I can see the last constraint used by the code. As you can see in the image below, I've tried to set a new constraint L13<=H13, where H13= 9,272 but the solver has 9272190.... maybe it is not "seeing" the decimal separator. Any idea?
Thank you for your time.
I'm using VBA to loop through several hundred rows with Objective cells to be minimized using Solver.
Solver often isn't able to find a solution, but provides nothing to indicate whether the Objective cell has legitimately been minimized or whether solver quit prematurely because it could not find a feasible solution.
I am using SolverSolve UserFinish:=True and SolverFinish KeepFinal:=1 to avoid clicking through hundreds of dialogue boxes.
Ideally, I would like to be able to return some sort of a flag beside the Objective cell to indicate whether solver was able to find a solution.
Below is a sample of my code:
For i = iStart To iStop
'clear solver
SolverReset
'set up formula
SolverOk SetCell:=Range("$EN$4").Offset(i, 0).Address, MaxMinVal:=2, ValueOf:=0, ByChange:= _
Range("$U$4:$AE$4,$BX$4:$CI$4,$CJ$4:$CU$4").Offset(i, 0).Address, _
Engine:=2, EngineDesc:="GRG Nonlinear"
'set parameters
'set variables as integers
'number of each model
SolverAdd CellRef:=Range("$U$4:$AE$4").Offset(i, 0).Address, _
Relation:=4, FormulaText:="integer"
'mono allocations
SolverAdd CellRef:=Range("$BX$4:$CI$4").Offset(i, 0).Address, _
Relation:=4, FormulaText:="integer"
'colour allocations
SolverAdd CellRef:=Range("$CJ$4:$CU$4").Offset(i, 0).Address, _
Relation:=4, FormulaText:="integer"
'set mono/colour max >= Optimal mono/colour click allocation
SolverAdd CellRef:=Range("$EI$4").Offset(i, 0).Address, _
Relation:=3, FormulaText:=Range("$EK$4").Offset(i, 0).Address
'set colour max >= Optimal total colour click allocation
SolverAdd CellRef:=Range("$EJ$4").Offset(i, 0).Address, _
Relation:=3, FormulaText:=Range("$EM$4").Offset(i, 0).Address
'solve and avoid popups
SolverSolve UserFinish:=True
SolverFinish KeepFinal:=1
Next i
The function SolverSolve returns a result you can use to determine the outcome
From MSDN:
If a Solver problem has not been completely defined, SolverSolve returns the #N/A error value. Otherwise the Solver runs, and SolverSolve returns an integer value corresponding to the message that appears in the Solver Results dialog box:
0 = Solver found a solution. All constraints and optimality conditions are satisfied.
1 = Solver has converged to the current solution. All constraints are satisfied.
2 = Solver cannot improve the current solution. All constraints are satisfied.
3 = Stop chosen when the maximum iteration limit was reached.
4 = The Objective Cell values do not converge.
5 = Solver could not find a feasible solution.
6 = Solver stopped at user's request.
7 = The linearity conditions required by this LP Solver are not satisfied.
8 = The problem is too large for Solver to handle.
9 = Solver encountered an error value in a target or constraint cell.
10 = Stop chosen when the maximum time limit was reached.
11 = There is not enough memory available to solve the problem.
13 = Error in model. Please verify that all cells and constraints are valid.
14 = Solver found an integer solution within tolerance. All constraints are satisfied.
15 = Stop chosen when the maximum number of feasible [integer] solutions was reached.
16 = Stop chosen when the maximum number of feasible [integer] subproblems was reached.
17 = Solver converged in probability to a global solution.
18 = All variables must have both upper and lower bounds.
19 = Variable bounds conflict in binary or alldifferent constraint.
20 = Lower and upper bounds on variables allow no feasible solution.
You can use this to determine the success or otherwise of the Solve, and then write a flag to the sheet as required
Refer MSDN article
Sorry, this is another VBA Solver looping problem. I've read many of the other questions/answers posted here and elsewhere, but being new to VBA (this is the first thing I am attempting), I'm unable to pinpoint my error.
I wish to set cell Ii to 0 while changing cells Ji and Ki (keeping results), where i are rows 3 to 21.
My current code does not come up with any errors, but the results only keep on the last row of the loop- please advise! I've tried using range() and range.offset (from other examples) instead of cells(), and also setting the active worksheet to no avail.
I am using Excel 2011 for Mac.
Sub SolveTwo()
'Not sure if this is necessary
Dim row As Integer
'Begin loop
For row = 3 To 21
'Test code shows it is stepping through loop
Cells(row, "U").Value = row
'Grab starting values from other columns
Cells(row, "J").Value = Cells(row, "S").Value
Cells(row, "K").Value = Cells(row, "T").Value
'Solver Code
SolverReset
SolverOptions Precision:=1e-05
SolverOk SetCell:=Cells(row, "I").Address, _
MaxMinVal:=3, ValueOf:=0, _
ByChange:=Cells(row, "J").Address & "," & Cells(row, "K").Address, _
Engine:=1, EngineDesc:="GRG Nonlinear"
SolverSolve UserFinish:=True
SolverFinish KeepFinal:=1
'Not sure if below is necessary
'SolverSave SaveArea:=Cells(row, "J").Address & "," & Cells(row,"K").Address
Next row
End Sub
Had the same problem, i.e. only retaining the solutions to the last solver call.
It's caused by Excel for Mac's solver operating asynchronously, and the solver macro only starts once the calling code has completed. Hence the solver parameters are reset repeatedly by the calling code, but the solver doesn't run until the last iteration.
There is no solution forthcoming currently but here are two workarounds. The first one is to have two modules: a regular module calling solver once, and a second class module which fires whenever the sheet calculates (solver kicks off a re-calc when finishing), and calls the second one. Iterate back and forth in a loop. See here for great solution by J Peltier which I've admittedly not tried: solution 1
Solution 2 which I used is to call solver from an Apple Script. Here's an example. The control flow in the macro uses worksheet cells for the loop counters etc, and my macro was called by shift-opt-cmd-O. My solver usually finished in 10 sec, so I waited 15.
on run {input, parameters}
-- Click “Microsoft Excel” in the Dock.
set timeoutSeconds to 2.0
set uiScript to "click UI Element \"Microsoft Excel\" of list 1 of application process \"Dock\""
my doWithTimeout(uiScript, timeoutSeconds)
-- Press ⇧⌥⌘O
repeat 496 times
set timeoutSeconds to 2.0
set uiScript to "keystroke \"Ø\" using {shift down, option down, command down}"
my doWithTimeout(uiScript, timeoutSeconds)
delay 15
say "done"
end repeat
return input
end run
Hope that helps!
Try something like this:
Sub SolveTwo()
Dim myRow As Integer
For myRow = 3 To 21
With Worksheets(2)
.Cells(myRow, "U") = myRow
.Cells(myRow, "J") = Worksheets(1).Cells(myRow, "S")
.Cells(myRow, "K") = Worksheets(1).Cells(myRow, "T")
End With
'add your solver code here.
Next myRow
End Sub
It will generate some results in Worksheets(2), if the sheet you are executing is the first one. Furthermore, do not use Row as a variable name, because it is used in the VBEditor.
I am having difficulty with solver. I have tried to develop a for-loop that would call solver many times but I am having issues. I have already added the reference of solver to the workbook from tools/references. I have successfully gotten the loop to work with the solver; unfortunately, solver won't change my input cells automatically. I felt that this issue could be resolved by the SolverReset function but every time I use it it fails, and the loop can no longer find a solution without manually re-solving the system. My code is as follows.
Sub Go_Click()
'Variable Types
Dim x As Double
Dim First_Variable As Range
Dim Second_Variable As Range
Dim Number_of_Calculations As Double
Dim Input_Cells As Range
Dim First_Dimension_Lower As Double
Dim y As Double
Number_of_Calculations = 6
x = (First_Dimension_Upper_Bound - First_Dimension_Lower_Bound) / Number_of_Calculations
For y = 1 To Number_of_Calculations
' x is the integer that the first dimension of the solve will increase by.
' by finding the difference between the upper and lower bound and dividing by the number of calculations
' then the rest is just a for loop, adding the value "x" to each loop
SolverOk SetCell:="First_Dimension", _
MaxMinVal:=3, _
ValueOf:=First_Dimension_Lower_Bound, _
ByChange:="Input_Cells", _
Engine:=1, EngineDesc:="GRG Nonlinear"
SolverSolve
'Just to test the results
MsgBox (Range("b4"))
'increase in the lower first dimension bound
First_Dimension_Lower_Bound = First_Dimension_Lower_Bound + x
Next y
End Sub
Check the return result of SolverSolve to discover if it completed successfully:
If a Solver problem has not been completely defined, SolverSolve
returns the #N/A error value. Otherwise the Solver runs, and
SolverSolve returns an integer value corresponding to the message that
appears in the Solver Results dialog box.
The linked page lists the possible integer values that are returned. For example, 5 indicates "Solver could not find a feasible solution".
You can also supply a Function name as the ShowRef argument to SolverSolve:
SolverSolve(UserFinish, ShowRef)
This Function will be called if Solver pauses for one of the reasons listed in the linked page. For example, 2 means:
Function called because the Max Time limit in the Solver Options
dialog box was exceeded.
I am trying to solve an optimization problem where one of the input variables must be bounded by a minimum and a maximum constraint. Because I don't run SolverReset at the end, I can tell afterwards that Solver is ignoring the third constraint ($F$5 <= 1). I can also tell because sometimes it gives me an answer where $F$5 > 1.
When I use Solver manually I'm able to add in the third constraint. I've tried recording the macro to see what I'm missing, but I'm still stumped. I'm running Excel 2007. Any ideas? Thanks,
Public Sub SEDMSolver()
SolverReset
SolverAdd CellRef:="$F$5", Relation:=3, FormulaText:="0.1"
SolverAdd CellRef:="$F$4", Relation:=3, FormulaText:="0"
SolverAdd CellRef:="$F$5", Relation:=1, FormulaText:="1"
SolverOk SetCell:="$G$8", MaxMinVal:=2, ValueOf:="0", ByChange:="$F$4:$F$5"
SolverSolve userFinish:=True
End Sub
Solver can be a bit fluky. Try setting your MaxMinVal=2 line above the first. When I run solver macros, I always have to set that above the constraints. Occasionally it will throw errors.
I tried to replicate your issue (using excel 2010), but it works for me. With the MxMinVal at the beginning and end. You could try restarting your machine and excel and see if the issue remains. But your code does work for me, all three constraints load.
Another general suggestion I would have for your code is to add:
Application.Calculation = xlAutomatic
This will turn the calculations to automatic. I have had it get turned off while running more complex macros involving solver.
Set some cell (e.g H9) to 1 and use reference to this cell in a code.
SolverAdd CellRef:="$F$5", Relation:=1, FormulaText:="$H$9"
From my experience using solver and trying to automate it with VBA, the best solution is to not automate Excel's sorver but write your own iteration to solve for your target.
for example
For j = 1 To 100
result = someCalculation
If result > minConstraint Then
result = j - 1
Exit For
Else
End If
Next j