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.
Related
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 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
I've noticed something new today that will cause me problems in the future regarding Excel's Solver, so I want to get a jump on it.
I'm using VBA to sequentially apply solver moving down a sheet (let's say this sheet belongs to 'workbook 1'). This all works fine and I'm happy with the results of Solver. Yay... My concern is this: When I have a second rather large workbook open (let's call this 'workbook 2'), WHICH HAS ABOSOLUTELY NO LINKS TO MY CURRENT WORKBOOK, Solver takes around 20 times as long to run.
Naturally the most reasonable thing to do is not have 'workbook 2' open when Solver is running. For now that's my solution, however, in the very near future I will need to have both workbooks open simultaneously. So I pose the following question:
Why would solver take longer to run with two books open even though it's not even touching one of them?
In case skeptics are concerned that my code is doing something unusual here it is:
Sub ExampleSeqSolver()
Dim Iter As Long
Dim Time0 As Double
Dim Duration As Double
Application.ScreenUpdating = False
' Solver requires that it is working on the 'active sheet', silly but w/e
Sheets("Sheet1").Activate
' watch optimization efficiency
Time0 = Timer
For Iter = 2 To 13
' my data are sometimes related to adjacent rows so I was considering supplying an initial solution to reduce the number of runs
' Sheets("Sheet1").Range("$AC$" & ITER & ":$AI$" & ITER) = _
' Sheets("Sheet1").Range("$AC$" & ITER - 1 & ":$AI$" & ITER - 1)
If Cells(Iter, 1) <> 0 Then
SolverReset
SolverOptions AssumeNonNeg:=True, Iterations:=100
SolverAdd CellRef:="$AK" & Iter, Relation:=2, FormulaText:="1"
SolverOK SetCell:="$AW$" & Iter, MaxMinVal:="2", ByChange:=Sheets("Sheet1").Range("$AC$" & Iter & ":$AI$" & Iter), Engine:=1
SolverSolve True
End If
Next Iter
' report optimization duration
Duration = Round(Timer - Time0, 2)
MsgBox "Optimization finished in " & Duration & " seconds", vbInformation
Application.ScreenUpdating = True
End Sub
The presence of 'workbook 2' is correlated but not causal. In my case there is one particular workbook that causes the solver slowdown; most others don't. The workbook that causes the slowdown is about 4mb. Much larger workbooks do not cause a slowdown. The one causing the slowdown does not to the best of my knowledge contain either macros or VB. I recommend that this problem be shown to Frontline systems who developed the original solver.
I'm conducting an optimization using Solver and I've had some issues now with decimals. Using a Swedish Excel my default decimal point is a comma "," but I've read from forums that Solver need to have decimals in the form of a period sign "."
Private Sub CommandButton1_Click()
Worksheets("Blad1").Activate
SolverReset
SolverOk SetCell:=B63, MaxMinVal:=1, ByChange:=Range("B45:B62")
SolverAdd CellRef:=B45, Relation:=1, FormulaText:=P24
SolverAdd CellRef:=B45, Relation:=3, FormulaText:=O24
SolverAdd CellRef:=L45, Relation:=1, FormulaText:=L3
SolverAdd CellRef:=L46, Relation:=3, FormulaText:=L4
SolverAdd CellRef:=B63, Relation:=3, FormulaText:=B42
SolverSolve
End Sub
The above is my code with in short (there are many more constraints in reality). Here all cell references are to cells containing decimal number with delimiter ",". I tried to add a Custom Format of the type "0.00" (if it's not possible to convert the decimals to periods and convert it back to commas in the answer, then that's not the optimal solution but an OK solution) but it resulted in integers, say 3, becoming "0.03" where the intention were to have it like "3.00".
Is there a way to read a decimal number having "," convert it to "." while doing calculation and subsequentially provide the answer with "," without having to "globally" change the decimals from commas to periods, as I have many Excel workbooks which will not work as intended using ".".
Thanks in advance
EDIT: Tested some more now and I realize that the Solver actually can "handle" comma decimals. Indeed Solver can print a solution consisting of comma decimals, however it appears that some functions, for instance SolverSolve, is based around end point decimals. I tested to implement the following in a new Workbook:
Sub Makro1()
Dim MyNumber1 As Double
Dim MyNumber2 As Double
Set MyNumber1 = Sheets("Blad1").Cell(20, 1).Value
Set MyNumber2 = Sheets("Blad1").Cell(21, 1).Value
Dim i As Integer
Dim rSetCell As Range, rByChange As Range, rPrecision As Range
Range("A1").Resize(1, 4) = Array("Precision", "c", "b", "a")
For i = 1 To 16
Set rPrecision = Range("A1").Offset(i, 0)
Set rSetCell = Range("A1").Offset(i, 1)
Set rByChange = Range("A1").Offset(i, 2).Resize(1, 2)
rSetCell.Formula = "=SQRT(" & rByChange(1).Address & "^2+" & rByChange(2).Address & "^2)"
rPrecision = 10 ^ -i
SolverReset
SolverOk MyNumber1, 3, 5, rByChange.Address
SolverOptions Precision:=rPrecision.Value
SolverAdd rByChange(1).Address, 4
SolverAdd MyNumber1, 1, MyNumber2
SolverSolve True
Next
End Sub
(Where the vast majority of code is taken from Andreas Killer at http://answers.microsoft.com/en-us/office/forum/office_2010-customize/excel-solver-macros-do-not-work-when-using-comma/8b595198-8492-4382-89c4-5fc144f7bc43?page=1 in order to check whether the program can print comma decimals, which it could).
Adding SolverAdd MyNumber1, 1, MyNumber2 where MyNumber1 is cell A20, which is 2,3 and MyNumber2 is A21 which is 2,5. Hence, the solution would not be feasible if the program actually could manage comma decimals (these parameters are never changed, and the constraint is always violated). Checking the TypeName Before adding the Dim Double for the two variables showed that A20 where, in fact, recognized as an String.
Trying to implement this solution gives me the error Object Required and a highlight on the code snippet Sub Makro1(). Why won't this work? Has anyone a clue how to make this work without needing to change the system language for all Excel workbooks, so I can avoid to adjust every Excel sheet I've ever created containing formulae?
EDIT:
Set MyNumber1 = Sheets("Blad1").Cell(20, 1).Value and Set MyNumber2 = .. both gives the error Object Required.
The problem is that solver accepts the cell reference not the cell values.
The MSDN page doesn't give any switches or options to change the format of numbers.
I am surprised that a comma is used in Sweeden for the decimal point.
What happens if you change your international settings in the control panel>Language settings (in additional settings you have to type a , no select on the combo). You can change the number format used.
I change my decimal point to use a comma and this chnaged how excel stored and showed it it. (the range properties .value .value2 and .text all had a comma instead of a full stop)
Try changing the language or the number format and see if this changes how they are displayed in excel so you can use solver.
Another concern is that they may not be stored as numbers in excel, but as text.
Please experiment.
Also here's some code that probably won't help, but may be of use:
This VBA function
replace("Mystringwith,commas", ",", ".")
will output
"Mystringwith.commas"
Although the parameters are a string you can use it with numbers as it will work (it implicitly converts the numbers to strings).
Also, the following code might give you some inspiration.
Sub aaa()
Dim c As Range
Set c = Worksheets("Sheet1").Range("B14")
c.Value = 1198.3
c.NumberFormat = "$#,##0_);($#,##0)"
Debug.Print c.Value ' 1198.3
Debug.Print c.Value2 ' 1198.3
Debug.Print c.Text ' £1,198.3
End Sub