I need to find a pool of solutions with AMPL (I am relatively new to it) using the option "poolstub" but I get an error when I try to retrive them. I will try to explain everything step by step. This is my code:
option solver cplex;
model my_model.mod;
data my_data.dat;
option cplex_options 'poolstub=multmip poolcapacity=10 populate=1 poolintensity=4 poolreplace=1';
solve;
At this point AMPLE gives me this:
CPLEX 20.1.0.0: poolstub=multmip
poolcapacity=10
populate=1
poolintensity=4
poolreplace=1
CPLEX 20.1.0.0: optimal solution; objective 4.153846154
66 dual simplex iterations (0 in phase I)
It seems like AMPL has not stored the solutions in the pool.
And in fact, if I try to retrive them with this code
for {i in 1..Current.npool} {
solution ('multmip' & i & '.sol');
display _varname, _var;
}
I get this error:
Bad suffix .npool for Initial
context: for {i in >>> 1..Current.npool} <<< {
Possible suffix values for Initial.suffix:
astatus exitcode message relax
result sstatus stage
for{...} { ? ampl: for{...} { ? ampl:
I have no integer variables, only real ones and I read that CPLEX doesn't support the populate method for linear programs. Could this be the problem or is something else missing? Thank you in advance
You have identified your problem correctly. Entity Initial does not have the npool suffix, which means the solver (in your case CPLEX) did not return one.
Gurobi can return that information for linear programs, but it seems to be identical to the optimal solution, so it would not give you any extra information (more info on AMPL-Gurobi options).
Here is an example AMPL script:
model net1.mod;
data net1.dat;
option solver gurobi;
option gurobi_options 'ams_stub=allopt ams_mode=1';
solve;
for {n in 1..Total_Cost.npool} {
solution ("allopt" & n & ".sol");
display Ship;
}
Output (on my machine):
Gurobi 9.1.1: ams_stub=allopt
ams_mode=2
ams_epsabs=0.5
Gurobi 9.1.1: optimal solution; objective 1819
1 simplex iterations
Alternative MIP solution 1, objective = 1819
1 alternative MIP solutions written to "allopt1.sol"
... "allopt1.sol".
Alternative solutions do not include dual variable values.
Best solution is available in "allopt1.sol".
suffix npool OUT;
Alternative MIP solution 1, objective = 1819
Ship :=
NE BOS 90
NE BWI 60
NE EWR 100
PITT NE 250
PITT SE 200
SE ATL 70
SE BWI 60
SE EWR 20
SE MCO 50
;
The files net1.mod and net1.dat are from the AMPL book.
When solving a MIP the solver can store sub-optimal solutions that it found along the way as they might be interesting for some reason to the modeler.
In terms of your LP, are you interested in the vertices the simplex algorithm visits?
How do you set a timeout for the z3 optimizer such that it will give you the best known solution when it runs out of time?
from z3 import *
s = Optimize()
# Hard Problem
print(s.check())
print(s.model())
Follow-up question, can you set z3 to randomized hill climbing or does it always perform a complete search?
Long answer short, you can't. That's simply not how the optimizer works. That is, it doesn't find a solution and then try to improve it. If you interrupt it or set a time-out, when the timer expires it may not even have a satisfying solution, let alone an "improved" one by any means. You should look at the optimization paper for details: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/nbjorner-nuz.pdf
It is true, however, that z3 does keep track of bounds of variables, for numerical quantities. You might be able to extract these, though in general, you'll have no means of knowing what values out of those intervals you'd need to pick to get a satisfying solution for the overall problem. See this answer for a discussion: Is it possible to get a legit range info when using a SMT constraint with Z3
This sort of "hill-climbing" questions come up often in this forum. And the answer is simply that's not how z3's optimizer works. Some prior questions in this manner:
Z3 Time Restricted Optimization
z3 minimization and timeout
There are few other questions along these lines in stack-overflow. Search for "optimize" and "timeout".
Your best bet
That's the theory side of it. In practice, I believe the best approach to deal with a problem of this sort is not to use the optimizer at all. Instead do the following:
State your problem
Ask for a model. If there's no model, respond unsat. Quit.
Hold on to the current model as "best-so-far"
Out of time? Return the model you have as "best-so-far". You are done.
Still have time?
5a. Compute the "cost" of this model. i.e., the metric you are trying to minimize or maximize. If you store the cost as a variable in your model, you can simply query its value from the model.
5b. Assert a new constraint saying the cost should be lower than the cost of the current model. (Or higher if you are maximizing.) Depending on how fancy you want to get, you might want to "double" the cost function, or implement some sort of binary-search to converge on a value faster. But all that is really dependent on the exact details of the problem.
5c. Ask for a new model. If unsat, return the last model you got as "optimal." Otherwise, repeat from step 3.
I believe this is the most practical approach for time-constraint optimization in z3. It gives you the full control on how many times to iterate, and guide the search in any way you want. (For instance, you can query for various variables at each model, and direct the search by saying "find me a bigger x, or a smaller y, etc., instead of looking at just one metric.) Hope that makes sense.
Summary
Note that an SMT solver can work like you're describing, i.e., give you an optimal-so-far solution when the time-out goes off. It's just that z3's optimizer does not work that way. For z3, I found the iterative loop described as above to be the most practical solution to this sort of timeout based optimization.
You can also look at OptiMathSAT (http://optimathsat.disi.unitn.it/) which might offer better facilities in this regard. #Patrick Trentin, who reads this forum often, is an expert on that and he might opine separately regarding its usage.
In general, #alias is right when he states that an OMT solver does not provide any guarantee of a solution being available at the end of the optimization search when this is interrupted by a timeout signal.
An OMT solver can look for an optimal solution in one of two ways:
by starting from an initial Model of the formula and trying to improve the value of the objective function; This is the case of the standard OMT approach, which enumerates a number of partially optimized solutions until it finds the optimal one.
by starting from more-than-optimal, unsatisfiable, assignment and progressively relaxing such assignment until it yields an optimal solution; AFAIK, this is only the case of the Maximum Resolution engine for dealing with MaxSMT problems.
When the OMT solver uses an optimization technique that falls in the first category, then it is possible to retrieve the best known solution when it runs out of time, provided that the OMT solver stores it in a safe place during the optimization search. This is not the case with the second MaxRes engine (see this Q/A).
A possible workaround. (CAVEAT: I haven't tested this)
z3 keeps track of the lower and upper bound of the objective function along the optimization search. When minimizing, the upper bound corresponds to the value of the objective function in the most recent partial solution found by the OMT solver (dual for maximization). After a timeout signal occurred when minimizing (resp. maximizing) an obj instance obtained from minimize() (resp. maximize()), one should be able to retrieve the latest approximation v of the optimal value of obj by calling obj.upper() (resp. obj.lower()). Assuming that such value v is different from +oo (resp. -oo), one can incrementally learn a constraint of the form cost = v and perform an incremental SMT check of satisfiability to reconstruct the model corresponding to the sub-optimal solution that was hit by z3.
OptiMathSAT is one OMT solver that stores in a safe place the latest solution it encounters during the optimization search. This makes it easy to achieve what you want to do.
There are two types of timeout signals in OptiMathSAT:
hard timeout: as soon as the timeout fires, the optimization search is stopped immediately; if the OMT solver found any solution, the result of the optimization search (accessible via msat_objective_result(env, obj)) is MSAT_OPT_SAT_PARTIAL and the Model corresponding to the latest sub-optimal solution can be extracted and printed; if instead the OMT solver didn't find any solution, the result of the optimization search is MSAT_UNKNOWN and no Model is available.
soft timeout: if a timeout fires after the OMT solver found any solution, then the search is stopped immediately as in the case of a hard timeout. Otherwise, the timeout is ignored until the OMT solver finds one solution.
The type of timeout signal can be set using the option opt.soft_timeout=[true|false].
Example: The following example is the timeout.py unit-test contained in my omt_python_examples github repository that features a number of examples of how to use the Python API interface of OptiMathSAT.
"""
timeout unit-test.
"""
###
### SETUP PATHS
###
import os
import sys
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
INCLUDE_DIR = os.path.join(BASE_DIR, '..', 'include')
LIB_DIR = os.path.join(BASE_DIR, '..', 'lib')
sys.path.append(INCLUDE_DIR)
sys.path.append(LIB_DIR)
from wrapper import * # pylint: disable=unused-wildcard-import,wildcard-import
###
### DATA
###
OPTIONS = {
"model_generation" : "true", # !IMPORTANT!
"opt.soft_timeout" : "false",
"opt.verbose" : "true",
}
###
### TIMEOUT UNIT-TEST
###
with create_config(OPTIONS) as cfg:
with create_env(cfg) as env:
# Load Hard Problem from file
with open(os.path.join(BASE_DIR, 'smt2', 'bacp-19.smt2'), 'r') as f:
TERM = msat_from_smtlib2(env, f.read())
assert not MSAT_ERROR_TERM(TERM)
msat_assert_formula(env, TERM)
# Impose a timeout of 3.0 seconds
CALLBACK = Timer(3.0)
msat_set_termination_test(env, CALLBACK)
with create_minimize(env, "objective", lower="23", upper="100") as obj:
assert_objective(env, obj)
solve(env) # optimization search until timeout
get_objectives_pretty(env) # print latest range of optimization search
load_model(env, obj) # retrieve sub-optimal model
dump_model(env) # print sub-optimal model
This is the verbose output of the optimization search:
# obj(.cost_0) := objective
# obj(.cost_0) - search start: [ 23, 100 ]
# obj(.cost_0) - linear step: 1
# obj(.cost_0) - new: 46
# obj(.cost_0) - update upper: [ 23, 46 ]
# obj(.cost_0) - linear step: 2
# obj(.cost_0) - new: 130/3
# obj(.cost_0) - update upper: [ 23, 130/3 ]
# obj(.cost_0) - linear step: 3
# obj(.cost_0) - new: 40
# obj(.cost_0) - update upper: [ 23, 40 ]
# obj(.cost_0) - linear step: 4
# obj(.cost_0) - new: 119/3
# obj(.cost_0) - update upper: [ 23, 119/3 ]
# obj(.cost_0) - linear step: 5
# obj(.cost_0) - new: 112/3
# obj(.cost_0) - update upper: [ 23, 112/3 ]
# obj(.cost_0) - linear step: 6
# obj(.cost_0) - new: 104/3
# obj(.cost_0) - update upper: [ 23, 104/3 ]
# obj(.cost_0) - linear step: 7
# obj(.cost_0) - new: 34
# obj(.cost_0) - update upper: [ 23, 34 ]
# obj(.cost_0) - linear step: 8
# obj(.cost_0) - new: 133/4
# obj(.cost_0) - update upper: [ 23, 133/4 ]
# obj(.cost_0) - linear step: 9
# obj(.cost_0) - new: 161/5
# obj(.cost_0) - update upper: [ 23, 161/5 ]
# obj(.cost_0) - linear step: 10
# obj(.cost_0) - new: 32
# obj(.cost_0) - update upper: [ 23, 32 ]
# obj(.cost_0) - linear step: 11
# obj(.cost_0) - new: 158/5
# obj(.cost_0) - update upper: [ 23, 158/5 ]
# obj(.cost_0) - linear step: 12
# obj(.cost_0) - new: 247/8
# obj(.cost_0) - update upper: [ 23, 247/8 ]
# obj(.cost_0) - linear step: 13
# obj(.cost_0) - new: 123/4
# obj(.cost_0) - update upper: [ 23, 123/4 ]
# obj(.cost_0) - linear step: 14
# obj(.cost_0) - new: 61/2
# obj(.cost_0) - update upper: [ 23, 61/2 ]
# obj(.cost_0) - linear step: 15
unknown ;; <== Timeout!
(objectives
(objective 61/2), partial search, range: [ 23, 61/2 ]
) ;; sub-optimal value, latest search interval
course_load__ARRAY__1 : 9 ;; and the corresponding sub-optimal model
course_load__ARRAY__2 : 1
course_load__ARRAY__3 : 2
course_load__ARRAY__4 : 10
course_load__ARRAY__5 : 3
course_load__ARRAY__6 : 4
course_load__ARRAY__7 : 1
course_load__ARRAY__8 : 10
course_load__ARRAY__9 : 4
course_load__ARRAY__10 : 1
course_load__ARRAY__11 : 1
course_load__ARRAY__12 : 5
course_load__ARRAY__13 : 10
course_load__ARRAY__14 : 9
course_load__ARRAY__15 : 1
...
;; the sub-optimal model is pretty long, it has been cut to fit this answer!
...
i am a complete beginner at Fortran and am working on a code that solves a kinetic mechanism by solving differential equations at different time steps using a differential equation solver.
Here is a link to download the zip file with the whole project:
http://www.filedropper.com/fortranmicropyrolyzersetup
The input variables for the differential solver are defined as follows in the code:
! Declaration of variables
implicit none
EXTERNAL :: FEXSB_AUTO, JEX_SB
integer :: neq,Mf,lrw,liw,iwork,itol,itask,istate,iopt !solver parameters
integer :: j,jjk,m !Counters
double precision :: ATOL,RTOL, RWORK !solver parameters
double precision :: T, TOUT !starting time (s), timestep time (s)
double precision :: Y, w !molar fraction of biomass (-), mass fraction of biomass (-)
double precision :: y_gas, w_gas, Conc !molar fraction in gas phase (-), concentration in gas phase (mol/m³), mass fraction in gas phase (-)
double precision :: n(speciescount) !number of moles (used temporarily to calculate initial molar fracions)
character*5 :: simulationNumber
!Setting the solver parameters
neq = SpeciesCount !number of equations
ITOL = 1 !RTOL and ATOL are integers
RTOL = 1.0D-8 !Relative tolerance
ATOL = 1.0D-15 !Absolute tolerance
ITASK = 1
ISTATE = 1
LRW = 22 + 9*SpeciesCount + 2*SpeciesCount**2 !Array sizing (see VODE)
LIW = 30+SpeciesCount !Array sizint (see VODE)
MF = 22 !Use BDF with finite difference Jacobian
IOPT = 1 !Optional input specified
Iwork(6) = 7000 !Increase maximum iteration steps from 500 to 2000 otherwise the solver does not converge
The differential solver is then called in a do loop for each time step as follows:
! Solve reactor equations (see FEXSB) and advance time, until stop criterium is met
TimeStep = 0 ! dimensionless time step
!DO while(wm(1).lt.0.9999) -> previously used stop criterium
DO while((y_gas(1).lt.0.99999).OR.(TimeStep.lt.10)) !stop criterium: molar fraction Helium = 0.9999 AND do at least 100 timesteps
TimeStep = TimeStep + 1
write(*,*)"Doing iteration for time step",TimeStep
call DVODE(FEXSB_AUTO,NEQ,Y,T,TOUT,ITOL,RTOL,ATOL,ITASK,ISTATE,IOPT,RWORK,LRW,IWORK,LIW,JEX_SB,MF) !solve reactor equations to Y
!CALL DVODE(FEXSB_AUTO,NEQ,Y,T,TOUT,ITOL,RTOL,ATOL,ITASK,ISTATE,IOPT,RWORK,LRW,IWORK,LIW,JEX_SB,MF,RPAR,IPAR)
! calculate w, y_gas, w_gas and Conc from Y
do j = 1, SpeciesCount
if (Y(j) .lt. 1.0D-10) then ! round to zero below 10e-10 to avoid negative numbers and numerical problems with small numbers
Y(j) = 0.0D0
endif
if (MolarFlowRate(j) .lt. 1.0D-10) then
MolarFlowRate(j) = 0.0D0
endif
w(j) = Y(j)*n0_tot*amms(j) / (mass_sample)
y_gas(j) = MolarFlowRate(j) / TotalMolarFlowRate
w_gas(j) = MolarFlowRate(j)*amms(j) / (1000*MassFlowRate) ! factor 1000 to put molar mass in kg/mol instead of g/mol
Conc(j) = MolarFlowRate(j) / VolumetricFlowRate
end do
The differential equation solver does not successfully complete the do loop of the line :
DO while((y_gas(1).lt.0.99999).OR.(TimeStep.lt.10))
The variables seem to be recognized for the first time step when the ODE Solver is called in the line:
call DVODE(FEXSB_AUTO,NEQ,Y,T,TOUT,ITOL,RTOL,ATOL,ITASK,ISTATE,IOPT,RWORK,LRW,IWORK,LIW,JEX_SB,MF)
And the solver successfully completes the first iteration. After the time step is increased one more time, the call function works again but this time the variables are not recognized somehow. When I stop the code to debug what is wrong after the first time step, I realized that the variables required for DVODE do not have set values anymore, somehow they get deleted after the first successful iteration.
What might be causing this problem?
*DECK DVODE
SUBROUTINE DVODE (F, NEQ, Y, T, TOUT, ITOL, RTOL, ATOL, ITASK,
1 ISTATE, IOPT, RWORK, LRW, IWORK, LIW, JAC, MF,
2 RPAR, IPAR)
EXTERNAL F, JAC
DOUBLE PRECISION Y, T, TOUT, RTOL, ATOL, RWORK, RPAR
INTEGER NEQ, ITOL, ITASK, ISTATE, IOPT, LRW, IWORK, LIW,
1 MF, IPAR
DIMENSION Y(*), RTOL(*), ATOL(*), RWORK(LRW), IWORK(LIW),
1 RPAR(*), IPAR(*)
!-----------------------------------------------------------------------
c dvode: Variable-coefficient Ordinary Differential Equation solver,
! with fixed-leading-coefficient implementation.
! This version is in double precision.
!
! DVODE solves the initial value problem for stiff or nonstiff
! systems of first order ODEs,
! dy/dt = f(t,y) , or, in component form,
! dy(i)/dt = f(i) = f(i,t,y(1),y(2),...,y(NEQ)) (i = 1,...,NEQ).
! DVODE is a package based on the EPISODE and EPISODEB packages, and
! on the ODEPACK user interface standard, with minor modifications.
!-----------------------------------------------------------------------
! Authors:
! Peter N. Brown and Alan !. Hindmarsh
! Center for Applied Scientific Computing, L-561
! Lawrence Livermore National Laboratory
! Livermore, CA 94551
! and
! George D. Byrne
! Illinois Institute of Technology
! Chicago, IL 60616
!-----------------------------------------------------------------------
Any help would be greatly appreciated. Please note that I am new to Fortran. If I should supply any additional information to help you answer my question, please don't hesitate to let me know. Thanks in advance!
The assumption that the parameters should be untouched after the first iteration is wrong.
In fortran function parameters are always passed by reference. Thus, a fortran function never guarantees that your original parameter set is the same after the call. It might be the intened (or poor) design of the function to DO change the parameters. Only documentation can help you, and what you provided in your question is not enough, which might very likely also mean: maybe there is not enough documentation for this case/function.
In contrast to C/C++ in fortran there is no "const" modifier for variables that would guarantee you what you have to assume right now.
To me it seem the only solution is to re-initialize all parameters right before every call to DVODE.
I'm using the neos-server to solve a highly constrained MINLP, using the bonmin algorithm. Solving using either a Branch and Bound or the hybrid method. The input code is AMPL
I want to know if it's possible to output variable results for a failed run?
I've tried just about every bonmin option listed here
https://projects.coin-or.org/Bonmin/browser/stable/1.7/Bonmin/doc/BONMIN_UsersManual.pdf?format=raw
I don't know enough about optimization solvers to really understand all of these options.
I've tried different AMPL options but these only work if I have a successful run.
Ultimately, I want to output all the variables in my model with the values from the latest failed run.
This is my commands file
options bonmin_options "bonmin.bb_log_level 4 \
bonmin.algorithm B-BB print_level 6";
solve;
option display_precision 10;
display solve_result_num, solve_result;
display cost.result;
display _varname, _var;
Below is a the header output from a failed run. This provides outputs for all my variables but they are all 0
Solver : minco:Bonmin:AMPL
Start : 2017-08-30 11:20:12
End : 2017-08-30 11:26:34
Host : NEOS HTCondor Pool
Disclaimer:
This information is provided without any express or
implied warranty. In particular, there is no warranty
of any kind concerning the fitness of this
information for any particular purpose.
*************************************************************
File exists
You are using the solver bonmin-ampl.
Executing AMPL.
processing data.
processing commands.
Executing on prod-exec-1.neos-server.org
Presolve eliminates 20629 constraints and 18794 variables.
Substitution eliminates 8664 variables.
Adjusted problem:
12175 variables:
7093 nonlinear variables
5082 linear variables
10647 constraints; 63680 nonzeros
2553 nonlinear constraints
8094 linear constraints
8084 equality constraints
2563 inequality constraints
1 linear objective; 17 nonzeros.
Setting $presolve_fixeps >= 1.41e-14 could change presolve results.
Bonmin 1.8.4 using Cbc 2.9.6 and Ipopt 3.12.4
bonmin: bonmin.bb_log_level 4
bonmin.algorithm B-BB
print_level 6
Start reading options from stream.
Finished reading options from file.
Cbc3007W No integer variables - nothing to do
******************************************************************************
This program contains Ipopt, a library for large-scale nonlinear optimization.
Ipopt is released as open source code under the Eclipse Public License (EPL).
For more information visit http://projects.coin-or.org/Ipopt
******************************************************************************
NLP0012I
Num Status Obj It time Location
NLP0014I 1 INFEAS 2.2729823 1144 178.86781
NLP0014I 2 INFEAS 2.2729823 1144 176.90811
Cbc3007W No integer variables - nothing to do
Cbc0006I The LP relaxation is infeasible or too expensive
"Finished"
bonmin: Infeasible problem
solve_result_num = 220
solve_result = infeasible
cost.result = infeasible
I'm trying to use the SCIP solver (http://scip.zib.de/). My input (1.lp) is in lpsolve format. It looks like this:
max: +2 x_0_0;
+x_0_0 <= 1;
+x_0_0 <= 1;
-3x_0_0 <= 0;
0 <= x_0_0 <= 1;
int x_0_0;
I run SCIP like this:
"c:\Program Files\SCIP\scip.exe" -f 1.lp -l 1.lp.out
However, SCIP generates this output:
SCIP version 3.0.0 [precision: 8 byte] [memory: block] [mode: optimized] [LP solver: SoPlex 1.7.0] [GitHash: c95600b]
Copyright (c) 2002-2012 Konrad-Zuse-Zentrum fuer Informationstechnik Berlin (ZIB)
External codes:
SoPlex 1.7.0 Linear Programming Solver developed at Zuse Institute Berlin (soplex.zib.de) [GitHash: 657dfe5]
cppad-20120101.3 Algorithmic Differentiation of C++ algorithms developed by B. Bell (www.coin-or.org/CppAD)
Ipopt 3.10.2 Interior Point Optimizer developed by A. Waechter et.al. (www.coin-or.org/Ipopt)
user parameter file <scip.set> not found - using default parameters
read problem <[...]1.lp>
============
input:
^
error reading file <[...]1.lp>
I guess that means it is choking on a whitespace... What am I doing wrong?
EDIT:
See my answer for details. After giving the input in CPLEX format, everything works fine.
The answer is that SCIP apparently cannot read lpsolve input files. The LP format they are referring to in this overview of readable file formats is in fact the CPLEX LP format.