AMPLPY: Setup & Quick Start

Documentation: http://amplpy.readthedocs.io

GitHub Repository: https://github.com/ampl/amplpy

PyPI Repository: https://pypi.python.org/pypi/amplpy

Setup

Install from the PiPY repository:

$ pip install amplpy

Or:

$ python -m pip install amplpy

Note: For Windows, Linux, and macOS, the amplpy package comes with 33 binary wheels for Python 2.7, 3.5, 3.6, 3.7, and 3.8. Please make sure that you are using the latest version of pip before installing amplpy (upgrade using "pip install pip --upgrade" or "python -m pip install pip --upgrade"). If a binary wheel for your platform is not available, a C++ compiler and python development libraries will be required.

Aditional packages

In this tutorial, we will also use Pandas and Bokeh. You can install these packages using "pip install pandas bokeh" or "python -m pip install pandas bokeh". Note that Bokeh is not mandatory for this tutorial.

We also recommend the use of Jupyter Notebook, which was used to create this tutorial. You can install Jupyter using "pip install jupyter" or "python -m pip install jupyter".

Quick start

Step 1: Import some packages that we will use


In [1]:
from __future__ import print_function

Import Pandas:


In [2]:
import pandas as pd

Import Bokeh (do not run if you do not have Bokeh installed):


In [3]:
from bokeh.layouts import row
from bokeh.plotting import figure, show

For Jupyter Notebooks only (do not run if you are not using Bokeh and Jupyter):


In [4]:
from bokeh.io import output_notebook
output_notebook()


Loading BokehJS ...

Step 2: Import the amplpy components that we will use


In [5]:
from amplpy import AMPL, Environment, DataFrame

Step 3: Create an AMPL object


In [6]:
ampl = AMPL()

If the AMPL installation directory is not in the system search path, you should create the AMPL object as follows instead:

ampl = AMPL(Environment('full path to the AMPL installation directory'))

Note that you may need to use raw strings (e.g., r'C:\ampl\ampl.mswin64') or escape the slashes (e.g., 'C:\\ampl\\ampl.mswin64') if the path includes backslashes.

Step 4: Select the solver


In [7]:
ampl.setOption('solver', 'gurobi')

Step 5: Define the model


In [8]:
ampl.eval('''
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];
''')

Note: Alternatively you can read the model from a file using "ampl.read(filename)".

Step 6: Define the initial data


In [9]:
foods = ['BEEF', 'CHK', 'FISH', 'HAM', 'MCH', 'MTL', 'SPG', 'TUR']
nutrients = ['A', 'C', 'B1', 'B2', 'NA', 'CAL']

Define AMPL sets fom python lists


In [10]:
ampl.getSet('FOOD').setValues(foods)
ampl.getSet('NUTR').setValues(nutrients)

Define data using an amplpy DataFrame


In [11]:
ampl.setData(DataFrame(
    index=[('FOOD', foods)], 
    columns=[
        ('cost', [3.59, 2.59, 2.29, 2.89, 1.89, 1.99, 1.99, 2.49]), 
        ('f_min', [2, 2, 2, 2, 2, 2, 2, 2]), 
        ('f_max', [10, 10, 10, 10, 10, 10, 10, 10])
    ]
))

Define data using a Pandas DataFrame


In [12]:
df = pd.DataFrame({
    'n_min': [700, 700, 700, 700, 0, 16000], 
    'n_max': [20000, 20000, 20000, 20000, 50000, 24000]
}, 
    index=nutrients
)
ampl.setData(DataFrame.fromPandas(df))

Define data using a python dictionary


In [13]:
amounts = [
    [ 60,    8,   8,  40,   15,  70,   25,   60],
    [ 20,    0,  10,  40,   35,  30,   50,   20],
    [ 10,   20,  15,  35,   15,  15,   25,   15],
    [ 15,   20,  10,  10,   15,  15,   15,   10],
    [928, 2180, 945, 278, 1182, 896, 1329, 1397],
    [295,  770, 440, 430,  315, 400,  379,  450]
]
df = DataFrame(('NUTR', 'FOOD'), 'amt')
df.setValues({
    (nutrient, food): amounts[i][j]
    for i, nutrient in enumerate(nutrients)
    for j, food in enumerate(foods)
})
ampl.setData(df)

Step 7: Solve the model


In [14]:
ampl.solve()


Gurobi 8.1.0: optimal solution; objective 119.9897589
5 simplex iterations

Step 8: Create a Pandas DataFrame with the values of the variable 'Buy'


In [15]:
ampl.getVariable('Buy').getValues().toPandas()


Out[15]:
Buy.val
BEEF 5.226933
CHK 2.000000
FISH 2.000000
HAM 10.000000
MCH 10.000000
MTL 10.000000
SPG 9.439734
TUR 2.000000

Step 9: Display the objective value


In [16]:
totalcost = ampl.getObjective('Total_Cost')
print("Objective is:", totalcost.value())


Objective is: 119.98975893599335

Step 10: Increase the costs of beef and ham


In [17]:
cost = ampl.getParameter('cost')
cost.setValues({'BEEF': 5.01, 'HAM': 4.55})
print("Increased costs of beef and ham.")


Increased costs of beef and ham.

Step 11: Solve the model with the new costs


In [18]:
ampl.solve()


Gurobi 8.1.0: optimal solution; objective 144.0120033
5 simplex iterations

Step 12: Display the new objective value


In [19]:
print("New objective value:", totalcost.value())


New objective value: 144.01200332502077

Step 13: Display the value of Buy['BEEF']


In [20]:
Buy = ampl.getVariable('Buy')
print("Buy['BEEF'].val = {}".format(Buy['BEEF'].value()))


Buy['BEEF'].val = 5.226932668329175

Step 14: Display the dual value of each diet constraint


In [21]:
diet = ampl.getConstraint('Diet')
for nutr in nutrients:
    print("Diet['{}'].dual = {}".format(nutr, diet[nutr].dual()))


Diet['A'].dual = 0.0
Diet['C'].dual = 0.0
Diet['B1'].dual = 0.0
Diet['B2'].dual = 0.7999285120532003
Diet['NA'].dual = -0.007531172069825435
Diet['CAL'].dual = 0.0

Step 15: Display the values of the variable 'Buy' using Bokeh


In [22]:
rows = [tuple(row) for row in Buy.getValues()]
factors = [index for index, value in rows]
x = [value for index, value in rows]

dot = figure(
    title="Categorical Dot Plot", tools='', toolbar_location=None,
    y_range=factors, x_range=[0,12]
)

dot.segment(0, factors, x, factors, line_width=2, line_color='green')
dot.circle(x, factors, size=15, fill_color='orange', line_color='green', line_width=3)
show(dot)