Draft Writeup of April 24, 1996


Enhancements to AMPL commands let you read new data (while leaving the model the same) in a more convenient variety of ways. The uses of data, update data and reset data have been extended, and a new read command has been provided for importing data not in the standard AMPL format (chapter 9).

Declarations of AMPL model components can be removed or redefined by use of the new purge, delete, and redeclare commands. Other new features let you change the value of a variable while fixing or unfixing it, and relax the integrality restrictions on variables.

Reading data: the data, update data and reset data commands

The command consisting of only the keyword data puts AMPL into data mode, where you can type the data tables and lists described by Chapter 9 of the book:

	ampl: model diet.mod;
	ampl: data;

	ampl data: set NUTR := A B1 B2 C ;
	ampl data: param:   n_min  n_max :=
	ampl data?    A      700   10000
	ampl data?    C      700   10000
	ampl data?    B1     700   10000
	ampl data?    B2     700   10000 ;

	ampl data: display n_min, n_max;

	:  n_min   n_max    :=
	A    700   10000
	B1   700   10000
	B2   700   10000
	C    700   10000
AMPL exits data mode when it sees any statement (such as display above) that does not begin with a keyword (such as set or param) that begins a data statement.

Normally data values are read from files rather than being typed at the AMPL prompts. A command of the form

data filename;
reads the contents of the named file as if it had been typed at the prompts, starting in data mode. The mode then reverts to whatever it was before the data statement was executed -- unless the last data statement in the file is incomplete, in which case data mode persists.

When you use data statements to assign values to model components, AMPL checks that no component is assigned a value more than once. Duplicate assignments are flagged as errors. In some situations, however, it is convenient to be able to change the data by issuing new data statements; for example, after solving for one scenario of a model, you may want to modify some of the data by reading a new data file that corresponds to a second scenario. The statements in the new file would normally be treated as erroneous duplicates, but you can tell AMPL to accept them by first giving one of the following commands:

reset data;
reset data

update data;
update data
The reset commands discard specified data, which must then be re-read before another problem can be generated and solved. The update commands retain the current data, but allow specified data values to be overwritten (once only) by subsequent data commands. The component-list, which has the same format as in the display command (Chapter 10.3), indicates the model components that are to be reset or updated. Without the component-list, these commands apply to all the components of the model.

Previous restrictions on the location of an AMPL data statement have now been lifted. In, particular, a data statement may appear within an if statement to conditionally read data. A data statement may also be used within a for or repeat statement, in conjunction with reset or update, to iteratively read a data file that is being regenerated at each pass through a loop, typically by some external program (an example is to be provided).  

Reading data: the read command

The new read command provides a way of reading unformatted data into AMPL parameters and other components. It has syntax similar to that of the print command:
read arglist redirectionopt ;
indexing-expr : arglist redirectionopt ;
As in the case of display, print and printf, the optional indexing-expr causes the read command to be executed separately for each member of the specified indexing set. Thus, for example, a statement beginning read {i in ORIG}: ... has the same effect as for {i in ORIG} read ... .

We describe first how read interprets its input, and then where it looks for the input.

Interpretation of input. The read command treats its input as an unformatted series of data values, separated by white space (any combination of spaces, tabs and newlines). The arglist specifies a series of components to which these values are assigned. As in the case of print, the arglist is a comma-separated list of args, which may be any of:

indexing-expr component-ref
arglist )
The component-ref must be a reference to a parameter, variable, or constraint; it is meaningless to read a value into a set member or any more general expression. As in the case of print, all indexing must be explicit, so that for example you must say read {j in DEST} demand[j] ranther than read demand.

Values are assigned to args in the order that they are read. Thus it is legal to write, say,

	param cost {ORIG,DEST} default 9999;
	param ic symbolic in ORIG;
	param jc symbolic in DEST;
	param npairs integer;

	read npairs, {1..npairs} (ic,jc,cost[ic,jc]);
The first input value, by being assigned to npairs, determines how much more data will be read. The remainder of the input comes in a series of threes; the first two values, read into ic and jc, determine where in cost the third value should be stored.

Sources of input. If no redirection is specified, values are read from the current input stream. Thus if you have typed the read command at an AMPL prompt, you type the values at subsequent prompts until all of the arglist entries have been assigned values. For example:

	ampl: read npairs, {1..npairs} (ic,jc,cost[ic,jc]);
	ampl? 3
	ampl? GARY FRA 3000
	ampl? GARY LAF 4500
	ampl? CLEV WIN 4200

	ampl: display cost;
	cost :=
	CLEV WIN   4200
	GARY FRA   3000
	GARY LAF   4500
The prompt changes from ampl? back to ampl: when all the needed input has been read. If instead you put read inside an AMPL script file that is read by use of include or commands, then the input is read from the same file, beginning directly after the ; of the read command.

Most often the input to read lies in a separate file. Then you can use the optional redirection to specify this file; its form is < filename, where filename is a string that identifies a file on your computer. You can read more than once from the same file,

	ampl: read npairs < pairs.dat;
	ampl: read {1..npairs} (ic,jc,cost[ic,jc]) < pairs.dat;
in which case each read starts reading the file where the previous one left off. (To force reading to start at the beginning again, use the command close filename.

What if you want an AMPL script to contain a read command that reads values typed interactively? In this case you must redirect the source of the values to the "standard input", which is accomplished by writing a - as the filename. This can be useful when you want a script to prompt the user. For example, suppose that your script contains

	param T integer > 0;

	printf "\nHow many of the periods do you want to use?\n";
	read T <- ;
and is stored in the file read.run. Then here's how it would look in use:
	ampl: include read.run;

	How many of the periods do you want to use?
	ampl? 5
In this case the value 5 would be assigned to T.

Removing or redefining model components

The delete command removes a previously declared model component, provided that no other components use it in their declarations. Thus normally you can delete a constraint, but you cannot delete a variable -- because it appears in subsequent constraint declarations. The form of the command is
delete component-list ;
where component-list is a space-separated or comma-separated list of names of sets, parameters, variables, objectives, constraints or
problems. You can also include a "name" of the form check n in the component-list, to delete the nth check statement in the current model.

The purge command has the same form,

purge component-list ;
It removes not only the named components, but also all components that depend on them either directly (by referring to them) or indirectly (by referring to their dependents). Thus for example in diet.mod we have
	param f_min {FOOD} >= 0;
	param f_max {j in FOOD} >= f_min[j];

	var Buy {j in FOOD} >= f_min[j], <= f_max[j];

	minimize total_cost:  sum {j in FOOD} cost[j] * Buy[j];
The command purge f_min deletes parameter f_min and the components whose declarations refer to f_min, including parameter f_max and variable Buy. It also deletes objective total_cost, which depends indirectly on f_min through its reference to Buy.

Once a component has been removed by delete or purge, any previously hidden meaning of the component's name becomes visible again. After a constraint named prod is deleted, for instance, AMPL again recognizes prod as an iterated multiplication operator (Table 7-1 of the AMPL book).

The name of a component removed by delete or purge becomes again unused, and may subsequently be declared as the name of any new component of any type. If you only want to make some relatively small revision to a component's declaration, however, then you will probably find AMPL's new redeclare feature to be more convenient. You can say

redeclare declaration
where declaration is the complete revised declaration that you would like to substitute. Looking again at diet.mod, for example,
redeclare param f_min {FOOD} > 0 integer;
changes only the validity conditions on f_min. The declarations of all components that depend on f_min are left unchanged, as are any values previously read for f_min. A redeclare can be applied to statements beginning with any of the following:

	subject to
You can also redeclare the nth check statement by writing redeclare check n in front of your new check declaration.

To request a list of all components that a given component refers to, use the new xref command.

Fixing or unfixing a variable at a new value

Rather than setting a variable to zero and then fixing it to zero,

	let Buy["beef"] := 0;
	fix Buy["beef"];
you can fix and set the variable with one command:
	fix Buy["beef"] := 0;
The := phrase may also be used with the indexed form of the fix command:
	fix {i in ORIG} Trans[i,"FRA"] := 100;
The unfix command works in the same way, to simultaneously unfix and reset the value of a variable.

Relaxing integrality

By changing the relax_integrality option from its default of 0 to any nonzero value,
	option relax_integrality 1;
you tell AMPL to drop any restriction of variables to integer values. Variables declared integer get whatever bounds you specified for them, while variables declared binary are given a lower bound of zero and an upper bound of one. To restore the integrality restrictions, set the relax_integrality option back to 0.

Some of the solvers that work with AMPL provide their own directives for relaxing integrality, but these do not necessarily have the same effect as the AMPL's relax option. AMPL drops integrality restrictions before its presolve phase, so that the solver receives a true continuous relaxation of the original integer problem. If the relaxation is performed by the solver, however, then the integrality restrictions are still in effect during AMPL's presolve phase, and AMPL may perform some additional tightening and simplification as a result. As a simple example, when presolve sees the declarations

	var X integer >= 0;
	subj to upXbd: 5 * X <= 12;
it removes the constraint upXbd and places an upper limit of 2 on the variable X; this upper limit is sent to the solver, where it remains even if you specify a solver directive for integrality relaxation. If instead option relax_integrality is set to 1, AMPL converts the constraint to an upper limit of 2.4, which is sent to the solver.

The same situation can arise in much less obvious circumstances, and can lead to unexpected results. In general, the optimal value of an integer program under AMPL's relax_integrality option may be lower (for minimization) or higher (for maximization) than the optimal value reported by the solver's relaxation directive, unless AMPL's presolve phase is turned off by the command option presolve 0.

Comments or questions?
Write to info@ampl.com or use our comment form.

Return to the AMPL update page.

Return to the AMPL home page.