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.
4150 lines
127 KiB
4150 lines
127 KiB
%* graphs.tex *%
|
|
|
|
%***********************************************************************
|
|
% This code is part of GLPK (GNU Linear Programming Kit).
|
|
%
|
|
% Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
|
|
% 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied
|
|
% Informatics, Moscow Aviation Institute, Moscow, Russia. All rights
|
|
% reserved. E-mail: <mao@gnu.org>.
|
|
%
|
|
% GLPK is free software: you can redistribute it and/or modify it
|
|
% under the terms of the GNU General Public License as published by
|
|
% the Free Software Foundation, either version 3 of the License, or
|
|
% (at your option) any later version.
|
|
%
|
|
% GLPK is distributed in the hope that it will be useful, but WITHOUT
|
|
% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
% or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
% License for more details.
|
|
%
|
|
% You should have received a copy of the GNU General Public License
|
|
% along with GLPK. If not, see <http://www.gnu.org/licenses/>.
|
|
%***********************************************************************
|
|
|
|
\documentclass[11pt]{report}
|
|
\usepackage{amssymb}
|
|
\usepackage[dvipdfm,linktocpage,colorlinks,linkcolor=blue,
|
|
urlcolor=blue]{hyperref}
|
|
\usepackage{indentfirst}
|
|
\usepackage[all]{xy}
|
|
|
|
\setlength{\textwidth}{6.5in}
|
|
\setlength{\textheight}{8.5in}
|
|
\setlength{\oddsidemargin}{0in}
|
|
\setlength{\topmargin}{0in}
|
|
\setlength{\headheight}{0in}
|
|
\setlength{\headsep}{0in}
|
|
\setlength{\footskip}{0.5in}
|
|
\setlength{\parindent}{16pt}
|
|
\setlength{\parskip}{5pt}
|
|
\setlength{\topsep}{0pt}
|
|
\setlength{\partopsep}{0pt}
|
|
\setlength{\itemsep}{\parskip}
|
|
\setlength{\parsep}{0pt}
|
|
\setlength{\leftmargini}{\parindent}
|
|
\renewcommand{\labelitemi}{---}
|
|
|
|
\def\para#1{\noindent{\bf#1}}
|
|
\def\synopsis{\para{Synopsis}}
|
|
\def\description{\para{Description}}
|
|
\def\returns{\para{Returns}}
|
|
|
|
\renewcommand\contentsname{\sf\bfseries Contents}
|
|
\renewcommand\chaptername{\sf\bfseries Chapter}
|
|
\renewcommand\appendixname{\sf\bfseries Appendix}
|
|
|
|
\newenvironment{retlist}
|
|
{ \def\arraystretch{1.5}
|
|
\noindent
|
|
\begin{tabular}{@{}p{1in}@{}p{5.5in}@{}}
|
|
}
|
|
{\end{tabular}}
|
|
|
|
\begin{document}
|
|
|
|
\thispagestyle{empty}
|
|
|
|
\begin{center}
|
|
|
|
\vspace*{1.5in}
|
|
|
|
\begin{huge}
|
|
\sf\bfseries GNU Linear Programming Kit
|
|
\end{huge}
|
|
|
|
\vspace{0.5in}
|
|
|
|
\begin{LARGE}
|
|
\sf Graph and Network Routines
|
|
\end{LARGE}
|
|
|
|
\vspace{0.5in}
|
|
|
|
\begin{LARGE}
|
|
\sf for GLPK Version 4.49
|
|
\end{LARGE}
|
|
|
|
\vspace{0.5in}
|
|
\begin{Large}
|
|
\sf (DRAFT, April 2013)
|
|
\end{Large}
|
|
\end{center}
|
|
|
|
\newpage
|
|
|
|
\vspace*{1in}
|
|
|
|
\vfill
|
|
|
|
\noindent
|
|
The GLPK package is part of the GNU Project released under the aegis of
|
|
GNU.
|
|
|
|
\noindent
|
|
Copyright \copyright{} 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
|
|
2008, 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied
|
|
Informatics, Moscow Aviation Institute, Moscow, Russia. All rights
|
|
reserved.
|
|
|
|
\noindent
|
|
Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
02110-1301, USA.
|
|
|
|
\noindent
|
|
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.
|
|
|
|
\noindent
|
|
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.
|
|
|
|
\noindent
|
|
Permission is granted to copy and distribute translations of this manual
|
|
into another language, under the above conditions for modified versions.
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
\newpage
|
|
|
|
{\setlength{\parskip}{0pt}
|
|
\tableofcontents
|
|
}
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
\chapter{Basic Graph API Routines}
|
|
|
|
\section{Graph program object}
|
|
|
|
In GLPK the base program object used to represent graphs and networks
|
|
is a directed graph (digraph).
|
|
|
|
Formally, {\it digraph} (or simply, {\it graph}) is a pair $G=(V,A)$,
|
|
where $V$ is a set of {\it vertices}, and $A$ is a set
|
|
{\it arcs}.\footnote{$A$ may be a multiset.} Each arc $a\in A$ is an
|
|
ordered pair of vertices $a=(x,y)$, where $x\in V$ is called {\it tail
|
|
vertex} of arc $a$, and $y\in V$ is called its {\it head vertex}.
|
|
|
|
Representation of a graph in the program includes three structs defined
|
|
by typedef in the header \verb|glpk.h|:
|
|
|
|
\vspace*{-8pt}
|
|
|
|
\begin{itemize}
|
|
\item \verb|glp_graph|, which represents the graph in a whole,
|
|
|
|
\item \verb|glp_vertex|, which represents a vertex of the graph, and
|
|
|
|
\item \verb|glp_arc|, which represents an arc of the graph.
|
|
\end{itemize}
|
|
|
|
\vspace*{-8pt}
|
|
|
|
All these three structs are ``semi-opaque'', i.e. the application
|
|
program can directly access their fields through pointers, however,
|
|
changing the fields directly is not allowed --- all changes should be
|
|
performed only with appropriate GLPK API routines.
|
|
|
|
\newenvironment{comment}
|
|
{\addtolength{\leftskip}{16pt}\noindent}
|
|
{\par\addtolength{\leftskip}{-16pt}}
|
|
|
|
\para{\bf glp\_graph.} The struct \verb|glp_graph| has the following
|
|
fields available to the application program:
|
|
|
|
\noindent
|
|
\verb|char *name;|
|
|
|
|
\begin{comment}Symbolic name assigned to the graph. It is a pointer to
|
|
a null terminated character string of length from 1 to 255 characters.
|
|
If no name is assigned to the graph, this field contains \verb|NULL|.
|
|
\end{comment}
|
|
|
|
\noindent
|
|
\verb|int nv;|
|
|
|
|
\begin{comment}The number of vertices in the graph, $nv\geq 0$.
|
|
\end{comment}
|
|
|
|
\noindent
|
|
\verb|int na;|
|
|
|
|
\begin{comment}The number of arcs in the graph, $na\geq 0$.
|
|
\end{comment}
|
|
|
|
\newpage
|
|
|
|
\noindent
|
|
\verb|glp_vertex **v;|
|
|
|
|
\begin{comment}Pointer to an array containing the list of vertices.
|
|
Element $v[0]$ is not used. Element $v[i]$, $1\leq i\leq nv$, is a
|
|
pointer to $i$-th vertex of the graph. Note that on adding new vertices
|
|
to the graph the field $v$ may be altered due to reallocation. However,
|
|
pointers $v[i]$ are not changed while corresponding vertices exist in
|
|
the graph.
|
|
\end{comment}
|
|
|
|
\noindent
|
|
\verb|int v_size;|
|
|
|
|
\begin{comment}Size of vertex data blocks, in bytes,
|
|
$0\leq v\_size\leq 256$. (See also the field \verb|data| in the struct
|
|
\verb|glp_vertex|.)
|
|
\end{comment}
|
|
|
|
\noindent
|
|
\verb|int a_size;|
|
|
|
|
\begin{comment}Size of arc data blocks, in bytes,
|
|
$0\leq v\_size\leq 256$. (See also the field \verb|data| in the struct
|
|
\verb|glp_arc|.)
|
|
\end{comment}
|
|
|
|
\para{\bf glp\_vertex.} The struct \verb|glp_vertex| has the following
|
|
fields available to the application program:
|
|
|
|
\noindent
|
|
\verb|int i;|
|
|
|
|
\begin{comment}Ordinal number of the vertex, $1\leq i\leq nv$. Note
|
|
that element $v[i]$ in the struct \verb|glp_graph| points to the vertex,
|
|
whose ordinal number is $i$.
|
|
\end{comment}
|
|
|
|
\noindent
|
|
\verb|char *name;|
|
|
|
|
\begin{comment}Symbolic name assigned to the vertex. It is a pointer to
|
|
a null terminated character string of length from 1 to 255 characters.
|
|
If no name is assigned to the vertex, this field contains \verb|NULL|.
|
|
\end{comment}
|
|
|
|
\noindent
|
|
\verb|void *data;|
|
|
|
|
\begin{comment}Pointer to a data block associated with the vertex. This
|
|
data block is automatically allocated on creating a new vertex and freed
|
|
on deleting the vertex. If $v\_size=0$, the block is not allocated, and
|
|
this field contains \verb|NULL|.
|
|
\end{comment}
|
|
|
|
\noindent
|
|
\verb|void *temp;|
|
|
|
|
\begin{comment}Working pointer, which may be used freely for any
|
|
purposes. The application program can change this field directly.
|
|
\end{comment}
|
|
|
|
\noindent
|
|
\verb|glp_arc *in;|
|
|
|
|
\begin{comment}Pointer to the (unordered) list of incoming arcs. If the
|
|
vertex has no incoming arcs, this field contains \verb|NULL|.
|
|
\end{comment}
|
|
|
|
\noindent
|
|
\verb|glp_arc *out;|
|
|
|
|
\begin{comment}Pointer to the (unordered) list of outgoing arcs. If the
|
|
vertex has no outgoing arcs, this field contains \verb|NULL|.
|
|
\end{comment}
|
|
|
|
\para{\bf glp\_arc.} The struct \verb|glp_arc| has the following fields
|
|
available to the application program:
|
|
|
|
\noindent
|
|
\verb|glp_vertex *tail;|
|
|
|
|
\begin{comment}Pointer to a vertex, which is tail endpoint of the arc.
|
|
\end{comment}
|
|
|
|
\noindent
|
|
\verb|glp_vertex *head;|
|
|
|
|
\begin{comment}Pointer to a vertex, which is head endpoint of the arc.
|
|
\end{comment}
|
|
|
|
\newpage
|
|
|
|
\noindent
|
|
\verb|void *data;|
|
|
|
|
\begin{comment}Pointer to a data block associated with the arc. This
|
|
data block is automatically allocated on creating a new arc and freed on
|
|
deleting the arc. If $v\_size=0$, the block is not allocated, and this
|
|
field contains \verb|NULL|.
|
|
\end{comment}
|
|
|
|
\noindent
|
|
\verb|void *temp;|
|
|
|
|
\begin{comment}Working pointer, which may be used freely for any
|
|
purposes. The application program can change this field directly.
|
|
\end{comment}
|
|
|
|
\noindent
|
|
\verb|glp_arc *t_next;|
|
|
|
|
\begin{comment}Pointer to another arc, which has the same tail endpoint
|
|
as this one. \verb|NULL| in this field indicates the end of the list of
|
|
outgoing arcs.
|
|
\end{comment}
|
|
|
|
\noindent
|
|
\verb|glp_arc *h_next;|
|
|
|
|
\begin{comment}Pointer to another arc, which has the same head endpoint
|
|
as this one. \verb|NULL| in this field indicates the end of the list of
|
|
incoming arcs.
|
|
\end{comment}
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
\newpage
|
|
|
|
\section{Graph creating and modifying routines}
|
|
|
|
\subsection{glp\_create\_graph --- create graph}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
glp_graph *glp_create_graph(int v_size, int a_size);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_create_graph| creates a new graph, which
|
|
initially is empty, i.e. has no vertices and arcs.
|
|
|
|
The parameter \verb|v_size| specifies the size of vertex data blocks,
|
|
in bytes, $0\leq v\_size\leq 256$.
|
|
|
|
The parameter \verb|a_size| specifies the size of arc data blocks, in
|
|
bytes, $0\leq a\_size\leq 256$.
|
|
|
|
\returns
|
|
|
|
The routine returns a pointer to the graph object created.
|
|
|
|
\subsection{glp\_set\_graph\_name --- assign (change) graph name}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
void glp_set_graph_name(glp_graph *G, const char *name);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_set_graph_name| assigns a symbolic name specified
|
|
by the character string \verb|name| (1 to 255 chars) to the graph.
|
|
|
|
If the parameter \verb|name| is \verb|NULL| or an empty string, the
|
|
routine erases the existing symbolic name of the graph.
|
|
|
|
\subsection{glp\_add\_vertices --- add new vertices to graph}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
int glp_add_vertices(glp_graph *G, int nadd);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_add_vertices| adds \verb|nadd| vertices to the
|
|
specified graph. New vertices are always added to the end of the vertex
|
|
list, so ordinal numbers of existing vertices remain unchanged. Note
|
|
that this operation may change the field \verb|v| in the struct
|
|
\verb|glp_graph| (pointer to the vertex array) due to reallocation.
|
|
|
|
Being added each new vertex is isolated, i.e. has no incident arcs.
|
|
|
|
If the size of vertex data blocks specified on creating the graph is
|
|
non-zero, the routine also allocates a memory block of that size for
|
|
each new vertex added, fills it by binary zeros, and stores a pointer
|
|
to it in the field \verb|data| of the struct \verb|glp_vertex|.
|
|
Otherwise, if the block size is zero, the field \verb|data| is set to
|
|
\verb|NULL|.
|
|
|
|
\returns
|
|
|
|
The routine \verb|glp_add_vertices| returns the ordinal number of the
|
|
first new vertex added to the graph.
|
|
|
|
\subsection{glp\_set\_vertex\_name --- assign (change) vertex name}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
void glp_set_vertex_name(glp_graph *G, int i, const char *name);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_set_vertex_name| assigns a given symbolic name
|
|
(1 up to 255 characters) to \verb|i|-th vertex of the specified graph.
|
|
|
|
If the parameter \verb|name| is \verb|NULL| or empty string, the
|
|
routine erases an existing name of \verb|i|-th vertex.
|
|
|
|
\subsection{glp\_add\_arc --- add new arc to graph}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
glp_arc *glp_add_arc(glp_graph *G, int i, int j);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_add_arc| adds one new arc to the specified graph.
|
|
|
|
The parameters \verb|i| and \verb|j| specify the ordinal numbers of,
|
|
resp., tail and head endpoints (vertices) of the arc. Note that
|
|
self-loops and multiple arcs are allowed.
|
|
|
|
If the size of arc data blocks specified on creating the graph is
|
|
non-zero, the routine also allocates a memory block of that size, fills
|
|
it by binary zeros, and stores a pointer to it in the field \verb|data|
|
|
of the struct \verb|glp_arc|. Otherwise, if the block size is zero, the
|
|
field \verb|data| is set to \verb|NULL|.
|
|
|
|
\subsection{glp\_del\_vertices --- delete vertices from graph}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
void glp_del_vertices(glp_graph *G, int ndel, const int num[]);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_del_vertices| deletes vertices along with all
|
|
incident arcs from the specified graph. Ordinal numbers of vertices to
|
|
be deleted should be placed in locations \verb|num[1]|, \dots,
|
|
\verb|num[ndel]|, \verb|ndel| $>0$.
|
|
|
|
Note that deleting vertices involves changing ordinal numbers of other
|
|
vertices remaining in the graph. New ordinal numbers of the remaining
|
|
vertices are assigned under the assumption that the original order of
|
|
vertices is not changed.
|
|
|
|
\newpage
|
|
|
|
\subsection{glp\_del\_arc --- delete arc from graph}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
void glp_del_arc(glp_graph *G, glp_arc *a);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_del_arc| deletes an arc from the specified graph.
|
|
The arc to be deleted must exist.
|
|
|
|
\subsection{glp\_erase\_graph --- erase graph content}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
void glp_erase_graph(glp_graph *G, int v_size, int a_size);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_erase_graph| erases the content of the specified
|
|
graph. The effect of this operation is the same as if the graph would
|
|
be deleted with the routine \verb|glp_delete_graph| and then created
|
|
anew with the routine \verb|glp_create_graph|, with exception that the
|
|
pointer to the graph remains valid.
|
|
|
|
The parameters \verb|v_size| and \verb|a_size| have the same meaning as
|
|
for \verb|glp_create_graph|.
|
|
|
|
\subsection{glp\_delete\_graph --- delete graph}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
void glp_delete_graph(glp_graph *G);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_delete_graph| deletes the specified graph and
|
|
frees all the memory allocated to this program object.
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
\newpage
|
|
|
|
\section{Graph searching routines}
|
|
|
|
\subsection{glp\_create\_v\_index --- create vertex name index}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
void glp_create_v_index(glp_graph *G);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_create_v_index| creates the name index for the
|
|
specified graph. The name index is an auxiliary data structure, which
|
|
is intended to quickly (i.e. for logarithmic time) find vertices by
|
|
their names.
|
|
|
|
This routine can be called at any time. If the name index already
|
|
exists, the routine does nothing.
|
|
|
|
\subsection{glp\_find\_vertex --- find vertex by its name}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
int glp_find_vertex(glp_graph *G, const char *name);
|
|
\end{verbatim}
|
|
|
|
\returns
|
|
|
|
The routine \verb|glp_find_vertex| returns the ordinal number of
|
|
a vertex, which is assigned (by the routine \verb|glp_set_vertex_name|)
|
|
the specified symbolic \verb|name|. If no such vertex exists, the
|
|
routine returns 0.
|
|
|
|
\subsection{glp\_delete\_v\_index --- delete vertex name index}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
void glp_delete_v_index(glp_graph *G);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_delete_v_index| deletes the name index previously
|
|
created by the routine \verb|glp_create_v_index| and frees the memory
|
|
allocated to this auxiliary data structure.
|
|
|
|
This routine can be called at any time. If the name index does not
|
|
exist, the routine does nothing.
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
\newpage
|
|
|
|
\section{Graph reading/writing routines}
|
|
|
|
\subsection{glp\_read\_graph --- read graph from plain text file}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
int glp_read_graph(glp_graph *G, const char *fname);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_read_graph| reads a graph from a plain text file,
|
|
whose name is specified by the parameter \verb|fname|. Note that before
|
|
reading data the current content of the graph object is completely
|
|
erased with the routine \verb|glp_erase_graph|.
|
|
|
|
For the file format see description of the routine
|
|
\verb|glp_write_graph|.
|
|
|
|
\returns
|
|
|
|
If the operation was successful, the routine returns zero. Otherwise
|
|
it prints an error message and returns non-zero.
|
|
|
|
\subsection{glp\_write\_graph --- write graph to plain text file}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
int glp_write_graph(glp_graph *G, const char *fname);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_write_graph| writes the graph to a plain text
|
|
file, whose name is specified by the parameter \verb|fname|.
|
|
|
|
\returns
|
|
|
|
If the operation was successful, the routine returns zero. Otherwise
|
|
it prints an error message and returns non-zero.
|
|
|
|
\para{File format}
|
|
|
|
The file created by the routine \verb|glp_write_graph| is a plain text
|
|
file, which contains the following information:
|
|
|
|
\begin{verbatim}
|
|
nv na
|
|
i[1] j[1]
|
|
i[2] j[2]
|
|
. . .
|
|
i[na] j[na]
|
|
\end{verbatim}
|
|
|
|
\noindent
|
|
where: \verb|nv| is the number of vertices (nodes); \verb|na| is the
|
|
number of arcs; \verb|i[k]|, $k=1,\dots,na$, is the index of tail
|
|
vertex of arc $k$; \verb|j[k]|, $k=1,\dots,na$, is the index of head
|
|
vertex of arc $k$.
|
|
|
|
\newpage
|
|
|
|
\subsection{glp\_read\_ccdata --- read graph from text file in DIMACS
|
|
clique/coloring\\format}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
int glp_read_ccdata(glp_graph *G, int v_wgt, const char *fname);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine {\tt glp\_read\_ccdata} reads a graph from a text file in
|
|
DIMACS clique/coloring format. (Though this format is originally
|
|
designed to represent data for the minimal vertex coloring and maximal
|
|
clique problems, it may be used to represent general undirected and
|
|
directed graphs, because the routine allows reading self-loops and
|
|
multiple edges/arcs keeping the order of vertices specified for each
|
|
edge/arc of the graph.)
|
|
|
|
The parameter {\tt G} specifies the graph object to be read in. Note
|
|
that before reading data the current content of the graph object is
|
|
completely erased with the routine {\tt glp\_erase\_graph}.
|
|
|
|
The parameter {\tt v\_wgt} specifies an offset of the field of type
|
|
{\tt double} in the vertex data block, to which the routine stores the
|
|
vertex weight. If {\tt v\_wgt} $<0$, the vertex weights are not stored.
|
|
|
|
The character string {\tt fname} specifies the name of a text file to
|
|
be read in. (If the file name ends with the suffix `\verb|.gz|', the
|
|
file is assumed to be compressed, in which case the routine
|
|
decompresses it ``on the fly''.)
|
|
|
|
\returns
|
|
|
|
If the operation was successful, the routine returns zero. Otherwise,
|
|
it prints an error message and returns non-zero.
|
|
|
|
\para{DIMACS clique/coloring format\footnote{This material is
|
|
based on the paper ``Clique and Coloring Problems Graph Format'', which
|
|
is publically available at \url{http://dimacs.rutgers.edu/Challenges}.}}
|
|
|
|
The DIMACS input file is a plain ASCII text file. It contains
|
|
{\it lines} of several types described below. A line is terminated with
|
|
an end-of-line character. Fields in each line are separated by at least
|
|
one blank space. Each line begins with a one-character designator to
|
|
identify the line type.
|
|
|
|
Note that DIMACS requires all numerical quantities to be integers in
|
|
the range $[-2^{31},2^{31}-1]$ while GLPK allows the quantities to be
|
|
floating-point numbers.
|
|
|
|
\para{Comment lines.} Comment lines give human-readable information
|
|
about the file and are ignored by programs. Comment lines can appear
|
|
anywhere in the file. Each comment line begins with a lower-case
|
|
character \verb|c|.
|
|
|
|
\begin{verbatim}
|
|
c This is a comment line
|
|
\end{verbatim}
|
|
|
|
\para{Problem line.} There is one problem line per data file.
|
|
The problem line must appear before any node or edge descriptor lines.
|
|
It has the following format:
|
|
|
|
\begin{verbatim}
|
|
p edge NODES EDGES
|
|
\end{verbatim}
|
|
|
|
\noindent
|
|
The lower-case letter \verb|p| signifies that this is a problem line.
|
|
The four-character problem designator \verb|edge| identifies the file
|
|
as containing data for the minimal vertex coloring or maximal clique
|
|
problem. The \verb|NODES| field contains an integer value specifying
|
|
the number of vertices in the graph. The \verb|EDGES| field contains an
|
|
integer value specifying the number of edges (arcs) in the graph.
|
|
|
|
\para{Vertex descriptors.} These lines give the weight assigned to
|
|
a vertex of the graph. There is one vertex descriptor line for each
|
|
vertex, with the following format. Vertices without a descriptor take
|
|
on a default value of 1.
|
|
|
|
\begin{verbatim}
|
|
n ID VALUE
|
|
\end{verbatim}
|
|
|
|
\noindent
|
|
The lower-case character \verb|n| signifies that this is a vertex
|
|
descriptor line. The \verb|ID| field gives a vertex identification
|
|
number, an integer between 1 and $n$, where $n$ is the number of
|
|
vertices in the graph. The \verb|VALUE| field gives a vertex weight,
|
|
which can either positive or negative (or zero).
|
|
|
|
\para{Edge descriptors.} There is one edge descriptor line for each
|
|
edge (arc) of the graph, each with the following format:
|
|
|
|
\begin{verbatim}
|
|
e I J
|
|
\end{verbatim}
|
|
|
|
\noindent
|
|
The lower-case character \verb|e| signifies that this is an edge
|
|
descriptor line. For an edge (arc) $(i,j)$ the fields \verb|I| and
|
|
\verb|J| specify its endpoints.
|
|
|
|
\para{Example.} The following example of an undirected graph:
|
|
|
|
\bigskip
|
|
|
|
\noindent\hfil
|
|
\xymatrix %@C=32pt
|
|
{&{v_1}\ar@{-}[ldd]\ar@{-}[dd]\ar@{-}[rd]\ar@{-}[rr]&&{v_2}\ar@{-}[ld]
|
|
\ar@{-}[dd]\ar@{-}[rdd]&\\
|
|
&&{v_7}\ar@{-}[ld]\ar@{-}[rd]&&\\
|
|
{v_6}\ar@{-}[r]\ar@{-}[rdd]&{v_{10}}\ar@{-}[rr]\ar@{-}[rd]\ar@{-}[dd]&&
|
|
{v_8}\ar@{-}[ld]\ar@{-}[dd]\ar@{-}[r]&{v_3}\ar@{-}[ldd]\\
|
|
&&{v_9}\ar@{-}[ld]\ar@{-}[rd]&&\\
|
|
&{v_5}\ar@{-}[rr]&&{v_4}&\\
|
|
}
|
|
|
|
\bigskip
|
|
|
|
\noindent
|
|
might be coded in DIMACS clique/coloring format as follows:
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
c sample.col
|
|
c
|
|
c This is an example of the vertex coloring problem data
|
|
c in DIMACS format.
|
|
c
|
|
p edge 10 21
|
|
c
|
|
e 1 2
|
|
e 1 6
|
|
e 1 7
|
|
e 1 10
|
|
e 2 3
|
|
e 2 7
|
|
e 2 8
|
|
e 3 4
|
|
e 3 8
|
|
e 4 5
|
|
e 4 8
|
|
e 4 9
|
|
e 5 6
|
|
e 5 9
|
|
e 5 10
|
|
e 6 10
|
|
e 7 8
|
|
e 7 10
|
|
e 8 9
|
|
e 8 10
|
|
e 9 10
|
|
c
|
|
c eof
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
\subsection{glp\_write\_ccdata --- write graph to text file in DIMACS
|
|
clique/coloring\\format}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
int glp_write_ccdata(glp_graph *G, int v_wgt, const char *fname);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine {\tt glp\_write\_ccdata} writes the graph object specified
|
|
by the parameter {\tt G} to a text file in DIMACS clique/coloring
|
|
format. (Though this format is originally designed to represent data
|
|
for the minimal vertex coloring and maximal clique problems, it may be
|
|
used to represent general undirected and directed graphs, because the
|
|
routine allows writing self-loops and multiple edges/arcs keeping the
|
|
order of vertices specified for each edge/arc of the graph.)
|
|
|
|
The parameter {\tt v\_wgt} specifies an offset of the field of type
|
|
{\tt double} in the vertex data block, which contains the vertex
|
|
weight. If {\tt v\_wgt} $<0$, it is assumed that the weight of each
|
|
vertex is 1.
|
|
|
|
The character string {\tt fname} specifies a name of the text file to
|
|
be written out. (If the file name ends with suffix `\verb|.gz|', the
|
|
file is assumed to be compressed, in which case the routine performs
|
|
automatic compression on writing it.)
|
|
|
|
\returns
|
|
|
|
If the operation was successful, the routine returns zero. Otherwise,
|
|
it prints an error message and returns non-zero.
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
\newpage
|
|
|
|
\section{Graph analysis routines}
|
|
|
|
\subsection{glp\_weak\_comp --- find all weakly connected components of
|
|
graph}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
int glp_weak_comp(glp_graph *G, int v_num);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_weak_comp| finds all weakly connected components
|
|
of the specified graph.
|
|
|
|
The parameter \verb|v_num| specifies an offset of the field of type
|
|
\verb|int| in the vertex data block, to which the routine stores the
|
|
number of a weakly connected component containing that vertex. If
|
|
\verb|v_num| $<0$, no component numbers are stored.
|
|
|
|
The components are numbered in arbitrary order from 1 to \verb|nc|,
|
|
where \verb|nc| is the total number of components found,
|
|
$0\leq$ \verb|nc| $\leq|V|$.
|
|
|
|
\returns
|
|
|
|
The routine returns \verb|nc|, the total number of components found.
|
|
|
|
\subsection{glp\_strong\_comp --- find all strongly connected
|
|
components of graph}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
int glp_strong_comp(glp_graph *G, int v_num);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_strong_comp| finds all strongly connected
|
|
components of the specified graph.
|
|
|
|
The parameter \verb|v_num| specifies an offset of the field of type
|
|
\verb|int| in the vertex data block, to which the routine stores the
|
|
number of a strongly connected component containing that vertex. If
|
|
\verb|v_num| $<0$, no component numbers are stored.
|
|
|
|
The components are numbered in arbitrary order from 1 to \verb|nc|,
|
|
where \verb|nc| is the total number of components found,
|
|
$0\leq$ \verb|nc| $\leq|V|$. However, the component numbering has the
|
|
property that for every arc $(i\rightarrow j)$ in the graph the
|
|
condition $num(i)\geq num(j)$ holds.
|
|
|
|
\returns
|
|
|
|
The routine returns \verb|nc|, the total number of components found.
|
|
|
|
\para{References}
|
|
|
|
I.~S.~Duff, J.~K.~Reid, Algorithm 529: Permutations to block triangular
|
|
form, ACM Trans. on Math. Softw. 4 (1978), 189-92.
|
|
|
|
\newpage
|
|
|
|
\para{Example}
|
|
|
|
The following program reads a graph from a plain text file
|
|
`\verb|graph.txt|' and finds all its strongly connected components.
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <glpk.h>
|
|
|
|
typedef struct { int num; } v_data;
|
|
|
|
#define vertex(v) ((v_data *)((v)->data))
|
|
|
|
int main(void)
|
|
{ glp_graph *G;
|
|
int i, nc;
|
|
G = glp_create_graph(sizeof(v_data), 0);
|
|
glp_read_graph(G, "graph.txt");
|
|
nc = glp_strong_comp(G, offsetof(v_data, num));
|
|
printf("nc = %d\n", nc);
|
|
for (i = 1; i <= G->nv; i++)
|
|
printf("num[%d] = %d\n", i, vertex(G->v[i])->num);
|
|
glp_delete_graph(G);
|
|
return 0;
|
|
}
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
\noindent
|
|
If the file `\verb|graph.txt|' contains the following graph:
|
|
|
|
\medskip
|
|
|
|
\noindent\hfil
|
|
\xymatrix
|
|
{1\ar[r]&2\ar[r]&3\ar[r]\ar[dd]&4\ar[dd]\\
|
|
5\ar[u]&6\ar[l]\\
|
|
7\ar[u]&&8\ar[lu]\ar[ll]\ar[r]&9\ar[r]&10\ar[r]\ar[d]&11\ar[d]\\
|
|
12\ar[u]\ar[rru]\ar@/_/[rr]&&13\ar[ll]\ar[u]\ar[rr]&&14\ar[lu]&15\ar[l]
|
|
\\
|
|
}
|
|
|
|
\medskip\medskip
|
|
|
|
\noindent
|
|
the program output may look like follows:
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
Reading graph from `graph.txt'...
|
|
Graph has 15 vertices and 30 arcs
|
|
31 lines were read
|
|
nc = 4
|
|
num[1] = 3
|
|
num[2] = 3
|
|
num[3] = 3
|
|
num[4] = 2
|
|
num[5] = 3
|
|
num[6] = 3
|
|
num[7] = 3
|
|
num[8] = 3
|
|
num[9] = 1
|
|
num[10] = 1
|
|
num[11] = 1
|
|
num[12] = 4
|
|
num[13] = 4
|
|
num[14] = 1
|
|
num[15] = 1
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
\subsection{glp\_top\_sort --- topological sorting of acyclic digraph}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
int glp_top_sort(glp_graph *G, int v_num);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_top_sort| performs topological sorting of
|
|
vertices of the specified acyclic digraph.
|
|
|
|
The parameter \verb|v_num| specifies an offset of the field of type
|
|
\verb|int| in the vertex data block, to which the routine stores the
|
|
vertex number assigned. If \verb|v_num| $<0$, vertex numbers are not
|
|
stored.
|
|
|
|
The vertices are numbered from 1 to $n$, where $n$ is the total number
|
|
of vertices in the graph. The vertex numbering has the property that
|
|
for every arc $(i\rightarrow j)$ in the graph the condition
|
|
$num(i)<num(j)$ holds. Special case $num(i)=0$ means that vertex $i$ is
|
|
not assigned a number, because the graph is {\it not} acyclic.
|
|
|
|
\returns
|
|
|
|
If the graph is acyclic and therefore all the vertices have been
|
|
assigned numbers, the routine \verb|glp_top_sort| returns zero.
|
|
Otherwise, if the graph is not acyclic, the routine returns the number
|
|
of vertices which have not been numbered, i.e. for which $num(i)=0$.
|
|
|
|
\para{Example}
|
|
|
|
The following program reads a digraph from a plain text file
|
|
`\verb|graph.txt|' and performs topological sorting of its vertices.
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <glpk.h>
|
|
|
|
typedef struct { int num; } v_data;
|
|
|
|
#define vertex(v) ((v_data *)((v)->data))
|
|
|
|
int main(void)
|
|
{ glp_graph *G;
|
|
int i, cnt;
|
|
G = glp_create_graph(sizeof(v_data), 0);
|
|
glp_read_graph(G, "graph.txt");
|
|
cnt = glp_top_sort(G, offsetof(v_data, num));
|
|
printf("cnt = %d\n", cnt);
|
|
for (i = 1; i <= G->nv; i++)
|
|
printf("num[%d] = %d\n", i, vertex(G->v[i])->num);
|
|
glp_delete_graph(G);
|
|
return 0;
|
|
}
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
\noindent
|
|
If the file `\verb|graph.txt|' contains the following graph:
|
|
|
|
\medskip
|
|
|
|
\noindent\hfil
|
|
\xymatrix @=20pt
|
|
{
|
|
1\ar[rrr]&&&2\ar[r]\ar[rddd]&3\ar[rd]&&&&\\
|
|
&&&4\ar[ru]&&5\ar[r]&6\ar[rd]\ar[dd]&&\\
|
|
7\ar[r]&8\ar[r]&9\ar[ruu]\ar[ru]\ar[r]\ar[rd]&10\ar[rr]\ar[rru]&&
|
|
11\ar[ru]&&12\ar[r]&13\\
|
|
&&&14\ar[r]&15\ar[rrru]\ar[rr]&&16\ar[rru]\ar[rr]&&17\\
|
|
}
|
|
|
|
\medskip\medskip
|
|
|
|
\noindent
|
|
the program output may look like follows:
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
Reading graph from `graph.txt'...
|
|
Graph has 17 vertices and 23 arcs
|
|
24 lines were read
|
|
cnt = 0
|
|
num[1] = 8
|
|
num[2] = 9
|
|
num[3] = 10
|
|
num[4] = 4
|
|
num[5] = 11
|
|
num[6] = 12
|
|
num[7] = 1
|
|
num[8] = 2
|
|
num[9] = 3
|
|
num[10] = 5
|
|
num[11] = 6
|
|
num[12] = 14
|
|
num[13] = 16
|
|
num[14] = 7
|
|
num[15] = 13
|
|
num[16] = 15
|
|
num[17] = 17
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
\noindent
|
|
The output corresponds to the following vertex numbering:
|
|
|
|
\medskip
|
|
|
|
\noindent\hfil
|
|
\xymatrix @=20pt
|
|
{
|
|
8\ar[rrr]&&&9\ar[r]\ar[rddd]&10\ar[rd]&&&&\\
|
|
&&&4\ar[ru]&&11\ar[r]&12\ar[rd]\ar[dd]&&\\
|
|
1\ar[r]&2\ar[r]&3\ar[ruu]\ar[ru]\ar[r]\ar[rd]&5\ar[rr]\ar[rru]&&
|
|
6\ar[ru]&&14\ar[r]&16\\
|
|
&&&7\ar[r]&13\ar[rrru]\ar[rr]&&15\ar[rru]\ar[rr]&&17\\
|
|
}
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
\chapter{Network optimization API routines}
|
|
|
|
\section{Minimum cost flow problem}
|
|
|
|
\subsection{Background}
|
|
|
|
The {\it minimum cost flow problem} (MCFP) is stated as follows. Let
|
|
there be given a directed graph (flow network) $G=(V,A)$, where $V$ is
|
|
a set of vertices (nodes), and $A\subseteq V\times V$ is a set of arcs.
|
|
Let for each node $i\in V$ there be given a quantity $b_i$ having the
|
|
following meaning:
|
|
|
|
if $b_i>0$, then $|b_i|$ is a {\it supply} at node $i$, which shows
|
|
how many flow units are {\it generated} at node $i$ (or, equivalently,
|
|
entering the network through node $i$ from outside);
|
|
|
|
if $b_i<0$, then $|b_i|$ is a {\it demand} at node $i$, which shows how
|
|
many flow units are {\it lost} at node $i$ (or, equivalently, leaving
|
|
the network through node $i$ to outside);
|
|
|
|
if $b_i=0$, then $i$ is a {\it transshipment} node, at which the flow
|
|
is conserved, i.e. neither generated nor lost.
|
|
|
|
Let also for each arc $a=(i,j)\in A$ there be given the following three
|
|
quantities:
|
|
|
|
$l_{ij}$, a (non-negative) lower bound to the flow through arc $(i,j)$;
|
|
|
|
$u_{ij}$, an upper bound to the flow through arc $(i,j)$, which is the
|
|
{\it arc capacity};
|
|
|
|
$c_{ij}$, a per-unit cost of the flow through arc $(i,j)$.
|
|
|
|
The problem is to find flows $x_{ij}$ through every arc of the network,
|
|
which satisfy the specified bounds and the conservation constraints at
|
|
all nodes, and minimize the total flow cost. Here the conservation
|
|
constraint at a node means that the total flow entering this node
|
|
through its incoming arcs plus the supply at this node must be equal to
|
|
the total flow leaving this node through its outgoing arcs plus the
|
|
demand at this node.
|
|
|
|
An example of the minimum cost flow problem is shown on Fig.~1.
|
|
|
|
\newpage
|
|
|
|
\noindent\hfil
|
|
\xymatrix @C=48pt
|
|
{_{20}\ar@{~>}[d]&
|
|
v_2\ar[r]|{_{0,10,\$2}}\ar[dd]|{_{0,9,\$3}}&
|
|
v_3\ar[dd]|{_{2,12,\$1}}\ar[r]|{_{0,18,\$0}}&
|
|
v_8\ar[rd]|{_{0,20,\$9}}&\\
|
|
v_1\ar[ru]|{_{0,14,\$0}}\ar[rd]|{_{0,23,\$0}}&&&
|
|
v_6\ar[d]|{_{0,7,\$0}}\ar[u]|{_{4,8,\$0}}&
|
|
v_9\ar@{~>}[d]\\
|
|
&v_4\ar[r]|{_{0,26,\$0}}&
|
|
v_5\ar[luu]|{_{0,11,\$1}}\ar[ru]|{_{0,25,\$5}}\ar[r]|{_{0,4,\$7}}&
|
|
v_7\ar[ru]|{_{0,15,\$3}}&_{20}\\
|
|
}
|
|
|
|
\noindent\hfil
|
|
\begin{tabular}{ccc}
|
|
\xymatrix @C=48pt{v_i\ar[r]|{\ l,u,\$c\ }&v_j\\}&
|
|
\xymatrix{\hbox{\footnotesize supply}\ar@{~>}[r]&v_i\\}&
|
|
\xymatrix{v_i\ar@{~>}[r]&\hbox{\footnotesize demand}\\}\\
|
|
\end{tabular}
|
|
|
|
\noindent\hfil
|
|
Fig.~1. An example of the minimum cost flow problem.
|
|
|
|
\medskip
|
|
|
|
The minimum cost flow problem can be naturally formulated as the
|
|
following LP problem:
|
|
|
|
\noindent
|
|
\hspace{1in}minimize
|
|
$$z=\sum_{(i,j)\in A}c_{ij}x_{ij}\eqno(1)$$
|
|
\hspace{1in}subject to
|
|
$$\sum_{(i,j)\in A}x_{ij}-\sum_{(j,i)\in A}x_{ji}=b_i\ \ \ \hbox
|
|
{for all}\ i\in V\eqno(2)$$
|
|
$$l_{ij}\leq x_{ij}\leq u_{ij}\ \ \ \hbox{for all}\ (i,j)\in A
|
|
\eqno(3)$$
|
|
|
|
\subsection{glp\_read\_mincost --- read minimum cost flow problem data
|
|
in DIMACS\\format}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
int glp_read_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
|
|
int a_cost, const char *fname);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_read_mincost| reads the minimum cost flow problem
|
|
data from a text file in DIMACS format.
|
|
|
|
The parameter \verb|G| specifies the graph object, to which the problem
|
|
data have to be stored. Note that before reading data the current
|
|
content of the graph object is completely erased with the routine
|
|
\verb|glp_erase_graph|.
|
|
|
|
The parameter \verb|v_rhs| specifies an offset of the field of type
|
|
\verb|double| in the vertex data block, to which the routine stores
|
|
$b_i$, the supply/demand value. If \verb|v_rhs| $<0$, the value is not
|
|
stored.
|
|
|
|
The parameter \verb|a_low| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, to which the routine stores
|
|
$l_{ij}$, the lower bound to the arc flow. If \verb|a_low| $<0$, the
|
|
lower bound is not stored.
|
|
|
|
The parameter \verb|a_cap| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, to which the routine stores
|
|
$u_{ij}$, the upper bound to the arc flow (the arc capacity). If
|
|
\verb|a_cap| $<0$, the upper bound is not stored.
|
|
|
|
The parameter \verb|a_cost| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, to which the routine stores
|
|
$c_{ij}$, the per-unit cost of the arc flow. If \verb|a_cost| $<0$, the
|
|
cost is not stored.
|
|
|
|
The character string \verb|fname| specifies the name of a text file to
|
|
be read in. (If the file name name ends with the suffix `\verb|.gz|',
|
|
the file is assumed to be compressed, in which case the routine
|
|
decompresses it ``on the fly''.)
|
|
|
|
\returns
|
|
|
|
If the operation was successful, the routine returns zero. Otherwise,
|
|
it prints an error message and returns non-zero.
|
|
|
|
\para{Example}
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
typedef struct
|
|
{ /* vertex data block */
|
|
...
|
|
double rhs;
|
|
...
|
|
} v_data;
|
|
|
|
typedef struct
|
|
{ /* arc data block */
|
|
...
|
|
double low, cap, cost;
|
|
...
|
|
} a_data;
|
|
|
|
int main(void)
|
|
{ glp_graph *G;
|
|
int ret;
|
|
G = glp_create_graph(sizeof(v_data), sizeof(a_data));
|
|
ret = glp_read_mincost(G, offsetof(v_data, rhs),
|
|
offsetof(a_data, low), offsetof(a_data, cap),
|
|
offsetof(a_data, cost), "sample.min");
|
|
if (ret != 0) goto ...
|
|
...
|
|
}
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
\para{DIMACS minimum cost flow problem format\footnote{This
|
|
material is based on the paper ``The First DIMACS International
|
|
Algorithm Implementation Challenge: Problem Definitions and
|
|
Specifications'', which is publically available at
|
|
\url{http://dimacs.rutgers.edu/Challenges}.}}
|
|
\label{subsecmincost}
|
|
|
|
The DIMACS input file is a plain ASCII text file. It contains
|
|
{\it lines} of several types described below. A line is terminated with
|
|
an end-of-line character. Fields in each line are separated by at least
|
|
one blank space. Each line begins with a one-character designator to
|
|
identify the line type.
|
|
|
|
Note that DIMACS requires all numerical quantities to be integers in
|
|
the range $[-2^{31},\ 2^{31}-1]$ while GLPK allows the quantities to be
|
|
floating-point numbers.
|
|
|
|
\para{Comment lines.} Comment lines give human-readable information
|
|
about the file and are ignored by programs. Comment lines can appear
|
|
anywhere in the file. Each comment line begins with a lower-case
|
|
character \verb|c|.
|
|
|
|
\begin{verbatim}
|
|
c This is a comment line
|
|
\end{verbatim}
|
|
|
|
\newpage
|
|
|
|
\para{Problem line.} There is one problem line per data file. The
|
|
problem line must appear before any node or arc descriptor lines. It
|
|
has the following format:
|
|
|
|
\begin{verbatim}
|
|
p min NODES ARCS
|
|
\end{verbatim}
|
|
|
|
\noindent
|
|
The lower-case character \verb|p| signifies that this is a problem line.
|
|
The three-character problem designator \verb|min| identifies the file as
|
|
containing specification information for the minimum cost flow problem.
|
|
The \verb|NODES| field contains an integer value specifying the number
|
|
of nodes in the network. The \verb|ARCS| field contains an integer value
|
|
specifying the number of arcs in the network.
|
|
|
|
\para{Node descriptors.} All node descriptor lines must appear before
|
|
all arc descriptor lines. The node descriptor lines describe supply and
|
|
demand nodes, but not transshipment nodes. That is, only nodes with
|
|
non-zero node supply/demand values appear. There is one node descriptor
|
|
line for each such node, with the following format:
|
|
|
|
\begin{verbatim}
|
|
n ID FLOW
|
|
\end{verbatim}
|
|
|
|
\noindent
|
|
The lower-case character \verb|n| signifies that this is a node
|
|
descriptor line. The \verb|ID| field gives a node identification
|
|
number, an integer between 1 and \verb|NODES|. The \verb|FLOW| field
|
|
gives the amount of supply (if positive) or demand (if negative) at
|
|
node \verb|ID|.
|
|
|
|
\para{Arc descriptors.} There is one arc descriptor line for each arc
|
|
in the network. Arc descriptor lines are of the following format:
|
|
|
|
\begin{verbatim}
|
|
a SRC DST LOW CAP COST
|
|
\end{verbatim}
|
|
|
|
\noindent
|
|
The lower-case character \verb|a| signifies that this is an arc
|
|
descriptor line. For a directed arc $(i,j)$ the \verb|SRC| field gives
|
|
the identification number $i$ for the tail endpoint, and the \verb|DST|
|
|
field gives the identification number $j$ for the head endpoint.
|
|
Identification numbers are integers between 1 and \verb|NODES|. The
|
|
\verb|LOW| field specifies the minimum amount of flow that can be sent
|
|
along arc $(i,j)$, and the \verb|CAP| field gives the maximum amount of
|
|
flow that can be sent along arc $(i,j)$ in a feasible flow. The
|
|
\verb|COST| field contains the per-unit cost of flow sent along arc
|
|
$(i,j)$.
|
|
|
|
\para{Example.} Below here is an example of the data file in DIMACS
|
|
format corresponding to the minimum cost flow problem shown on Fig~1.
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
c sample.min
|
|
c
|
|
c This is an example of the minimum cost flow problem data
|
|
c in DIMACS format.
|
|
c
|
|
p min 9 14
|
|
c
|
|
n 1 20
|
|
n 9 -20
|
|
c
|
|
a 1 2 0 14 0
|
|
a 1 4 0 23 0
|
|
a 2 3 0 10 2
|
|
a 2 4 0 9 3
|
|
a 3 5 2 12 1
|
|
a 3 8 0 18 0
|
|
a 4 5 0 26 0
|
|
a 5 2 0 11 1
|
|
a 5 6 0 25 5
|
|
a 5 7 0 4 7
|
|
a 6 7 0 7 0
|
|
a 6 8 4 8 0
|
|
a 7 9 0 15 3
|
|
a 8 9 0 20 9
|
|
c
|
|
c eof
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
\subsection{glp\_write\_mincost --- write minimum cost flow problem
|
|
data in DIMACS\\format}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
int glp_write_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
|
|
int a_cost, const char *fname);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_write_mincost| writes the minimum cost flow
|
|
problem data to a text file in DIMACS format.
|
|
|
|
The parameter \verb|G| is the graph (network) program object, which
|
|
specifies the minimum cost flow problem instance.
|
|
|
|
The parameter \verb|v_rhs| specifies an offset of the field of type
|
|
\verb|double| in the vertex data block, which contains $b_i$, the
|
|
supply/demand value. If \verb|v_rhs| $<0$, it is assumed that $b_i=0$
|
|
for all nodes.
|
|
|
|
The parameter \verb|a_low| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, which contains $l_{ij}$, the lower
|
|
bound to the arc flow. If \verb|a_low| $<0$, it is assumed that
|
|
$l_{ij}=0$ for all arcs.
|
|
|
|
The parameter \verb|a_cap| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, which contains $u_{ij}$, the upper
|
|
bound to the arc flow (the arc capacity). If the upper bound is
|
|
specified as \verb|DBL_MAX|, it is assumed that $u_{ij}=\infty$, i.e.
|
|
the arc is uncapacitated. If \verb|a_cap| $<0$, it is assumed that
|
|
$u_{ij}=1$ for all arcs.
|
|
|
|
The parameter \verb|a_cost| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, which contains $c_{ij}$, the
|
|
per-unit cost of the arc flow. If \verb|a_cost| $<0$, it is assumed
|
|
that $c_{ij}=0$ for all arcs.
|
|
|
|
The character string \verb|fname| specifies a name of the text file to
|
|
be written out. (If the file name ends with suffix `\verb|.gz|', the
|
|
file is assumed to be compressed, in which case the routine performs
|
|
automatic compression on writing it.)
|
|
|
|
\returns
|
|
|
|
If the operation was successful, the routine returns zero. Otherwise,
|
|
it prints an error message and returns non-zero.
|
|
|
|
\newpage
|
|
|
|
\subsection{glp\_mincost\_lp --- convert minimum cost flow problem
|
|
to LP}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
void glp_mincost_lp(glp_prob *P, glp_graph *G, int names, int v_rhs,
|
|
int a_low, int a_cap, int a_cost);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_mincost_lp| builds LP problem (1)---(3), which
|
|
corresponds to the specified minimum cost flow problem.
|
|
|
|
The parameter \verb|P| is the resultant LP problem object to be built.
|
|
Note that on entry its current content is erased with the routine
|
|
\verb|glp_erase_prob|.
|
|
|
|
The parameter \verb|G| is the graph (network) program object, which
|
|
specifies the minimum cost flow problem instance.
|
|
|
|
The parameter \verb|names| is a flag. If it is \verb|GLP_ON|, the
|
|
routine uses symbolic names of the graph object components to assign
|
|
symbolic names to the LP problem object components. If the flag is
|
|
\verb|GLP_OFF|, no symbolic names are assigned.
|
|
|
|
The parameter \verb|v_rhs| specifies an offset of the field of type
|
|
\verb|double| in the vertex data block, which contains $b_i$, the
|
|
supply/demand value. If \verb|v_rhs| $<0$, it is assumed that $b_i=0$
|
|
for all nodes.
|
|
|
|
The parameter \verb|a_low| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, which contains $l_{ij}$, the lower
|
|
bound to the arc flow. If \verb|a_low| $<0$, it is assumed that
|
|
$l_{ij}=0$ for all arcs.
|
|
|
|
The parameter \verb|a_cap| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, which contains $u_{ij}$, the upper
|
|
bound to the arc flow (the arc capacity). If the upper bound is
|
|
specified as \verb|DBL_MAX|, it is assumed that $u_{ij}=\infty$, i.e.
|
|
the arc is uncapacitated. If \verb|a_cap| $<0$, it is assumed that
|
|
$u_{ij}=1$ for all arcs.
|
|
|
|
The parameter \verb|a_cost| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, which contains $c_{ij}$, the
|
|
per-unit cost of the arc flow. If \verb|a_cost| $<0$, it is assumed that
|
|
$c_{ij}=0$ for all arcs.
|
|
|
|
\para{Example}
|
|
|
|
The example program below reads the minimum cost problem instance in
|
|
DIMACS format from file `\verb|sample.min|', converts the instance to
|
|
LP, and then writes the resultant LP in CPLEX format to file
|
|
`\verb|mincost.lp|'.
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
#include <stddef.h>
|
|
#include <glpk.h>
|
|
|
|
typedef struct { double rhs; } v_data;
|
|
typedef struct { double low, cap, cost; } a_data;
|
|
|
|
int main(void)
|
|
{ glp_graph *G;
|
|
glp_prob *P;
|
|
G = glp_create_graph(sizeof(v_data), sizeof(a_data));
|
|
glp_read_mincost(G, offsetof(v_data, rhs),
|
|
offsetof(a_data, low), offsetof(a_data, cap),
|
|
offsetof(a_data, cost), "sample.min");
|
|
P = glp_create_prob();
|
|
glp_mincost_lp(P, G, GLP_ON, offsetof(v_data, rhs),
|
|
offsetof(a_data, low), offsetof(a_data, cap),
|
|
offsetof(a_data, cost));
|
|
glp_delete_graph(G);
|
|
glp_write_lp(P, NULL, "mincost.lp");
|
|
glp_delete_prob(P);
|
|
return 0;
|
|
}
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
If `\verb|sample.min|' is the example data file from the subsection
|
|
describing \verb|glp_read_mincost|, file `\verb|mincost.lp|' may look
|
|
like follows:
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
Minimize
|
|
obj: + 3 x(2,4) + 2 x(2,3) + x(3,5) + 7 x(5,7) + 5 x(5,6)
|
|
+ x(5,2) + 3 x(7,9) + 9 x(8,9)
|
|
|
|
Subject To
|
|
r_1: + x(1,2) + x(1,4) = 20
|
|
r_2: - x(5,2) + x(2,3) + x(2,4) - x(1,2) = 0
|
|
r_3: + x(3,5) + x(3,8) - x(2,3) = 0
|
|
r_4: + x(4,5) - x(2,4) - x(1,4) = 0
|
|
r_5: + x(5,2) + x(5,6) + x(5,7) - x(4,5) - x(3,5) = 0
|
|
r_6: + x(6,7) + x(6,8) - x(5,6) = 0
|
|
r_7: + x(7,9) - x(6,7) - x(5,7) = 0
|
|
r_8: + x(8,9) - x(6,8) - x(3,8) = 0
|
|
r_9: - x(8,9) - x(7,9) = -20
|
|
|
|
Bounds
|
|
0 <= x(1,4) <= 23
|
|
0 <= x(1,2) <= 14
|
|
0 <= x(2,4) <= 9
|
|
0 <= x(2,3) <= 10
|
|
0 <= x(3,8) <= 18
|
|
2 <= x(3,5) <= 12
|
|
0 <= x(4,5) <= 26
|
|
0 <= x(5,7) <= 4
|
|
0 <= x(5,6) <= 25
|
|
0 <= x(5,2) <= 11
|
|
4 <= x(6,8) <= 8
|
|
0 <= x(6,7) <= 7
|
|
0 <= x(7,9) <= 15
|
|
0 <= x(8,9) <= 20
|
|
|
|
End
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
\newpage
|
|
|
|
\subsection{glp\_mincost\_okalg --- solve minimum cost flow problem
|
|
with out-of-kilter\\algorithm}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
int glp_mincost_okalg(glp_graph *G, int v_rhs, int a_low, int a_cap,
|
|
int a_cost, double *sol, int a_x, int v_pi);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_mincost_okalg| finds optimal solution to the
|
|
minimum cost flow problem with the out-of-kilter
|
|
algorithm.\footnote{GLPK implementation of the out-of-kilter algorithm
|
|
is based on the following book: L.~R.~Ford,~Jr., and D.~R.~Fulkerson,
|
|
``Flows in Networks,'' The RAND Corp., Report R-375-PR (August 1962),
|
|
Chap. III ``Minimal Cost Flow Problems,'' pp.~113-26.} Note that this
|
|
routine requires all the problem data to be integer-valued.
|
|
|
|
The parameter \verb|G| is a graph (network) program object which
|
|
specifies the minimum cost flow problem instance to be solved.
|
|
|
|
The parameter \verb|v_rhs| specifies an offset of the field of type
|
|
\verb|double| in the vertex data block, which contains $b_i$, the
|
|
supply/demand value. This value must be integer in the range
|
|
[$-$\verb|INT_MAX|, $+$\verb|INT_MAX|]. If \verb|v_rhs| $<0$, it is
|
|
assumed that $b_i=0$ for all nodes.
|
|
|
|
The parameter \verb|a_low| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, which contains $l_{ij}$, the lower
|
|
bound to the arc flow. This bound must be integer in the range
|
|
[$0$, \verb|INT_MAX|]. If \verb|a_low| $<0$, it is assumed that
|
|
$l_{ij}=0$ for all arcs.
|
|
|
|
The parameter \verb|a_cap| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, which contains $u_{ij}$, the upper
|
|
bound to the arc flow (the arc capacity). This bound must be integer in
|
|
the range [$l_{ij}$, \verb|INT_MAX|]. If \verb|a_cap| $<0$, it is
|
|
assumed that $u_{ij}=1$ for all arcs.
|
|
|
|
The parameter \verb|a_cost| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, which contains $c_{ij}$, the
|
|
per-unit cost of the arc flow. This value must be integer in the range
|
|
[$-$\verb|INT_MAX|, $+$\verb|INT_MAX|]. If \verb|a_cost| $<0$, it is
|
|
assumed that $c_{ij}=0$ for all arcs.
|
|
|
|
The parameter \verb|sol| specifies a location, to which the routine
|
|
stores the objective value (that is, the total cost) found. If
|
|
\verb|sol| is NULL, the objective value is not stored.
|
|
|
|
The parameter \verb|a_x| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, to which the routine stores
|
|
$x_{ij}$, the arc flow found. If \verb|a_x| $<0$, the arc flow value is
|
|
not stored.
|
|
|
|
The parameter \verb|v_pi| specifies an offset of the field of type
|
|
\verb|double| in the vertex data block, to which the routine stores
|
|
$\pi_i$, the node potential, which is the Lagrange multiplier for the
|
|
corresponding flow conservation equality constraint (see (2) in
|
|
Subsection ``Background''). If necessary, the application program may
|
|
use the node potentials to compute $\lambda_{ij}$, reduced costs of the
|
|
arc flows $x_{ij}$, which are the Lagrange multipliers for the arc flow
|
|
bound constraints (see (3) ibid.), using the following formula:
|
|
$$\lambda_{ij}=c_{ij}-(\pi_i-\pi_j),$$
|
|
where $c_{ij}$ is the per-unit cost for arc $(i,j)$.
|
|
|
|
\newpage
|
|
|
|
Note that all solution components (the objective value, arc flows, and
|
|
node potentials) computed by the routine are always integer-valued.
|
|
|
|
\returns
|
|
|
|
\begin{retlist}
|
|
0 & Optimal solution found.\\
|
|
|
|
\verb|GLP_ENOPFS| & No (primal) feasible solution exists.\\
|
|
|
|
\verb|GLP_EDATA| & Unable to start the search, because some problem
|
|
data are either not integer-valued or out of range. This code is also
|
|
returned if the total supply, which is the sum of $b_i$ over all source
|
|
nodes (nodes with $b_i>0$), exceeds \verb|INT_MAX|.\\
|
|
|
|
\verb|GLP_ERANGE| & The search was prematurely terminated because of
|
|
integer overflow.\\
|
|
|
|
\verb|GLP_EFAIL| & An error has been detected in the program logic.
|
|
(If this code is returned for your problem instance, please report to
|
|
\verb|<bug-glpk@gnu.org>|.)\\
|
|
\end{retlist}
|
|
|
|
\para{Comments}
|
|
|
|
By design the out-of-kilter algorithm is applicable only to networks,
|
|
where $b_i=0$ for {\it all} nodes, i.e. actually this algorithm finds a
|
|
minimal cost {\it circulation}. Due to this requirement the routine
|
|
\verb|glp_mincost_okalg| converts the original network to a network
|
|
suitable for the out-of-kilter algorithm in the following
|
|
way:\footnote{The conversion is performed internally and does not change
|
|
the original network program object passed to the routine.}
|
|
|
|
1) it adds two auxiliary nodes $s$ and $t$;
|
|
|
|
2) for each original node $i$ with $b_i>0$ the routine adds auxiliary
|
|
supply arc $(s\rightarrow i)$, flow $x_{si}$ through which is costless
|
|
($c_{si}=0$) and fixed to $+b_i$ ($l_{si}=u_{si}=+b_i$);
|
|
|
|
3) for each original node $i$ with $b_i<0$ the routine adds auxiliary
|
|
demand arc $(i\rightarrow t)$, flow $x_{it}$ through which is costless
|
|
($c_{it}=0$) and fixed to $-b_i$ ($l_{it}=u_{it}=-b_i$);
|
|
|
|
4) finally, the routine adds auxiliary feedback arc $(t\rightarrow s)$,
|
|
flow $x_{ts}$ through which is also costless ($c_{ts}=0$) and fixed to
|
|
$F$ ($l_{ts}=u_{ts}=F$), where $\displaystyle F=\sum_{b_i>0}b_i$ is the
|
|
total supply.
|
|
|
|
\para{Example}
|
|
|
|
The example program below reads the minimum cost problem instance in
|
|
DIMACS format from file `\verb|sample.min|', solves it by using the
|
|
routine \verb|glp_mincost_okalg|, and writes the solution found on the
|
|
standard output.
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <glpk.h>
|
|
|
|
typedef struct { double rhs, pi; } v_data;
|
|
typedef struct { double low, cap, cost, x; } a_data;
|
|
|
|
#define node(v) ((v_data *)((v)->data))
|
|
#define arc(a) ((a_data *)((a)->data))
|
|
|
|
int main(void)
|
|
{ glp_graph *G;
|
|
glp_vertex *v, *w;
|
|
glp_arc *a;
|
|
int i, ret;
|
|
double sol;
|
|
G = glp_create_graph(sizeof(v_data), sizeof(a_data));
|
|
glp_read_mincost(G, offsetof(v_data, rhs),
|
|
offsetof(a_data, low), offsetof(a_data, cap),
|
|
offsetof(a_data, cost), "sample.min");
|
|
ret = glp_mincost_okalg(G, offsetof(v_data, rhs),
|
|
offsetof(a_data, low), offsetof(a_data, cap),
|
|
offsetof(a_data, cost), &sol, offsetof(a_data, x),
|
|
offsetof(v_data, pi));
|
|
printf("ret = %d; sol = %5g\n", ret, sol);
|
|
for (i = 1; i <= G->nv; i++)
|
|
{ v = G->v[i];
|
|
printf("node %d: pi = %5g\n", i, node(v)->pi);
|
|
for (a = v->out; a != NULL; a = a->t_next)
|
|
{ w = a->head;
|
|
printf("arc %d->%d: x = %5g; lambda = %5g\n",
|
|
v->i, w->i, arc(a)->x,
|
|
arc(a)->cost - (node(v)->pi - node(w)->pi));
|
|
}
|
|
}
|
|
glp_delete_graph(G);
|
|
return 0;
|
|
}
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
If `\verb|sample.min|' is the example data file from the subsection
|
|
describing \verb|glp_read_mincost|, the output may look like follows:
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
Reading min-cost flow problem data from `sample.min'...
|
|
Flow network has 9 nodes and 14 arcs
|
|
24 lines were read
|
|
ret = 0; sol = 213
|
|
node 1: pi = -12
|
|
arc 1->4: x = 13; lambda = 0
|
|
arc 1->2: x = 7; lambda = 0
|
|
node 2: pi = -12
|
|
arc 2->4: x = 0; lambda = 3
|
|
arc 2->3: x = 7; lambda = 0
|
|
node 3: pi = -14
|
|
arc 3->8: x = 5; lambda = 0
|
|
arc 3->5: x = 2; lambda = 3
|
|
node 4: pi = -12
|
|
arc 4->5: x = 13; lambda = 0
|
|
node 5: pi = -12
|
|
arc 5->7: x = 4; lambda = -1
|
|
arc 5->6: x = 11; lambda = 0
|
|
arc 5->2: x = 0; lambda = 1
|
|
node 6: pi = -17
|
|
arc 6->8: x = 4; lambda = 3
|
|
arc 6->7: x = 7; lambda = -3
|
|
node 7: pi = -20
|
|
arc 7->9: x = 11; lambda = 0
|
|
node 8: pi = -14
|
|
arc 8->9: x = 9; lambda = 0
|
|
node 9: pi = -23
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
\subsection{glp\_mincost\_relax4 --- solve minimum cost flow problem
|
|
with relaxation\\method of Bertsekas and Tseng (RELAX-IV)}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
int glp_mincost_relax4(glp_graph *G, int v_rhs, int a_low, int a_cap,
|
|
int a_cost, int crash, double *sol, int a_x, int a_rc);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_mincost_relax4| finds optimal solution to the
|
|
minimum cost flow problem with the relaxation method RELAX-IV developed
|
|
by Bertsekas and Tseng.\footnote{GLPK implementation of this method is
|
|
based on a C translation of the original Fortran code {\tt RELAX4}
|
|
written by Dimitri P. Bertsekas and Paul Tseng, with a contribution by
|
|
Jonathan Eckstein in the phase II initialization.} This method is one
|
|
of most efficient methods for network optimization.
|
|
|
|
Note that this routine requires all the problem data to be
|
|
integer-valued.
|
|
|
|
The parameter \verb|G| is a graph (network) program object which
|
|
specifies the minimum cost flow problem instance to be solved.
|
|
|
|
The parameter \verb|v_rhs| specifies an offset of the field of type
|
|
\verb|double| in the vertex data block, which contains $b_i$, the
|
|
supply/demand value. This value must be integer in the range
|
|
[$-$\verb|INT_MAX|/4, $+$\verb|INT_MAX|/4]. If \verb|v_rhs| $<0$, it is
|
|
assumed that $b_i=0$ for all nodes.
|
|
|
|
The parameter \verb|a_low| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, which contains $l_{ij}$, the lower
|
|
bound to the arc flow. This bound must be integer in the range
|
|
{\linebreak} [$0$, \verb|INT_MAX|/4]. If \verb|a_low| $<0$, it is
|
|
assumed that $l_{ij}=0$ for all arcs.
|
|
|
|
The parameter \verb|a_cap| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, which contains $u_{ij}$, the upper
|
|
bound to the arc flow (the arc capacity). This bound must be integer in
|
|
the range [$l_{ij}$, \verb|INT_MAX|/4]. If \verb|a_cap| $<0$, it is
|
|
assumed that $u_{ij}=1$ for all arcs.
|
|
|
|
The parameter \verb|a_cost| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, which contains $c_{ij}$, the
|
|
per-unit cost of the arc flow. This value must be integer in the range
|
|
[$-$\verb|INT_MAX|/4, $+$\verb|INT_MAX|/4]. If \verb|a_cost| $<0$, it
|
|
is assumed that $c_{ij}=0$ for all arcs.
|
|
|
|
The parameter \verb|crash| is option specifying initialization method:
|
|
|
|
0 --- default initialization is used;
|
|
|
|
1 --- auction initialization is used.
|
|
|
|
\noindent
|
|
If \verb|crash| = 1, initialization is performed with a special crash
|
|
procedure based on an auction/shorest path method. This option is
|
|
recommended for difficult problems where the default initialization
|
|
results in long running times.
|
|
|
|
The parameter \verb|sol| specifies a location, to which the routine
|
|
stores the objective value (that is, the total cost) found. If
|
|
\verb|sol| is NULL, the objective value is not stored.
|
|
|
|
\newpage
|
|
|
|
The parameter \verb|a_x| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, to which the routine stores
|
|
$x_{ij}$, the arc flow found. If \verb|a_x| $<0$, the arc flow value is
|
|
not stored.
|
|
|
|
The parameter \verb|a_rc| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, to which the routine stores
|
|
the reduced cost for corresponding arc flow (see (3) in Subsection
|
|
``Background''). If \verb|a_rc| $<0$, the reduced cost is not stored.
|
|
|
|
Note that all solution components (the objective value, arc flows, and
|
|
node potentials) computed by the routine are always integer-valued.
|
|
|
|
\returns
|
|
|
|
\begin{retlist}
|
|
0 & Optimal solution found.\\
|
|
|
|
\verb|GLP_ENOPFS| & No (primal) feasible solution exists.\\
|
|
|
|
\verb|GLP_EDATA| & Unable to start the search, because some problem
|
|
data are either not integer-valued or out of range.\\
|
|
|
|
\verb|GLP_ERANGE| & Unable to start the search because of integer
|
|
overflow.\\
|
|
\end{retlist}
|
|
|
|
\para{Example}
|
|
|
|
The example program below reads the minimum cost problem instance in
|
|
DIMACS format from file `\verb|sample.min|', solves it by using the
|
|
routine \verb|glp_mincost_relax4|, and writes the solution found on the
|
|
standard output.
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <glpk.h>
|
|
|
|
typedef struct { double rhs; } v_data;
|
|
typedef struct { double low, cap, cost, x, rc; } a_data;
|
|
|
|
#define node(v) ((v_data *)((v)->data))
|
|
#define arc(a) ((a_data *)((a)->data))
|
|
|
|
int main(void)
|
|
{ glp_graph *G;
|
|
glp_vertex *v, *w;
|
|
glp_arc *a;
|
|
int i, ret;
|
|
double sol;
|
|
G = glp_create_graph(sizeof(v_data), sizeof(a_data));
|
|
glp_read_mincost(G, offsetof(v_data, rhs),
|
|
offsetof(a_data, low), offsetof(a_data, cap),
|
|
offsetof(a_data, cost), "sample.min");
|
|
ret = glp_mincost_relax4(G, offsetof(v_data, rhs),
|
|
offsetof(a_data, low), offsetof(a_data, cap),
|
|
offsetof(a_data, cost), 0, &sol, offsetof(a_data, x),
|
|
offsetof(a_data, rc));
|
|
printf("ret = %d; sol = %5g\n", ret, sol);
|
|
for (i = 1; i <= G->nv; i++)
|
|
{ v = G->v[i];
|
|
for (a = v->out; a != NULL; a = a->t_next)
|
|
{ w = a->head;
|
|
printf("arc %d->%d: x = %5g; rc = %5g\n",
|
|
v->i, w->i, arc(a)->x, arc(a)->rc);
|
|
}
|
|
}
|
|
glp_delete_graph(G);
|
|
return 0;
|
|
}
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
If `\verb|sample.min|' is the example data file from the subsection
|
|
describing \verb|glp_read_mincost|, the output may look like follows:
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
Reading min-cost flow problem data from `sample.min'...
|
|
Flow network has 9 nodes and 14 arcs
|
|
24 lines were read
|
|
ret = 0; sol = 213
|
|
arc 1->4: x = 13; rc = 0
|
|
arc 1->2: x = 7; rc = 0
|
|
arc 2->4: x = 0; rc = 3
|
|
arc 2->3: x = 7; rc = 0
|
|
arc 3->8: x = 5; rc = 0
|
|
arc 3->5: x = 2; rc = 3
|
|
arc 4->5: x = 13; rc = 0
|
|
arc 5->7: x = 4; rc = -1
|
|
arc 5->6: x = 11; rc = 0
|
|
arc 5->2: x = 0; rc = 1
|
|
arc 6->8: x = 4; rc = 3
|
|
arc 6->7: x = 7; rc = -3
|
|
arc 7->9: x = 11; rc = 0
|
|
arc 8->9: x = 9; rc = 0
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
\subsection{glp\_netgen --- Klingman's network problem generator}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
int glp_netgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
|
|
const int parm[1+15]);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_netgen| is a GLPK version of the network problem
|
|
generator developed by Dr.~Darwin~Klingman.\footnote{D.~Klingman,
|
|
A.~Napier, and J.~Stutz. NETGEN: A program for generating large scale
|
|
capacitated assignment, transportation, and minimum cost flow networks.
|
|
Management Science 20 (1974), 814-20.} It can create capacitated and
|
|
uncapacitated minimum cost flow (or transshipment), transportation, and
|
|
assignment problems.
|
|
|
|
The parameter \verb|G| specifies the graph object, to which the
|
|
generated problem data have to be stored. Note that on entry the graph
|
|
object is erased with the routine \verb|glp_erase_graph|.
|
|
|
|
The parameter \verb|v_rhs| specifies an offset of the field of type
|
|
\verb|double| in the vertex data block, to which the routine stores the
|
|
supply or demand value. If \verb|v_rhs| $<0$, the value is not stored.
|
|
|
|
The parameter \verb|a_cap| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, to which the routine stores the
|
|
arc capacity. If \verb|a_cap| $<0$, the capacity is not stored.
|
|
|
|
\newpage
|
|
|
|
The parameter \verb|a_cost| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, to which the routine stores the
|
|
per-unit cost if the arc flow. If \verb|a_cost| $<0$, the cost is not
|
|
stored.
|
|
|
|
The array \verb|parm| contains description of the network to be
|
|
generated:
|
|
|
|
\begin{tabular}{@{}lll@{}}
|
|
\verb|parm[0] |& ¬ used\\
|
|
\verb|parm[1] |&\verb|iseed |&8-digit positive random number seed\\
|
|
\verb|parm[2] |&\verb|nprob |&8-digit problem id number\\
|
|
\verb|parm[3] |&\verb|nodes |&total number of nodes\\
|
|
\verb|parm[4] |&\verb|nsorc |&total number of source nodes
|
|
(including transshipment nodes)\\
|
|
\verb|parm[5] |&\verb|nsink |&total number of sink nodes
|
|
(including transshipment nodes)\\
|
|
\verb|parm[6] |&\verb|iarcs |&number of arc\\
|
|
\verb|parm[7] |&\verb|mincst|&minimum cost for arcs\\
|
|
\verb|parm[8] |&\verb|maxcst|&maximum cost for arcs\\
|
|
\verb|parm[9] |&\verb|itsup |&total supply\\
|
|
\verb|parm[10]|&\verb|ntsorc|&number of transshipment source nodes\\
|
|
\verb|parm[11]|&\verb|ntsink|&number of transshipment sink nodes\\
|
|
\verb|parm[12]|&\verb|iphic |&percentage of skeleton arcs to be given
|
|
the maximum cost\\
|
|
\verb|parm[13]|&\verb|ipcap |&percentage of arcs to be capacitated\\
|
|
\verb|parm[14]|&\verb|mincap|&minimum upper bound for capacitated arcs\\
|
|
\verb|parm[15]|&\verb|maxcap|&maximum upper bound for capacitated arcs\\
|
|
\end{tabular}
|
|
|
|
\returns
|
|
|
|
If the instance was successfully generated, the routine
|
|
\verb|glp_netgen| returns zero; otherwise, if specified parameters are
|
|
inconsistent, the routine returns a non-zero error code.
|
|
|
|
\para{Notes}
|
|
|
|
1. The routine generates a transportation problem if:
|
|
$${\tt nsorc}+{\tt nsink}={\tt nodes},
|
|
\ {\tt ntsorc}=0,\ \mbox{and}\ {\tt ntsink}=0.$$
|
|
|
|
2. The routine generates an assignment problem if the requirements for
|
|
a transportation problem are met and:
|
|
$${\tt nsorc}={\tt nsink}\ \mbox{and}\ {\tt itsup}={\tt nsorc}.$$
|
|
|
|
3. The routine always generates connected graphs. So, if the number of
|
|
requested arcs has been reached and the generated instance is not fully
|
|
connected, the routine generates a few remaining arcs to ensure
|
|
connectedness. Thus, the actual number of arcs generated by the routine
|
|
may be greater than the requested number of arcs.
|
|
|
|
\subsection{glp\_netgen\_prob --- Klingman's standard network problem
|
|
instance}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
void glp_netgen_prob(int nprob, int parm[1+15]);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_netgen_prob| provides the set of parameters for
|
|
Klingman's network problem generator (see the routine
|
|
\verb|glp_netgen|), which describe a standard network problem instance.
|
|
|
|
The parameter \verb|nprob| ($101\leq$ \verb|nprob| $\leq 150$)
|
|
specifies the problem instance number.
|
|
|
|
The array \verb|parm| contains description of the network, provided by
|
|
the routine. (For detailed description of these parameters see comments
|
|
to the routine \verb|glp_netgen|.)
|
|
|
|
\para{Problem characteristics}
|
|
|
|
The table below shows characteristics of Klingman's standard network
|
|
problem instances.
|
|
$$
|
|
\begin{array}{crrr}
|
|
{\rm Problem} & {\rm Nodes} & {\rm Arcs} & {\rm Optimum} \\
|
|
\hline
|
|
101 & 5000 & 25336 & 6191726 \\
|
|
102 & 5000 & 25387 & 72337144 \\
|
|
103 & 5000 & 25355 & 218947553 \\
|
|
104 & 5000 & 25344 & -19100371 \\
|
|
105 & 5000 & 25332 & 31192578 \\
|
|
106 & 5000 & 12870 & 4314276 \\
|
|
107 & 5000 & 37832 & 7393769 \\
|
|
108 & 5000 & 50309 & 8405738 \\
|
|
109 & 5000 & 75299 & 9190300 \\
|
|
110 & 5000 & 12825 & 8975048 \\
|
|
111 & 5000 & 37828 & 4747532 \\
|
|
112 & 5000 & 50325 & 4012671 \\
|
|
113 & 5000 & 75318 & 2979725 \\
|
|
114 & 5000 & 26514 & 5821181 \\
|
|
115 & 5000 & 25962 & 6353310 \\
|
|
116 & 5000 & 25304 & 5915426 \\
|
|
117 & 5000 & 12816 & 4420560 \\
|
|
118 & 5000 & 37797 & 7045842 \\
|
|
119 & 5000 & 50301 & 7724179 \\
|
|
120 & 5000 & 75330 & 8455200 \\
|
|
121 & 5000 & 25000 & 66366360 \\
|
|
122 & 5000 & 25000 & 30997529 \\
|
|
123 & 5000 & 25000 & 23388777 \\
|
|
124 & 5000 & 25000 & 17803443 \\
|
|
125 & 5000 & 25000 & 14119622 \\
|
|
\end{array}
|
|
\hspace{.5in}
|
|
\begin{array}{crrr}
|
|
{\rm Problem} & {\rm Nodes} & {\rm Arcs} & {\rm Optimum} \\
|
|
\hline
|
|
126 & 5000 & 12500 & 18802218 \\
|
|
127 & 5000 & 37500 & 27674647 \\
|
|
128 & 5000 & 50000 & 30906194 \\
|
|
129 & 5000 & 75000 & 40905209 \\
|
|
130 & 5000 & 12500 & 38939608 \\
|
|
131 & 5000 & 37500 & 16752978 \\
|
|
132 & 5000 & 50000 & 13302951 \\
|
|
133 & 5000 & 75000 & 9830268 \\
|
|
134 & 1000 & 25000 & 3804874 \\
|
|
135 & 2500 & 25000 & 11729616 \\
|
|
136 & 7500 & 25000 & 33318101 \\
|
|
137 & 10000 & 25000 & 46426030 \\
|
|
138 & 5000 & 25000 & 60710879 \\
|
|
139 & 5000 & 25000 & 32729682 \\
|
|
140 & 5000 & 25000 & 27183831 \\
|
|
141 & 5000 & 25000 & 19963286 \\
|
|
142 & 5000 & 25000 & 20243457 \\
|
|
143 & 5000 & 25000 & 18586777 \\
|
|
144 & 5000 & 25000 & 2504591 \\
|
|
145 & 5000 & 25000 & 215956138 \\
|
|
146 & 5000 & 25000 & 2253113811 \\
|
|
147 & 5000 & 25000 & -427908373 \\
|
|
148 & 5000 & 25000 & -92965318 \\
|
|
149 & 5000 & 25000 & 86051224 \\
|
|
150 & 5000 & 25000 & 619314919 \\
|
|
\end{array}
|
|
$$
|
|
|
|
\subsection{glp\_gridgen --- grid-like network problem generator}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
int glp_gridgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
|
|
const int parm[1+14]);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_gridgen| is a GLPK version of the grid-like
|
|
network problem generator developed by Yusin Lee and Jim
|
|
Orlin.\footnote{Y.~Lee and J.~Orlin. GRIDGEN generator., 1991. The
|
|
original code is publically available from
|
|
\url{ftp://dimacs.rutgers.edu/pub/netflow/generators/network/gridgen}.}
|
|
|
|
\newpage
|
|
|
|
The parameter \verb|G| specifies the graph object, to which the
|
|
generated problem data have to be stored. Note that on entry the graph
|
|
object is erased with the routine \verb|glp_erase_graph|.
|
|
|
|
The parameter \verb|v_rhs| specifies an offset of the field of type
|
|
\verb|double| in the vertex data block, to which the routine stores the
|
|
supply or demand value. If \verb|v_rhs| $<0$, the value is not stored.
|
|
|
|
The parameter \verb|a_cap| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, to which the routine stores the
|
|
arc capacity. If \verb|a_cap| $<0$, the capacity is not stored.
|
|
|
|
The parameter \verb|a_cost| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, to which the routine stores the
|
|
per-unit cost if the arc flow. If \verb|a_cost| $<0$, the cost is not
|
|
stored.
|
|
|
|
The array \verb|parm| contains parameters of the network to be
|
|
generated:
|
|
|
|
\begin{tabular}{@{}ll@{}}
|
|
\verb|parm[0] |¬ used\\
|
|
\verb|parm[1] |&two-ways arcs indicator:\\
|
|
&1 --- if links in both direction should be generated\\
|
|
&0 --- otherwise\\
|
|
\verb|parm[2] |&random number seed (a positive integer)\\
|
|
\verb|parm[3] |&number of nodes (the number of nodes generated might
|
|
be slightly different to\\&make the network a grid)\\
|
|
\verb|parm[4] |&grid width\\
|
|
\verb|parm[5] |&number of sources\\
|
|
\verb|parm[6] |&number of sinks\\
|
|
\verb|parm[7] |&average degree\\
|
|
\verb|parm[8] |&total flow\\
|
|
\verb|parm[9] |&distribution of arc costs:
|
|
1 --- uniform, 2 --- exponential\\
|
|
\verb|parm[10]|&lower bound for arc cost (uniform),
|
|
$100\lambda$ (exponential)\\
|
|
\verb|parm[11]|&upper bound for arc cost (uniform),
|
|
not used (exponential)\\
|
|
\verb|parm[12]|&distribution of arc capacities:
|
|
1 --- uniform, 2 --- exponential\\
|
|
\verb|parm[13]|&lower bound for arc capacity (uniform),
|
|
$100\lambda$ (exponential)\\
|
|
\verb|parm[14]|&upper bound for arc capacity (uniform),
|
|
not used (exponential)\\
|
|
\end{tabular}
|
|
|
|
\returns
|
|
|
|
If the instance was successfully generated, the routine
|
|
\verb|glp_gridgen| returns zero; otherwise, if specified parameters are
|
|
inconsistent, the routine returns a non-zero error code.
|
|
|
|
\para{Comments\footnote{This material is based on comments
|
|
to the original version of GRIDGEN.}}
|
|
|
|
This network generator generates a grid-like network plus a super node.
|
|
In additional to the arcs connecting the nodes in the grid, there is an
|
|
arc from each supply node to the super node and from the super node to
|
|
each demand node to guarantee feasiblity. These arcs have very high
|
|
costs and very big capacities.
|
|
|
|
The idea of this network generator is as follows: First, a grid of
|
|
$n_1\times n_2$ is generated. For example, $5\times 3$. The nodes are
|
|
numbered as 1 to 15, and the supernode is numbered as
|
|
$n_1\times n_2+1$. Then arcs between adjacent nodes are generated.
|
|
For these arcs, the user is allowed to specify either to generate
|
|
two-way arcs or one-way arcs. If two-way arcs are to be generated, two
|
|
arcs, one in each direction, will be generated between each adjacent
|
|
node pairs. Otherwise, only one arc will be generated. If this is the
|
|
case, the arcs will be generated in alterntive directions as shown
|
|
below.
|
|
|
|
\medskip
|
|
|
|
\noindent\hfil
|
|
\xymatrix
|
|
{1\ar[r]\ar[d]&2\ar[r]&3\ar[r]\ar[d]&4\ar[r]&5\ar[d]\\
|
|
6\ar[d]&7\ar[l]\ar[u]&8\ar[l]\ar[d]&9\ar[l]\ar[u]&10\ar[l]\ar[d]\\
|
|
11\ar[r]&12\ar[r]\ar[u]&13\ar[r]&14\ar[r]\ar[u]&15\\
|
|
}
|
|
|
|
\medskip
|
|
|
|
Then the arcs between the super node and the source/sink nodes are
|
|
added as mentioned before. If the number of arcs still doesn't reach
|
|
the requirement, additional arcs will be added by uniformly picking
|
|
random node pairs. There is no checking to prevent multiple arcs
|
|
between any pair of nodes. However, there will be no self-arcs (arcs
|
|
that poins back to its tail node) in the network.
|
|
|
|
The source and sink nodes are selected uniformly in the network, and
|
|
the imbalances of each source/sink node are also assigned by uniform
|
|
distribution.
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
\newpage
|
|
|
|
\section{Maximum flow problem}
|
|
|
|
\subsection{Background}
|
|
|
|
The {\it maximum flow problem} (MAXFLOW) is stated as follows. Let
|
|
there be given a directed graph (flow network) $G=(V,A)$, where $V$ is
|
|
a set of vertices (nodes), and $A\subseteq V\times V$ is a set of arcs.
|
|
Let also for each arc $a=(i,j)\in A$ there be given its capacity
|
|
$u_{ij}$. The problem is, for given {\it source} node $s\in V$ and
|
|
{\it sink} node $t\in V$, to find flows $x_{ij}$ through every arc of
|
|
the network, which satisfy the specified arc capacities and the
|
|
conservation constraints at all nodes, and maximize the total flow $F$
|
|
through the network from $s$ to $t$. Here the conservation constraint
|
|
at a node means that the total flow entering this node through its
|
|
incoming arcs (plus $F$, if it is the source node) must be equal to the
|
|
total flow leaving this node through its outgoing arcs (plus $F$, if it
|
|
is the sink node). An example of the maximum flow problem,
|
|
where $s=v_1$ and $t=v_9$, is shown on Fig.~2.
|
|
|
|
\medskip
|
|
|
|
\noindent\hfil
|
|
\xymatrix @C=48pt
|
|
{_{F}\ar@{~>}[d]&
|
|
v_2\ar[r]|{_{10}}\ar[dd]|{_{9}}&
|
|
v_3\ar[dd]|{_{12}}\ar[r]|{_{18}}&
|
|
v_8\ar[rd]|{_{20}}&\\
|
|
v_1\ar[ru]|{_{14}}\ar[rd]|{_{23}}&&&
|
|
v_6\ar[d]|{_{7}}\ar[u]|{_{8}}&
|
|
v_9\ar@{~>}[d]\\
|
|
&v_4\ar[r]|{_{26}}&
|
|
v_5\ar[luu]|{_{11}}\ar[ru]|{_{25}}\ar[r]|{_{4}}&
|
|
v_7\ar[ru]|{_{15}}&_{F}\\
|
|
}
|
|
|
|
\medskip
|
|
|
|
\noindent\hfil
|
|
Fig.~2. An example of the maximum flow problem.
|
|
|
|
\medskip
|
|
|
|
The maximum flow problem can be naturally formulated as the following
|
|
LP problem:
|
|
|
|
\noindent
|
|
\hspace{1in}maximize
|
|
$$F\eqno(4)$$
|
|
\hspace{1in}subject to
|
|
$$\sum_{(i,j)\in A}x_{ij}-\sum_{(j,i)\in A}x_{ji}=\left\{
|
|
\begin{array}{@{\ }rl}
|
|
+F,&\hbox{for}\ i=s\\
|
|
0,&\hbox{for all}\ i\in V\backslash\{s,t\}\\
|
|
-F,&\hbox{for}\ i=t\\
|
|
\end{array}
|
|
\right.\eqno(5)
|
|
$$
|
|
$$0\leq x_{ij}\leq u_{ij}\ \ \ \hbox{for all}\ (i,j)\in A
|
|
\eqno(6)$$
|
|
|
|
\noindent
|
|
where $F\geq 0$ is an additional variable playing the role of the
|
|
objective.
|
|
|
|
Another LP formulation of the maximum flow problem, which does not
|
|
include the variable $F$, is the following:
|
|
|
|
\noindent
|
|
\hspace{1in}maximize
|
|
$$z=\sum_{(s,j)\in A}x_{sj}-\sum_{(j,s)\in A}x_{js}\ (=F)\eqno(7)$$
|
|
\hspace{1in}subject to
|
|
$$\sum_{(i,j)\in A}x_{ij}-\sum_{(j,i)\in A}x_{ji}\left\{
|
|
\begin{array}{@{\ }rl}
|
|
\geq 0,&\hbox{for}\ i=s\\
|
|
=0,&\hbox{for all}\ i\in V\backslash\{s,t\}\\
|
|
\leq 0,&\hbox{for}\ i=t\\
|
|
\end{array}
|
|
\right.\eqno(8)
|
|
$$
|
|
$$0\leq x_{ij}\leq u_{ij}\ \ \ \hbox{for all}\ (i,j)\in A
|
|
\eqno(9)$$
|
|
|
|
\subsection{glp\_read\_maxflow --- read maximum flow problem data in
|
|
DIMACS\\format}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
int glp_read_maxflow(glp_graph *G, int *s, int *t, int a_cap,
|
|
const char *fname);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_read_maxflow| reads the maximum flow problem
|
|
data from a text file in DIMACS format.
|
|
|
|
The parameter \verb|G| specifies the graph object, to which the problem
|
|
data have to be stored. Note that before reading data the current
|
|
content of the graph object is completely erased with the routine
|
|
\verb|glp_erase_graph|.
|
|
|
|
The pointer \verb|s| specifies a location, to which the routine stores
|
|
the ordinal number of the source node. If \verb|s| is \verb|NULL|, the
|
|
source node number is not stored.
|
|
|
|
The pointer \verb|t| specifies a location, to which the routine stores
|
|
the ordinal number of the sink node. If \verb|t| is \verb|NULL|, the
|
|
sink node number is not stored.
|
|
|
|
The parameter \verb|a_cap| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, to which the routine stores
|
|
$u_{ij}$, the arc capacity. If \verb|a_cap| $<0$, the arc capacity is
|
|
not stored.
|
|
|
|
The character string \verb|fname| specifies the name of a text file to
|
|
be read in. (If the file name name ends with the suffix `\verb|.gz|',
|
|
the file is assumed to be compressed, in which case the routine
|
|
decompresses it ``on the fly''.)
|
|
|
|
\returns
|
|
|
|
If the operation was successful, the routine returns zero. Otherwise,
|
|
it prints an error message and returns non-zero.
|
|
|
|
\para{Example}
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
typedef struct
|
|
{ /* arc data block */
|
|
...
|
|
double cap;
|
|
...
|
|
} a_data;
|
|
|
|
int main(void)
|
|
{ glp_graph *G;
|
|
int s, t, ret;
|
|
G = glp_create_graph(..., sizeof(a_data));
|
|
ret = glp_read_maxflow(G, &s, &t, offsetof(a_data, cap),
|
|
"sample.max");
|
|
if (ret != 0) goto ...
|
|
...
|
|
}
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
\newpage
|
|
|
|
\para{DIMACS maximum flow problem format\footnote{This material is
|
|
based on the paper ``The First DIMACS International Algorithm
|
|
Implementation Challenge: Problem Definitions and Specifications'',
|
|
which is publically available at
|
|
\url{http://dimacs.rutgers.edu/Challenges/}.}}
|
|
\label{subsecmaxflow}
|
|
|
|
The DIMACS input file is a plain ASCII text file. It contains
|
|
{\it lines} of several types described below. A line is terminated with
|
|
an end-of-line character. Fields in each line are separated by at least
|
|
one blank space. Each line begins with a one-character designator to
|
|
identify the line type.
|
|
|
|
Note that DIMACS requires all numerical quantities to be integers in
|
|
the range $[-2^{31},\ 2^{31}-1]$ while GLPK allows the quantities to be
|
|
floating-point numbers.
|
|
|
|
\para{Comment lines.} Comment lines give human-readable information
|
|
about the file and are ignored by programs. Comment lines can appear
|
|
anywhere in the file. Each comment line begins with a lower-case
|
|
character \verb|c|.
|
|
|
|
\begin{verbatim}
|
|
c This is a comment line
|
|
\end{verbatim}
|
|
|
|
\para{Problem line.} There is one problem line per data file. The
|
|
problem line must appear before any node or arc descriptor lines.
|
|
It has the following format:
|
|
|
|
\begin{verbatim}
|
|
p max NODES ARCS
|
|
\end{verbatim}
|
|
|
|
\noindent
|
|
The lower-case character \verb|p| signifies that this is a problem line.
|
|
The three-character problem designator \verb|max| identifies the file as
|
|
containing specification information for the maximum flow problem. The
|
|
\verb|NODES| field contains an integer value specifying the number of
|
|
nodes in the network. The \verb|ARCS| field contains an integer value
|
|
specifying the number of arcs in the network.
|
|
|
|
\para{Node descriptors.} Two node descriptor lines for the source and
|
|
sink nodes must appear before all arc descriptor lines. They may appear
|
|
in either order, each with the following format:
|
|
|
|
\begin{verbatim}
|
|
n ID WHICH
|
|
\end{verbatim}
|
|
|
|
\noindent
|
|
The lower-case character \verb|n| signifies that this a node descriptor
|
|
line. The \verb|ID| field gives a node identification number,
|
|
an integer between 1 and \verb|NODES|. The \verb|WHICH| field gives
|
|
either a lower-case \verb|s| or \verb|t|, designating the source and
|
|
sink, respectively.
|
|
|
|
\para{Arc descriptors.} There is one arc descriptor line for each arc
|
|
in the network. Arc descriptor lines are of the following format:
|
|
|
|
\begin{verbatim}
|
|
a SRC DST CAP
|
|
\end{verbatim}
|
|
|
|
\noindent
|
|
The lower-case character \verb|a| signifies that this is an arc
|
|
descriptor line. For a directed arc $(i,j)$ the \verb|SRC| field gives
|
|
the identification number $i$ for the tail endpoint, and the \verb|DST|
|
|
field gives the identification number $j$ for the head endpoint.
|
|
Identification numbers are integers between 1 and \verb|NODES|. The
|
|
\verb|CAP| field gives the arc capacity, i.e. maximum amount of flow
|
|
that can be sent along arc $(i,j)$ in a feasible flow.
|
|
|
|
\para{Example.} Below here is an example of the data file in DIMACS
|
|
format corresponding to the maximum flow problem shown on Fig~2.
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
c sample.max
|
|
c
|
|
c This is an example of the maximum flow problem data
|
|
c in DIMACS format.
|
|
c
|
|
p max 9 14
|
|
c
|
|
n 1 s
|
|
n 9 t
|
|
c
|
|
a 1 2 14
|
|
a 1 4 23
|
|
a 2 3 10
|
|
a 2 4 9
|
|
a 3 5 12
|
|
a 3 8 18
|
|
a 4 5 26
|
|
a 5 2 11
|
|
a 5 6 25
|
|
a 5 7 4
|
|
a 6 7 7
|
|
a 6 8 8
|
|
a 7 9 15
|
|
a 8 9 20
|
|
c
|
|
c eof
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
\subsection{glp\_write\_maxflow --- write maximum flow problem data in
|
|
DIMACS\\format}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap,
|
|
const char *fname);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_write_maxflow| writes the maximum flow problem
|
|
data to a text file in DIMACS format.
|
|
|
|
The parameter \verb|G| is the graph (network) program object, which
|
|
specifies the maximum flow problem instance.
|
|
|
|
The parameter \verb|s| specifies the ordinal number of the source node.
|
|
|
|
The parameter \verb|t| specifies the ordinal number of the sink node.
|
|
|
|
The parameter \verb|a_cap| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, which contains $u_{ij}$, the upper
|
|
bound to the arc flow (the arc capacity). If the upper bound is
|
|
specified as \verb|DBL_MAX|, it is assumed that $u_{ij}=\infty$, i.e.
|
|
the arc is uncapacitated. If \verb|a_cap| $<0$, it is assumed that
|
|
$u_{ij}=1$ for all arcs.
|
|
|
|
The character string \verb|fname| specifies a name of the text file to
|
|
be written out. (If the file name ends with suffix `\verb|.gz|', the
|
|
file is assumed to be compressed, in which case the routine performs
|
|
automatic compression on writing it.)
|
|
|
|
\returns
|
|
|
|
If the operation was successful, the routine returns zero. Otherwise,
|
|
it prints an error message and returns non-zero.
|
|
|
|
\newpage
|
|
|
|
\subsection{glp\_maxflow\_lp --- convert maximum flow problem to LP}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
void glp_maxflow_lp(glp_prob *P, glp_graph *G, int names, int s, int t,
|
|
int a_cap);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_maxflow_lp| builds LP problem (7)---(9), which
|
|
corresponds to the specified maximum flow problem.
|
|
|
|
The parameter \verb|P| is the resultant LP problem object to be built.
|
|
Note that on entry its current content is erased with the routine
|
|
\verb|glp_erase_prob|.
|
|
|
|
The parameter \verb|G| is the graph (network) program object, which
|
|
specifies the maximum flow problem instance.
|
|
|
|
The parameter \verb|names| is a flag. If it is \verb|GLP_ON|, the
|
|
routine uses symbolic names of the graph object components to assign
|
|
symbolic names to the LP problem object components. If the flag is
|
|
\verb|GLP_OFF|, no symbolic names are assigned.
|
|
|
|
The parameter \verb|s| specifies the ordinal number of the source node.
|
|
|
|
The parameter \verb|t| specifies the ordinal number of the sink node.
|
|
|
|
The parameter \verb|a_cap| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, which contains $u_{ij}$, the upper
|
|
bound to the arc flow (the arc capacity). If the upper bound is
|
|
specified as \verb|DBL_MAX|, it is assumed that $u_{ij}=\infty$, i.e.
|
|
the arc is uncapacitated. If \verb|a_cap| $<0$, it is assumed that
|
|
$u_{ij}=1$ for all arcs.
|
|
|
|
\para{Example}
|
|
|
|
The example program below reads the maximum flow problem in DIMACS
|
|
format from file `\verb|sample.max|', converts the instance to LP, and
|
|
then writes the resultant LP in CPLEX format to file
|
|
`\verb|maxflow.lp|'.
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
#include <stddef.h>
|
|
#include <glpk.h>
|
|
|
|
int main(void)
|
|
{ glp_graph *G;
|
|
glp_prob *P;
|
|
int s, t;
|
|
G = glp_create_graph(0, sizeof(double));
|
|
glp_read_maxflow(G, &s, &t, 0, "sample.max");
|
|
P = glp_create_prob();
|
|
glp_maxflow_lp(P, G, GLP_ON, s, t, 0);
|
|
glp_delete_graph(G);
|
|
glp_write_lp(P, NULL, "maxflow.lp");
|
|
glp_delete_prob(P);
|
|
return 0;
|
|
}
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
If `\verb|sample.max|' is the example data file from the previous
|
|
subsection, the output `\verb|maxflow.lp|' may look like follows:
|
|
|
|
\newpage
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
Maximize
|
|
obj: + x(1,4) + x(1,2)
|
|
|
|
Subject To
|
|
r_1: + x(1,2) + x(1,4) >= 0
|
|
r_2: - x(5,2) + x(2,3) + x(2,4) - x(1,2) = 0
|
|
r_3: + x(3,5) + x(3,8) - x(2,3) = 0
|
|
r_4: + x(4,5) - x(2,4) - x(1,4) = 0
|
|
r_5: + x(5,2) + x(5,6) + x(5,7) - x(4,5) - x(3,5) = 0
|
|
r_6: + x(6,7) + x(6,8) - x(5,6) = 0
|
|
r_7: + x(7,9) - x(6,7) - x(5,7) = 0
|
|
r_8: + x(8,9) - x(6,8) - x(3,8) = 0
|
|
r_9: - x(8,9) - x(7,9) <= 0
|
|
|
|
Bounds
|
|
0 <= x(1,4) <= 23
|
|
0 <= x(1,2) <= 14
|
|
0 <= x(2,4) <= 9
|
|
0 <= x(2,3) <= 10
|
|
0 <= x(3,8) <= 18
|
|
0 <= x(3,5) <= 12
|
|
0 <= x(4,5) <= 26
|
|
0 <= x(5,7) <= 4
|
|
0 <= x(5,6) <= 25
|
|
0 <= x(5,2) <= 11
|
|
0 <= x(6,8) <= 8
|
|
0 <= x(6,7) <= 7
|
|
0 <= x(7,9) <= 15
|
|
0 <= x(8,9) <= 20
|
|
|
|
End
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
\subsection{glp\_maxflow\_ffalg --- solve maximum flow problem with
|
|
Ford-Fulkerson\\algorithm}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
int glp_maxflow_ffalg(glp_graph *G, int s, int t, int a_cap, double *sol,
|
|
int a_x, int v_cut);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_mincost_ffalg| finds optimal solution to the
|
|
maximum flow problem with the Ford-Fulkerson algorithm.\footnote{GLPK
|
|
implementation of the Ford-Fulkerson algorithm is based on the
|
|
following book: L.~R.~Ford,~Jr., and D.~R.~Fulkerson, ``Flows in
|
|
Networks,'' The RAND Corp., Report R-375-PR (August 1962), Chap. I
|
|
``Static Maximal Flow,'' pp.~30-33.} Note that this routine requires
|
|
all the problem data to be integer-valued.
|
|
|
|
The parameter \verb|G| is a graph (network) program object which
|
|
specifies the maximum flow problem instance to be solved.
|
|
|
|
The parameter $s$ specifies the ordinal number of the source node.
|
|
|
|
\newpage
|
|
|
|
The parameter $t$ specifies the ordinal number of the sink node.
|
|
|
|
The parameter \verb|a_cap| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, which contains $u_{ij}$, the upper
|
|
bound to the arc flow (the arc capacity). This bound must be integer in
|
|
the range [0, \verb|INT_MAX|]. If \verb|a_cap| $<0$, it is assumed that
|
|
$u_{ij}=1$ for all arcs.
|
|
|
|
The parameter \verb|sol| specifies a location, to which the routine
|
|
stores the objective value (that is, the total flow from $s$ to $t$)
|
|
found. If \verb|sol| is NULL, the objective value is not stored.
|
|
|
|
The parameter \verb|a_x| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, to which the routine stores
|
|
$x_{ij}$, the arc flow found. If \verb|a_x| $<0$, the arc flow values
|
|
are not stored.
|
|
|
|
The parameter \verb|v_cut| specifies an offset of the field of type
|
|
\verb|int| in the vertex data block, to which the routine stores node
|
|
flags corresponding to the optimal solution found: if the node flag is
|
|
1, the node is labelled, and if the node flag is 0, the node is
|
|
unlabelled. The calling program may use these node flags to determine
|
|
the {\it minimal cut}, which is a subset of arcs whose one endpoint is
|
|
labelled and other is not. If \verb|v_cut| $<0$, the node flags are not
|
|
stored.
|
|
|
|
Note that all solution components (the objective value and arc flows)
|
|
computed by the routine are always integer-valued.
|
|
|
|
\returns
|
|
|
|
\begin{retlist}
|
|
0 & Optimal solution found.\\
|
|
|
|
\verb|GLP_EDATA| & Unable to start the search, because some problem
|
|
data are either not integer-valued or out of range.\\
|
|
\end{retlist}
|
|
|
|
\para{Example}
|
|
|
|
The example program shown below reads the maximum flow problem instance
|
|
in DIMACS format from file `\verb|sample.max|', solves it using the
|
|
routine \verb|glp_maxflow_ffalg|, and write the solution found to the
|
|
standard output.
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <glpk.h>
|
|
|
|
typedef struct { int cut; } v_data;
|
|
typedef struct { double cap, x; } a_data;
|
|
|
|
#define node(v) ((v_data *)((v)->data))
|
|
#define arc(a) ((a_data *)((a)->data))
|
|
|
|
int main(void)
|
|
{ glp_graph *G;
|
|
glp_vertex *v, *w;
|
|
glp_arc *a;
|
|
int i, s, t, ret;
|
|
double sol;
|
|
G = glp_create_graph(sizeof(v_data), sizeof(a_data));
|
|
glp_read_maxflow(G, &s, &t, offsetof(a_data, cap),
|
|
"sample.max");
|
|
ret = glp_maxflow_ffalg(G, s, t, offsetof(a_data, cap),
|
|
&sol, offsetof(a_data, x), offsetof(v_data, cut));
|
|
printf("ret = %d; sol = %5g\n", ret, sol);
|
|
for (i = 1; i <= G->nv; i++)
|
|
{ v = G->v[i];
|
|
for (a = v->out; a != NULL; a = a->t_next)
|
|
{ w = a->head;
|
|
printf("x[%d->%d] = %5g (%d)\n", v->i, w->i,
|
|
arc(a)->x, node(v)->cut ^ node(w)->cut);
|
|
}
|
|
}
|
|
glp_delete_graph(G);
|
|
return 0;
|
|
}
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
If `\verb|sample.max|' is the example data file from the subsection
|
|
describing \verb|glp_read_maxflow|, the output may look like follows:
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
Reading maximum flow problem data from `sample.max'...
|
|
Flow network has 9 nodes and 14 arcs
|
|
24 lines were read
|
|
ret = 0; sol = 29
|
|
x[1->4] = 19 (0)
|
|
x[1->2] = 10 (0)
|
|
x[2->4] = 0 (0)
|
|
x[2->3] = 10 (1)
|
|
x[3->8] = 10 (0)
|
|
x[3->5] = 0 (1)
|
|
x[4->5] = 19 (0)
|
|
x[5->7] = 4 (1)
|
|
x[5->6] = 15 (0)
|
|
x[5->2] = 0 (0)
|
|
x[6->8] = 8 (1)
|
|
x[6->7] = 7 (1)
|
|
x[7->9] = 11 (0)
|
|
x[8->9] = 18 (0)
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
\subsection{glp\_rmfgen --- Goldfarb's maximum flow problem generator}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
int glp_rmfgen(glp_graph *G, int *s, int *t, int a_cap, const int parm[1+5]);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_rmfgen| is a GLPK version of the maximum flow
|
|
problem generator developed by D.~Goldfarb and
|
|
M.~Grigoriadis.\footnote{D.~Goldfarb and M.~D.~Grigoriadis,
|
|
``A computational comparison of the Dinic and network simplex methods
|
|
for maximum flow.'' Annals of Op. Res. 13 (1988),
|
|
pp.~83-123.}$^{,}$\footnote{U.~Derigs and W.~Meier, ``Implementing
|
|
Goldberg's max-flow algorithm: A computational investigation.''
|
|
Zeitschrift f\"ur Operations Research 33 (1989),
|
|
pp.~383-403.}$^{,}$\footnote{The original code of RMFGEN implemented by
|
|
Tamas Badics is publically available from
|
|
\url{ftp://dimacs.rutgers.edu/pub/netflow/generators/network/genrmf}.}
|
|
|
|
The parameter \verb|G| specifies the graph object, to which the
|
|
generated problem data have to be stored. Note that on entry the graph
|
|
object is erased with the routine \verb|glp_erase_graph|.
|
|
|
|
\newpage
|
|
|
|
The pointers \verb|s| and \verb|t| specify locations, to which the
|
|
routine stores the source and sink node numbers, respectively. If
|
|
\verb|s| or \verb|t| is \verb|NULL|, corresponding node number is not
|
|
stored.
|
|
|
|
The parameter \verb|a_cap| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, to which the routine stores the arc
|
|
capacity. If \verb|a_cap| $<0$, the capacity is not stored.
|
|
|
|
The array \verb|parm| contains description of the network to be
|
|
generated:
|
|
|
|
\begin{tabular}{@{}lll@{}}
|
|
\verb|parm[0]|& ¬ used\\
|
|
\verb|parm[1]|&\verb|seed|&random number seed (a positive integer)\\
|
|
\verb|parm[2]|&\verb|a |&frame size\\
|
|
\verb|parm[3]|&\verb|b |&depth\\
|
|
\verb|parm[4]|&\verb|c1 |&minimal arc capacity\\
|
|
\verb|parm[5]|&\verb|c2 |&maximal arc capacity\\
|
|
\end{tabular}
|
|
|
|
\returns
|
|
|
|
If the instance was successfully generated, the routine
|
|
\verb|glp_netgen| returns zero; otherwise, if specified parameters are
|
|
inconsistent, the routine returns a non-zero error code.
|
|
|
|
\para{Comments\footnote{This material is based on comments to the
|
|
original version of RMFGEN.}}
|
|
|
|
The generated network is as follows. It has $b$ pieces of frames of
|
|
size $a\times a$. (So alltogether the number of vertices is
|
|
$a\times a\times b$.)
|
|
|
|
In each frame all the vertices are connected with their neighbours
|
|
(forth and back). In addition the vertices of a frame are connected
|
|
one to one with the vertices of next frame using a random permutation
|
|
of those vertices.
|
|
|
|
The source is the lower left vertex of the first frame, the sink is
|
|
the upper right vertex of the $b$-th frame.
|
|
|
|
\begin{verbatim}
|
|
t
|
|
+-------+
|
|
| .|
|
|
| . |
|
|
/ | / |
|
|
+-------+/ -+ b
|
|
| | |/.
|
|
a | -v- |/
|
|
| | |/
|
|
+-------+ 1
|
|
s a
|
|
\end{verbatim}
|
|
|
|
The capacities are randomly chosen integers from the range of
|
|
$[c_1,c_2]$ in the case of interconnecting edges, and $c_2\cdot a^2$
|
|
for the in-frame edges.
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
\newpage
|
|
|
|
\section{Assignment problem}
|
|
|
|
\subsection{Background}
|
|
|
|
Let there be given an undirected bipartite graph $G=(R\cup S,E)$, where
|
|
$R$ and $S$ are disjoint sets of vertices (nodes), and
|
|
$E\subseteq R\times S$ is a set of edges. Let also for each edge
|
|
$e=(i,j)\in E$ there be given its cost $c_{ij}$. A {\it matching}
|
|
(which in case of bipartite graph is also called {\it assignment})
|
|
$M\subseteq E$ in $G$ is a set of pairwise non-adjacent edges, that is,
|
|
no two edges in $M$ share a common vertex. A matching, which matches
|
|
all vertices of the graph, is called a {\it perfect matching}.
|
|
Obviously, a perfect matching in bipartite graph $G=(R\cup S,E)$
|
|
defines some bijection $R\leftrightarrow S$.
|
|
|
|
The {\it assignment problem} has two different variants. In the first
|
|
variant the problem is to find matching (assignment) $M$, which
|
|
maximizes the sum:
|
|
$$\sum_{(i,j)\in M}c_{ij}\eqno(10)$$
|
|
(so this variant is also called the {\it maximum weighted bipartite
|
|
matching problem} or, if all $c_{ij}=1$, the {\it maximum cardinality
|
|
bipartite matching problem}). In the second, classic variant the
|
|
problem is to find {\it perfect} matching (assignment) $M$, which
|
|
minimizes or maximizes the sum (10).
|
|
|
|
An example of the assignment problem, which is the maximum weighted
|
|
bipartite matching problem, is shown on Fig. 3.
|
|
|
|
The maximum weighted bipartite matching problem can be naturally
|
|
formulated as the following LP problem:
|
|
|
|
\noindent
|
|
\hspace{1in}maximize
|
|
$$z=\sum_{(i,j)\in E}c_{ij}x_{ij}\eqno(11)$$
|
|
\hspace{1in}subject to
|
|
$$\sum_{(i,j)\in E}x_{ij}\leq 1\ \ \ \hbox{for all}\ i\in R\eqno(12)$$
|
|
$$\sum_{(i,j)\in E}x_{ij}\leq 1\ \ \ \hbox{for all}\ j\in S\eqno(13)$$
|
|
$$\ \ \ \ \ \ \ \ 0\leq x_{ij}\leq 1\ \ \ \hbox{for all}\ (i,j)\in E
|
|
\eqno(14)$$
|
|
|
|
\noindent
|
|
where $x_{ij}=1$ means that $(i,j)\in M$, and $x_{ij}=0$ means that
|
|
$(i,j)\notin M$.\footnote{The constraint matrix of LP formulation
|
|
(11)---(14) is totally unimodular, due to which $x_{ij}\in\{0,1\}$ for
|
|
any basic solution.}
|
|
|
|
\newpage
|
|
|
|
\noindent\hfil
|
|
\xymatrix @C=48pt
|
|
{v_1\ar@{-}[rr]|{_{13}}\ar@{-}[rrd]|{_{21}}\ar@{-}[rrddd]|(.2){_{20}}&&
|
|
v_9\\
|
|
v_2\ar@{-}[rr]|{_{12}}\ar@{-}[rrdd]|(.3){_{8}}
|
|
\ar@{-}[rrddd]|(.4){_{26}}&&v_{10}\\
|
|
v_3\ar@{-}[rr]|(.2){_{22}}\ar@{-}[rrdd]|(.3){_{11}}&&v_{11}\\
|
|
v_4\ar@{-}[rruuu]|(.6){_{12}}\ar@{-}[rr]|(.2){_{36}}
|
|
\ar@{-}[rrdd]|(.7){_{25}}&&v_{12}\\
|
|
v_5\ar@{-}[rruu]|(.42){_{41}}\ar@{-}[rru]|(.4){_{40}}
|
|
\ar@{-}[rr]|(.75){_{11}}\ar@{-}[rrd]|(.6){_{4}}\ar@{-}[rrdd]|{_{8}}
|
|
\ar@{-}[rrddd]|{_{35}}\ar@{-}[rrdddd]|{_{32}}&&v_{13}\\
|
|
v_6\ar@{-}[rruuuuu]|(.7){_{13}}&&v_{14}\\
|
|
v_7\ar@{-}[rruuuuu]|(.15){_{19}}&&v_{15}\\
|
|
v_8\ar@{-}[rruuuuuu]|(.25){_{39}}\ar@{-}[rruuuuu]|(.65){_{15}}&&
|
|
v_{16}\\
|
|
&&v_{17}\\
|
|
}
|
|
|
|
\medskip
|
|
|
|
\noindent\hfil
|
|
Fig.~3. An example of the assignment problem.
|
|
|
|
\medskip
|
|
|
|
Similarly, the perfect assignment problem can be naturally formulated
|
|
as the following LP problem:
|
|
|
|
\noindent
|
|
\hspace{1in}minimize (or maximize)
|
|
$$z=\sum_{(i,j)\in E}c_{ij}x_{ij}\eqno(15)$$
|
|
\hspace{1in}subject to
|
|
$$\sum_{(i,j)\in E}x_{ij}=1\ \ \ \hbox{for all}\ i\in R\eqno(16)$$
|
|
$$\sum_{(i,j)\in E}x_{ij}=1\ \ \ \hbox{for all}\ j\in S\eqno(17)$$
|
|
$$\ \ \ \ \ \ \ \ 0\leq x_{ij}\leq 1\ \ \ \hbox{for all}\ (i,j)\in E
|
|
\eqno(18)$$
|
|
|
|
\noindent
|
|
where variables $x_{ij}$ have the same meaning as for (11)---(14)
|
|
above.
|
|
|
|
In GLPK an undirected bipartite graph $G=(R\cup S,E)$ is represented as
|
|
directed graph $\overline{G}=(V,A)$, where $V=R\cup S$ and
|
|
$A=\{(i,j):(i,j)\in E\}$, i.e. every edge $(i,j)\in E$ in $G$
|
|
corresponds to arc $(i\rightarrow j)\in A$ in $\overline{G}$.
|
|
|
|
\subsection{glp\_read\_asnprob --- read assignment problem data in
|
|
DIMACS format}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
int glp_read_asnprob(glp_graph *G, int v_set, int a_cost, const char *fname);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_read_asnprob| reads the assignment problem data
|
|
from a text file in DIMACS format.
|
|
|
|
The parameter \verb|G| specifies the graph object, to which the problem
|
|
data have to be stored. Note that before reading data the current
|
|
content of the graph object is completely erased with the routine
|
|
\verb|glp_erase_graph|.
|
|
|
|
The parameter \verb|v_set| specifies an offset of the field of type
|
|
\verb|int| in the vertex data block, to which the routine stores the
|
|
node set indicator:
|
|
|
|
0 --- the node is in set $R$;
|
|
|
|
1 --- the node is in set $S$.
|
|
|
|
\noindent
|
|
If \verb|v_set| $<0$, the node set indicator is not stored.
|
|
|
|
The parameter \verb|a_cost| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, to which the routine stores the
|
|
edge cost $c_{ij}$. If \verb|a_cost| $<0$, the edge cost is not stored.
|
|
|
|
The character string \verb|fname| specifies the name of a text file to
|
|
be read in. (If the file name name ends with the suffix `\verb|.gz|',
|
|
the file is assumed to be compressed, in which case the routine
|
|
decompresses it ``on the fly''.)
|
|
|
|
\returns
|
|
|
|
If the operation was successful, the routine returns zero. Otherwise,
|
|
it prints an error message and returns non-zero.
|
|
|
|
\para{Example.} Below here is an example program that read the
|
|
assignment problem data in DIMACS format from a text file
|
|
`\verb|sample.asn|'.
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
typedef struct
|
|
{ /* vertex data block */
|
|
...
|
|
int set;
|
|
...
|
|
} v_data;
|
|
|
|
typedef struct
|
|
{ /* arc data block */
|
|
...
|
|
double cost;
|
|
...
|
|
} a_data;
|
|
|
|
int main(void)
|
|
{ glp_graph *G;
|
|
int ret;
|
|
G = glp_create_graph(sizeof(v_data), sizeof(a_data));
|
|
ret = glp_read_asnprob(G, offsetof(v_data, set),
|
|
offsetof(a_data, cost), "sample.asn");
|
|
if (ret != 0) goto ...
|
|
...
|
|
}
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
\para{DIMACS assignment problem format\footnote{This material is based
|
|
on the paper ``The First DIMACS International Algorithm Implementation
|
|
Challenge: Problem Definitions and Specifications'', which is
|
|
publically available at \url{http://dimacs.rutgers.edu/Challenges/}.}}
|
|
\label{subsecasnprob}
|
|
|
|
The DIMACS input file is a plain ASCII text file. It contains
|
|
{\it lines} of several types described below. A line is terminated with
|
|
an end-of-line character. Fields in each line are separated by at least
|
|
one blank space. Each line begins with a one-character designator to
|
|
identify the line type.
|
|
|
|
Note that DIMACS requires all numerical quantities to be integers in
|
|
the range $[-2^{31},\ 2^{31}-1]$ while GLPK allows the quantities to be
|
|
floating-point numbers.
|
|
|
|
\para{Comment lines.} Comment lines give human-readable information
|
|
about the file and are ignored by programs. Comment lines can appear
|
|
anywhere in the file. Each comment line begins with a lower-case
|
|
character \verb|c|.
|
|
|
|
\begin{verbatim}
|
|
c This is a comment line
|
|
\end{verbatim}
|
|
|
|
\para{Problem line.} There is one problem line per data file. The
|
|
problem line must appear before any node or arc descriptor lines. It
|
|
has the following format:
|
|
|
|
\begin{verbatim}
|
|
p asn NODES EDGES
|
|
\end{verbatim}
|
|
|
|
\noindent
|
|
The lower-case character \verb|p| signifies that this is a problem line.
|
|
The three-character problem designator \verb|asn| identifies the file as
|
|
containing specification information for the assignment problem.
|
|
The \verb|NODES| field contains an integer value specifying the total
|
|
number of nodes in the graph (i.e. in both sets $R$ and $S$). The
|
|
\verb|EDGES| field contains an integer value specifying the number of
|
|
edges in the graph.
|
|
|
|
\para{Node descriptors.} All node descriptor lines must appear before
|
|
all edge descriptor lines. The node descriptor lines lists the nodes in
|
|
set $R$ only, and all other nodes are assumed to be in set $S$. There
|
|
is one node descriptor line for each such node, with the following
|
|
format:
|
|
|
|
\begin{verbatim}
|
|
n ID
|
|
\end{verbatim}
|
|
|
|
\noindent
|
|
The lower-case character \verb|n| signifies that this is a node
|
|
descriptor line. The \verb|ID| field gives a node identification number,
|
|
an integer between 1 and \verb|NODES|.
|
|
|
|
\para{Edge descriptors.} There is one edge descriptor line for each
|
|
edge in the graph. Edge descriptor lines are of the following format:
|
|
|
|
\begin{verbatim}
|
|
a SRC DST COST
|
|
\end{verbatim}
|
|
|
|
\noindent
|
|
The lower-case character \verb|a| signifies that this is an edge
|
|
descriptor line. For each edge $(i,j)$, where $i\in R$ and $j\in S$,
|
|
the \verb|SRC| field gives the identification number of vertex $i$, and
|
|
the \verb|DST| field gives the identification number of vertex $j$.
|
|
Identification numbers are integers between 1 and \verb|NODES|. The
|
|
\verb|COST| field contains the cost of edge $(i,j)$.
|
|
|
|
\para{Example.} Below here is an example of the data file in DIMACS
|
|
format corresponding to the assignment problem shown on Fig~3.
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
c sample.asn
|
|
c
|
|
c This is an example of the assignment problem data
|
|
c in DIMACS format.
|
|
c
|
|
p asn 17 22
|
|
c
|
|
n 1
|
|
n 2
|
|
n 3
|
|
n 4
|
|
n 5
|
|
n 6
|
|
n 7
|
|
n 8
|
|
c
|
|
a 1 9 13
|
|
a 1 10 21
|
|
a 1 12 20
|
|
a 2 10 12
|
|
a 2 12 8
|
|
a 2 13 26
|
|
a 3 11 22
|
|
a 3 13 11
|
|
a 4 9 12
|
|
a 4 12 36
|
|
a 4 14 25
|
|
a 5 11 41
|
|
a 5 12 40
|
|
a 5 13 11
|
|
a 5 14 4
|
|
a 5 15 8
|
|
a 5 16 35
|
|
a 5 17 32
|
|
a 6 9 13
|
|
a 7 10 19
|
|
a 8 10 39
|
|
a 8 11 15
|
|
c
|
|
c eof
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
\newpage
|
|
|
|
\subsection{glp\_write\_asnprob --- write assignment problem data in
|
|
DIMACS format}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
int glp_write_asnprob(glp_graph *G, int v_set, int a_cost, const char *fname);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_write_asnprob| writes the assignment problem data
|
|
to a text file in DIMACS format.
|
|
|
|
The parameter \verb|G| is the graph program object, which specifies the
|
|
assignment problem instance.
|
|
|
|
The parameter \verb|v_set| specifies an offset of the field of type
|
|
\verb|int| in the vertex data block, which contains the node set
|
|
indicator:
|
|
|
|
0 --- the node is in set $R$;
|
|
|
|
1 --- the node is in set $S$.
|
|
|
|
\noindent
|
|
If \verb|v_set| $<0$, it is assumed that a node having no incoming arcs
|
|
is in set $R$, and a node having no outgoing arcs is in set $S$.
|
|
|
|
The parameter \verb|a_cost| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, which contains $c_{ij}$, the edge
|
|
cost. If \verb|a_cost| $<0$, it is assumed that $c_{ij}=1$ for all
|
|
edges.
|
|
|
|
The character string \verb|fname| specifies a name of the text file to
|
|
be written out. (If the file name ends with suffix `\verb|.gz|', the
|
|
file is assumed to be compressed, in which case the routine performs
|
|
automatic compression on writing it.)
|
|
|
|
\para{Note}
|
|
|
|
The routine \verb|glp_write_asnprob| does not check that the specified
|
|
graph object correctly represents a bipartite graph. To make sure that
|
|
the problem data are correct, use the routine \verb|glp_check_asnprob|.
|
|
|
|
\returns
|
|
|
|
If the operation was successful, the routine returns zero. Otherwise,
|
|
it prints an error message and returns non-zero.
|
|
|
|
\vspace*{-4pt}
|
|
|
|
\subsection{glp\_check\_asnprob --- check correctness of assignment
|
|
problem data}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
int glp_check_asnprob(glp_graph *G, int v_set);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_check_asnprob| checks that the specified graph
|
|
object \verb|G| correctly represents a bipartite graph.
|
|
|
|
The parameter \verb|v_set| specifies an offset of the field of type
|
|
\verb|int| in the vertex data block, which contains the node set
|
|
indicator:
|
|
|
|
0 --- the node is in set $R$;
|
|
|
|
1 --- the node is in set $S$.
|
|
|
|
\noindent
|
|
If \verb|v_set| $<0$, it is assumed that a node having no incoming arcs
|
|
is in set $R$, and a node having no outgoing arcs is in set $S$.
|
|
|
|
\returns
|
|
|
|
0 --- the data are correct;
|
|
|
|
1 --- the set indicator of some node is 0, however, that node has one
|
|
or more incoming arcs;
|
|
|
|
2 --- the set indicator of some node is 1, however, that node has one
|
|
or more outgoing arcs;
|
|
|
|
3 --- the set indicator of some node is invalid (neither 0 nor 1);
|
|
|
|
4 --- some node has both incoming and outgoing arcs.
|
|
|
|
\subsection{glp\_asnprob\_lp --- convert assignment problem to LP}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
int glp_asnprob_lp(glp_prob *P, int form, glp_graph *G, int names, int v_set,
|
|
int a_cost);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_asnprob_lp| builds LP problem, which corresponds
|
|
to the specified assignment problem.
|
|
|
|
The parameter \verb|P| is the resultant LP problem object to be built.
|
|
Note that on entry its current content is erased with the routine
|
|
\verb|glp_erase_prob|.
|
|
|
|
The parameter \verb|form| defines which LP formulation should be used:
|
|
|
|
\verb|GLP_ASN_MIN| --- perfect matching (15)---(18), minimization;
|
|
|
|
\verb|GLP_ASN_MAX| --- perfect matching (15)---(18), maximization;
|
|
|
|
\verb|GLP_ASN_MMP| --- maximum weighted matching (11)---(14).
|
|
|
|
The parameter \verb|G| is the graph program object, which specifies the
|
|
assignment problem instance.
|
|
|
|
The parameter \verb|names| is a flag. If it is \verb|GLP_ON|, the
|
|
routine uses symbolic names of the graph object components to assign
|
|
symbolic names to the LP problem object components. If the \verb|flag|
|
|
is \verb|GLP_OFF|, no symbolic names are assigned.
|
|
|
|
The parameter \verb|v_set| specifies an offset of the field of type
|
|
\verb|int| in the vertex data block, which contains the node set
|
|
indicator:
|
|
|
|
0 --- the node is in set $R$;
|
|
|
|
1 --- the node is in set $S$.
|
|
|
|
\noindent
|
|
If \verb|v_set| $<0$, it is assumed that a node having no incoming arcs
|
|
is in set $R$, and a node having no outgoing arcs is in set $S$.
|
|
|
|
The parameter \verb|a_cost| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, which contains $c_{ij}$, the edge
|
|
cost. If \verb|a_cost| $<0$, it is assumed that $c_{ij}=1$ for all
|
|
edges.
|
|
|
|
\newpage
|
|
|
|
\returns
|
|
|
|
If the LP problem has been successfully built, the routine
|
|
\verb|glp_asnprob_lp| returns zero, otherwise, non-zero (see the
|
|
routine \verb|glp_check_asnprob|).
|
|
|
|
\para{Example}
|
|
|
|
The example program below reads the assignment problem instance in
|
|
DIMACS format from file `\verb|sample.asn|', converts the instance to
|
|
LP (11)---(14), and writes the resultant LP in CPLEX format to file
|
|
`\verb|matching.lp|'.
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
#include <stddef.h>
|
|
#include <glpk.h>
|
|
|
|
typedef struct { int set; } v_data;
|
|
typedef struct { double cost; } a_data;
|
|
|
|
int main(void)
|
|
{ glp_graph *G;
|
|
glp_prob *P;
|
|
G = glp_create_graph(sizeof(v_data), sizeof(a_data));
|
|
glp_read_asnprob(G, offsetof(v_data, set),
|
|
offsetof(a_data, cost), "sample.asn");
|
|
P = glp_create_prob();
|
|
glp_asnprob_lp(P, GLP_ASN_MMP, G, GLP_ON,
|
|
offsetof(v_data, set), offsetof(a_data, cost));
|
|
glp_delete_graph(G);
|
|
glp_write_lp(P, NULL, "matching.lp");
|
|
glp_delete_prob(P);
|
|
return 0;
|
|
}
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
If `\verb|sample.asn|' is the example data file from the subsection
|
|
describing \verb|glp_read_asnprob|, file `\verb|matching.lp|' may look
|
|
like follows:
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
Maximize
|
|
obj: + 20 x(1,12) + 21 x(1,10) + 13 x(1,9) + 26 x(2,13) + 8 x(2,12)
|
|
+ 12 x(2,10) + 11 x(3,13) + 22 x(3,11) + 25 x(4,14) + 36 x(4,12)
|
|
+ 12 x(4,9) + 32 x(5,17) + 35 x(5,16) + 8 x(5,15) + 4 x(5,14)
|
|
+ 11 x(5,13) + 40 x(5,12) + 41 x(5,11) + 13 x(6,9) + 19 x(7,10)
|
|
+ 15 x(8,11) + 39 x(8,10)
|
|
|
|
Subject To
|
|
r_1: + x(1,9) + x(1,10) + x(1,12) <= 1
|
|
r_2: + x(2,10) + x(2,12) + x(2,13) <= 1
|
|
r_3: + x(3,11) + x(3,13) <= 1
|
|
r_4: + x(4,9) + x(4,12) + x(4,14) <= 1
|
|
r_5: + x(5,11) + x(5,12) + x(5,13) + x(5,14) + x(5,15) + x(5,16)
|
|
+ x(5,17) <= 1
|
|
r_6: + x(6,9) <= 1
|
|
r_7: + x(7,10) <= 1
|
|
r_8: + x(8,10) + x(8,11) <= 1
|
|
r_9: + x(6,9) + x(4,9) + x(1,9) <= 1
|
|
r_10: + x(8,10) + x(7,10) + x(2,10) + x(1,10) <= 1
|
|
r_11: + x(8,11) + x(5,11) + x(3,11) <= 1
|
|
r_12: + x(5,12) + x(4,12) + x(2,12) + x(1,12) <= 1
|
|
r_13: + x(5,13) + x(3,13) + x(2,13) <= 1
|
|
r_14: + x(5,14) + x(4,14) <= 1
|
|
r_15: + x(5,15) <= 1
|
|
r_16: + x(5,16) <= 1
|
|
r_17: + x(5,17) <= 1
|
|
|
|
Bounds
|
|
0 <= x(1,12) <= 1
|
|
0 <= x(1,10) <= 1
|
|
0 <= x(1,9) <= 1
|
|
0 <= x(2,13) <= 1
|
|
0 <= x(2,12) <= 1
|
|
0 <= x(2,10) <= 1
|
|
0 <= x(3,13) <= 1
|
|
0 <= x(3,11) <= 1
|
|
0 <= x(4,14) <= 1
|
|
0 <= x(4,12) <= 1
|
|
0 <= x(4,9) <= 1
|
|
0 <= x(5,17) <= 1
|
|
0 <= x(5,16) <= 1
|
|
0 <= x(5,15) <= 1
|
|
0 <= x(5,14) <= 1
|
|
0 <= x(5,13) <= 1
|
|
0 <= x(5,12) <= 1
|
|
0 <= x(5,11) <= 1
|
|
0 <= x(6,9) <= 1
|
|
0 <= x(7,10) <= 1
|
|
0 <= x(8,11) <= 1
|
|
0 <= x(8,10) <= 1
|
|
|
|
End
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
\subsection{glp\_asnprob\_okalg --- solve assignment problem with
|
|
out-of-kilter\\algorithm}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
int glp_asnprob_okalg(int form, glp_graph *G, int v_set, int a_cost,
|
|
double *sol, int a_x);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_mincost_okalg| finds optimal solution to the
|
|
assignment problem with the out-of-kilter
|
|
algorithm.\footnote{GLPK implementation of the out-of-kilter algorithm
|
|
is based on the following book: L.~R.~Ford,~Jr., and D.~R.~Fulkerson,
|
|
``Flows in Networks,'' The RAND Corp., Report R-375-PR (August 1962),
|
|
Chap. III ``Minimal Cost Flow Problems,'' pp.~113-26.} Note that this
|
|
routine requires all the problem data to be integer-valued.
|
|
|
|
The parameter \verb|form| defines which LP formulation should be used:
|
|
|
|
\verb|GLP_ASN_MIN| --- perfect matching (15)---(18), minimization;
|
|
|
|
\verb|GLP_ASN_MAX| --- perfect matching (15)---(18), maximization;
|
|
|
|
\verb|GLP_ASN_MMP| --- maximum weighted matching (11)---(14).
|
|
|
|
\newpage
|
|
|
|
The parameter \verb|G| is the graph program object, which specifies the
|
|
assignment problem instance.
|
|
|
|
The parameter \verb|v_set| specifies an offset of the field of type
|
|
\verb|int| in the vertex data block, which contains the node set
|
|
indicator:
|
|
|
|
0 --- the node is in set $R$;
|
|
|
|
1 --- the node is in set $S$.
|
|
|
|
\noindent
|
|
If \verb|v_set| $<0$, it is assumed that a node having no incoming arcs
|
|
is in set $R$, and a node having no outgoing arcs is in set $S$.
|
|
|
|
The parameter \verb|a_cost| specifies an offset of the field of type
|
|
\verb|double| in the arc data block, which contains $c_{ij}$, the edge
|
|
cost. This value must be integer in the range [\verb|-INT_MAX|,
|
|
\verb|+INT_MAX|]. If \verb|a_cost| $<0$, it is assumed that $c_{ij}=1$
|
|
for all edges.
|
|
|
|
The parameter \verb|sol| specifies a location, to which the routine
|
|
stores the objective value (that is, the total cost) found.
|
|
If \verb|sol| is \verb|NULL|, the objective value is not stored.
|
|
|
|
The parameter \verb|a_x| specifies an offset of the field of type
|
|
\verb|int| in the arc data block, to which the routine stores $x_{ij}$.
|
|
If \verb|a_x| $<0$, this value is not stored.
|
|
|
|
\returns
|
|
|
|
\begin{retlist}
|
|
0 & Optimal solution found.\\
|
|
|
|
\verb|GLP_ENOPFS| & No (primal) feasible solution exists.\\
|
|
|
|
\verb|GLP_EDATA| & Unable to start the search, because the assignment
|
|
problem data are either incorrect (this error is detected by the
|
|
routine \verb|glp_check_asnprob|), not integer-valued or out of range.\\
|
|
|
|
\verb|GLP_ERANGE| & The search was prematurely terminated because of
|
|
integer overflow.\\
|
|
|
|
\verb|GLP_EFAIL| & An error has been detected in the program logic.
|
|
(If this code is returned for your problem instance, please report to
|
|
\verb|<bug-glpk@gnu.org>|.)\\
|
|
\end{retlist}
|
|
|
|
\para{Comments}
|
|
|
|
Since the out-of-kilter algorithm is designed to find a minimal cost
|
|
circulation, the routine \verb|glp_asnprob_okalg| converts the original
|
|
graph to a network suitable for this algorithm in the following
|
|
way:\footnote{The conversion is performed internally and does not
|
|
change the original graph program object passed to the routine.}
|
|
|
|
1) it replaces each edge $(i,j)$ by arc $(i\rightarrow j)$,
|
|
flow $x_{ij}$ through which has zero lower bound ($l_{ij}=0$), unity
|
|
upper bound ($u_{ij}=1$), and per-unit cost $+c_{ij}$ (in case of
|
|
\verb|GLP_ASN_MIN|), or $-c_{ij}$ (in case of \verb|GLP_ASN_MAX| and
|
|
\verb|GLP_ASN_MMP|);
|
|
|
|
2) then it adds one auxiliary feedback node $k$;
|
|
|
|
3) for each original node $i\in R$ the routine adds auxiliary supply
|
|
arc $(k\rightarrow i)$, flow $x_{ki}$ through which is costless
|
|
($c_{ki}=0$) and either fixed at 1 ($l_{ki}=u_{ki}=1$, in case of
|
|
\verb|GLP_ASN_MIN| and \verb|GLP_ASN_MAX|) or has zero lower bound and
|
|
unity upper bound ($l_{ij}=0$, $u_{ij}=1$, in case of
|
|
\verb|GLP_ASN_MMP|);
|
|
|
|
\newpage
|
|
|
|
4) similarly, for each original node $j\in S$ the routine adds
|
|
auxiliary demand arc $(j\rightarrow k)$, flow $x_{jk}$ through which is
|
|
costless ($c_{jk}=0$) and either fixed at 1 ($l_{jk}=u_{jk}=1$, in case
|
|
of \verb|GLP_ASN_MIN| and \verb|GLP_ASN_MAX|) or has zero lower bound
|
|
and unity upper bound ($l_{jk}=0$, $u_{jk}=1$, in case of
|
|
\verb|GLP_ASN_MMP|).
|
|
|
|
\para{Example}
|
|
|
|
The example program shown below reads the assignment problem instance
|
|
in DIMACS format from file `\verb|sample.asn|', solves it by using the
|
|
routine \verb|glp_asnprob_okalg|, and writes the solution found to the
|
|
standard output.
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <glpk.h>
|
|
|
|
typedef struct { int set; } v_data;
|
|
typedef struct { double cost; int x; } e_data;
|
|
|
|
#define node(v) ((v_data *)((v)->data))
|
|
#define edge(e) ((e_data *)((e)->data))
|
|
|
|
int main(void)
|
|
{ glp_graph *G;
|
|
glp_vertex *v;
|
|
glp_arc *e;
|
|
int i, ret;
|
|
double sol;
|
|
G = glp_create_graph(sizeof(v_data), sizeof(e_data));
|
|
glp_read_asnprob(G, offsetof(v_data, set),
|
|
offsetof(e_data, cost), "sample.asn");
|
|
ret = glp_asnprob_okalg(GLP_ASN_MMP, G,
|
|
offsetof(v_data, set), offsetof(e_data, cost), &sol,
|
|
offsetof(e_data, x));
|
|
printf("ret = %d; sol = %5g\n", ret, sol);
|
|
for (i = 1; i <= G->nv; i++)
|
|
{ v = G->v[i];
|
|
for (e = v->out; e != NULL; e = e->t_next)
|
|
printf("edge %2d %2d: x = %d; c = %g\n",
|
|
e->tail->i, e->head->i, edge(e)->x, edge(e)->cost);
|
|
}
|
|
glp_delete_graph(G);
|
|
return 0;
|
|
}
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
If `\verb|sample.asn|' is the example data file from the subsection
|
|
describing \verb|glp_read_asnprob|, the output may look like follows:
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
Reading assignment problem data from `sample.asn'...
|
|
Assignment problem has 8 + 9 = 17 nodes and 22 arcs
|
|
38 lines were read
|
|
ret = 0; sol = 180
|
|
edge 1 12: x = 1; c = 20
|
|
edge 1 10: x = 0; c = 21
|
|
edge 1 9: x = 0; c = 13
|
|
edge 2 13: x = 1; c = 26
|
|
edge 2 12: x = 0; c = 8
|
|
edge 2 10: x = 0; c = 12
|
|
edge 3 13: x = 0; c = 11
|
|
edge 3 11: x = 1; c = 22
|
|
edge 4 14: x = 1; c = 25
|
|
edge 4 12: x = 0; c = 36
|
|
edge 4 9: x = 0; c = 12
|
|
edge 5 17: x = 0; c = 32
|
|
edge 5 16: x = 1; c = 35
|
|
edge 5 15: x = 0; c = 8
|
|
edge 5 14: x = 0; c = 4
|
|
edge 5 13: x = 0; c = 11
|
|
edge 5 12: x = 0; c = 40
|
|
edge 5 11: x = 0; c = 41
|
|
edge 6 9: x = 1; c = 13
|
|
edge 7 10: x = 0; c = 19
|
|
edge 8 11: x = 0; c = 15
|
|
edge 8 10: x = 1; c = 39
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
\subsection{glp\_asnprob\_hall --- find bipartite matching of maximum
|
|
cardinality}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
int glp_asnprob_hall(glp_graph *G, int v_set, int a_x);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_asnprob_hall| finds a matching of maximal
|
|
cardinality in the specified bipartite graph. It uses a version of the
|
|
Fortran routine \verb|MC21A| developed by
|
|
I.~S.~Duff\footnote{I.~S.~Duff, Algorithm 575: Permutations for
|
|
zero-free diagonal, ACM Trans. on Math. Softw. 7 (1981),\linebreak
|
|
pp.~387-390.}, which implements Hall's algorithm.\footnote{M.~Hall,
|
|
``An Algorithm for Distinct Representatives,'' Am. Math. Monthly 63
|
|
(1956), pp.~716-717.}
|
|
|
|
The parameter \verb|G| is a pointer to the graph program object.
|
|
|
|
The parameter \verb|v_set| specifies an offset of the field of type
|
|
\verb|int| in the vertex data block, which contains the node set
|
|
indicator:
|
|
|
|
0 --- the node is in set $R$;
|
|
|
|
1 --- the node is in set $S$.
|
|
|
|
\noindent
|
|
If \verb|v_set| $<0$, it is assumed that a node having no incoming arcs
|
|
is in set $R$, and a node having no outgoing arcs is in set $S$.
|
|
|
|
The parameter \verb|a_x| specifies an offset of the field of type
|
|
\verb|int| in the arc data block, to which the routine stores $x_{ij}$.
|
|
If \verb|a_x| $<0$, this value is not stored.
|
|
|
|
\returns
|
|
|
|
The routine \verb|glp_asnprob_hall| returns the cardinality of the
|
|
matching found. However, if the specified graph is incorrect (as
|
|
detected by the routine \verb|glp_check_asnprob|), this routine returns
|
|
a negative value.
|
|
|
|
\newpage
|
|
|
|
\para{Comments}
|
|
|
|
The same solution may be obtained with the routine
|
|
\verb|glp_asnprob_okalg| (for LP formulation \verb|GLP_ASN_MMP| and
|
|
all edge costs equal to 1). However, the routine
|
|
\verb|glp_asnprob_hall| is much faster.
|
|
|
|
\para{Example}
|
|
|
|
The example program shown below reads the assignment problem instance
|
|
in DIMACS format from file `\verb|sample.asn|', finds a bipartite
|
|
matching of maximal cardinality by using the routine
|
|
\verb|glp_asnprob_hall|, and writes the solution found to the standard
|
|
output.
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <glpk.h>
|
|
|
|
typedef struct { int set; } v_data;
|
|
typedef struct { int x; } e_data;
|
|
|
|
#define node(v) ((v_data *)((v)->data))
|
|
#define edge(e) ((e_data *)((e)->data))
|
|
|
|
int main(void)
|
|
{ glp_graph *G;
|
|
glp_vertex *v;
|
|
glp_arc *e;
|
|
int i, card;
|
|
G = glp_create_graph(sizeof(v_data), sizeof(e_data));
|
|
glp_read_asnprob(G, offsetof(v_data, set), -1,
|
|
"sample.asn");
|
|
card = glp_asnprob_hall(G, offsetof(v_data, set),
|
|
offsetof(e_data, x));
|
|
printf("card = %d\n", card);
|
|
for (i = 1; i <= G->nv; i++)
|
|
{ v = G->v[i];
|
|
for (e = v->out; e != NULL; e = e->t_next)
|
|
printf("edge %2d %2d: x = %d\n",
|
|
e->tail->i, e->head->i, edge(e)->x);
|
|
}
|
|
glp_delete_graph(G);
|
|
return 0;
|
|
}
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
If `\verb|sample.asn|' is the example data file from the subsection
|
|
describing \verb|glp_read_asnprob|, the output may look like follows:
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
Reading assignment problem data from `sample.asn'...
|
|
Assignment problem has 8 + 9 = 17 nodes and 22 arcs
|
|
38 lines were read
|
|
card = 7
|
|
edge 1 12: x = 1
|
|
edge 1 10: x = 0
|
|
edge 1 9: x = 0
|
|
edge 2 13: x = 1
|
|
edge 2 12: x = 0
|
|
edge 2 10: x = 0
|
|
edge 3 13: x = 0
|
|
edge 3 11: x = 1
|
|
edge 4 14: x = 1
|
|
edge 4 12: x = 0
|
|
edge 4 9: x = 0
|
|
edge 5 17: x = 1
|
|
edge 5 16: x = 0
|
|
edge 5 15: x = 0
|
|
edge 5 14: x = 0
|
|
edge 5 13: x = 0
|
|
edge 5 12: x = 0
|
|
edge 5 11: x = 0
|
|
edge 6 9: x = 1
|
|
edge 7 10: x = 1
|
|
edge 8 11: x = 0
|
|
edge 8 10: x = 0
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
\newpage
|
|
|
|
\section{Critical path problem}
|
|
|
|
\subsection{Background}
|
|
|
|
The {\it critical path problem} (CPP) is stated as follows. Let there
|
|
be given a project $J$, which is a set of jobs (tasks, activities,
|
|
etc.). Performing each job $i\in J$ requires time $t_i\geq 0$. Besides,
|
|
over the set $J$ there is given a precedence relation
|
|
$R\subseteq J\times J$, where $(i,j)\in R$ means that job $i$
|
|
immediately precedes job $j$, i.e. performing job $j$ cannot start
|
|
until job $i$ has been completely performed. The problem is to find
|
|
starting times $x_i$ for each job $i\in J$, which satisfy to the
|
|
precedence relation and minimize the total duration (makespan) of the
|
|
project.
|
|
|
|
The following is an example of the critical path problem:
|
|
|
|
\bigskip
|
|
|
|
\begin{center}
|
|
\begin{tabular}{|c|l|c|c|}
|
|
\hline
|
|
Job&Desription&Time&Predecessors\\
|
|
\hline
|
|
A&Excavate&3&---\\
|
|
B&Lay foundation&4&A\\
|
|
C&Rough plumbing&3&B\\
|
|
D&Frame&10&B\\
|
|
E&Finish exterior&8&D\\
|
|
F&Install HVAC&4&D\\
|
|
G&Rough electric&6&D\\
|
|
H&Sheet rock&8&C, E, F, G\\
|
|
I&Install cabinets&5&H\\
|
|
J&Paint&5&H\\
|
|
K&Final plumbing&4&I\\
|
|
L&Final electric&2&J\\
|
|
M&Install flooring&4&K, L\\
|
|
\hline
|
|
\end{tabular}
|
|
\end{center}
|
|
|
|
\bigskip
|
|
|
|
Obviously, the project along with the precedence relation can be
|
|
represented as a directed graph $G=(J,R)$ called {\it project network},
|
|
where each node $i\in J$ corresponds to a job, and arc
|
|
$(i\rightarrow j)\in R$ means that job $i$ immediately precedes job
|
|
$j$.\footnote{There exists another network representation of the
|
|
critical path problem, where jobs correspond to arcs while nodes
|
|
correspond to events introduced to express the precedence relation.
|
|
That representation, however, is much less convenient than the one,
|
|
where jobs are represented as nodes of the network.} The project network
|
|
for the example above is shown on Fig.~4.
|
|
|
|
May note that the project network must be acyclic; otherwise, it would
|
|
be impossible to satisfy to the precedence relation for any job that
|
|
belongs to a cycle.
|
|
|
|
\newpage
|
|
|
|
\hspace*{.5in}
|
|
\xymatrix
|
|
{&&&C|3\ar[rd]&&I|5\ar[r]&K|4\ar[rd]&\\
|
|
A|3\ar[r]&B|4\ar[rru]\ar[rd]&&E|8\ar[r]&H|8\ar[ru]\ar[rd]&&&M|4\\
|
|
&&D|10\ar[ru]\ar[r]\ar[rd]&F|4\ar[ru]&&J|5\ar[r]&L|2\ar[ru]&\\
|
|
&&&G|6\ar[ruu]&&&&\\
|
|
}
|
|
|
|
\medskip
|
|
|
|
\noindent\hfil
|
|
Fig.~4. An example of the project network.
|
|
|
|
\medskip
|
|
|
|
The critical path problem can be naturally formulated as the following
|
|
LP problem:
|
|
|
|
\medskip
|
|
|
|
\noindent
|
|
\hspace{.5in}minimize
|
|
$$z\eqno(19)$$
|
|
\hspace{.5in}subject to
|
|
$$x_i+t_i\leq z\ \ \ \hbox{for all}\ i\in J\ \ \ \ \eqno(20)$$
|
|
$$x_i+t_i\leq x_j\ \ \ \hbox{for all}\ (i,j)\in R\eqno(21)$$
|
|
$$x_i\geq 0\ \ \ \ \ \ \ \hbox{for all}\ i\in J\ \ \eqno(22)$$
|
|
|
|
The inequality constraints (21), which are active in the optimal
|
|
solution, define so called {\it critical path} having the following
|
|
property: the minimal project duration $z$ can be decreased only by
|
|
decreasing the times $t_j$ for jobs on the critical path, and delaying
|
|
any critical job delays the entire project.
|
|
|
|
\subsection{glp\_cpp --- solve critical path problem}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
double glp_cpp(glp_graph *G, int v_t, int v_es, int v_ls);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine \verb|glp_cpp| solves the critical path problem represented
|
|
in the form of the project network.
|
|
|
|
The parameter \verb|G| is a pointer to the graph object, which
|
|
specifies the project network. This graph must be acyclic. Multiple
|
|
arcs are allowed being considered as single arcs.
|
|
|
|
The parameter \verb|v_t| specifies an offset of the field of type
|
|
\verb|double| in the vertex data block, which contains time $t_i\geq 0$
|
|
needed to perform corresponding job $j\in J$. If \verb|v_t| $<0$, it is
|
|
assumed that $t_i=1$ for all jobs.
|
|
|
|
The parameter \verb|v_es| specifies an offset of the field of type
|
|
\verb|double| in the vertex data block, to which the routine stores
|
|
the {\it earliest start time} for corresponding job. If \verb|v_es|
|
|
$<0$, this time is not stored.
|
|
|
|
\newpage
|
|
|
|
The parameter \verb|v_ls| specifies an offset of the field of type
|
|
\verb|double| in the vertex data block, to which the routine stores
|
|
the {\it latest start time} for corresponding job. If \verb|v_ls|
|
|
$<0$, this time is not stored.
|
|
|
|
The difference between the latest and earliest start times of some job
|
|
is called its {\it time reserve}. Delaying a job within its time
|
|
reserve does not affect the project duration, so if the time reserve is
|
|
zero, the corresponding job is critical.
|
|
|
|
\para{Returns}
|
|
|
|
The routine \verb|glp_cpp| returns the minimal project duration, i.e.
|
|
minimal time needed to perform all jobs in the project.
|
|
|
|
\para{Example}
|
|
|
|
The example program below solves the critical path problem shown on
|
|
Fig.~4 by using the routine \verb|glp_cpp| and writes the solution
|
|
found on the standard output.
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <glpk.h>
|
|
|
|
typedef struct { double t, es, ls; } v_data;
|
|
|
|
#define node(v) ((v_data *)((v)->data))
|
|
|
|
int main(void)
|
|
{ glp_graph *G;
|
|
int i;
|
|
double t, es, ef, ls, lf, total;
|
|
G = glp_create_graph(sizeof(v_data), 0);
|
|
glp_add_vertices(G, 13);
|
|
node(G->v[1])->t = 3; /* A: Excavate */
|
|
node(G->v[2])->t = 4; /* B: Lay foundation */
|
|
node(G->v[3])->t = 3; /* C: Rough plumbing */
|
|
node(G->v[4])->t = 10; /* D: Frame */
|
|
node(G->v[5])->t = 8; /* E: Finish exterior */
|
|
node(G->v[6])->t = 4; /* F: Install HVAC */
|
|
node(G->v[7])->t = 6; /* G: Rough elecrtic */
|
|
node(G->v[8])->t = 8; /* H: Sheet rock */
|
|
node(G->v[9])->t = 5; /* I: Install cabinets */
|
|
node(G->v[10])->t = 5; /* J: Paint */
|
|
node(G->v[11])->t = 4; /* K: Final plumbing */
|
|
node(G->v[12])->t = 2; /* L: Final electric */
|
|
node(G->v[13])->t = 4; /* M: Install flooring */
|
|
glp_add_arc(G, 1, 2); /* A precedes B */
|
|
glp_add_arc(G, 2, 3); /* B precedes C */
|
|
glp_add_arc(G, 2, 4); /* B precedes D */
|
|
glp_add_arc(G, 4, 5); /* D precedes E */
|
|
glp_add_arc(G, 4, 6); /* D precedes F */
|
|
glp_add_arc(G, 4, 7); /* D precedes G */
|
|
glp_add_arc(G, 3, 8); /* C precedes H */
|
|
glp_add_arc(G, 5, 8); /* E precedes H */
|
|
glp_add_arc(G, 6, 8); /* F precedes H */
|
|
glp_add_arc(G, 7, 8); /* G precedes H */
|
|
glp_add_arc(G, 8, 9); /* H precedes I */
|
|
glp_add_arc(G, 8, 10); /* H precedes J */
|
|
glp_add_arc(G, 9, 11); /* I precedes K */
|
|
glp_add_arc(G, 10, 12); /* J precedes L */
|
|
glp_add_arc(G, 11, 13); /* K precedes M */
|
|
glp_add_arc(G, 12, 13); /* L precedes M */
|
|
total = glp_cpp(G, offsetof(v_data, t), offsetof(v_data, es),
|
|
offsetof(v_data, ls));
|
|
printf("Minimal project duration is %.2f\n\n", total);
|
|
printf("Job Time ES EF LS LF\n");
|
|
printf("--- ------ ------ ------ ------ ------\n");
|
|
for (i = 1; i <= G->nv; i++)
|
|
{ t = node(G->v[i])->t;
|
|
es = node(G->v[i])->es;
|
|
ef = es + node(G->v[i])->t;
|
|
ls = node(G->v[i])->ls;
|
|
lf = ls + node(G->v[i])->t;
|
|
printf("%3d %6.2f %s %6.2f %6.2f %6.2f %6.2f\n",
|
|
i, t, ls - es < 0.001 ? "*" : " ", es, ef, ls, lf);
|
|
}
|
|
glp_delete_graph(G);
|
|
return 0;
|
|
}
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
The output from the example program shown below includes job number,
|
|
the time needed to perform a job, earliest start time (\verb|ES|),
|
|
earliest finish time (\verb|EF|), latest start time (\verb|LS|), and
|
|
latest finish time (\verb|LF|) for each job in the project. Critical
|
|
jobs are marked by asterisks.
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
Minimal project duration is 46.00
|
|
|
|
Job Time ES EF LS LF
|
|
--- ------ ------ ------ ------ ------
|
|
1 3.00 * 0.00 3.00 0.00 3.00
|
|
2 4.00 * 3.00 7.00 3.00 7.00
|
|
3 3.00 7.00 10.00 22.00 25.00
|
|
4 10.00 * 7.00 17.00 7.00 17.00
|
|
5 8.00 * 17.00 25.00 17.00 25.00
|
|
6 4.00 17.00 21.00 21.00 25.00
|
|
7 6.00 17.00 23.00 19.00 25.00
|
|
8 8.00 * 25.00 33.00 25.00 33.00
|
|
9 5.00 * 33.00 38.00 33.00 38.00
|
|
10 5.00 33.00 38.00 35.00 40.00
|
|
11 4.00 * 38.00 42.00 38.00 42.00
|
|
12 2.00 38.00 40.00 40.00 42.00
|
|
13 4.00 * 42.00 46.00 42.00 46.00
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
\chapter{Graph Optimization API Routines}
|
|
|
|
\section{Maximum clique problem}
|
|
|
|
\subsection{Background}
|
|
|
|
The {\it maximum clique problem (MCP)} is a classic combinatorial
|
|
optimization problem. Given an undirected graph $G=(V,E)$, where $V$ is
|
|
a set of vertices, and $E$ is a set of edges, this problem is to find
|
|
the largest {\it clique} $C\subseteq G$, i.e. the largest induced
|
|
complete subgraph. A generalization of this problem is the {\it maximum
|
|
weight clique problem (MWCP)}, which is to find a clique $C\subseteq G$
|
|
of the largest weight $\displaystyle\sum_{v\in C}w(v)\rightarrow\max$,
|
|
where $w(v)$ is a weight of vertex $v\in V$.
|
|
|
|
An example of the maximum weight clique problem is shown on Fig.~5.
|
|
|
|
\begin{figure}
|
|
\noindent\hfil
|
|
\begin{tabular}{c}
|
|
{\xymatrix %@C=16pt
|
|
{&&&{v_1}\ar@{-}[lllddd]\ar@{-}[llddddd]\ar@{-}[dddddd]
|
|
\ar@{-}[rrrddd]&&&\\
|
|
&{v_2}\ar@{-}[rrrr]\ar@{-}[rrrrdddd]\ar@{-}[rrddddd]\ar@{-}[dddd]&&&&
|
|
{v_3}\ar@{-}[llllldd]\ar@{-}[lllldddd]\ar@{-}[dddd]&\\
|
|
&&&&&&\\
|
|
{v_4}\ar@{-}[rrrrrr]\ar@{-}[rrrddd]&&&&&&{v_5}\ar@{-}[lllddd]
|
|
\ar@{-}[ldd]\\
|
|
&&&&&&\\
|
|
&{v_6}\ar@{-}[rrrr]&&&&{v_7}&\\
|
|
&&&{v_8}&&&\\
|
|
}}
|
|
\end{tabular}
|
|
\begin{tabular}{r@{\ }c@{\ }l}
|
|
$w(v_1)$&=&3\\$w(v_2)$&=&4\\$w(v_3)$&=&8\\$w(v_4)$&=&1\\
|
|
$w(v_5)$&=&5\\$w(v_6)$&=&2\\$w(v_7)$&=&1\\$w(v_8)$&=&3\\
|
|
\end{tabular}
|
|
|
|
\bigskip
|
|
|
|
\begin{center}
|
|
Fig.~5. An example of the maximum weight clique problem.
|
|
\end{center}
|
|
\end{figure}
|
|
|
|
\subsection{glp\_wclique\_exact --- find maximum weight clique with
|
|
exact algorithm}
|
|
|
|
\synopsis
|
|
|
|
\begin{verbatim}
|
|
int glp_wclique_exact(glp_graph *G, int v_wgt, double *sol, int v_set);
|
|
\end{verbatim}
|
|
|
|
\description
|
|
|
|
The routine {\tt glp\_wclique\_exact} finds a maximum weight clique in
|
|
the specified undirected graph with the exact algorithm developed by
|
|
Patric \"Osterg{\aa}rd.\footnote{P.~R.~J.~\"Osterg{\aa}rd, A new
|
|
algorithm for the maximum-weight clique problem, Nordic J. of
|
|
Computing, Vol.~8, No.~4, 2001, pp.~424--36.}
|
|
|
|
The parameter {\tt G} is the program object, which specifies
|
|
an undirected graph. Each arc $(x\rightarrow y)$ in {\tt G} is
|
|
considered as edge $(x,y)$, self-loops are ignored, and multiple edges,
|
|
if present, are replaced (internally) by simple edges.
|
|
|
|
The parameter {\tt v\_wgt} specifies an offset of the field of type
|
|
{\tt double} in the vertex data block, which contains a weight of
|
|
corresponding vertex. Vertex weights must be integer-valued in the
|
|
range $[0,$ {\tt INT\_MAX}$]$. If {\tt v\_wgt} $<0$, it is assumed that
|
|
all vertices of the graph have the weight 1.
|
|
|
|
\newpage
|
|
|
|
The parameter {\tt sol} specifies a location, to which the routine
|
|
stores the weight of the clique found (the clique weight is the sum
|
|
of weights of all vertices included in the clique.) If {\tt sol} is
|
|
{\tt NULL}, the solution is not stored.
|
|
|
|
The parameter {\tt v\_set} specifies an offset of the field of type
|
|
{\tt int} in the vertex data block, to which the routines stores a
|
|
vertex flag: 1 means that the corresponding vertex is included in the
|
|
clique found, and 0 otherwise. If {\tt v\_set} $<0$, vertex flags are
|
|
not stored.
|
|
|
|
\returns
|
|
|
|
\begin{retlist}
|
|
0 & Optimal solution found.\\
|
|
|
|
\verb|GLP_EDATA| & Unable to start the search, because some vertex
|
|
weights are either not integer-valued or out of range. This code is
|
|
also returned if the sum of weights of all vertices exceeds
|
|
{\tt INT\_MAX}. \\
|
|
\end{retlist}
|
|
|
|
\para{Notes}
|
|
|
|
1. The routine {\it glp\_wclique\_exact} finds exact solution. Since
|
|
both MCP and MWCP problems are NP-complete, the algorithm may require
|
|
exponential time in worst cases.
|
|
|
|
2. Internally the specified graph is converted to an adjacency matrix
|
|
in {\it dense} format. This requires about $|V|^2/16$ bytes of memory,
|
|
where $|V|$ is the number of vertices in the graph.
|
|
|
|
\para{Example}
|
|
|
|
The example program shown below reads a MWCP instance in DIMACS
|
|
clique/coloring format from file `\verb|sample.clq|', finds the clique
|
|
of largest weight, and writes the solution found on the standard
|
|
output.
|
|
|
|
\newpage
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <glpk.h>
|
|
|
|
typedef struct { double wgt; int set; } v_data;
|
|
|
|
#define vertex(v) ((v_data *)((v)->data))
|
|
|
|
int main(void)
|
|
{ glp_graph *G;
|
|
glp_vertex *v;
|
|
int i, ret;
|
|
double sol;
|
|
G = glp_create_graph(sizeof(v_data), 0);
|
|
glp_read_ccdata(G, offsetof(v_data, wgt), "sample.clq");
|
|
ret = glp_wclique_exact(G, offsetof(v_data, wgt), &sol,
|
|
offsetof(v_data, set));
|
|
printf("ret = %d; sol = %g\n", ret, sol);
|
|
for (i = 1; i <= G->nv; i++)
|
|
{ v = G->v[i];
|
|
printf("vertex %d: weight = %g, flag = %d\n",
|
|
i, vertex(v)->wgt, vertex(v)->set);
|
|
}
|
|
glp_delete_graph(G);
|
|
return 0;
|
|
}
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
For the example shown on Fig.~5 the data file may look like follows:
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
c sample.clq
|
|
c
|
|
c This is an example of the maximum weight clique
|
|
c problem in DIMACS clique/coloring format.
|
|
c
|
|
p edge 8 16
|
|
n 1 3
|
|
n 2 4
|
|
n 3 8
|
|
n 5 5
|
|
n 6 2
|
|
n 8 3
|
|
e 1 4
|
|
e 1 5
|
|
e 1 6
|
|
e 1 8
|
|
e 2 3
|
|
e 2 6
|
|
e 2 7
|
|
e 2 8
|
|
e 3 4
|
|
e 3 6
|
|
e 3 7
|
|
e 4 5
|
|
e 4 8
|
|
e 5 7
|
|
e 5 8
|
|
e 6 7
|
|
c
|
|
c eof
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
The corresponding output from the example program is the following:
|
|
|
|
\begin{footnotesize}
|
|
\begin{verbatim}
|
|
Reading graph from `sample.clq'...
|
|
Graph has 8 vertices and 16 edges
|
|
28 lines were read
|
|
ret = 0; sol = 15
|
|
vertex 1: weight = 3, flag = 0
|
|
vertex 2: weight = 4, flag = 1
|
|
vertex 3: weight = 8, flag = 1
|
|
vertex 4: weight = 1, flag = 0
|
|
vertex 5: weight = 5, flag = 0
|
|
vertex 6: weight = 2, flag = 1
|
|
vertex 7: weight = 1, flag = 1
|
|
vertex 8: weight = 3, flag = 0
|
|
\end{verbatim}
|
|
\end{footnotesize}
|
|
|
|
\end{document}
|