AMPL - spreadsheet handling with amplxl

amplxl.ipynb Open In Colab Kaggle Gradient Open In SageMaker Studio Lab Hits

Description: Basic example of reading/writing data into/from a .xlsx spreadsheet with amplxl

Tags: ampl, amplxl, spreadsheet, excel, xlsx

Notebook author: Nicolau Santos <nfbvs@ampl.com>

# Install dependencies
%pip install -q amplpy
# Google Colab & Kaggle integration
from amplpy import AMPL, ampl_notebook

ampl = ampl_notebook(
    modules=["highs", "plugins"],  # modules to install
    license_uuid="default",  # license to use
)  # instantiate AMPL object and register magics

amplxl

amplxl is a table handler for spreadsheets in the .xlsx format. amplxl is available by default in most AMPL bundles. If it’s ot available in your AMPL install you canget it from the above link.

To load the library you need to add the instruction

load amplxl.dll;

in your AMPL file.

In this notebook we will take a quick look on how to use amplxl in the diet problem, available on Chapter 2 of the AMPL book.

%%writefile diet.mod

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];
Overwriting diet.mod

Sample data

First we download a spreadsheet with the data for the diet problem from our github repository.

url = "https://raw.githubusercontent.com/ampl/colab.ampl.com/master/datasets/nfbvs/diet2D.xlsx"

import urllib.request

urllib.request.urlretrieve(url, "diet2D.xlsx")
('diet2D.xlsx', <http.client.HTTPMessage at 0x20439740950>)

When we open the spredsheet we have a sheet named nutr with the following information:

nutr.png

The table in this sheet contains the data for the indexing set NUTR and for the parameters n_mix and n_max, that are indexed by NUTR.

In the sheet food we have the data for the indexing set FOOD and for the associated parameters cost, f_min and f_max.

food.png

The sheet amt contains information for the amt parameter, that is indexed both by NUTR and FOOD.

amt.png

Note that the amt parameter is represented as a 2-dimentional table and the definition of FOOD is implicit.

Establishing connection

Now we need to establish a connection between the data in the spreadsheet and AMPL. For each table in the spreadsheet we need a table declaration. For the data in the nutr sheet the table declaration is the following:

table nutr IN "amplxl" "diet2D.xlsx":
    NUTR <- [NUTR], n_min, n_max;

The declaration starts with the keyword table followed by the name of the sheet where the data is to be read from. IN indicates that we are reading data from the spreadsheet, "amplxl" is the name of the table handler and "diet.xlsx" is the path to the spreadsheet. The indexing sets in the table are enclosed between [ and ] symbols, followed by the associated parameters n_min and n_max. NUTR <- [NUTR] indicates that the data from the NUTR table in the spreadsheet is to be read into the NUTR set in AMPL.

The process is identical for the data in the food sheet

table food IN "amplxl" "diet2D.xlsx":
    FOOD <- [FOOD], cost, f_min, f_max;

and similar to the data in the amt table

table amt IN "amplxl" "2D" "diet2D.xlsx":
    [NUTR, FOOD], amt;

As amt is a 2-dimentional table, you need to specify the 2D keyword in the table declaration. The driver will detect the NUTR indexing set in the first column and assume that the elements in FOOD are the remaining elements of the first row. Also note that you will need a table for each indexing set.

To load the data use the read command

read table nutr;
read table food;
read table amt;

Choose a solver and solve

Now we are able to specify a solver and solve the model.

option solver highs;
solve;

We can wrap up all the statements in a single file “diet.run”.

%%writefile diet.run

reset;
load amplxl.dll;

model diet.mod;

table nutr IN "amplxl" "diet2D.xlsx":
    NUTR <- [NUTR], n_min, n_max;

table food IN "amplxl" "diet2D.xlsx":
    FOOD <- [FOOD], cost, f_min, f_max;
    
table amt IN "amplxl" "2D" "diet2D.xlsx":
    [NUTR, FOOD], amt;

read table nutr;
read table food;
read table amt;

option solver highs;
solve;
Overwriting diet.run

and include the file with the following instruction

%%ampl_eval
include diet.run;

Report results

It’s also possible to write the obtained results in an .xlsx spreadsheet. As an example we will create a table with values associated with the Buy variable (lower bounds, values, upper bounds and reduced cost). The syntax is very simillar to the read example above. The main differences are that we use OUT keyword, instead of the IN one, and that we change direction of the -> arrow.

table buy OUT "amplxl":
	FOOD -> [FOOD], Buy.lb, Buy, Buy.ub, Buy.rc;

Afterwars the read instruction is replaced by a write one.

write table buy;

As no filename was specified the driver will create a file with the name of table and the .xlsx file extension, “buy.xlsx”, and write the table information into it.

%%ampl_eval
table buy OUT "amplxl":
    FOOD -> [FOOD], Buy.lb, Buy, Buy.ub, Buy.rc;

write table buy;