Quick Start

MATLAB can easily consume Java objects, therefore usage of AMPL API from MATLAB is very direct. Because of this, just a few MATLAB files are distributed, located in the MATLAB subdirectory of the distribution directory. An helper script (setUp.m) is provided for the user, which sets MATLABs Javaclasspaths (the paths in which Matlab searches for Java classes) and imports the library’s functionalities. A function (initAMPL.m) is distributed too, to facilitate the process of creating a new AMPL object. When running the examples, the user can just run the convenient setupOnce.m script, located in the examples directory, which takes care of executing the main setup routine. Full class reference is given in MATLAB API Reference.

Complete listing

The complete MATLAB script is below:

% Create an AMPL instance
ampl = AMPL;

%% If the AMPL installation directory is not in the system search path:
% ampl = AMPL('full path to the AMPL installation directory');

% Display version
ampl.eval('option version;')

% Initialisation
basef = fileparts(which('dietModel'));
addpath(fullfile(basef, '../../matlab'));
modeldirectory = fullfile(basef, '.', 'models');

% Load from file the ampl model
ampl.read([modeldirectory  '/' 'diet.mod']);
ampl.readData([modeldirectory  '/' 'diet.dat']);

% Solve
ampl.solve

% Get objective map by AMPL name
totalcost = ampl.getObjective('Total_Cost');
% Print it
fprintf('Objective is: %f\n' ,totalcost.value());

% Reassign data - specific instances
cost = ampl.getParameter('cost');
cost.setValues({'BEEF';'HAM'}, [5.01; 4.55]);
disp('Increased costs of beef and ham.');

% Resolve and display objective
ampl.solve();
fprintf('New objective value: %f\n', totalcost.value());

% Reassign data - all instances
cost.setValues([3, 5, 5, 6, 1, 2, 5.01, 4.55]);

disp('Updated all costs');

% Resolve and display objective
ampl.solve();
fprintf('New objective value: %f\n', totalcost.value());

% Get the values of the variable Buy in a dataframe object
buy = ampl.getVariable('Buy');
df = buy.getValues;
% Print them
df


% Close the AMPL object
ampl.close();

Initialisation

To initialise the MATLAB interface, navigate to the MATLAB directory of the distribution and execute the script setUp.m. This should return something on the lines of:

>> setUp
Using api at D:/Development/AMPLApi/git/examples/matlab/../../matlab/../ampl-1.0.jar
Using ampl in the folder D:/Development/AMPLApi/git/examples/matlab/../../matlab/../ampl

This procedure must be executed once every session. To execute the examples, the script setupOnce.m is provided in the examples directory and should be used instead. The main object needed to interact with AMPL is of the AMPL class and can be instantiated as shown below:

>> ampl = AMPL;

The statement above creates an instance of the API and names is ampl.

AMPL Environment creation

Since the structure of AMPL API for MATLAB is the same as AMPL API for Java, the main method is the AMPL.eval function. Copy the following statements to have a hello world application which interprets the command option version; in the underlying AMPL executable and prints the result on the console.

% Create an AMPL instance
ampl = AMPL;
% Display version
ampl.eval('option version;')

The output of the statements above should be something of the form:

ans =
option version 'AMPL Version 20140220 (MS VC++ 10.0, 64-bit)';

Load a model from file

The following lines use the method AMPL.read to load a model and data stored in external (AMPL) files. If the files are not found, an error will be displayed.

ampl.read([modeldirectory  '/' 'diet.mod']);
ampl.readData([modeldirectory  '/' 'diet.dat']);

Once these commands are executed, the AMPL interpreter will have interpreted the content of the two files. No further communication is made between the AMPL interpreter and MATLAB, as every entity is created lazily (as needed).

Solve a model

To solve the model, it is sufficient to issue the command:

ampl.solve;

which should display, depending on the default solver used, something like:

CBC trunk optimal, objective 118.0594032
3 iterations

Get an AMPL entity in the programming environment (get objective value)

AMPL API provides Java representations of the AMPL entities, which can be directly used in MATLAB. Usually, not all the entities are of interest for the programmer. The generic procedure is:

  1. Identify the entities that need interaction (either data read or modification)

  2. For each of these entities, create an object of the appropriate class in Java

  3. Get the entity through the AMPL API using AMPL.getEntity or one of its type safe alternatives (AMPL.getVariable, AMPL.getParameter, AMPL.getObjective , AMPL.getSet, AMPL.getConstraint)

To gain access to a specific entity, we can assign to a MATLAB placeholder. In this example, we want to be able to refer to the AMPL objective Total_Cost as totalcost in MATLAB. We can use the following statements to do that and display the current values of the objective.

totalcost = ampl.getObjective('Total_Cost');
fprintf('Objective is: %f\n', totalcost.value);

The output of the lines above is:

Objective is: 118.05940323955669

An alternative way to access a scalar value from the underlying interpreter is to use the function AMPL.getValue. This function has a very simple syntax and it is useful for all the times in which we are only interested in getting a value, without having to manipulate the underlying entity. This approach is shown below:

fprintf('Objective is: %f\n', ampl.getValue('Total_Cost'));

Modify model data (assign values to parameters)

The input data of an optimisation model is stored in its parameters; these can be scalar or vectorial entities. Two ways are provided to change the value of vectorial parameter: change specific values or change all values at once. The example shows an example of both ways, reassigning the values of the parameter costs firstly specifically, then altogether. Each time, it then solves the model and get the objective function. The functions that can be used to modify the values are Parameter.set and Parameter.setValues.

cost = ampl.getParameter('cost');
cost.setValues({'BEEF','HAM'}, [5.01; 4.55]);
disp('Increased costs of beef and ham.');

The code above assigns the values 5.01 and 4.55 to the parameter cost for the objects beef and ham respectively. The model is then solved again and the new objective is printed with:

ampl.solve();
fprintf('New objective value: %f\n', totalcost.value);

If the order of the indexing of an entity is known (i.e. for multiple reassignment), it is not necessary to specify both the indices and the values. The data vector is assigned to each of the parameter values, in the order they are represented in AMPL.

% Reassign data - all instances
cost.setValues(3, 5, 5, 6, 1, 2, 5.01, 4.55);
disp('Updated all costs');
% Resolve and display objective
ampl.solve;
fprintf('New objective value: %f\n', totalcost.value());

The statements above produce the following output:

Increased costs of beef and ham.
New objective value: 144.415720
Updated all costs
New objective value: 164.543750

Get numeric values from variables and other entities

To access all the numeric values contained in a Variable or any other entity, use a DataFrame object. Doing so, the data is detached from the entity, and there is a considerable performance gain. To do so, we first get the Variable object from AMPL, then we get its data with the functions, available for all entities: Variable.getValues, Constraint.getValues, Objective.getValues, Parameter.getValues and Set.getValues.

% Get the values of the variable Buy in a dataframe object
buy = ampl.getVariable('Buy');
df = buy.getValues;
% Print them
df

The statements above produce the following output:

df =
   j in FOOD  |  Buy
   BEEF       |  10.0
   CHK        |  2.0
   FISH       |  2.0
   HAM        |  7.01644736842106
   MCH        |  10.0
   MTL        |  10.0
   SPG        |  6.65570175438596
   TUR        |  2.0

Get arbitrary values via ampl expressions

Often we are interested in very specific values coming out of the optimization session. To make use of the power of AMPL expressions and avoiding cluttering up the environment by creating entities, fetching data through arbitrary AMPL expressions is possible. For this model, we are interested in knowing how close each decision variable is to its upper bound, in percentage. We can obtain this data into a dataframe with the code:

% Get the values of an expression into a DataFrame object
df2 = ampl.getData('{j in FOOD} 100*Buy[j]/Buy[j].ub');

The statements above produce the following output:

df2 =
index0  |  100*Buy[j]/(Buy[j].ub)
BEEF    |  53.60613810741687
CHK     |  20.0
FISH    |  20.0
HAM     |  100.0
MCH     |  100.0
MTL     |  100.0
SPG     |  93.06052855924978
TUR     |  20.0

Close the AMPL object to free the resources

Since the AMPL object is very resource-hungry, it is good practice to make sure it is closed and all its resources released when it is not needed anymore. This can be easily achieved by calling the function AMPL.close.

ampl.close();