Closed xrixhon closed 1 year ago
Hi Xavier,
In order to achieve this, it is necessary to use an upcoming feature of AMPL called snapshot that even though is still not part of the official version of AMPL, it is part of the development version that is now available to the public. The development version of AMPL is called ampldev
, and it is available on portal.ampl.com (in My Downloads) and it is included on newly generated bundles (if you are using a bundle, you just need to generate a new one and ampldev will be there). At the moment the only difference between ampl
and ampldev
is the snapshot command.
You need to be using at least amplpy 0.8.0 (you can install it with python -m pip install amplpy==0.8.0
). With this version of amplpy it is now possible to pass an additional argument to Environment (https://amplpy.readthedocs.io/en/stable/classes/environment.html) that allows specifing the executable name as follows:
ampl = AMPL(Environment('', 'ampldev'))
You can then use AMPL.getOutput
/AMPL.get_output
to retrieve the output of the new command "snapshot;" as a string. The string returned is a compact representation of the AMPL state (model declaration, data, solution loaded, options, etc.)
snapshot = ampl.getOutput('snapshot;')
print(snapshot)
This string can then be passed to another AMPL object using AMPL.eval
. The following example produces the output below:
from amplpy import AMPL, Environment
print('First object:')
ampl = AMPL(Environment('', 'ampldev'))
ampl.read('diet.mod')
ampl.read_data('diet.dat')
ampl.option['solver'] = 'gurobi'
ampl.solve()
print('Second object:')
ampl2 = AMPL(Environment('', 'ampldev'))
snapshot = ampl.get_output('snapshot;')
print(snapshot, file=open('snapshot.run', 'w'))
ampl2.eval(snapshot)
ampl2.display('Buy')
print('Third object:')
ampl3 = AMPL(Environment('', 'ampldev'))
ampl3.eval(ampl2.get_output('snapshot;'))
ampl3.display('_VARS;')
ampl3.eval('option solver;')
First object:
Gurobi 9.1.2: optimal solution; objective 88.2
1 simplex iterations
Second object:
Buy [*] :=
BEEF 0
CHK 0
FISH 0
HAM 0
MCH 46.6667
MTL 0
SPG 0
TUR 0
;
Third object:
set _VARS := Buy;
option solver gurobi;
One thing that may also be useful: In the example, there is the line print(snapshot, file=open('snapshot.run', 'w'))
that writes the snapshot to a file called snapshot.run
. This file can be loaded into AMPL (e.g., for debugging) as follows:
$ ampl
ampl: include "snapshot.run";
ampl: display Buy;
Buy [*] :=
BEEF 0
CHK 0
FISH 0
HAM 0
MCH 46.6667
MTL 0
SPG 0
TUR 0
;
The snapshot feature is not finished and it is still being perfected. If you encounter any issues, please let us know.
Hi Xavier,
We have just release a new version of this development version with snapshot. If fixes a couple of issues that were reported meanwhile.
Please note that the name of the experimental binary was changed from ampldev
to x-ampl
(eXperimental AMPL). This new version is available from the AMPL portal under this new name and is included in every bundle including any newly generated time-limited bundles.
Starting from amplpy v0.12.0, AMPL.snapshot is now available by default and it produces a very reliable representation of the AMPL state. The following now works without any issues:
from amplpy import AMPL
ampl1 = AMPL()
ampl1.eval(r"""
set NUTR;
set FOOD;
param cost {FOOD} > 0;
param f_min {FOOD} >= 0;
param f_max {j in FOOD} >= f_min[j];
param n_min {NUTR} >= 0;
param n_max {i in NUTR} >= n_min[i];
param amt {NUTR,FOOD} >= 0;
var Buy {j in FOOD} >= f_min[j], <= f_max[j];
minimize Total_Cost: sum {j in FOOD} cost[j] * Buy[j];
subject to Diet {i in NUTR}:
n_min[i] <= sum {j in FOOD} amt[i,j] * Buy[j] <= n_max[i];
""")
ampl1.eval(r"""
data;
set NUTR := A B1 B2 C ;
set FOOD := BEEF CHK FISH HAM MCH MTL SPG TUR ;
param: cost f_min f_max :=
BEEF 3.19 0 100
CHK 2.59 0 100
FISH 2.29 0 100
HAM 2.89 0 100
MCH 1.89 0 100
MTL 1.99 0 100
SPG 1.99 0 100
TUR 2.49 0 100 ;
param: n_min n_max :=
A 700 10000
C 700 10000
B1 700 10000
B2 700 10000 ;
param amt (tr):
A C B1 B2 :=
BEEF 60 20 10 15
CHK 8 0 20 20
FISH 8 10 15 10
HAM 40 40 35 10
MCH 15 35 15 15
MTL 70 30 15 15
SPG 25 50 25 15
TUR 60 20 15 10 ;
""")
snapshot = ampl1.snapshot()
ampl2 = AMPL()
ampl2.eval(snapshot)
ampl2.display("amt")
You can store the snapshot
string in the pickle and use it anywhere else to get AMPL to the same state as when the snapshot was taken.
Hello,
I would like to know if it is possible, after the ampl problem has been solved, to store the whole ampl object in python (with something similar to PICKLE) to be able to interact further on with this object and it solution (i.e. values of the variables, dual variables, etc.)
Thank you in advance for your answer,
Best regards,
Xavier Rixhon