[AMPL 24769] How to read .sol files

Hi,
I used ampl.setOption(‘cplex_options’,‘poolstub savesol’)to generate feasible solution, but I do not know how to open this files and see the generated solutions

Could you please help? Thanks

CPLEX organizes the solutions as follows:

  • The solution files are savesol1.sol, savesol2.sol, . . .
  • The number of solution files saved is .npool – where is replaced by the name of your model’s objective function.
    To read a solution, use a command of the form

solution savesol<n>.sol

where is replaced by the solution number – for example, “solution savesol2.sol;” to read the second solution file. Here is an example of a loop that reads through all of the solutions:

for {k in 1..Total_Cost.npool} {
   solution ("savesol" & k & ".sol");
   display Trans;
};

(Replace Total_Cost by the name of your objective, and “display Trans;” by the commands you want to use to view or process each solution.)

Thanks a lot, it works well in AMPL. Is there a link to show how to do that in python as I am using amplpy?

Using amplpy, you can do that as follows:

from amplpy import AMPL
ampl = AMPL()
ampl.eval(
r"“”
set I := 1…1000000;
var x{I} integer >= 0 <= 1;
param v{i in I} := 10 + Irand224() mod 200;
param w{i in I} := v[i] + Irand224() mod 200;
maximize profit: sum{i in I} v[i] * x[i];
s.t. capacity: sum{i in I} x[i] <= 200;
“”"
)
ampl.option[“solver”] = “cplex”
ampl.option[“cplex_options”] = “poolstub savesol”
ampl.solve()
for i in range(1, ampl.get_value(“profit.npool”) + 1):
ampl.eval(f"solution savesol{i}.sol;“) # load the solution
print(i, ampl.get_data(r”{i in I: x[i] > 0} x[i]").to_dict()) # display the non-zero variables

Thanks a lot for your reply. I changed the name of the objective function from profit to cost, I tried the following :

for i in range(1, ampl.get_value(“cost.npool”) + 1):
ampl.eval(f"solution savesol{i}.sol;“)
print(i, ampl.get_data(r"x”).to_dict())

But it gives me this error
File “C:\Users\enhan\PycharmProjects\strategiesHM\scripts\get_AMPL_solution.py”, line 53, in main
for i in range(1, ampl.get_value(“cost.npool”) + 1):
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “C:\Users\enhan\AppData\Local\Programs\Python\Python311\Lib\site-packages\amplpy\ampl.py”, line 437, in get_value
return self._impl.getValue(scalar_expression)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
RuntimeError: file -
line 1 offset 33
Bad suffix .npool for cost

Any idea about resolving this error? thanks

Did you set CPLEX options with ampl.option[“cplex_options”] = “poolstub savesol”? Please send us the output from cplex, it should indicate that it exported that suffix if poolstub was set.

Here is my script in python

def main(argc, argv):
#os.chdir(os.path.dirname(file) or os.curdir)

ampl.set_option(“solver”, “cplex”)
ampl.setOption(‘cplex_options’,‘poolstub savesol’)

if argc > 1:
ampl.set_option(“solver”, argv[1])

ampl.read(“C:/bin/lin_strategies.mod”)
ampl.read_data(“C:/bin/strategies_1.txt”)

ampl.solve()

for i in range(1, ampl.get_value(“cost.npool”) + 1):
ampl.eval(f"solution savesol{i}.sol;“) # load the solution
data_x = ampl.get_data(r"x”).to_dict() # store the value of variable x
print(data_x)

if name == “main”:
try:
main(len(sys.argv), sys.argv)
except Exception as e:
print(e)
raise

Now it gives me this output. It doesn’t print data_x

CPLEX 12.6.0.1: poolstub savesol
CPLEX 12.6.0.1: optimal integer solution within mipgap or absmipgap; objective 43723.26731
6645 MIP simplex iterations
0 branch-and-bound nodes
absmipgap = 3, relmipgap = 6.86134e-05
Wrote 12 solutions in solution pool
to files savesol1.sol … savesol12.sol.
suffix npool OUT;

How to save x in a new variable, then print it?

Also, I want to do something similar using Gurobi because it is faster. I used the following to set the option: ampl.setOption(‘gurobi_options’, ‘ams_stub=allopt ams_mode=2 ams_epsabs=0.5’)
and the following loop to access the solution pool

for i in range(1, ampl.get_value(“cost.npool”) + 1):
ampl.eval(f"solution allopt{i}.sol;“) # load the solution
data_x = ampl.get_data(r"x”).to_dict() # store the value of variable x
print(data_x)

but it doesn’t work, and gives me this error

Gurobi 5.6.3: ams_stub=allopt
Gurobi 5.6.3: optimal solution; objective 43723.26731
56105 simplex iterations
plus 74 simplex iterations for intbasis
absmipgap = 3, relmipgap = 6.86e-05
Alternative MIP solution 1, objective = 44973.26731
Alternative MIP solution 2, objective = 45571.76731
Alternative MIP solution 3, objective = 49931.26731
Alternative MIP solution 4, objective = 52515.26731
4 alternative MIP solutions written to allopt1.sol
allopt4.sol
“option abs_boundtol 2.220446049250313e-16;”
or “option rel_boundtol 2.220446049250313e-16;”
will change deduced dual values.
file -
line 1 offset 33
Bad suffix .npool for cost
Traceback (most recent call last):
File “C:\Program Files\JetBrains\PyCharm 2023.1\plugins\python\helpers\pydev\pydevconsole.py”, line 364, in runcode
coro = func()
^^^^^^
File “”, line 1, in
File “C:\Program Files\JetBrains\PyCharm 2023.1\plugins\python\helpers\pydev_pydev_bundle\pydev_umd.py”, line 198, in runfile
pydev_imports.execfile(filename, global_vars, local_vars) # execute the script
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “C:\Program Files\JetBrains\PyCharm 2023.1\plugins\python\helpers\pydev_pydev_imps_pydev_execfile.py”, line 18, in execfile
exec(compile(contents+“\n”, file, ‘exec’), glob, loc)
File “C:\Users\enhan\PycharmProjects\strategiesHM\scripts\get_AMPL_solution.py”, line 109, in
main(len(sys.argv), sys.argv)
File “C:\Users\enhan\PycharmProjects\strategiesHM\scripts\get_AMPL_solution.py”, line 58, in main
for i in range(1, ampl.get_value(“cost.npool”) + 1):
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “C:\Users\enhan\AppData\Local\Programs\Python\Python311\Lib\site-packages\amplpy\ampl.py”, line 437, in get_value
return self._impl.getValue(scalar_expression)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
RuntimeError: file -
line 1 offset 33
Bad suffix .npool for cost

Thanks a lot for your support

You have Gurobi 5.6.3 and CPLEX 12.6.0.1, which are extremely old versions of both solvers (release in 2014). By upgrading to the latest version, with Gurobi 10, you can do that as follows:

from amplpy import AMPL
ampl = AMPL()
ampl.eval(
r"“”
set I := 1…10000;
var x{I} integer >= 0 <= 1;
param v{i in I} := 10 + Irand224() mod 200;
param w{i in I} := v[i] + Irand224() mod 200;
maximize profit: sum{i in I} v[i] * x[i];
s.t. capacity: sum{i in I} x[i] <= 200;
“”"
)
ampl.option[“solver”] = “gurobi”
ampl.option[“gurobi_options”] = “solstub=savesol”
ampl.solve()
for i in range(1, ampl.get_value(“profit.npool”) + 1):
ampl.eval(f"solution savesol{i}.sol;“)
print(
ampl.get_data(r”{i in 1…_nvars: _var[i] != 0} (_varname[i], _var[i])").to_list(
skip_index=True
),
)

In the code example from the previous message I retrieved the values for variable x, but you need to adjust the code to the variable names in your models. In the code example above, it retrieves the values for all non-zero variables in a list of pairs (variable, value).

It works fine with the latest Cplex, but still I have the same problem with Groubi 10, please see below. Thanks

PyDev console: starting.
Python 3.11.4 (tags/v3.11.4:d2340ef, Jun 7 2023, 05:45:37) [MSC v.1934 64 bit (AMD64)] on win32
runfile(‘C:\Users\enhan\PycharmProjects\strategiesHM\scripts\get_AMPL_solution.py’, wdir=‘C:\Users\enhan\PycharmProjects\strategiesHM’)
Gurobi 10.0.2: sol:poolgapabs = 150
Gurobi 10.0.2: optimal solution; objective 43723.26731
6793 simplex iterations
1 branching nodes
absmipgap=3, relmipgap=6.86134e-05
file -
line 1 offset 33
Bad suffix .npool for cost
Traceback (most recent call last):
File “C:\Program Files\JetBrains\PyCharm 2023.1\plugins\python\helpers\pydev\pydevconsole.py”, line 364, in runcode
coro = func()
^^^^^^
File “”, line 1, in
File “C:\Program Files\JetBrains\PyCharm 2023.1\plugins\python\helpers\pydev_pydev_bundle\pydev_umd.py”, line 198, in runfile
pydev_imports.execfile(filename, global_vars, local_vars) # execute the script
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “C:\Program Files\JetBrains\PyCharm 2023.1\plugins\python\helpers\pydev_pydev_imps_pydev_execfile.py”, line 18, in execfile
exec(compile(contents+“\n”, file, ‘exec’), glob, loc)
File “C:\Users\enhan\PycharmProjects\strategiesHM\scripts\get_AMPL_solution.py”, line 109, in
main(len(sys.argv), sys.argv)
File “C:\Users\enhan\PycharmProjects\strategiesHM\scripts\get_AMPL_solution.py”, line 58, in main
for i in range(1, ampl.get_value(“cost.npool”) + 1):
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “C:\Users\enhan\AppData\Local\Programs\Python\Python311\Lib\site-packages\amplpy\ampl.py”, line 437, in get_value
return self._impl.getValue(scalar_expression)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
RuntimeError: file -
line 1 offset 33
Bad suffix .npool for cost

Could you please send us the line where you set Gurobi options?

It should be something like ampl.option[“gurobi_options”] = “solstub=savesol” but the solver output only shows “sol:poolgapabs = 150”. You can combine the two options as follows:


ampl.option[“gurobi_options”] = “solstub=savesol sol:poolgapabs = 150”

Thanks for the support, it works fine with Groubi. Now, using Cplex, if I set this option ampl.setOption(‘cplex_options’, “mipsearch = 2”) to change the search method it gives an error. Please see below

import sys
from amplpy import AMPL, Environment

ampl = AMPL(Environment(r’C:/bin’))

def main(argc, argv):
#os.chdir(os.path.dirname(file) or os.curdir)

ampl.set_option(“solver”, “cplex”)
ampl.setOption(‘cplex_options’,‘poolstub savesol’)
ampl.setOption(‘cplex_options’, “mipsearch = 2”)

if argc > 1:
ampl.set_option(“solver”, argv[1])

ampl.read(“C:/bin/lin_strategies.mod”)
ampl.read_data(“C:/bin/strategies_1.txt”)

ampl.solve()

for i in range(1, ampl.get_value(“cost.npool”) + 1):
ampl.eval(f"solution savesol{i}.sol;“) # load the solution
data_x = ampl.get_data(r"x”).to_dict() # store the value of variable x
print(data_x)

if name == “main”:
try:
main(len(sys.argv), sys.argv)
except Exception as e:
print(e)
raise

it gives this error

CPLEX 22.1.1.0: mipsearch = 2
CPLEX 22.1.1.0: optimal integer solution within mipgap or absmipgap; objective 43723.26731
498571 MIP simplex iterations
4377 branch-and-bound nodes
absmipgap = 4.25, relmipgap = 9.72023e-05
file -
line 1 offset 33
Bad suffix .npool for cost
Traceback (most recent call last):
File “C:\Program Files\JetBrains\PyCharm 2023.1\plugins\python\helpers\pydev\pydevconsole.py”, line 364, in runcode
coro = func()
^^^^^^
File “”, line 1, in
File “C:\Program Files\JetBrains\PyCharm 2023.1\plugins\python\helpers\pydev_pydev_bundle\pydev_umd.py”, line 198, in runfile
pydev_imports.execfile(filename, global_vars, local_vars) # execute the script
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “C:\Program Files\JetBrains\PyCharm 2023.1\plugins\python\helpers\pydev_pydev_imps_pydev_execfile.py”, line 18, in execfile
exec(compile(contents+“\n”, file, ‘exec’), glob, loc)
File “C:\Users\enhan\PycharmProjects\strategiesHM\scripts\try_solver.py”, line 30, in
main(len(sys.argv), sys.argv)
File “C:\Users\enhan\PycharmProjects\strategiesHM\scripts\try_solver.py”, line 23, in main
for i in range(1, ampl.get_value(“cost.npool”) + 1):
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “C:\Users\enhan\AppData\Local\Programs\Python\Python311\Lib\site-packages\amplpy\ampl.py”, line 437, in get_value
return self._impl.getValue(scalar_expression)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
RuntimeError: file -
line 1 offset 33
Bad suffix .npool for cost

When you set the same option multiple times only the last value is kept. For instance:

ampl.setOption(‘cplex_options’,‘poolstub savesol’)
ampl.setOption(‘cplex_options’, “mipsearch = 2”)

is equivalent to just:

ampl.setOption(‘cplex_options’, “mipsearch = 2”)

In order to set both options you need to set them as follows:

ampl.setOption(‘cplex_options’,‘poolstub savesol mipsearch = 2’)

it works perfect now, thanks a lot.
I have another issue, I set this option ampl.setOption(‘cplex_options’,‘poolstub savesol mipsearch = 2 nodesel = 3’) , and solved the model 10 times using looping. The pool of the first iteration contains 28 solutions, but afterwards the pool of at any other iteration contains only two solutions. Is there a reason for that? I am trying to generate as much feasible solutions as passible

Also, how to add a new seed to this option ampl.setOption(‘cplex_options’,‘poolstub savesol mipsearch = 2 nodesel = 3’)
I tried this, but doesn’t work
random_num = round((random.uniform(0.0, 10000)),0)
seed_value = f’seed=random_num’
ampl.setOption(‘cplex_options’,“poolstub savesol mipsearch = 2 nodesel = 3 seed_value”)

Regarding the number of solutions found, there are options like poolintensity that may help (see all options for CPLEX at https://dev.ampl.com/solvers/cplex/options.html).

Regarding seed, you can do it as follows:

random_num = round((random.uniform(0.0, 10000)),0)
ampl.setOption('cplex_options", f"poolstub savesol mipsearch = 2 nodesel = 3 seed={random_num}")

Thanks,
I used this

random_num = round((random.uniform(0, 10000)), 0)
ampl.setOption(“cplex_options”, f"poolstub savesol mipsearch = 2 nodesel = 3 seed={random_num}")

still gives an error, I do not know where “.0” comes from

CPLEX 22.1.1.0: poolstub savesol
mipsearch = 2
nodesel = 3
seed=4629
Unknown keyword “.0”
CPLEX 22.1.1.0: Error in $cplex_options.
file -
line 1 offset 33
Bad suffix .npool for cost

Even after rounding random_num is still a float so there is still a “.0” in formated string . You can cast it it int or format the f-string with 0 decimal points as follows:

ampl.setOption(“cplex_options”, f"poolstub savesol mipsearch = 2 nodesel = 3 seed={random_num:.0}")

Sorry, missed the f in the previous reply:

ampl.setOption(“cplex_options”, f"poolstub savesol mipsearch = 2 nodesel = 3 seed={random_num:.0f}")