You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
283 lines
9.4 KiB
283 lines
9.4 KiB
@.@ LP/MIP PREPROCESSING ROUTINES
|
|
=================================
|
|
|
|
@.@.1 Introduction
|
|
|
|
GLPK has a set of routines that constitute so called the LP/MIP
|
|
preprocessor. Its main purpose is to improve a given formulation of the
|
|
LP or MIP problem instance provided by the user.
|
|
|
|
As a rule the LP/MIP preprocessor is used internally (if enabled) in
|
|
the LP or MIP solver. However, for various reasons the user may need
|
|
to call the preprocessing routines directly in his/her application
|
|
program, in which case he/she may use API routines described in this
|
|
section.
|
|
|
|
The preprocessing of an LP/MIP problem instance and recovering its
|
|
solution include several steps, which are performed in the following
|
|
order.
|
|
|
|
1. Allocating the workspace. The preprocessor allocates the workspace,
|
|
an internal data structure used on all subsequent steps.
|
|
|
|
2. Loading the original problem instance. The preprocessor copies all
|
|
the problem components from the original problem object (glp_prob)
|
|
specified by the user into the workspace. On this step the user also
|
|
should specify the solution type: basic solution (assumes the
|
|
primal or dual simplex solver), interior-point solution (assumes the
|
|
interior-point solver), or MIP solution (assumes the MIP solver).
|
|
This is needed, because some preprocessing transformations depend on
|
|
the solution type.
|
|
|
|
3. Preprocessing. The user calls preprocessing routines that transform
|
|
the problem instance residing in the workspace.
|
|
|
|
4. Building the resultant problem instance. The preprocessor converts
|
|
the problem instance from an internal workspace representation
|
|
to the standard problem object (glp_prob) and returns that object to
|
|
the user.
|
|
|
|
5. Solving the resultant problem instance. The user calls an
|
|
appropriate solver routine to obtain a solution to the resultant
|
|
problem instance.
|
|
|
|
6. Postprocessing. The user provides the solution to the resultant
|
|
problem instance found on the previous step, and the preprocessor
|
|
performs inverse transformations to recover the solution to the
|
|
original problem instance. Should note that only optimal or integer
|
|
feasible (for MIP) solutions can be recovered.
|
|
|
|
7. Obtaining original solution. The preprocessor copies the solution
|
|
to the original problem instance recovered on the previous step from
|
|
the workspace to the original problem object (glp_prob). The effect
|
|
is the same as if the solution were computed by a solver. Note that
|
|
steps 6 and 7 can be performed multiple times (for example, to
|
|
recover intermediate integer feasible solutions during the integer
|
|
optimization).
|
|
|
|
8. Freeing the workspace. The preprocessor frees all the memory
|
|
allocated to the workspace.
|
|
|
|
EXAMPLE
|
|
|
|
In this example the program reads the LP problem data from input file
|
|
murtagh.mps\footnote{This is an example model included in the GLPK
|
|
distribution.}, performs standard preprocessing, solves the resultant
|
|
LP with the primal simplex method, and then recovers the solution to
|
|
the original LP.
|
|
|
|
/* nppsamp.c */
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <glpk.h>
|
|
|
|
int main(void)
|
|
{ glp_prep *npp;
|
|
glp_prob *P, *Q;
|
|
int ret;
|
|
npp = glp_npp_alloc_wksp();
|
|
P = glp_create_prob();
|
|
ret = glp_read_mps(P, GLP_MPS_DECK, NULL, "murtagh.mps");
|
|
if (ret != 0)
|
|
{ printf("Error on reading problem data\n");
|
|
goto skip;
|
|
}
|
|
glp_set_obj_dir(P, GLP_MAX);
|
|
glp_npp_load_prob(npp, P, GLP_SOL, GLP_ON);
|
|
ret = glp_npp_preprocess1(npp, 0);
|
|
switch (ret)
|
|
{ case 0:
|
|
break;
|
|
case GLP_ENOPFS:
|
|
printf("LP has no primal feasible solution\n");
|
|
goto skip;
|
|
case GLP_ENODFS:
|
|
printf("LP has no dual feasible solution\n");
|
|
goto skip;
|
|
default:
|
|
xassert(ret != ret);
|
|
}
|
|
Q = glp_create_prob();
|
|
glp_npp_build_prob(npp, Q);
|
|
ret = glp_simplex(Q, NULL);
|
|
if (ret == 0 && glp_get_status(Q) == GLP_OPT)
|
|
{ glp_npp_postprocess(npp, Q);
|
|
glp_npp_obtain_sol(npp, P);
|
|
}
|
|
else
|
|
printf("Unable to recover non-optimal solution\n");
|
|
glp_delete_prob(Q);
|
|
skip: glp_npp_free_wksp(npp);
|
|
glp_delete_prob(P);
|
|
return 0;
|
|
}
|
|
|
|
/* eof */
|
|
------------------------------------------------------------------------
|
|
@.@.2 glp_npp_alloc_wksp - allocate the preprocessor workspace
|
|
|
|
SYNOPSIS
|
|
|
|
glp_prep *glp_npp_alloc_wksp(void);
|
|
|
|
DESCRIPTION
|
|
|
|
The routine glp_npp_alloc_wksp allocates the preprocessor workspace.
|
|
(Note that multiple instances of the workspace may be allocated, if
|
|
necessary.)
|
|
|
|
RETURNS
|
|
|
|
The routine returns a pointer to the workspace, which should be used in
|
|
all subsequent operations.
|
|
------------------------------------------------------------------------
|
|
@.@.3 glp_npp_load_prob - load original problem instance
|
|
|
|
SYNOPSIS
|
|
|
|
void glp_npp_load_prob(glp_prep *prep, glp_prob *P, int sol,
|
|
int names);
|
|
|
|
DESCRIPTION
|
|
|
|
The routine glp_npp_load_prob loads the original problem instance from
|
|
the specified problem object P into the preprocessor workspace. (Note
|
|
that this operation can be performed only once.)
|
|
|
|
The parameter sol specifies which solution is required:
|
|
|
|
GLP_SOL - basic solution;
|
|
|
|
GLP_IPT - interior-point solution;
|
|
|
|
GLP_MIP - mixed integer solution.
|
|
|
|
The parameter names is a flag. If it is GLP_ON, the symbolic names of
|
|
original rows and columns are also loaded into the workspace. Otherwise,
|
|
if the flag is GLP_OFF, the row and column names are not loaded.
|
|
------------------------------------------------------------------------
|
|
@.@.4 glp_npp_preprocess1 - perform basic LP/MIP preprocessing
|
|
|
|
SYNOPSIS
|
|
|
|
int glp_npp_preprocess1(glp_prep *prep, int hard);
|
|
|
|
DESCRIPTION
|
|
|
|
The routine glp_npp_preprocess1 performs basic LP/MIP preprocessing
|
|
that currently includes:
|
|
|
|
-- removing free rows;
|
|
|
|
-- replacing double-sided constraint rows with almost identical bounds,
|
|
by equality constraint rows;
|
|
|
|
-- removing fixed columns;
|
|
|
|
-- replacing double-bounded columns with almost identical bounds by
|
|
fixed columns and removing those columns;
|
|
|
|
-- removing empty rows;
|
|
|
|
-- removing equality constraint row singletons and corresponding
|
|
columns;
|
|
|
|
-- removing inequality constraint row singletons and corresponding
|
|
columns;
|
|
|
|
-- performing general row analysis;
|
|
|
|
-- removing redundant row bounds;
|
|
|
|
-- removing forcing rows and corresponding columns;
|
|
|
|
-- removing rows which become free due to redundant bounds;
|
|
|
|
-- computing implied bounds for all columns and using them to
|
|
strengthen current column bounds (MIP only, optional, performed if
|
|
the flag hard is on);
|
|
|
|
-- fixing and removing empty columns;
|
|
|
|
-- removing column singletons, which are implied slack variables, and
|
|
corresponding rows;
|
|
|
|
-- removing bounds of columns, which are implied free variables, and
|
|
replacing corresponding rows by equality constraints.
|
|
|
|
If the flag hard is GLP_ON, the routine attempts to improve current
|
|
column bounds multiple times within the main processing loop, in which
|
|
case this feature may take a time. Otherwise, if the flag hard is
|
|
GLP_OFF, improving column bounds is performed only once at the end of
|
|
the main loop. (Note that this feature is used for MIP only.)
|
|
|
|
RETURNS
|
|
|
|
0 - the problem instance has been successfully preprocessed;
|
|
|
|
GLP_ENOPFS - primal/integer infeasibility has been detected;
|
|
|
|
GLP_ENODFS - dual infeasibility has been detected.
|
|
------------------------------------------------------------------------
|
|
@.@.5 glp_npp_build_prob - build resultant problem instance
|
|
|
|
SYNOPSIS
|
|
|
|
void glp_npp_build_prob(glp_prep *prep, glp_prob *Q);
|
|
|
|
DESCRIPTION
|
|
|
|
The routine glp_npp_build_prob obtains all necessary information from
|
|
the preprocessor workspace to build the resultant (preprocessed)
|
|
problem instance, and stores it in the specified problem object Q. Note
|
|
that before building the current content of this problem object is
|
|
erased with the routine glp_erase_prob.
|
|
------------------------------------------------------------------------
|
|
@.@.6 glp_npp_postprocess - postprocess solution to resultant problem
|
|
|
|
SYNOPSIS
|
|
|
|
void glp_npp_postprocess(glp_prep *prep, glp_prob *Q);
|
|
|
|
DESCRIPTION
|
|
|
|
The routine glp_npp_postprocess performs postprocessing of a solution
|
|
to the resultant (preprocessed) problem instance specified by the
|
|
problem object Q and recovers corrseponding solution to the original
|
|
problem instance. The recovered solution is stored in the preprocessor
|
|
workspace and can be obtained with the routine glp_npp_obtain_sol.
|
|
|
|
It is assumed that the resultant problem instance Q has been solved
|
|
with an appropriate solver depending on the solution type previously
|
|
passed to the routine glp_npp_load_prob (the parameter sol). Note that
|
|
only optimal or integer feasible (for MIP) solution can be recovered,
|
|
so the calling program should use the routine glp_status to make sure
|
|
that this condition is met.
|
|
------------------------------------------------------------------------
|
|
@.@.7 glp_npp_obtain_sol - obtain solution to original problem
|
|
|
|
SYNOPSIS
|
|
|
|
void glp_npp_obtain_sol(glp_prep *prep, glp_prob *P);
|
|
|
|
DESCRIPTION
|
|
|
|
The routine glp_npp_obtain_sol copies the solution to the original
|
|
problem instance previously recovered by the routine
|
|
glp_npp_postorocess from the preprocessor workspace to the problem
|
|
object P. The effect is the same as if the solution were computed by an
|
|
appropriate solver.
|
|
------------------------------------------------------------------------
|
|
@.@.8 glp_npp_free_wksp - free the preprocessor workspace
|
|
|
|
SYNOPSIS
|
|
|
|
void glp_npp_free_wksp(glp_prep *prep);
|
|
|
|
DESCRIPTION
|
|
|
|
The routine glp_npp_free_wksp frees all the memory allocated to the
|
|
preprocessor workspace.
|
|
|
|
===EOF===
|