           GLPK/L MODELING LANGUAGE: A BRIEF DESCRIPTION
             Supplement to GLPK User's Guide, May 2001

          Andrew Makhorin <mao@mai2.rcnet.ru, mao@gnu.org>



This document is a supplement to GLPK User's Guide. It describes a
preliminary version of the GLPK/L modeling language.



CONTENTS
********

1. INTRODUCTION
2. MATHEMATICAL PROGRAMMING PROBLEM
3. MODEL DESCRIPTION
   3.1. Symbolic names
   3.2. Numeric constants
   3.3. Delimiters
   3.4. Comment sequences
4. SETS
5. PARAMETERS
6. PREDICATES
7. VARIABLES
8. CONSTRAINTS
9. EXPRESSIONS
   9.1. Mute letters
   9.2. Constants
   9.3. Designators
   9.4. Operators
   9.6. Built-in function data()
   9.7. Built-in function table()
   9.8. Built-in function sum()
10. ASSIGNMENT STATEMENT
11. OBJECTIVE STATEMENT
12. DISPLAY STATEMENT
APPENDIX A. USING THE LANGUAGE PROCESSOR FROM GLPK API
APPENDIX B. USING GLPK/L MODELS WITH THE SOLVER GLPSOL
APPENDIX C. EXAMPLE OF MODEL DESCRIPTION
APPENDIX D. LP PROBLEM GENERATED FROM THE EXAMPLE MODEL
APPENDIX E. SOLUTION OF THE GENERATED LP PROBLEM



1. INTRODUCTION
***************

The GLPK/L modeling language is intended for writing mathematical
programming models. The name GLPK/L is derived from GNU Linear
Programming Kit Language.

Model description written in the GLPK/L language consists of a sequence
of statements constructed by the user from the language elements
described in this document.

In a process called translation, a program called the language processor
analyzes the model description statements and translates them into
internal data structures, which may be then used either for generating
mathematical programming problem data or directly by a program called
the solver for obtaining numerical solution of the corresponding
problem.

The GLPK/L modeling language is a part of the GLPK package.



2. MATHEMATICAL PROGRAMMING PROBLEM
***********************************

GLPK/L assumes the following formulation of mathematical non-linear
programming (NLP) problem:

   minimize (or maximize)

      Z = x[obj]                                                   (2.1)

  subject to (non-linear) constraints

      x[1] = f[1](x[m+1], x[m+2], ..., x[m+n])
      x[2] = f[2](x[m+1], x[m+2], ..., x[m+n])                     (2.2)
            .  .  .  .  .  .  .  .  .  .
      x[m] = f[m](x[m+1], x[m+2], ..., x[m+n])

   and bounds of variables

        l[1] <=  x[1]  <= u[1]
        l[2] <=  x[2]  <= u[2]                                     (2.3)
          .  .  .  .  .  .  .
      l[m+n] <= x[m+n] <= u[m+n]

where:
x[1], x[2], ..., x[m]       -- rows or auxiliary variables;
x[m+1], x[m+2], ..., x[m+n] -- columns or structural variables;
Z                           -- objective function;
obj                         -- number of row that defines the objective
                               function;
f[1], f[2], ..., f[m]       -- non-linear functions that defines
                               equality constraints;
l[1], l[2], ..., l[m]       -- lower bounds of variables;
u[1], u[2], ..., u[m]       -- upper bounds of variables.

(Processing model description written in GLPK/L assumes generating data
for mathematical programming problem. Although currently the GLPK
package is intended for linear and mixed linear programming only, the
GLPK/L language is suitable to express linear as well as non-linear
models. That's why the general formulation is given here.)

If all the functions f[1], f[2], ..., f[m] are linear, the problem
(2.1)--(2.3) is linear programming (LP) problem. LP differs from NLP
only in the system of equality constraints, which in case of LP is the
following:

      x[1] = a[1,1]*x[m+1] + a[1,2]*x[m+2] + ... + a[1,n]*x[m+n]
      x[2] = a[2,1]*x[m+1] + a[2,2]*x[m+2] + ... + a[2,n]*x[m+n]   (2.4)
            .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
      x[m] = a[m,1]*x[m+1] + a[m,2]*x[m+2] + ... + a[m,n]*x[m+n]

where a[1,1], a[1,2], ..., a[m,n] -- constraint coefficients.

Auxiliary variables are called rows, because they correspond to rows of
the constraint matrix (i.e. matrix formed by constraint coefficients as
in case of LP problem). Analogously, structural variables are called
columns, because they correspond to columns of the constraint matrix.

Bounds of variables can be finite as well as infinite. Besides, lower
and upper bounds can be equal to each other. Thus, the following types
of variables are possible:

      Bounds of variable      Type of variable
      -------------------------------------------------
      -inf <  x[k] <  +inf    Free (unbounded) variable
      l[k] <= x[k] <  +inf    Variable with lower bound
      -inf <  x[k] <= u[k]    Variable with upper bound
      l[k] <= x[k] <= u[k]    Double-bounded variable
      l[k]  = x[k]  = u[k]    Fixed variable

Note that types of variables shown above are applicable to structural as
well as to auxiliary variables.

In addition to LP and NLP problems GLPK/L allows mixed integer linear
or non-linear programming (MIP) problems, in which some variables are
required to be integer. GLPK/L assumes that MIP problem has the same
formulation as ordinary (pure) LP or NLP problem, i.e. includes
auxiliary and structural variables, which may have lower and/or upper
bounds. Note that GLPK/L allows only structural variables to be of
integer kind.



3. MODEL DESCRIPTION
********************

The GLPK/L modeling language is intended to simplify preparing problem
data, especially in case of large-scale problems.

So far as components of mathematical programming problems usually
correspond to entities of the real world, composing such problems is
called modeling, and a description of such problems expressed in a
formal modeling language is called mathematical model. In GLPK/L
mathematical model is described in terms of sets, parameters,
predicates, variables, and constraints.

Syntactically model description written in GLPK/L is a sequence of
sentences called statements and has the following format:

   model <name>;
   <statement>
   <statement>
   ...
   <statement>
   end;

where <name> is a symbolic name of the model.

In a process called translation, a program called the language processor
analyzes the model description statements and translates them into
internal data structures, which may be then used either for generating
mathematical programming problem data or directly by a program called
the solver for obtaining numerical solution of the corresponding
problem.

Model description is written in the form of a plain text file using the
language elements described below.

3.1. Symbolic names
-------------------

Symbolic name is a sequence of letters of Latin alphabet (including
underscore _ which is considered as a letter) and decimal digits. The
first character of symbolic name should be a letter. Maximal length of
symbolic name is 31 characters. All symbolic names are distinct (case
sensitive).

Examples:   alpha
            this_is_a_name
            P123_abc321_
            _12345

Symbolic names are used to identify the following objects: sets, items,
parameters, predicates, variables, and constraints. No objects can have
the same symbolic name.

In GLPK/L there are some reserved key words which have fixed meaning and
therefore should not be used as symbolic names:

   and         binary      constraint  constraints
   end         in          integer     maximize
   minimize    model       not         or
   parameter   parameters  predicate   predicates
   set         sets        variable    variables
   where

3.2. Numeric constants
----------------------

Numeric constants has the following syntax:

<digit> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
<integer constant> ::= <digit> | <integer> <digit>
<base constant> ::= <integer constant> | <integer constant> . |
      . <integer constant> | <integer constant> . <integer constant>
<exponent> ::= e <integer constant> | e + <integer constant> |
      e - <integer constant>
<numeric constant> ::= <base constant> | <base constant> <exponent>

(it is allowed to write the letter 'E' instead the letter 'e').

Examples:   0
            123
            3.14
            56.
            .78
            123.456e-3

Numeric constants are self-defined literals that have obvious fixed
meaning.

3.3. Delimiters
---------------

Delimiter is one or two graphic characters. There are the following
delimiters in GLPK/L:

   +     -     *     /     (     )     #
   <     <=    =     >=    >     ++    --
   !=    ,     .     [     ]     :     :=

In case of two-character delimiter there should be no white-space
characters between delimiter characters.

Delimiters are used for different purposes. Their meaning will be
explained below.

3.4. Comment sequences
----------------------

The user can provide the model description with comments in order to
improve its readability and also for documenting purposes.

Comment sequence is a sequence of arbitary characters enclosed in
comment brackets /* and */. For example:

   /* this is a comment */

Comment sequences may appear anywhere in the model description. They
are ignored by the language processor.



4. SETS
*******

Set is a collection of abstract objects, which in GLPK/L are called
items. Each set and each item should be provided with a symbolic name,
which uniquely identifies the corresponding object and is intended for
referecing purposes.

The user introduces sets and items into model description using the set
statement. For example:

   sets months = (Jan, Feb, Mar, Apr, May, Jun),
        cities = (Boston, Chicago, Dallas, Memphis, Portland),
        empty = ();

Note that sets can't have the same items, i.e. intersection of any
different sets should be the empty set.

In GLPK/L sets are used only as index sets (domains).



5. PARAMETERS
*************

Parameter is a multidimensional array built over sets. A particular
element of parameter is called parameter member. Within array each
parameter member is uniquely identified by its subscript list, i.e. by
an ordered sequence of items of the corresponding index sets.

The user can declare parameters using the parameter statement. For
example:

   parameters a, dist[cities,cities], st[months,cities,cities];

In this example the parameter 'a' is 0-dimensional array, i.e. scalar,
the parameter 'dist' is 2-dimensional array built over the set 'cities',
and the parameter 'st' is 3-dimensional array built over the sets
'months' and 'cities'.

GLPK/L allows parameters to be sparse. Sparse parameter is a parameter,
where some (or all) members are missing.

If a parameter member exists, it always has an assigned value. Values
assigned to parameter members are model expressions built of model
variables, numeric constants, and arithmetic operators (so, parameter
are close to the computer algebra objects). The user can think model
expressions assigned to parameter members as character strings that
represent the corresponding formulae. So far as model expressions may
have the form of numeric constants (in which case expressions are called
constant expressions), parameters also may represent ordinary arrays of
numeric data.

Formally, a parameter F is the mapping

      F: S[1] x S[2] x ... x S[n] -> EXPR,                         (5.1)

where S[1] x S[2] x ... x S[n] is the Cartesian product of index sets,
over which the parameter F is defined, EXPR is the set of model
expressions (expanded with the special value 'nil', to which all missing
parameter members are mapped).

From the formal definition (5.1) it follows that:

a) all members of a parameter should have different tuples, i.e.
   multiplets (members with identical tuples) are not allowed;

b) in case of 0-dimensional (scalar) parameter the Cartesian product
   formally has one element. And so far sparse parameters are allowed,
   scalar parameter can have either one member or no member.

Being declared a parameter initially has no members. In order to create
some parameter members and assign some values to them the assignment
statement may be used. For example:

   a := 3.14;
   dist[#Boston,#Chicago] := 58;
   dist[#Chicago,#Memphis] := 32;
   dist[#Chicago,Portland] := 130;
   dist[#Dallas,#Memphis] := 28;
   dist[#Dallas,#Boston] := 75;
   dist[#Portland,#Chicago] := 130;
   dist[#Portland,#Dallas] := 48;

In this example assignment to the parameter 'dist' may also be written
in more convenient format using the data() built-in function:

   dist[i,j] := data(i in cities, j in cities:
                     Boston       Chicago       58
                     Chicago      Memphis       32
                     Chicago      Portland      130
                     Dallas       Memphis       28
                     Dallas       Boston        75
                     Portland     Chicago       130
                     Portland     Dallas        48    );

In case of two-dimensional parameters the table() built-in function may
also be used. For example:

   dist[i,j] := table(i in cities, j in cities:
                  Boston   Chicago  Dallas   Memphis  Portland:
      Boston      .        58       .        .        .
      Chicago     .        .        .        32       130
      Dallas      75       .        .        28       .
      Memphis     55       .        82       .        .
      Portland    .        130      48       .        .        );

where period (.) indicates missing parameter member.



6. PREDICATES
*************

Predicate has the same structure as parameter, i.e. predicate is a
multidimensional array built over sets. However, predicate members have
no assigned values.

Formally, a predicate P is the mapping

      P: S[1] x S[2] x ... x S[n] -> { true, false },              (6.1)

where S[1] x S[2] x ... x S[n] is the Cartesian product of index sets,
over which the predicate P is defined, { true, false } is the set of
Boolean values. Existing predicate members are mapped to 'true', and all
other elements of the Cartesian product are mapped to 'false' (thus,
predicates also have sparse structure).

Predicates are intended for expressing relationships between sets, that
may be used for constructing various logical conditions.

As a rule predicates appear as intermediate results in expressions, but
the user may explicily declare a named predicate using the predicate
statement, for example:

   predicate cond[cities,cities];

and then assign something to the predicate 'cond' using the assignment
statement, for example:

   cond[i,j] := dist[i,j] >= 70;

As a result of this assignment the predicate 'cond' will have the member
cond[#Chicago,#Portland], because dist[#Chicago,#Portland] = 130 >= 70,
but it won't have the member cond[#Portland,#Dallas], because
dist[#Portland,#Dallas] = 48 < 70.

May note that predicates are similar to Boolean arrays in programming
languages.



7. VARIABLES
************

Variable has the same structure as parameter, i.e. variable is a
multidimensional array built over sets. However, each variable member
called elemental variable is considered as structural variable of the
corresponding mathematical programming problem.

Variables are declared using the variable statement. For example, the
user may write:

   variable x[cities,cities];

that involves introducing 25 elemental variables (because the set
'cities' has 5 items) into the problem. These elemental variables are:
x[#Boston,#Boston], x[#Boston,#Chicago], ..., x[#Portland,#Memphis],
x[#Portland,#Portland].

Formally, a variable V is the mapping

      V: S[1] x S[2] x ... x S[n] -> SV,                           (7.1)

where S[1] x S[2] x ... x S[n] is the Cartesian product of index sets,
over which the variable V is defined, SV is the set of structural
variables of the corresponding mathematical programming problem.

Note that all elemental variables (i.e. variable members) are created
by the variable statement (unlike parameters and predicates, where being
declared these objects initially have no members).

As a rule there is no need to have sparse variables, i.e. variables, in
which some elemental variables are missing. However, the user may
declare sparse variable using a predicate-controlled declaration in the
variable statement. For example:

   variable x[i in cities,j in cities] where dist[i,j] >= 70;

In this case the variable 'x' will have only those elemental variables
x[i,j], on which the predicate dist[i,j] >= 70 is true.

If the key word 'variable' is used in the variable stetement, it means
continuous non-negative variable (as in pure LP and NLP problems). In
order to declare integer non-negative variables the additional key word
'integer' should be written before the keyword 'variable'. For example:

   integer variables y, z[cities,months];

GLPK/L also allows to declare binary variables, i.e. integer variables,
whose lower bound iz zero and upper bound is one. For example:

   binary variable t[months];

The variable statement doesn't allow to explicitly specify lower and/or
upper bounds of variables. However, the user can explicitly specify
bounds of variables by means of the assignment statement (see below).

Nothing can be assigned to variables, because variables are unknown
quantities. However, variables can be used in expressions in order to
construct constraints.

Each variable always has three associated implicit parameters:
lo-parameter, up-parameter, and fx-parameter. These parameters has the
same dimension and are defined over the same sets as the corresponding
variable. Whether a member belongs to an implicit parameter or not
depends on the type of a particular elemental structural variable as
shown in the folloiwng table:

   Type of structural variable   lo-param    up-param    fx-param
   --------------------------------------------------------------
   Free (unbounded) variable        -           -           -
   Variable with lower bound       l[k]         -           -
   Variable with upper bound        -          u[k]         -
   Double-bounded variable         l[k]        u[k]         -
   Fixed variable                   -           -          s[k]

where '-' denotes missing member, l[k] is lower bound, u[k] is upper
bound, and s[k] is fixed value of the elemental structural variable x[k]
respectively.

Note that values assigned to members of implicit parameters can be only
constant expressions (see Section 9 below).

Implicit parameters may be used in expressions and assignment statements
in the same way as explicit parameters.



8. CONSTRAINTS
**************

Constraint has the same structure as parameter, i.e. constraint is a
multidimensional array built over sets. However, each constraint member
called elemental constraint is considered as a particular constraint of
the corresponding mathematical programming problem.

Constraints are declared using the constraint statement. For example:

   constraints r, rd[cities], rs[months,cities,cities];

Formally, a constraint R is the mapping

      R: S[1] x S[2] x ... x S[n] -> SC,                           (8.1)

where S[1] x S[2] x ... x S[n] is the Cartesian product of index sets,
over which the constraint R is defined, SC is the set of constraints of
the corresponding mathematical programming problem.

Like parameters, predicates, and variables GLPK/L allows constraints to
be sparse.

Being declared a constraint initially has no members. In order to create
some elemental constraints (i.e. constraint members) and assign some
values to them the assignment statement may be used. For example:

   rd[i] := sum(j, dist[i,j] * x[j]) >= 20 * y[j];

So far as the parameter rd is defined over the set 'cities', which has
five items, five elemental constraints (constraint memebers) will be
created.

Should note that the language processor always automatically transforms
expressions assigned to elemental constraints to the form with zero
right-hand side. In particular, the assignment statement given above
would be transformed to the following:

   rd[i] := sum(j, dist[i,j] * x[j]) - 20 * y[j] >= 0;

Assuming that the parameter 'dist' is defined as in example given in
Section 5 (see above), the expression assigned, say, to the member
rd[#Chicago] is the following:

   rd[#Chicago] = 32 * x[#Memphis] + 130 * x[#Portland] -
                  20 * y[#Chicago] >= 0

The constraint member rd[#Chicago] in itself gives the corresponding
auxiliary variable, and the assigned expression gives the corresponding
(linear or non-linear) constraint function.

Like variables each constraint always has three associated implicit
parameters: lo-parameter, up-parameter, and fx-parameter. These
parameters has the same dimension and are defined over the same sets as
the corresponding constraint. Whether a member belongs to an implicit
parameter or not depends on the type of a particular elemental
constraint (i.e. auxiliary) variable as shown in the folloiwng table:

   Type of auxiliary variable    lo-param    up-param    fx-param
   --------------------------------------------------------------
   Free (unbounded) variable        -           -           -
   Variable with lower bound       l[k]         -           -
   Variable with upper bound        -          u[k]         -
   Double-bounded variable         l[k]        u[k]         -
   Fixed variable                   -           -          s[k]

where '-' denotes missing member, l[k] is lower bound, u[k] is upper
bound, and s[k] is fixed value of the elemental auxiliary variable x[k]
respectively.

Note that values assigned to members of implicit parameters can be only
constant expressions.

Implicit parameters may be used in expressions and assignment statements
in the same way as explicit parameters.



9. EXPRESSIONS
**************

Syntactically expressions are built of primary expressions, operators,
and parentheses.

In GLPK/L the result of computation of any (intermediate or final)
expression is always either parameter or predicate. Such temporary
objects are implicitly introduced into the model by the language
processor.

Consider, for example, the following expression:

   a + b * c

This expression is computed by the language processor as follows:

   t1 := a;
   t2 := b;
   t3 := c;
   t4 := t2 * t3;
   t5 := t1 + t4;

where t1, ..., t5 are temporary parameters or predicates (depending on
what the original operands a, b, and c are).

9.2. Mute letters
-----------------

Being computed each temporary parameter or predicate always acquires so
called mute letters.

Mute letter is an auxiliary object, which denotes an index set. The user
also can think mute letters as symbols (indices), whose values are items
of index sets.

In case of primary expressions mute letters are introduced by the user.
If a temporary parameter or predicate is the result of an operation, it
automatically inherits mute letters of operands.

All mute letters associated with index positions of a temporary
parameter or predicate are always different. 0-dimensional (scalar)
temporary parameters and predicates have no mute letters.

Let, for example, the following declaration is given:

   parameter dist[cities,cities];

and consider the following expression:

   0.5 * (dist[i,j] + dist[j,i])

In this expression the letters 'i' and 'j' are mute letters. They are
used to explain how the language processor should perform addition. In
this case the expression is computed in the folloiwng way:

   t1[i,j] := dist[i,j]            for all i in cities, all j in cities
   t2[i,j] := dist[j,i]            for all i in cities, all j in cities
   t3[i,j] := t1[i,j] + t2[i,j]    for all i in cities, all j in cities
   t4[i,j] := 0.5 * t3[i,j]        for all i in cities, all j in cities

where t4 is a temporary parameter, which corresponds to the result of
computation.

Now consider another expression:

   0.5 * (dist[i,j] + dist[j,k])

This expression is computed as follows:

   t1[i,j] := dist[i,j]            for all i in cities, all j in cities
   t2[j,k] := dist[j,k]            for all j in cities, all k in cities
   t3[i,j,k] := t1[i,j] + t2[j,k]  for all i in cities, all j in cities,
                                       all k in cities
   t4[i,j,k] := 0.5 * t3[i,j,k]    for all i in cities, all j in cities,
                                       all k in cities

Finally, consider yet another expression:

   0.5 * (dist[i,i] + dist[i,#Boston])

This expression is computed as follows:

   t1[i] := dist[i,i]              for all i in cities
   t2[i] := dist[i,j]              for all i in cities, j = Boston
   t3[i] := t1[i] + t2[i]          for all i in cities
   t4[i] := 0.5 * t3[i]            for all i in cities

Syntactically mute letter is a lower case letter of Latin alphabet.

Mute letters needn't to be explicitly declared. They are recognized by
context.

Note that identical mute letters denote the same set only within a
particular statement. If identical mute letters are used in different
statements, they may denote different sets.

9.3. Constants
--------------

The following constants may be used in expressions: numeric constant
(see Subsection 3.2), nil, true, and false.

The result of computation of numeric constant is 0-dimensional (scalar)
parameter, which has the only member. A value assigned to this member is
the numeric constant.

The result of computation of the constant nil is 0-dimensional (scalar)
parameter, which has no member (see Section 5).

The result of computation of the constant true is 0-dimensional (scalar)
predicate, which has the only member.

The result of computation of the constant false is 0-dimensional
(scalar) predicate, which has no member.

9.4. Designators
----------------

Designator is a primary expression, which allows to refer to such model
objects as sets, parameters, predicates, variables, and constraints.

Designators has the following syntax:

<parameter name> ::= <symbolic name>
<predicate name> ::= <symbolic name>
<set name> ::= <symbolic name>
<variable name> ::= <symbolic name>
<constraint name> ::= <symbolic name>
<reference> ::= <parameter name> | <predicate name> | <set name>
      <variable name> | <variable name> . lo | <variable name> . up |
      <variable name> .fx | <constraint name> | <constraint name> . lo |
      <constraint name> . up | <constraint name> . fx
<subscript> ::= <mute letter> | <mute letter> + <integer> |
      <mute letter> - <integer> | <mute letter> ++ <integer> |
      <mute letter> -- <integer> | # <item name>
<subscript list> ::= <subscript> | <subscript list> , <subscript>
<designator> ::= <reference> | <reference> [ <subscript list> ]

Number of subscripts in designator should be equal to dimension of the
corresponding object. If the object is 0-dimensional (scalar), subscript
list and square brackets [ and ] should be omitted.

The correspondence between subscripts and index sets, over which the
object is defined, is positional, i.e. the first subscript corresponds
to the first index set given in the object declaration, the second
subscript corresponds to the second index set, and so on.

If all subscripts are different mute letters, the result of computation
of the designator is determined as follows:

1. If reference is a parmeter, the result is an exact copy of this
   parameter, which additionaly acquires the mute letters specified in
   the designator.

2. If reference is a predicate, the result is an exact copy of this
   predicate, which additionally acquires the mute letters specified in
   the designator.

3. If reference is a set, the result is 1-dimensional predicate defined
   over the specified set, whose members correspond to items of the set.
   Being temporary the resultant predicate also acquires the mute letter
   specified in the designator.

4. If reference is a variable, the result is the parameter, which has
   the same dimension, defined on the same index sets, and has the same
   members as the variable. The value assigned to a particular member
   of the resultant parameter is the corresponding elemental variable.
   Being temporary the resultant parameter also acquires the mute
   letters specified in the designator.

5. If reference is a constraint, the result is the parameter, which has
   the same dimension, defined on the same index sets, and has the same
   members as the constraint. The value assigned to a particular member
   of the resultant parameter is the model expression assigned to the
   corresponding elemental constraint. Being temporary the resultant
   parameter also acquires the mute letters specified in the designator.

If some subscripts are the same mute letter, the result of computation
of the designator will have only those members, where items that
correspond to the same mute letters are equal to each other. Besides,
in the resultant object identical mute letters are replaced by one mute
letter, which involves decreasing object dimension. For example, being
computed the designator u[i,j,j,i] gives the temporary object v[i,j].

If subscript is a particular item, i.e. has the form # <item name>, the
result of computation of the designator will have only those members,
where items that correspond to such subscript are equal to the specified
item. Using particular items also involves decreasing object dimension.
For example, being computed the designator u[i,#aaa,k,#bbb] gives the
temporary object v[i,k].

GLPK/L allows to specify so called lead and lag operators, which have
the following syntactic forms:

   i + n       linear lead operator
   i - n       linear lag operator
   i ++ n      circular lead operator
   i -- n      circular lag operator

where i is a mute letter, n is an unsigned integer.

The result of computation of the designator, in which lead/lag operators
are used, may be explained by the following example.

Let the set 's' is declared as follows:

   set s = (a, b, c, d, e);

and the one-dimensional parameter 'u' is defined over the set 's':

   parameter u[s];

   u[i] := data(i in s: a 1, b 2, c 3, d 4, e 5);

Then the resultant parameters are computed as follows:

      u[i]     u[i+2]   u[i-2]   u[i++2]  u[i--2]
      -------------------------------------------
      a 1        -       c 1       d 1      c 1
      b 2        -       d 2       e 2      d 2
      c 3       a 3      e 3       a 3      e 3
      d 4       b 4       -        b 4      a 4
      e 5       c 5       -        c 5      b 5

where '-' denotes that the corresponding member is not included into
the resultant object. Note that the order of set items is the order, in
which these items are enumerated in the set declaration.

If reference is the name of a variable or constraint followed by the
suffix '.lo', '.up', or '.fx', it refers to the corresponding implicit
parameter associated with the variable or constraint (see Sections 7
and 8). Such designators are computed by the language processor in the
same way as if they would be ordinary explicit parameters.

9.5. Operators
--------------

Intermediate expressions (constant, designators, expressions enclosed
in parentheses) may be used as operands of the following operators:

      + <ae>               unary plus
      - <ae>               unary minus
      <ae> + <ae>          addition
      <ae> - <ae>          subtraction
      <ae> * <ae>          multiplication
      <ae> / <ae>          division
      <ae> where <pe>      selection
      <ae> <  <ae>         comparison on "less than"
      <ae> <= <ae>         comparison on "less than or equal to"
      <ae> =  <ae>         comparison on "equal to"
      <ae> >= <ae>         comparison on "greater than or equal to"
      <ae> >  <ae>         comparison on "greater than"
      <ae> != <ae>         comparison on "not equal to"
      not <pe>             inversion
      <pe> or <pe>         disjunction
      <pe> and <pe>        conjunction
      ( <e> )              parenthesizing

where <ae> is a parameter expression, <pe> is a predicate expression,
<e> is either parameter or predicate expression.

*Unary plus*

The resultant parameter is an exact copy of the operand.

*Unary minus*

The resultant parameter has the same dimension, is defined on the same
sets, and has the same member as the operand. If a value assigned to a
member of the operand is the model expression t, the value assigned to
the corresponding member of the resultant parameter is (-t).

*Addition*

If operands have the same mute letters, these letters should refer to
the same sets.

If one operand has a mute letter, which is missing in other operand,
other operand is expanded over the corresponding set. For example:

   u[i,j] + v[j,k]

In this example the mute letter 'i' is missing in the second operand.
Therefore the second operand is expanded over the set defined by the
letter 'i' as follows:

   v'[i,j,k] := v[j,k] for all i in the set

and then the second operand is temporarily replaced by the expanded
object.

If it necessary, expansion is applied several times in order that both
operands have the same mute letters.

After expansion addition is performed. Members included into the
resultant parameter is the union of members of operands. If values
assigned to members (with the same tuples) of the first and the second
operands are model expressions t1 and t2 respectively, the value
assigned to the corresponding member of the resultant parameter is
(t1 + t2). If a member doesn't exist, it is assumed that its value is
zero.

*Subtraction*

Subtraction is preformed in the same way as addition. However, the
value assigned to the corresponding member of the resultant parameter is
(t1 - t2).

*Multiplication*

If it necessary, before multiplication expansion is performed in the
same way as in case of addition in order that both operands have the
same mute letters.

Members included into the resultant parameter is the intersection of
members of operands. If values assigned to members (with the same
tuples) of the first and the second operands are model expressions t1
and t2 respectively, the value assigned to the corresponding member of
the resultant parameter is (t1 * t2).

*Division*

The value t assigned to each member of the second operand is temporarily
replaced by (1 / t), and then multiplication is performed.

*Selection*

All mute letters of the second operand should be presented in the first
operand.

If it is necessary, expansion is applied to the second operand in order
that both operands have the same mute letters.

Then all members of the first operand, which are missing in the second
operand, are deleted, that gives the resultant parameter.

*Comparison*

Values assigned to all members of both operands should be constant model
expressions.

In order to perform comparison the language processor computes the
arithmetic difference between the first and the second operands in the
same way as in case of subtraction. Then values assigned to each member
of the difference are analyzed. If a value is satisfy to the specified
condition (for example, if ">=" is specified, the value should be
non-negative), the corresponding member is kept, otherwise the member
is deleted. Then values assigned to the kept members are cancelled, that
gives the resultant predicate.

*Inversion*

The resultant predicate has the same dimension and is defined on the
same sets as the operand. The language processor generates all members
for Cartesian product of the corresponding sets and includes into the
resultant predicate those members, which are missing in the operand.

Note that so far as sparse parameters are allowed, in general case the
predicate

   dist[i,j] >= 70

is NOT equivalent to the predicate

   not dist[i,j] < 70

*Disjunction*

If it necessary, before disjunction expansion is performed in the same
way as in case of addition in order that both operands have the same
mute letters.

Members included into the resultant predicate is the union of members of
the operands.

*Conjunction*

If it necessary, before conjunction expansion is performed in the same
way as in case of addition in order that both operands have the same
mute letters.

Members included into the resultant predicate is the intersection of
members of the operands.

*Parenthesizing*

Parenthesizing may be used in order to explicitly specify the order
of computation of intermediate expressions. The resultant object is an
exact copy of the operand.

9.6. Built-in function data()
-----------------------------

The built-in function data() allows to construct temporary parameter,
which may be used as a primary expression.

The data() function call has the following syntax:

<domain> ::= <mute letter> in <set name>
<domain list> ::= <domain> | <domain list> , <domain>
<item list> ::= <item name> | <item list> , <item name>
<member> ::= <item list> , <expression>
<member list> ::= <member> | <member list> , <member>
<data> ::= data ( <domain list> : <member list> )

The comma between <item list> and <item name>, or between <item list>
and <expression>, or between <member list> and <member> is optional and
may be omitted.

From syntactic definition it follows that the data() function call has
the form:

   data(i in S, ..., i in S:
        item,   ..., item,   expression,
        item,   ..., item,   expression,
         . . . . . . . . . . . .
        item,   ..., item,   expression)

The resultant parameter inherits mute letters and index sets specified
in <domain list>. Each <member> specified in <member list> is included
into the resultant parameter. Note that <expression> should be scalar
parameter.

For the sake of convenience it is allowed to write the period (.)
instead <item name>. In this case the corresponding item name from the
previous member is used.

9.7. Built-in function table()
------------------------------

The built-in function table() allows to construct 2-dimensional
temporary parameter, which may be used as a primary expression.

The table() function call has the following syntax:

<domain> ::= <mute letter> in <set name>
<item list> ::= <item name> | <item list> , <item name>
<expression list> ::= <expression> | <expression list> , <expression>
<row> ::= <item name> <expression list>
<row list> ::= <row> | <row list> , <row>
<table> ::= table ( <domain> , <domain> : <item list> : <row list> )

The comma between <expression list> and <expression>, or between
<row list> and <row> is optional and may be omitted.

From syntactic definition it follows that the data() function call has
the form:

   table(i in S, j in T:
         item,       ..., item,
   item, expression, ..., expression,
   item, expression, ..., expression,
      . . . . . . . . . . . . . .
   item, expression, ..., expression)

The resultant 2-dimensional parameter inherits two mute letters and two
corresponding index sets specified in the <table>. Each <expression>,
which should be scalar parameter, gives one member, which is included
into the resultant parameter. The first item assigned to a member is
the item in the corresponding row, and the second item assigned to a
member is the item in the corresponding column. If instead <expression>
the period (.) is given, the corresponding member is not included into
the resultant parameter.

9.8. Built-in function sum()
----------------------------

The built-in function sum() is so called aggregate function, which
allows to sum parameter members over given sets. This function may be
used as a primary expression.

The sum() function call has one of the following forms:

   sum(i, expr)

or

   sum((i, j, ...), expr)

where i, j, ... are mute letters, expr is a parameter expression.

Each mute letter given in the sum() function call should be presented
in the specified parameter expression.

In order to compute the resultant parameter the language processor sums
members of the operand over the sets specified by mute letters. Thus,
for example,

   sum((i,k), u[i,j,k,l])

gives the temporary parameter v[j,l], where

   v[j,l] = sum of u[i,j,k,l] for all i in I, k in K

Note that mute letters specified in the sum() function call drop out
from the resultant parameter, that involves decreasing dimension.



10. ASSIGNMENT STATEMENT
************************

The assignment statement may be used in order to create or delete some
members of a parameter, or a predicate, or a constraint, and to assign
some values to members of a parameter or a constraint.

The assignment statement has the following syntax:

<parameter name> ::= <symbolic name>
<predicate name> ::= <symbolic name>
<variable name> ::= <symbolic name>
<constraint name> ::= <symbolic name>
<reference> ::= <parameter name> | <predicate name> |
      <variable name> . lo | <variable name> . up |
      <variable name> .fx | <constraint name> | <constraint name> . lo |
      <constraint name> . up | <constraint name> . fx
<subscript> ::= <mute letter> | # <item name>
<subscript list> ::= <subscript> | <subscript list> , <subscript>
<destination> ::= <reference> | <reference> [ <subscript list> ]
<assignment statement> ::= <destination> := <expression> ; |
      <destination> where <expression> := <expression> ;

Number of subscripts in destination should be equal to dimension of the
corresponding object. If the object is 0-dimensional (scalar), subscript
list and square brackets [ and ] should be omitted.

The correspondence between subscripts and index sets, over which the
object is defined, is positional, i.e. the first subscript corresponds
to the first index set given in the object declaration, the second
subscript corresponds to the second index set, and so on.

All mute letters given in subscript list should be different.

The result of computation of the expression given in the left of
assignment statement after the key word 'where' whould be a predicate.
All mute letters of this predicate should be presented in destination.

The assignemnt statement is performed as follows:

1. Reference and mute letters specified in the destination are
   processed.

2. The expression that follows the key word 'where' is computed. If no
   condition is given, the constant 'true' is assumed.

   The result of computation of this expression should be a predicate,
   all mute letters of which should be presented in the destination.
   If it is necessary, this predicate is expanded (in the same way as
   in case of addition; see above Subsection 9.5) in order that this
   predicate has the same mute letters as the destination.

3. The expression in the right part of the assignment statement is
   computed.

   The result of computation of this expression should be either a
   parameter or predicate, all mute letters of which should be presented
   in the destination. If it is necessary, this parameter or predicate
   is expanded in order that it has the same mute letters as the
   destination.

4. All members of the distination, which falls under specified items
   (or all members, if no items are specified) and which satisfy to the
   given condition, are deleted from the destination object.

5. All members of the object computed on the step 3, which satisfy to
   the given condition, are included to the destination. All other
   members are ignored. If there are items specified for the
   destination, they are used in order to adjust tuples of members,
   which are included to the destination.

Consider, for example, the following assignment statement:

   v[i,#red,j] where p[j] := u[i];

At first, the language processor computes the predicate p and expands
it to p'[i,j], and computes the object u and expands it to u'[i,j].
Then the language processor deletes from the object 'v' such members,
which have the form v[i,#red,j] (for all i in I and for all j in J) and
for which the predicate p'[i,j] is true. Finally, the language processor
includess into the object v such members of the object u', for which the
predicate p'[i,j] is true. So far as v is 3-dimensional object, but u'
is 2-dimensional object, tuples of each member of u' are expanded by the
item 'red'.

Note that members of the destination are deleted *after* the object in
the right part of the assignemnt statement has been computed. Therefore
the destination object may be used in the right part expression.

If the destination is a parameter, the right part object should be also
parameter.

If the destination is a predicate, the right part object should be also
predicate.

The destination, which is a variable, is not allowed.

If the destination is a constraint, the right part expression should
has one of the following forms:

   <expression>

   <expression> = <expression>

   <expression> >= <expression>

   <expression> <= <expression>

Note that although in the last three cases the right part formally
corresponds to a predicate, both expressions are processed separately
as it was explained in Section 8.

If the destination is lo-parameter, up-parameter, or fx-parameter (see
Section 7 and 8), the right part should be a parameter, and values
assigned to its members should be constant model expressions.

In order to eliminate lower or upper bounds of elemental structural or
auxiliary variables, the 'nil' constant may be used, for example:

   x.lo[i,j] := nil;

In order to eliminate both lower and upper bounds at the same time, i.e.
to make the corresponding elemental variables free, the 'nil' constant
may be assigned to fx-parameter, for example:

   x.fx[i,j] := nil;

Note that assignment to fx-parameter affects on lo- and up-parameters
and vice versa.



11. OBJECTIVE STATEMENT
***********************

The objective statement is used: a) to specify optimization direction;
and b) to specify elemental constraint, expression assigned to which is
the objective function.

The objective statement has the following syntax:

<constraint name> ::= <symbolic name>
<item name> ::= <symbolic name>
<item list> ::= # <item name> | <item list> , # <item name>
<objective function> ::= <constraint name> |
      <constraint name> [ <item list> ]
<objective statement> ::= minimize <objective function> ; |
      maximize <objective function> ;

Number of items in <objective function> should be equal to dimension of
the corresponding constraint. If the constraint is 0-dimensional
(scalar), item list and square brackets [ and ] should be omitted.

The correspondence between items and index sets, over which the
constraint is defined, is positional, i.e. the first item corresponds
to the first index set given in the constraint declaration, the second
item corresponds to the second index set, and so on.

The objective statement may appear in the model description only once.



12. DISPLAY STATEMENT
*********************

The display statement allows to display any object or the result of
computation of any expression. This statement is intended mainly for
model debugging purposes.

The display statement has the following syntax:

<object> ::= <symbolic name> | ( <expression> )
<object list> ::= <object> | <object list> , <object>
<display statement> ::= display <object list> ;

Example:

   display x, y, (y[i,j]), (0.5 * (x[i,j] + x[j,i]));

If an expression is specified, the display statement also displays all
mute letters associated with the corresponding object.

In the current implementation the display statement sends all output to
stdout.



APPENDIX A. USING THE LANGUAGE PROCESSOR FROM GLPK API
******************************************************

The current version of GLPK includes the API routine glp_read_lpm. This
routine may be used in the same way as the API routine glp_read_mps (see
"GLPK User's Guide").

*Synopsis*

#include "glpk.h:
int glp_read_lpm(char *fname);

*Description*

The glp_read_lpm routine reads an LP model written in the modeling
language GLPK/L from the text file whose name is the character string
fname into the workspace.

As a rule the workspace should be empty before a call to the
glp_read_lpm routine, i.e. the workspace should contain no rows and
no columns.

*Control parameters*

The behavior of the glp_read_lpm routine depends on the following
control parameters:

fn_gener (name of the file to output generated LP/MIP problem).

*Returns*

0 - no errors;
1 - the operation failed because of errors. All diagnostics was sent
    to stderr.



APPENDIX B. USING GLPK/L MODELS WITH THE SOLVER GLPSOL
******************************************************

The current version of the solver GLPSOL (which is a part of the GLPK
package) allows processing model descriptions written in GLPK/L.

In order to tell the solver that the input file is a model description
the option '--lpm' should be given in the command line. For example:

   glpsol --lpm foobar.lpm

where '.lpm' is a recommended extension (which means Linear Programming
Model).

In order to see what a problem has been generated from the specified
model description the option '--gener' should be given in the command
line. For example:

   glpsol --lpm foobar.lpm --gener foobar.lst

In this case the solver writes the generated LP/MIP problem to the text
file, whose name follows the '--gener' option, in plain text format.

In order not to solve the generated problem the option '--check' may be
passed to the solver. For example:

   glpsol --lpm foobar.lpm --gener foobar.lst --check

In this case the solver just reads the input text file and writes the
output text file.



APPENDIX C. EXAMPLE OF MODEL DESCRIPTION
****************************************

model TRNSPORT /* TRANSPORTATION PROBLEM */;

/*----------------------------------------------------------------------
* This problem finds a least cost shipping schedule that meets
* requirements at markets and supplies at factories.
*
*  References:
*              Dantzig, G B., Linear Programming and Extensions
*              Princeton University Press, Princeton, New Jersey, 1963,
*              Chapter 3-3. */

  sets I   /* canning plants */   = ( SEATTLE, SAN_DIEGO ),
       J   /* markets        */   = ( NEW_YORK, CHICAGO, TOPEKA ) ;

  parameters
       A[I]  /* capacity of plant i in cases */,
       B[J]  /* demand at market j in cases  */;

  A[i] := data(i in I:
              SEATTLE     350
              SAN_DIEGO   600  );

  B[j] := data(j in J:
              NEW_YORK    325
              CHICAGO     300
              TOPEKA      275  ) ;

  parameter D[I,J]  /* distance in thousands of miles */;

  D[i,j] := table(i in I, j in J:
                    NEW_YORK       CHICAGO      TOPEKA:
      SEATTLE          2.5           1.7          1.8
      SAN_DIEGO        2.5           1.8          1.4  );

  parameter F /* freight in dollars per case per thousand miles */;

  F := 90;

  parameter C[I,J]
              /* transport cost in thousands of dollars per case */;

  C[i,j] := F * D[i,j] / 1000 ;

  variables
       X[I,J] /* shipment quantities in cases */;

  constraints
       Z      /* total transportation costs in thousands of dollars */,
       SUPPLY[I]   /* observe supply limit at plant i */,
       DEMAND[J]   /* satisfy demand at market j */;

  Z := sum((i,j), C[i,j]*X[i,j]) ;

  SUPPLY[i] :=   sum(j, X[i,j])  <=  A[i] ;

  DEMAND[j] :=   sum(i, X[i,j])  >=  B[j] ;

  minimize Z;

end;



APPENDIX D. LP PROBLEM GENERATED FROM THE EXAMPLE MODEL
*******************************************************

Generated LP/MIP problem

Problem:    TRNSPORT
Rows:       6
Columns:    6
Non-zeros:  18
Objective:  Z (MINimization)

****** ROWS (CONSTRAINTS) ******

row 1: DEMAND[NEW_YORK] >= 325
   1 * X[SEATTLE,NEW_YORK]
   1 * X[SAN_DIEGO,NEW_YORK]

row 2: DEMAND[CHICAGO] >= 300
   1 * X[SEATTLE,CHICAGO]
   1 * X[SAN_DIEGO,CHICAGO]

row 3: DEMAND[TOPEKA] >= 275
   1 * X[SEATTLE,TOPEKA]
   1 * X[SAN_DIEGO,TOPEKA]

row 4: SUPPLY[SEATTLE] <= 350
   1 * X[SEATTLE,NEW_YORK]
   1 * X[SEATTLE,CHICAGO]
   1 * X[SEATTLE,TOPEKA]

row 5: SUPPLY[SAN_DIEGO] <= 600
   1 * X[SAN_DIEGO,NEW_YORK]
   1 * X[SAN_DIEGO,CHICAGO]
   1 * X[SAN_DIEGO,TOPEKA]

row 6: Z
   0.225 * X[SEATTLE,NEW_YORK]
   0.153 * X[SEATTLE,CHICAGO]
   0.162 * X[SEATTLE,TOPEKA]
   0.225 * X[SAN_DIEGO,NEW_YORK]
   0.162 * X[SAN_DIEGO,CHICAGO]
   0.126 * X[SAN_DIEGO,TOPEKA]

****** COLUMNS (VARIABLES) ******

col 1: X[SEATTLE,NEW_YORK] >= 0
   DEMAND[NEW_YORK] ... 1
   SUPPLY[SEATTLE] ... 1
   Z ... 0.225

col 2: X[SEATTLE,CHICAGO] >= 0
   DEMAND[CHICAGO] ... 1
   SUPPLY[SEATTLE] ... 1
   Z ... 0.153

col 3: X[SEATTLE,TOPEKA] >= 0
   DEMAND[TOPEKA] ... 1
   SUPPLY[SEATTLE] ... 1
   Z ... 0.162

col 4: X[SAN_DIEGO,NEW_YORK] >= 0
   DEMAND[NEW_YORK] ... 1
   SUPPLY[SAN_DIEGO] ... 1
   Z ... 0.225

col 5: X[SAN_DIEGO,CHICAGO] >= 0
   DEMAND[CHICAGO] ... 1
   SUPPLY[SAN_DIEGO] ... 1
   Z ... 0.162

col 6: X[SAN_DIEGO,TOPEKA] >= 0
   DEMAND[TOPEKA] ... 1
   SUPPLY[SAN_DIEGO] ... 1
   Z ... 0.126

End of output



APPENDIX E. SOLUTION OF THE GENERATED LP PROBLEM
************************************************

Problem:    TRNSPORT
Rows:       6
Columns:    6
Non-zeros:  18
Objective:  Z = 153.675 (MINimization)
Status:     OPTIMAL

  Row name     St   Activity    Lower bound   Upper bound    Marginal
------------   -- ------------ ------------- ------------- -------------
DEMAND[NEW_YORK]
               NL          325           325                       0.225
DEMAND[CHICAGO]
               NL          300           300                       0.153
DEMAND[TOPEKA]
               NL          275           275                       0.126
SUPPLY[SEATTLE]
               B           300                         350 
SUPPLY[SAN_DIEGO]
               B           600                         600 
Z              B       153.675                             

Column name    St   Activity    Lower bound   Upper bound    Marginal
------------   -- ------------ ------------- ------------- -------------
X[SEATTLE,NEW_YORK]
               NL            0             0                       < eps
X[SEATTLE,CHICAGO]
               B           300             0               
X[SEATTLE,TOPEKA]
               NL            0             0                       0.036
X[SAN_DIEGO,NEW_YORK]
               B           325             0               
X[SAN_DIEGO,CHICAGO]
               NL            0             0                       0.009
X[SAN_DIEGO,TOPEKA]
               B           275             0               

End of output

------------------------------------------------------------------------

The GLPK package is a part of the GNU project, released under the aegis
of GNU.

Copyright (C) 2001 Andrew Makhorin, Department for Applied Informatics,
Moscow Aviation Institute, Moscow, Russia. All rights reserved.

Free Software Foundation, Inc., 59 Temple Place -- Suite 330, Boston,
MA 02111, USA.

Permission is granted to make and distribute verbatim copies of this
manual provided the copyright notice and this permission notice are
preserved on all copies.

Permission is granted to copy and distribute modified versions of this
manual under the conditions for verbatim copying, provided also that the
entire resulting derived work is distributed under the terms of a
permission notice identical to this one.

Permission is granted to copy and distribute translations of this manual
into another language, under the above conditions for modified versions.
