alpar@1
|
1 |
%* graphs.tex *%
|
alpar@1
|
2 |
|
alpar@1
|
3 |
%***********************************************************************
|
alpar@1
|
4 |
% This code is part of GLPK (GNU Linear Programming Kit).
|
alpar@1
|
5 |
%
|
alpar@1
|
6 |
% Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
|
alpar@1
|
7 |
% 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
|
alpar@1
|
8 |
% Moscow Aviation Institute, Moscow, Russia. All rights reserved.
|
alpar@1
|
9 |
% E-mail: <mao@gnu.org>.
|
alpar@1
|
10 |
%
|
alpar@1
|
11 |
% GLPK is free software: you can redistribute it and/or modify it
|
alpar@1
|
12 |
% under the terms of the GNU General Public License as published by
|
alpar@1
|
13 |
% the Free Software Foundation, either version 3 of the License, or
|
alpar@1
|
14 |
% (at your option) any later version.
|
alpar@1
|
15 |
%
|
alpar@1
|
16 |
% GLPK is distributed in the hope that it will be useful, but WITHOUT
|
alpar@1
|
17 |
% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
alpar@1
|
18 |
% or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
alpar@1
|
19 |
% License for more details.
|
alpar@1
|
20 |
%
|
alpar@1
|
21 |
% You should have received a copy of the GNU General Public License
|
alpar@1
|
22 |
% along with GLPK. If not, see <http://www.gnu.org/licenses/>.
|
alpar@1
|
23 |
%***********************************************************************
|
alpar@1
|
24 |
|
alpar@1
|
25 |
\documentclass[11pt]{report}
|
alpar@1
|
26 |
\usepackage{amssymb}
|
alpar@1
|
27 |
\usepackage[dvipdfm,linktocpage,colorlinks,linkcolor=blue,
|
alpar@1
|
28 |
urlcolor=blue]{hyperref}
|
alpar@1
|
29 |
\usepackage[all]{xy}
|
alpar@1
|
30 |
|
alpar@1
|
31 |
\renewcommand\contentsname{\sf\bfseries Contents}
|
alpar@1
|
32 |
\renewcommand\chaptername{\sf\bfseries Chapter}
|
alpar@1
|
33 |
\renewcommand\appendixname{\sf\bfseries Appendix}
|
alpar@1
|
34 |
|
alpar@1
|
35 |
\begin{document}
|
alpar@1
|
36 |
|
alpar@1
|
37 |
\thispagestyle{empty}
|
alpar@1
|
38 |
|
alpar@1
|
39 |
\begin{center}
|
alpar@1
|
40 |
|
alpar@1
|
41 |
\vspace*{1in}
|
alpar@1
|
42 |
|
alpar@1
|
43 |
\begin{huge}
|
alpar@1
|
44 |
\sf\bfseries GNU Linear Programming Kit
|
alpar@1
|
45 |
\end{huge}
|
alpar@1
|
46 |
|
alpar@1
|
47 |
\vspace{0.5in}
|
alpar@1
|
48 |
|
alpar@1
|
49 |
\begin{LARGE}
|
alpar@1
|
50 |
\sf Graph and Network Routines
|
alpar@1
|
51 |
\end{LARGE}
|
alpar@1
|
52 |
|
alpar@1
|
53 |
\vspace{0.5in}
|
alpar@1
|
54 |
|
alpar@1
|
55 |
\begin{LARGE}
|
alpar@1
|
56 |
\sf for GLPK Version 4.45
|
alpar@1
|
57 |
\end{LARGE}
|
alpar@1
|
58 |
|
alpar@1
|
59 |
\vspace{0.5in}
|
alpar@1
|
60 |
\begin{Large}
|
alpar@1
|
61 |
\sf (DRAFT, December 2010)
|
alpar@1
|
62 |
\end{Large}
|
alpar@1
|
63 |
\end{center}
|
alpar@1
|
64 |
|
alpar@1
|
65 |
\newpage
|
alpar@1
|
66 |
|
alpar@1
|
67 |
\vspace*{1in}
|
alpar@1
|
68 |
|
alpar@1
|
69 |
\vfill
|
alpar@1
|
70 |
|
alpar@1
|
71 |
\noindent
|
alpar@1
|
72 |
The GLPK package is part of the GNU Project released under the aegis of
|
alpar@1
|
73 |
GNU.
|
alpar@1
|
74 |
|
alpar@1
|
75 |
\medskip \noindent
|
alpar@1
|
76 |
Copyright \copyright{} 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
|
alpar@1
|
77 |
2008, 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
|
alpar@1
|
78 |
Moscow Aviation Institute, Moscow, Russia. All rights reserved.
|
alpar@1
|
79 |
|
alpar@1
|
80 |
\medskip \noindent
|
alpar@1
|
81 |
Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
alpar@1
|
82 |
02110-1301, USA.
|
alpar@1
|
83 |
|
alpar@1
|
84 |
\medskip \noindent
|
alpar@1
|
85 |
Permission is granted to make and distribute verbatim copies of this
|
alpar@1
|
86 |
manual provided the copyright notice and this permission notice are
|
alpar@1
|
87 |
preserved on all copies.
|
alpar@1
|
88 |
|
alpar@1
|
89 |
\medskip \noindent
|
alpar@1
|
90 |
Permission is granted to copy and distribute modified versions of this
|
alpar@1
|
91 |
manual under the conditions for verbatim copying, provided also that the
|
alpar@1
|
92 |
entire resulting derived work is distributed under the terms of
|
alpar@1
|
93 |
a permission notice identical to this one.
|
alpar@1
|
94 |
|
alpar@1
|
95 |
\medskip \noindent
|
alpar@1
|
96 |
Permission is granted to copy and distribute translations of this manual
|
alpar@1
|
97 |
into another language, under the above conditions for modified versions.
|
alpar@1
|
98 |
|
alpar@1
|
99 |
\tableofcontents
|
alpar@1
|
100 |
|
alpar@1
|
101 |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
alpar@1
|
102 |
|
alpar@1
|
103 |
\chapter{Basic Graph API Routines}
|
alpar@1
|
104 |
|
alpar@1
|
105 |
\section{Graph program object}
|
alpar@1
|
106 |
|
alpar@1
|
107 |
In GLPK the base program object used to represent graphs and networks
|
alpar@1
|
108 |
is a directed graph (digraph).
|
alpar@1
|
109 |
|
alpar@1
|
110 |
Formally, {\it digraph} (or simply, {\it graph}) is a pair $G=(V,A)$,
|
alpar@1
|
111 |
where $V$ is a set of {\it vertices}, and $A$ is a set
|
alpar@1
|
112 |
{\it arcs}.\footnote{$A$ may be a multiset.} Each arc $a\in A$ is an
|
alpar@1
|
113 |
ordered pair of vertices $a=(x,y)$, where $x\in V$ is called {\it tail
|
alpar@1
|
114 |
vertex} of arc $a$, and $y\in V$ is called its {\it head vertex}.
|
alpar@1
|
115 |
|
alpar@1
|
116 |
Representation of a graph in the program includes three structs defined
|
alpar@1
|
117 |
by typedef in the header \verb|glpk.h|:
|
alpar@1
|
118 |
|
alpar@1
|
119 |
\medskip
|
alpar@1
|
120 |
|
alpar@1
|
121 |
$\bullet$ \verb|glp_graph|, which represents the graph in a whole,
|
alpar@1
|
122 |
|
alpar@1
|
123 |
$\bullet$ \verb|glp_vertex|, which represents a vertex of the graph, and
|
alpar@1
|
124 |
|
alpar@1
|
125 |
$\bullet$ \verb|glp_arc|, which represents an arc of the graph.
|
alpar@1
|
126 |
|
alpar@1
|
127 |
\medskip
|
alpar@1
|
128 |
|
alpar@1
|
129 |
All these three structs are ``semi-opaque'', i.e. the application
|
alpar@1
|
130 |
program can directly access their fields through pointers, however,
|
alpar@1
|
131 |
changing the fields directly is not allowed---all changes should be
|
alpar@1
|
132 |
performed only with appropriate GLPK API routines.
|
alpar@1
|
133 |
|
alpar@1
|
134 |
\newpage
|
alpar@1
|
135 |
|
alpar@1
|
136 |
\newenvironment{comment}
|
alpar@1
|
137 |
{\addtolength{\leftskip}{17pt}\noindent}
|
alpar@1
|
138 |
{\par\addtolength{\leftskip}{-17pt}}
|
alpar@1
|
139 |
|
alpar@1
|
140 |
\noindent
|
alpar@1
|
141 |
{\bf glp\_graph.} The struct \verb|glp_graph| has the following
|
alpar@1
|
142 |
fields available to the application program:
|
alpar@1
|
143 |
|
alpar@1
|
144 |
\medskip
|
alpar@1
|
145 |
|
alpar@1
|
146 |
\noindent
|
alpar@1
|
147 |
\verb|char *name;|
|
alpar@1
|
148 |
|
alpar@1
|
149 |
\begin{comment}Symbolic name assigned to the graph. It is a pointer to
|
alpar@1
|
150 |
a null terminated character string of length from 1 to 255 characters.
|
alpar@1
|
151 |
If no name is assigned to the graph, this field contains \verb|NULL|.
|
alpar@1
|
152 |
\end{comment}
|
alpar@1
|
153 |
|
alpar@1
|
154 |
\medskip
|
alpar@1
|
155 |
|
alpar@1
|
156 |
\noindent
|
alpar@1
|
157 |
\verb|int nv;|
|
alpar@1
|
158 |
|
alpar@1
|
159 |
\begin{comment}The number of vertices in the graph, $nv\geq 0$.
|
alpar@1
|
160 |
\end{comment}
|
alpar@1
|
161 |
|
alpar@1
|
162 |
\medskip
|
alpar@1
|
163 |
|
alpar@1
|
164 |
\noindent
|
alpar@1
|
165 |
\verb|int na;|
|
alpar@1
|
166 |
|
alpar@1
|
167 |
\begin{comment}The number of arcs in the graph, $na\geq 0$.
|
alpar@1
|
168 |
\end{comment}
|
alpar@1
|
169 |
|
alpar@1
|
170 |
\medskip
|
alpar@1
|
171 |
|
alpar@1
|
172 |
\noindent
|
alpar@1
|
173 |
\verb|glp_vertex **v;|
|
alpar@1
|
174 |
|
alpar@1
|
175 |
\begin{comment}Pointer to an array containing the list of vertices.
|
alpar@1
|
176 |
Element $v[0]$ is not used. Element $v[i]$, $1\leq i\leq nv$, is a
|
alpar@1
|
177 |
pointer to $i$-th vertex of the graph. Note that on adding new vertices
|
alpar@1
|
178 |
to the graph the field $v$ may be altered due to reallocation. However,
|
alpar@1
|
179 |
pointers $v[i]$ are not changed while corresponding vertices exist in
|
alpar@1
|
180 |
the graph.
|
alpar@1
|
181 |
\end{comment}
|
alpar@1
|
182 |
|
alpar@1
|
183 |
\medskip
|
alpar@1
|
184 |
|
alpar@1
|
185 |
\noindent
|
alpar@1
|
186 |
\verb|int v_size;|
|
alpar@1
|
187 |
|
alpar@1
|
188 |
\begin{comment}Size of vertex data blocks, in bytes,
|
alpar@1
|
189 |
$0\leq v\_size\leq 256$. (See also the field \verb|data| in the struct
|
alpar@1
|
190 |
\verb|glp_vertex|.)
|
alpar@1
|
191 |
\end{comment}
|
alpar@1
|
192 |
|
alpar@1
|
193 |
\medskip
|
alpar@1
|
194 |
|
alpar@1
|
195 |
\noindent
|
alpar@1
|
196 |
\verb|int a_size;|
|
alpar@1
|
197 |
|
alpar@1
|
198 |
\begin{comment}Size of arc data blocks, in bytes,
|
alpar@1
|
199 |
$0\leq v\_size\leq 256$. (See also the field \verb|data| in the struct
|
alpar@1
|
200 |
\verb|glp_arc|.)
|
alpar@1
|
201 |
\end{comment}
|
alpar@1
|
202 |
|
alpar@1
|
203 |
\bigskip
|
alpar@1
|
204 |
|
alpar@1
|
205 |
\noindent
|
alpar@1
|
206 |
{\bf glp\_vertex.} The struct \verb|glp_vertex| has the following
|
alpar@1
|
207 |
fields available to the application program:
|
alpar@1
|
208 |
|
alpar@1
|
209 |
\medskip
|
alpar@1
|
210 |
|
alpar@1
|
211 |
\noindent
|
alpar@1
|
212 |
\verb|int i;|
|
alpar@1
|
213 |
|
alpar@1
|
214 |
\begin{comment}Ordinal number of the vertex, $1\leq i\leq nv$. Note
|
alpar@1
|
215 |
that element $v[i]$ in the struct \verb|glp_graph| points to the vertex,
|
alpar@1
|
216 |
whose ordinal number is $i$.
|
alpar@1
|
217 |
\end{comment}
|
alpar@1
|
218 |
|
alpar@1
|
219 |
\medskip
|
alpar@1
|
220 |
|
alpar@1
|
221 |
\noindent
|
alpar@1
|
222 |
\verb|char *name;|
|
alpar@1
|
223 |
|
alpar@1
|
224 |
\begin{comment}Symbolic name assigned to the vertex. It is a pointer to
|
alpar@1
|
225 |
a null terminated character string of length from 1 to 255 characters.
|
alpar@1
|
226 |
If no name is assigned to the vertex, this field contains \verb|NULL|.
|
alpar@1
|
227 |
\end{comment}
|
alpar@1
|
228 |
|
alpar@1
|
229 |
\medskip
|
alpar@1
|
230 |
|
alpar@1
|
231 |
\noindent
|
alpar@1
|
232 |
\verb|void *data;|
|
alpar@1
|
233 |
|
alpar@1
|
234 |
\begin{comment}Pointer to a data block associated with the vertex. This
|
alpar@1
|
235 |
data block is automatically allocated on creating a new vertex and freed
|
alpar@1
|
236 |
on deleting the vertex. If $v\_size=0$, the block is not allocated, and
|
alpar@1
|
237 |
this field contains \verb|NULL|.
|
alpar@1
|
238 |
\end{comment}
|
alpar@1
|
239 |
|
alpar@1
|
240 |
\medskip
|
alpar@1
|
241 |
|
alpar@1
|
242 |
\noindent
|
alpar@1
|
243 |
\verb|void *temp;|
|
alpar@1
|
244 |
|
alpar@1
|
245 |
\begin{comment}Working pointer, which may be used freely for any
|
alpar@1
|
246 |
purposes. The application program can change this field directly.
|
alpar@1
|
247 |
\end{comment}
|
alpar@1
|
248 |
|
alpar@1
|
249 |
\medskip
|
alpar@1
|
250 |
|
alpar@1
|
251 |
\noindent
|
alpar@1
|
252 |
\verb|glp_arc *in;|
|
alpar@1
|
253 |
|
alpar@1
|
254 |
\begin{comment}Pointer to the (unordered) list of incoming arcs. If the
|
alpar@1
|
255 |
vertex has no incoming arcs, this field contains \verb|NULL|.
|
alpar@1
|
256 |
\end{comment}
|
alpar@1
|
257 |
|
alpar@1
|
258 |
\medskip
|
alpar@1
|
259 |
|
alpar@1
|
260 |
\noindent
|
alpar@1
|
261 |
\verb|glp_arc *out;|
|
alpar@1
|
262 |
|
alpar@1
|
263 |
\begin{comment}Pointer to the (unordered) list of outgoing arcs. If the
|
alpar@1
|
264 |
vertex has no outgoing arcs, this field contains \verb|NULL|.
|
alpar@1
|
265 |
\end{comment}
|
alpar@1
|
266 |
|
alpar@1
|
267 |
\bigskip
|
alpar@1
|
268 |
|
alpar@1
|
269 |
\noindent
|
alpar@1
|
270 |
{\bf glp\_arc.} The struct \verb|glp_arc| has the following fields
|
alpar@1
|
271 |
available to the application program:
|
alpar@1
|
272 |
|
alpar@1
|
273 |
\medskip
|
alpar@1
|
274 |
|
alpar@1
|
275 |
\noindent
|
alpar@1
|
276 |
\verb|glp_vertex *tail;|
|
alpar@1
|
277 |
|
alpar@1
|
278 |
\begin{comment}Pointer to a vertex, which is tail endpoint of the arc.
|
alpar@1
|
279 |
\end{comment}
|
alpar@1
|
280 |
|
alpar@1
|
281 |
\medskip
|
alpar@1
|
282 |
|
alpar@1
|
283 |
\noindent
|
alpar@1
|
284 |
\verb|glp_vertex *head;|
|
alpar@1
|
285 |
|
alpar@1
|
286 |
\begin{comment}Pointer to a vertex, which is head endpoint of the arc.
|
alpar@1
|
287 |
\end{comment}
|
alpar@1
|
288 |
|
alpar@1
|
289 |
\medskip
|
alpar@1
|
290 |
|
alpar@1
|
291 |
\noindent
|
alpar@1
|
292 |
\verb|void *data;|
|
alpar@1
|
293 |
|
alpar@1
|
294 |
\begin{comment}Pointer to a data block associated with the arc. This
|
alpar@1
|
295 |
data block is automatically allocated on creating a new arc and freed on
|
alpar@1
|
296 |
deleting the arc. If $v\_size=0$, the block is not allocated, and this
|
alpar@1
|
297 |
field contains \verb|NULL|.
|
alpar@1
|
298 |
\end{comment}
|
alpar@1
|
299 |
|
alpar@1
|
300 |
\medskip
|
alpar@1
|
301 |
|
alpar@1
|
302 |
\noindent
|
alpar@1
|
303 |
\verb|void *temp;|
|
alpar@1
|
304 |
|
alpar@1
|
305 |
\begin{comment}Working pointer, which may be used freely for any
|
alpar@1
|
306 |
purposes. The application program can change this field directly.
|
alpar@1
|
307 |
\end{comment}
|
alpar@1
|
308 |
|
alpar@1
|
309 |
\medskip
|
alpar@1
|
310 |
|
alpar@1
|
311 |
\noindent
|
alpar@1
|
312 |
\verb|glp_arc *t_next;|
|
alpar@1
|
313 |
|
alpar@1
|
314 |
\begin{comment}Pointer to another arc, which has the same tail endpoint
|
alpar@1
|
315 |
as this one. \verb|NULL| in this field indicates the end of the list of
|
alpar@1
|
316 |
outgoing arcs.
|
alpar@1
|
317 |
\end{comment}
|
alpar@1
|
318 |
|
alpar@1
|
319 |
\medskip
|
alpar@1
|
320 |
|
alpar@1
|
321 |
\noindent
|
alpar@1
|
322 |
\verb|glp_arc *h_next;|
|
alpar@1
|
323 |
|
alpar@1
|
324 |
\begin{comment}Pointer to another arc, which has the same head endpoint
|
alpar@1
|
325 |
as this one. \verb|NULL| in this field indicates the end of the list of
|
alpar@1
|
326 |
incoming arcs.
|
alpar@1
|
327 |
\end{comment}
|
alpar@1
|
328 |
|
alpar@1
|
329 |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
alpar@1
|
330 |
|
alpar@1
|
331 |
\newpage
|
alpar@1
|
332 |
|
alpar@1
|
333 |
\section{Graph creating and modifying routines}
|
alpar@1
|
334 |
|
alpar@1
|
335 |
\subsection{glp\_create\_graph---create graph}
|
alpar@1
|
336 |
|
alpar@1
|
337 |
\subsubsection*{Synopsis}
|
alpar@1
|
338 |
|
alpar@1
|
339 |
\begin{verbatim}
|
alpar@1
|
340 |
glp_graph *glp_create_graph(int v_size, int a_size);
|
alpar@1
|
341 |
\end{verbatim}
|
alpar@1
|
342 |
|
alpar@1
|
343 |
\subsubsection*{Description}
|
alpar@1
|
344 |
|
alpar@1
|
345 |
The routine \verb|glp_create_graph| creates a new graph, which
|
alpar@1
|
346 |
initially is\linebreak empty, i.e. has no vertices and arcs.
|
alpar@1
|
347 |
|
alpar@1
|
348 |
The parameter \verb|v_size| specifies the size of vertex data blocks,
|
alpar@1
|
349 |
in bytes, $0\leq v\_size\leq 256$.
|
alpar@1
|
350 |
|
alpar@1
|
351 |
The parameter \verb|a_size| specifies the size of arc data blocks, in
|
alpar@1
|
352 |
bytes, $0\leq a\_size\leq 256$.
|
alpar@1
|
353 |
|
alpar@1
|
354 |
\subsubsection*{Returns}
|
alpar@1
|
355 |
|
alpar@1
|
356 |
The routine returns a pointer to the graph created.
|
alpar@1
|
357 |
|
alpar@1
|
358 |
\subsection{glp\_set\_graph\_name---assign (change) graph name}
|
alpar@1
|
359 |
|
alpar@1
|
360 |
\subsubsection*{Synopsis}
|
alpar@1
|
361 |
|
alpar@1
|
362 |
\begin{verbatim}
|
alpar@1
|
363 |
void glp_set_graph_name(glp_graph *G, const char *name);
|
alpar@1
|
364 |
\end{verbatim}
|
alpar@1
|
365 |
|
alpar@1
|
366 |
\subsubsection*{Description}
|
alpar@1
|
367 |
|
alpar@1
|
368 |
The routine \verb|glp_set_graph_name| assigns a symbolic name specified
|
alpar@1
|
369 |
by the character string \verb|name| (1 to 255 chars) to the graph.
|
alpar@1
|
370 |
|
alpar@1
|
371 |
If the parameter \verb|name| is \verb|NULL| or an empty string, the
|
alpar@1
|
372 |
routine erases the existing symbolic name of the graph.
|
alpar@1
|
373 |
|
alpar@1
|
374 |
\newpage
|
alpar@1
|
375 |
|
alpar@1
|
376 |
\subsection{glp\_add\_vertices---add new vertices to graph}
|
alpar@1
|
377 |
|
alpar@1
|
378 |
\subsubsection*{Synopsis}
|
alpar@1
|
379 |
|
alpar@1
|
380 |
\begin{verbatim}
|
alpar@1
|
381 |
int glp_add_vertices(glp_graph *G, int nadd);
|
alpar@1
|
382 |
\end{verbatim}
|
alpar@1
|
383 |
|
alpar@1
|
384 |
\subsubsection*{Description}
|
alpar@1
|
385 |
|
alpar@1
|
386 |
The routine \verb|glp_add_vertices| adds \verb|nadd| vertices to the
|
alpar@1
|
387 |
specified graph. New vertices are always added to the end of the vertex
|
alpar@1
|
388 |
list, so ordinal numbers of existing vertices remain unchanged. Note
|
alpar@1
|
389 |
that this operation may change the field \verb|v| in the struct
|
alpar@1
|
390 |
\verb|glp_graph| (pointer to the vertex array) due to reallocation.
|
alpar@1
|
391 |
|
alpar@1
|
392 |
Being added each new vertex is isolated, i.e. has no incident arcs.
|
alpar@1
|
393 |
|
alpar@1
|
394 |
If the size of vertex data blocks specified on creating the graph is
|
alpar@1
|
395 |
non-zero, the routine also allocates a memory block of that size for
|
alpar@1
|
396 |
each new vertex added, fills it by binary zeros, and stores a pointer to
|
alpar@1
|
397 |
it in the field \verb|data| of the struct \verb|glp_vertex|. Otherwise,
|
alpar@1
|
398 |
if the block size is zero, the field \verb|data| is set to \verb|NULL|.
|
alpar@1
|
399 |
|
alpar@1
|
400 |
\subsubsection*{Returns}
|
alpar@1
|
401 |
|
alpar@1
|
402 |
The routine \verb|glp_add_vertices| returns the ordinal number of the
|
alpar@1
|
403 |
first new vertex added to the graph.
|
alpar@1
|
404 |
|
alpar@1
|
405 |
\subsection{glp\_set\_vertex\_name---assign (change) vertex name}
|
alpar@1
|
406 |
|
alpar@1
|
407 |
\subsubsection*{Synopsis}
|
alpar@1
|
408 |
|
alpar@1
|
409 |
\begin{verbatim}
|
alpar@1
|
410 |
void glp_set_vertex_name(glp_graph *G, int i, const char *name);
|
alpar@1
|
411 |
\end{verbatim}
|
alpar@1
|
412 |
|
alpar@1
|
413 |
\subsubsection*{Description}
|
alpar@1
|
414 |
|
alpar@1
|
415 |
The routine \verb|glp_set_vertex_name| assigns a given symbolic name
|
alpar@1
|
416 |
(1 up to 255 characters) to \verb|i|-th vertex of the specified graph.
|
alpar@1
|
417 |
|
alpar@1
|
418 |
If the parameter \verb|name| is \verb|NULL| or empty string, the
|
alpar@1
|
419 |
routine erases an existing name of \verb|i|-th vertex.
|
alpar@1
|
420 |
|
alpar@1
|
421 |
\newpage
|
alpar@1
|
422 |
|
alpar@1
|
423 |
\subsection{glp\_add\_arc---add new arc to graph}
|
alpar@1
|
424 |
|
alpar@1
|
425 |
\subsubsection*{Synopsis}
|
alpar@1
|
426 |
|
alpar@1
|
427 |
\begin{verbatim}
|
alpar@1
|
428 |
glp_arc *glp_add_arc(glp_graph *G, int i, int j);
|
alpar@1
|
429 |
\end{verbatim}
|
alpar@1
|
430 |
|
alpar@1
|
431 |
\subsubsection*{Description}
|
alpar@1
|
432 |
|
alpar@1
|
433 |
The routine \verb|glp_add_arc| adds one new arc to the specified graph.
|
alpar@1
|
434 |
|
alpar@1
|
435 |
The parameters \verb|i| and \verb|j| specify the ordinal numbers of,
|
alpar@1
|
436 |
resp., tail and head endpoints (vertices) of the arc. Note that
|
alpar@1
|
437 |
self-loops and multiple arcs are allowed.
|
alpar@1
|
438 |
|
alpar@1
|
439 |
If the size of arc data blocks specified on creating the graph is
|
alpar@1
|
440 |
non-zero, the routine also allocates a memory block of that size, fills
|
alpar@1
|
441 |
it by binary zeros, and stores a pointer to it in the field \verb|data|
|
alpar@1
|
442 |
of the struct \verb|glp_arc|. Otherwise, if the block size is zero, the
|
alpar@1
|
443 |
field \verb|data| is set to \verb|NULL|.
|
alpar@1
|
444 |
|
alpar@1
|
445 |
\subsection{glp\_del\_vertices---delete vertices from graph}
|
alpar@1
|
446 |
|
alpar@1
|
447 |
\subsubsection*{Synopsis}
|
alpar@1
|
448 |
|
alpar@1
|
449 |
\begin{verbatim}
|
alpar@1
|
450 |
void glp_del_vertices(glp_graph *G, int ndel, const int num[]);
|
alpar@1
|
451 |
\end{verbatim}
|
alpar@1
|
452 |
|
alpar@1
|
453 |
\subsubsection*{Description}
|
alpar@1
|
454 |
|
alpar@1
|
455 |
The routine \verb|glp_del_vertices| deletes vertices along with all
|
alpar@1
|
456 |
incident arcs from the specified graph. Ordinal numbers of vertices to
|
alpar@1
|
457 |
be deleted should be placed in locations \verb|num[1]|, \dots,
|
alpar@1
|
458 |
\verb|num[ndel]|, \verb|ndel| $>0$.
|
alpar@1
|
459 |
|
alpar@1
|
460 |
Note that deleting vertices involves changing ordinal numbers of other
|
alpar@1
|
461 |
vertices remaining in the graph. New ordinal numbers of the remaining
|
alpar@1
|
462 |
vertices are assigned under the assumption that the original order of
|
alpar@1
|
463 |
vertices is not changed.
|
alpar@1
|
464 |
|
alpar@1
|
465 |
\subsection{glp\_del\_arc---delete arc from graph}
|
alpar@1
|
466 |
|
alpar@1
|
467 |
\subsubsection*{Synopsis}
|
alpar@1
|
468 |
|
alpar@1
|
469 |
\begin{verbatim}
|
alpar@1
|
470 |
void glp_del_arc(glp_graph *G, glp_arc *a);
|
alpar@1
|
471 |
\end{verbatim}
|
alpar@1
|
472 |
|
alpar@1
|
473 |
\subsubsection*{Description}
|
alpar@1
|
474 |
|
alpar@1
|
475 |
The routine \verb|glp_del_arc| deletes an arc from the specified graph.
|
alpar@1
|
476 |
The arc to be deleted must exist.
|
alpar@1
|
477 |
|
alpar@1
|
478 |
\subsection{glp\_erase\_graph---erase graph content}
|
alpar@1
|
479 |
|
alpar@1
|
480 |
\subsubsection*{Synopsis}
|
alpar@1
|
481 |
|
alpar@1
|
482 |
\begin{verbatim}
|
alpar@1
|
483 |
void glp_erase_graph(glp_graph *G, int v_size, int a_size);
|
alpar@1
|
484 |
\end{verbatim}
|
alpar@1
|
485 |
|
alpar@1
|
486 |
\subsubsection*{Description}
|
alpar@1
|
487 |
|
alpar@1
|
488 |
The routine \verb|glp_erase_graph| erases the content of the specified
|
alpar@1
|
489 |
graph. The effect of this operation is the same as if the graph would be
|
alpar@1
|
490 |
deleted with the routine \verb|glp_delete_graph| and then created anew
|
alpar@1
|
491 |
with the routine \verb|glp_create_graph|, with exception that the handle
|
alpar@1
|
492 |
(pointer) to the graph remains valid.
|
alpar@1
|
493 |
|
alpar@1
|
494 |
The parameters \verb|v_size| and \verb|a_size| have the same meaning as
|
alpar@1
|
495 |
for the routine \verb|glp_create_graph|.
|
alpar@1
|
496 |
|
alpar@1
|
497 |
\subsection{glp\_delete\_graph---delete graph}
|
alpar@1
|
498 |
|
alpar@1
|
499 |
\subsubsection*{Synopsis}
|
alpar@1
|
500 |
|
alpar@1
|
501 |
\begin{verbatim}
|
alpar@1
|
502 |
void glp_delete_graph(glp_graph *G);
|
alpar@1
|
503 |
\end{verbatim}
|
alpar@1
|
504 |
|
alpar@1
|
505 |
\subsubsection*{Description}
|
alpar@1
|
506 |
|
alpar@1
|
507 |
The routine \verb|glp_delete_graph| deletes the specified graph and
|
alpar@1
|
508 |
frees all the memory allocated to this program object.
|
alpar@1
|
509 |
|
alpar@1
|
510 |
\newpage
|
alpar@1
|
511 |
|
alpar@1
|
512 |
\section{Graph searching routines}
|
alpar@1
|
513 |
|
alpar@1
|
514 |
\subsection{glp\_create\_v\_index---create vertex name index}
|
alpar@1
|
515 |
|
alpar@1
|
516 |
\subsubsection*{Synopsis}
|
alpar@1
|
517 |
|
alpar@1
|
518 |
\begin{verbatim}
|
alpar@1
|
519 |
void glp_create_v_index(glp_graph *G);
|
alpar@1
|
520 |
\end{verbatim}
|
alpar@1
|
521 |
|
alpar@1
|
522 |
\subsubsection*{Description}
|
alpar@1
|
523 |
|
alpar@1
|
524 |
The routine \verb|glp_create_v_index| creates the name index for the
|
alpar@1
|
525 |
specified graph. The name index is an auxiliary data structure, which
|
alpar@1
|
526 |
is intended to quickly (i.e. for logarithmic time) find vertices by
|
alpar@1
|
527 |
their names.
|
alpar@1
|
528 |
|
alpar@1
|
529 |
This routine can be called at any time. If the name index already
|
alpar@1
|
530 |
exists, the routine does nothing.
|
alpar@1
|
531 |
|
alpar@1
|
532 |
\subsection{glp\_find\_vertex---find vertex by its name}
|
alpar@1
|
533 |
|
alpar@1
|
534 |
\subsubsection*{Synopsis}
|
alpar@1
|
535 |
|
alpar@1
|
536 |
\begin{verbatim}
|
alpar@1
|
537 |
int glp_find_vertex(glp_graph *G, const char *name);
|
alpar@1
|
538 |
\end{verbatim}
|
alpar@1
|
539 |
|
alpar@1
|
540 |
\subsubsection*{Returns}
|
alpar@1
|
541 |
|
alpar@1
|
542 |
The routine \verb|glp_find_vertex| returns the ordinal number of
|
alpar@1
|
543 |
a vertex, which is assigned (by the routine \verb|glp_set_vertex_name|)
|
alpar@1
|
544 |
the specified symbolic \verb|name|. If no such vertex exists, the
|
alpar@1
|
545 |
routine returns 0.
|
alpar@1
|
546 |
|
alpar@1
|
547 |
\subsection{glp\_delete\_v\_index---delete vertex name index}
|
alpar@1
|
548 |
|
alpar@1
|
549 |
\subsubsection*{Synopsis}
|
alpar@1
|
550 |
|
alpar@1
|
551 |
\begin{verbatim}
|
alpar@1
|
552 |
void glp_delete_v_index(glp_graph *G);
|
alpar@1
|
553 |
\end{verbatim}
|
alpar@1
|
554 |
|
alpar@1
|
555 |
\subsubsection*{Description}
|
alpar@1
|
556 |
|
alpar@1
|
557 |
The routine \verb|glp_delete_v_index| deletes the name index previously
|
alpar@1
|
558 |
created by the routine \verb|glp_create_v_index| and frees the memory
|
alpar@1
|
559 |
allocated to this auxiliary data structure.
|
alpar@1
|
560 |
|
alpar@1
|
561 |
This routine can be called at any time. If the name index does not
|
alpar@1
|
562 |
exist, the routine does nothing.
|
alpar@1
|
563 |
|
alpar@1
|
564 |
\newpage
|
alpar@1
|
565 |
|
alpar@1
|
566 |
\section{Graph reading/writing routines}
|
alpar@1
|
567 |
|
alpar@1
|
568 |
\subsection{glp\_read\_graph---read graph from plain text file}
|
alpar@1
|
569 |
|
alpar@1
|
570 |
\subsubsection*{Synopsis}
|
alpar@1
|
571 |
|
alpar@1
|
572 |
\begin{verbatim}
|
alpar@1
|
573 |
int glp_read_graph(glp_graph *G, const char *fname);
|
alpar@1
|
574 |
\end{verbatim}
|
alpar@1
|
575 |
|
alpar@1
|
576 |
\subsubsection*{Description}
|
alpar@1
|
577 |
|
alpar@1
|
578 |
The routine \verb|glp_read_graph| reads a graph from a plain text file,
|
alpar@1
|
579 |
whose name is specified by the parameter \verb|fname|. Note that before
|
alpar@1
|
580 |
reading data the current content of the graph object is completely
|
alpar@1
|
581 |
erased with the routine \verb|glp_erase_graph|.
|
alpar@1
|
582 |
|
alpar@1
|
583 |
For the file format see description of the routine
|
alpar@1
|
584 |
\verb|glp_write_graph|.
|
alpar@1
|
585 |
|
alpar@1
|
586 |
\subsubsection*{Returns}
|
alpar@1
|
587 |
|
alpar@1
|
588 |
If the operation was successful, the routine returns zero. Otherwise
|
alpar@1
|
589 |
it prints an error message and returns non-zero.
|
alpar@1
|
590 |
|
alpar@1
|
591 |
\subsection{glp\_write\_graph---write graph to plain text file}
|
alpar@1
|
592 |
|
alpar@1
|
593 |
\subsubsection*{Synopsis}
|
alpar@1
|
594 |
|
alpar@1
|
595 |
\begin{verbatim}
|
alpar@1
|
596 |
int glp_write_graph(glp_graph *G, const char *fname);
|
alpar@1
|
597 |
\end{verbatim}
|
alpar@1
|
598 |
|
alpar@1
|
599 |
\subsubsection*{Description}
|
alpar@1
|
600 |
|
alpar@1
|
601 |
The routine \verb|glp_write_graph| writes the graph to a plain text
|
alpar@1
|
602 |
file, whose name is specified by the parameter \verb|fname|.
|
alpar@1
|
603 |
|
alpar@1
|
604 |
\subsubsection*{Returns}
|
alpar@1
|
605 |
|
alpar@1
|
606 |
If the operation was successful, the routine returns zero. Otherwise
|
alpar@1
|
607 |
it prints an error message and returns non-zero.
|
alpar@1
|
608 |
|
alpar@1
|
609 |
\subsubsection*{File format}
|
alpar@1
|
610 |
|
alpar@1
|
611 |
The file created by the routine \verb|glp_write_graph| is a plain text
|
alpar@1
|
612 |
file, which contains the following information:
|
alpar@1
|
613 |
|
alpar@1
|
614 |
\begin{verbatim}
|
alpar@1
|
615 |
nv na
|
alpar@1
|
616 |
i[1] j[1]
|
alpar@1
|
617 |
i[2] j[2]
|
alpar@1
|
618 |
. . .
|
alpar@1
|
619 |
i[na] j[na]
|
alpar@1
|
620 |
\end{verbatim}
|
alpar@1
|
621 |
|
alpar@1
|
622 |
\noindent
|
alpar@1
|
623 |
where:
|
alpar@1
|
624 |
|
alpar@1
|
625 |
\noindent
|
alpar@1
|
626 |
\verb|nv| is the number of vertices (nodes);
|
alpar@1
|
627 |
|
alpar@1
|
628 |
\noindent
|
alpar@1
|
629 |
\verb|na| is the number of arcs;
|
alpar@1
|
630 |
|
alpar@1
|
631 |
\noindent
|
alpar@1
|
632 |
\verb|i[k]|, $k=1,\dots,na$, is the index of tail vertex of arc $k$;
|
alpar@1
|
633 |
|
alpar@1
|
634 |
\noindent
|
alpar@1
|
635 |
\verb|j[k]|, $k=1,\dots,na$, is the index of head vertex of arc $k$.
|
alpar@1
|
636 |
|
alpar@1
|
637 |
\subsection{glp\_read\_ccdata---read graph from text file in DIMACS
|
alpar@1
|
638 |
clique/coloring format}
|
alpar@1
|
639 |
|
alpar@1
|
640 |
\subsubsection*{Synopsis}
|
alpar@1
|
641 |
|
alpar@1
|
642 |
\begin{verbatim}
|
alpar@1
|
643 |
int glp_read_ccdata(glp_graph *G, int v_wgt,
|
alpar@1
|
644 |
const char *fname);
|
alpar@1
|
645 |
\end{verbatim}
|
alpar@1
|
646 |
|
alpar@1
|
647 |
\subsubsection*{Description}
|
alpar@1
|
648 |
|
alpar@1
|
649 |
The routine {\it glp\_read\_ccdata} reads a graph from a text file in
|
alpar@1
|
650 |
DIMACS clique/coloring format. (Though this format is originally
|
alpar@1
|
651 |
designed to represent data for the minimal vertex coloring and maximal
|
alpar@1
|
652 |
clique problems, it may be used to represent general undirected and
|
alpar@1
|
653 |
directed graphs, because the routine allows reading self-loops and
|
alpar@1
|
654 |
multiple edges/arcs keeping the order of vertices specified for each
|
alpar@1
|
655 |
edge/arc of the graph.)
|
alpar@1
|
656 |
|
alpar@1
|
657 |
The parameter $G$ specifies the graph object to be read in. Note that
|
alpar@1
|
658 |
before reading data the current content of the graph object is
|
alpar@1
|
659 |
completely erased with the routine {\it glp\_erase\_graph}.
|
alpar@1
|
660 |
|
alpar@1
|
661 |
The parameter {\it v\_wgt} specifies an offset of the field of type
|
alpar@1
|
662 |
{\bf double} in the vertex data block, to which the routine stores the
|
alpar@1
|
663 |
vertex weight. If {\it v\_wgt} $<0$, the vertex weights are not stored.
|
alpar@1
|
664 |
|
alpar@1
|
665 |
The character string {\it fname} specifies the name of a text file to
|
alpar@1
|
666 |
be read in. (If the file name ends with the suffix `\verb|.gz|', the
|
alpar@1
|
667 |
file is assumed to be compressed, in which case the routine decompresses
|
alpar@1
|
668 |
it ``on the fly''.)
|
alpar@1
|
669 |
|
alpar@1
|
670 |
\subsubsection*{Returns}
|
alpar@1
|
671 |
|
alpar@1
|
672 |
If the operation was successful, the routine returns zero. Otherwise,
|
alpar@1
|
673 |
it prints an error message and returns non-zero.
|
alpar@1
|
674 |
|
alpar@1
|
675 |
\subsubsection*{DIMACS clique/coloring format\footnote{This material is
|
alpar@1
|
676 |
based on the paper ``Clique and Coloring Problems Graph Format'', which
|
alpar@1
|
677 |
is publically available at
|
alpar@1
|
678 |
{\tt http://dimacs.rutgers.edu/Challenges/}.}}
|
alpar@1
|
679 |
|
alpar@1
|
680 |
The DIMACS input file is a plain ASCII text file. It contains
|
alpar@1
|
681 |
{\it lines} of several types described below. A line is terminated with
|
alpar@1
|
682 |
an end-of-line character. Fields in each line are separated by at least
|
alpar@1
|
683 |
one blank space. Each line begins with a one-character designator to
|
alpar@1
|
684 |
identify the line type.
|
alpar@1
|
685 |
|
alpar@1
|
686 |
Note that DIMACS requires all numerical quantities to be integers in
|
alpar@1
|
687 |
the range $[-2^{31},2^{31}-1]$ while GLPK allows the quantities to be
|
alpar@1
|
688 |
floating-point numbers.
|
alpar@1
|
689 |
|
alpar@1
|
690 |
\paragraph{Comment lines.} Comment lines give human-readable information
|
alpar@1
|
691 |
about the file and are ignored by programs. Comment lines can appear
|
alpar@1
|
692 |
anywhere in the file. Each comment line begins with a lower-case
|
alpar@1
|
693 |
character \verb|c|.
|
alpar@1
|
694 |
|
alpar@1
|
695 |
\begin{verbatim}
|
alpar@1
|
696 |
c This is a comment line
|
alpar@1
|
697 |
\end{verbatim}
|
alpar@1
|
698 |
|
alpar@1
|
699 |
\paragraph{Problem line.} There is one problem line per data file. The
|
alpar@1
|
700 |
problem line must appear before any node or edge descriptor lines. It
|
alpar@1
|
701 |
has the following format:
|
alpar@1
|
702 |
|
alpar@1
|
703 |
\begin{verbatim}
|
alpar@1
|
704 |
p edge NODES EDGES
|
alpar@1
|
705 |
\end{verbatim}
|
alpar@1
|
706 |
|
alpar@1
|
707 |
\noindent
|
alpar@1
|
708 |
The lower-case letter \verb|p| signifies that this is a problem line.
|
alpar@1
|
709 |
The four-character problem designator \verb|edge| identifies the file
|
alpar@1
|
710 |
as containing data for the minimal vertex coloring or maximal clique
|
alpar@1
|
711 |
problem. The \verb|NODES| field contains an integer value specifying
|
alpar@1
|
712 |
the number of vertices in the graph. The \verb|EDGES| field contains an
|
alpar@1
|
713 |
integer value specifying the number of edges (arcs) in the graph.
|
alpar@1
|
714 |
|
alpar@1
|
715 |
\paragraph{Vertex descriptors.} These lines give the weight assigned to
|
alpar@1
|
716 |
a vertex of the graph. There is one vertex descriptor line for each
|
alpar@1
|
717 |
vertex, with the following format. Vertices without a descriptor take on
|
alpar@1
|
718 |
a default value of 1.
|
alpar@1
|
719 |
|
alpar@1
|
720 |
\begin{verbatim}
|
alpar@1
|
721 |
n ID VALUE
|
alpar@1
|
722 |
\end{verbatim}
|
alpar@1
|
723 |
|
alpar@1
|
724 |
\noindent
|
alpar@1
|
725 |
The lower-case character \verb|n| signifies that this is a vertex
|
alpar@1
|
726 |
descriptor line. The \verb|ID| field gives a vertex identification
|
alpar@1
|
727 |
number, an integer between 1 and $n$, where $n$ is the number of
|
alpar@1
|
728 |
vertices in the graph. The \verb|VALUE| field gives a vertex weight,
|
alpar@1
|
729 |
which can either positive or negative (or zero).
|
alpar@1
|
730 |
|
alpar@1
|
731 |
\paragraph{Edge descriptors.} There is one edge descriptor line for
|
alpar@1
|
732 |
each edge (arc) of the graph, each with the following format:
|
alpar@1
|
733 |
|
alpar@1
|
734 |
\begin{verbatim}
|
alpar@1
|
735 |
e I J
|
alpar@1
|
736 |
\end{verbatim}
|
alpar@1
|
737 |
|
alpar@1
|
738 |
\noindent
|
alpar@1
|
739 |
The lower-case character \verb|e| signifies that this is an edge
|
alpar@1
|
740 |
descriptor line. For an edge (arc) $(i,j)$ the fields \verb|I| and
|
alpar@1
|
741 |
\verb|J| specify its endpoints.
|
alpar@1
|
742 |
|
alpar@1
|
743 |
\paragraph{Example.} The following example of an undirected graph:
|
alpar@1
|
744 |
|
alpar@1
|
745 |
\bigskip
|
alpar@1
|
746 |
|
alpar@1
|
747 |
\noindent\hfil
|
alpar@1
|
748 |
\xymatrix %@C=32pt
|
alpar@1
|
749 |
{&{v_1}\ar@{-}[ldd]\ar@{-}[dd]\ar@{-}[rd]\ar@{-}[rr]&&{v_2}\ar@{-}[ld]
|
alpar@1
|
750 |
\ar@{-}[dd]\ar@{-}[rdd]&\\
|
alpar@1
|
751 |
&&{v_7}\ar@{-}[ld]\ar@{-}[rd]&&\\
|
alpar@1
|
752 |
{v_6}\ar@{-}[r]\ar@{-}[rdd]&{v_{10}}\ar@{-}[rr]\ar@{-}[rd]\ar@{-}[dd]&&
|
alpar@1
|
753 |
{v_8}\ar@{-}[ld]\ar@{-}[dd]\ar@{-}[r]&{v_3}\ar@{-}[ldd]\\
|
alpar@1
|
754 |
&&{v_9}\ar@{-}[ld]\ar@{-}[rd]&&\\
|
alpar@1
|
755 |
&{v_5}\ar@{-}[rr]&&{v_4}&\\
|
alpar@1
|
756 |
}
|
alpar@1
|
757 |
|
alpar@1
|
758 |
\bigskip
|
alpar@1
|
759 |
|
alpar@1
|
760 |
\noindent
|
alpar@1
|
761 |
might be coded in DIMACS clique/coloring format as follows:
|
alpar@1
|
762 |
|
alpar@1
|
763 |
\begin{footnotesize}
|
alpar@1
|
764 |
\begin{verbatim}
|
alpar@1
|
765 |
c sample.col
|
alpar@1
|
766 |
c
|
alpar@1
|
767 |
c This is an example of the vertex coloring problem data
|
alpar@1
|
768 |
c in DIMACS format.
|
alpar@1
|
769 |
c
|
alpar@1
|
770 |
p edge 10 21
|
alpar@1
|
771 |
c
|
alpar@1
|
772 |
e 1 2
|
alpar@1
|
773 |
e 1 6
|
alpar@1
|
774 |
e 1 7
|
alpar@1
|
775 |
e 1 10
|
alpar@1
|
776 |
e 2 3
|
alpar@1
|
777 |
e 2 7
|
alpar@1
|
778 |
e 2 8
|
alpar@1
|
779 |
e 3 4
|
alpar@1
|
780 |
e 3 8
|
alpar@1
|
781 |
e 4 5
|
alpar@1
|
782 |
e 4 8
|
alpar@1
|
783 |
e 4 9
|
alpar@1
|
784 |
e 5 6
|
alpar@1
|
785 |
e 5 9
|
alpar@1
|
786 |
e 5 10
|
alpar@1
|
787 |
e 6 10
|
alpar@1
|
788 |
e 7 8
|
alpar@1
|
789 |
e 7 10
|
alpar@1
|
790 |
e 8 9
|
alpar@1
|
791 |
e 8 10
|
alpar@1
|
792 |
e 9 10
|
alpar@1
|
793 |
c
|
alpar@1
|
794 |
c eof
|
alpar@1
|
795 |
\end{verbatim}
|
alpar@1
|
796 |
\end{footnotesize}
|
alpar@1
|
797 |
|
alpar@1
|
798 |
\subsection{glp\_write\_ccdata---write graph to text file in DIMACS
|
alpar@1
|
799 |
clique/coloring format}
|
alpar@1
|
800 |
|
alpar@1
|
801 |
\subsubsection*{Synopsis}
|
alpar@1
|
802 |
|
alpar@1
|
803 |
\begin{verbatim}
|
alpar@1
|
804 |
int glp_write_ccdata(glp_graph *G, int v_wgt,
|
alpar@1
|
805 |
const char *fname);
|
alpar@1
|
806 |
\end{verbatim}
|
alpar@1
|
807 |
|
alpar@1
|
808 |
\subsection*{Description}
|
alpar@1
|
809 |
|
alpar@1
|
810 |
The routine {\it glp\_write\_ccdata} writes the graph object specified
|
alpar@1
|
811 |
by the parameter $G$ to a text file in DIMACS clique/coloring format.
|
alpar@1
|
812 |
(Though this format is originally designed to represent data for the
|
alpar@1
|
813 |
minimal vertex coloring and maximal clique problems, it may be used to
|
alpar@1
|
814 |
represent general undirected and directed graphs, because the routine
|
alpar@1
|
815 |
allows writing self-loops and multiple edges/arcs keeping the order of
|
alpar@1
|
816 |
vertices specified for each edge/arc of the graph.)
|
alpar@1
|
817 |
|
alpar@1
|
818 |
The parameter {\it v\_wgt} specifies an offset of the field of type
|
alpar@1
|
819 |
{\bf double} in the vertex data block, which contains the vertex weight.
|
alpar@1
|
820 |
If {\it v\_wgt} $<0$, it is assumed that the weight of each vertex is 1.
|
alpar@1
|
821 |
|
alpar@1
|
822 |
The character string {\it fname} specifies a name of the text file to be
|
alpar@1
|
823 |
written out. (If the file name ends with suffix `\verb|.gz|', the file
|
alpar@1
|
824 |
is assumed to be compressed, in which case the routine performs
|
alpar@1
|
825 |
automatic compression on writing it.)
|
alpar@1
|
826 |
|
alpar@1
|
827 |
\subsubsection*{Returns}
|
alpar@1
|
828 |
|
alpar@1
|
829 |
If the operation was successful, the routine returns zero. Otherwise,
|
alpar@1
|
830 |
it prints an error message and returns non-zero.
|
alpar@1
|
831 |
|
alpar@1
|
832 |
\newpage
|
alpar@1
|
833 |
|
alpar@1
|
834 |
\section{Graph analysis routines}
|
alpar@1
|
835 |
|
alpar@1
|
836 |
\subsection{glp\_weak\_comp---find all weakly connected components of
|
alpar@1
|
837 |
graph}
|
alpar@1
|
838 |
|
alpar@1
|
839 |
\subsubsection*{Synopsis}
|
alpar@1
|
840 |
|
alpar@1
|
841 |
\begin{verbatim}
|
alpar@1
|
842 |
int glp_weak_comp(glp_graph *G, int v_num);
|
alpar@1
|
843 |
\end{verbatim}
|
alpar@1
|
844 |
|
alpar@1
|
845 |
\subsubsection*{Description}
|
alpar@1
|
846 |
|
alpar@1
|
847 |
The routine \verb|glp_weak_comp| finds all weakly connected components
|
alpar@1
|
848 |
of the specified graph.
|
alpar@1
|
849 |
|
alpar@1
|
850 |
The parameter \verb|v_num| specifies an offset of the field of type
|
alpar@1
|
851 |
\verb|int| in the vertex data block, to which the routine stores the
|
alpar@1
|
852 |
number of a weakly connected component containing that vertex. If
|
alpar@1
|
853 |
\verb|v_num| $<0$, no component numbers are stored.
|
alpar@1
|
854 |
|
alpar@1
|
855 |
The components are numbered in arbitrary order from 1 to \verb|nc|,
|
alpar@1
|
856 |
where \verb|nc| is the total number of components found,
|
alpar@1
|
857 |
$0\leq$ \verb|nc| $\leq|V|$.
|
alpar@1
|
858 |
|
alpar@1
|
859 |
\subsubsection*{Returns}
|
alpar@1
|
860 |
|
alpar@1
|
861 |
The routine returns \verb|nc|, the total number of components found.
|
alpar@1
|
862 |
|
alpar@1
|
863 |
\subsection{glp\_strong\_comp---find all strongly connected components
|
alpar@1
|
864 |
of graph}
|
alpar@1
|
865 |
|
alpar@1
|
866 |
\subsubsection*{Synopsis}
|
alpar@1
|
867 |
|
alpar@1
|
868 |
\begin{verbatim}
|
alpar@1
|
869 |
int glp_strong_comp(glp_graph *G, int v_num);
|
alpar@1
|
870 |
\end{verbatim}
|
alpar@1
|
871 |
|
alpar@1
|
872 |
\subsubsection*{Description}
|
alpar@1
|
873 |
|
alpar@1
|
874 |
The routine \verb|glp_strong_comp| finds all strongly connected
|
alpar@1
|
875 |
components of the specified graph.
|
alpar@1
|
876 |
|
alpar@1
|
877 |
The parameter \verb|v_num| specifies an offset of the field of type
|
alpar@1
|
878 |
\verb|int| in the vertex data block, to which the routine stores the
|
alpar@1
|
879 |
number of a strongly connected component containing that vertex. If
|
alpar@1
|
880 |
\verb|v_num| $<0$, no component numbers are stored.
|
alpar@1
|
881 |
|
alpar@1
|
882 |
The components are numbered in arbitrary order from 1 to \verb|nc|,
|
alpar@1
|
883 |
where \verb|nc| is the total number of components found,
|
alpar@1
|
884 |
$0\leq$ \verb|nc| $\leq|V|$. However, the component numbering has the
|
alpar@1
|
885 |
property that for every arc $(i\rightarrow j)$ in the graph the
|
alpar@1
|
886 |
condition $num(i)\geq num(j)$ holds.
|
alpar@1
|
887 |
|
alpar@1
|
888 |
\subsubsection*{Returns}
|
alpar@1
|
889 |
|
alpar@1
|
890 |
The routine returns \verb|nc|, the total number of components found.
|
alpar@1
|
891 |
|
alpar@1
|
892 |
\subsubsection*{References}
|
alpar@1
|
893 |
|
alpar@1
|
894 |
I.~S.~Duff, J.~K.~Reid, Algorithm 529: Permutations to block triangular
|
alpar@1
|
895 |
form, ACM Trans. on Math. Softw. 4 (1978), 189-92.
|
alpar@1
|
896 |
|
alpar@1
|
897 |
\subsubsection*{Example}
|
alpar@1
|
898 |
|
alpar@1
|
899 |
The following program reads a graph from a plain text file
|
alpar@1
|
900 |
`\verb|graph.txt|' and finds all its strongly connected components.
|
alpar@1
|
901 |
|
alpar@1
|
902 |
\begin{footnotesize}
|
alpar@1
|
903 |
\begin{verbatim}
|
alpar@1
|
904 |
#include <stddef.h>
|
alpar@1
|
905 |
#include <stdio.h>
|
alpar@1
|
906 |
#include <stdlib.h>
|
alpar@1
|
907 |
#include <glpk.h>
|
alpar@1
|
908 |
|
alpar@1
|
909 |
typedef struct { int num; } v_data;
|
alpar@1
|
910 |
|
alpar@1
|
911 |
#define vertex(v) ((v_data *)((v)->data))
|
alpar@1
|
912 |
|
alpar@1
|
913 |
int main(void)
|
alpar@1
|
914 |
{ glp_graph *G;
|
alpar@1
|
915 |
int i, nc;
|
alpar@1
|
916 |
G = glp_create_graph(sizeof(v_data), 0);
|
alpar@1
|
917 |
glp_read_graph(G, "graph.txt");
|
alpar@1
|
918 |
nc = glp_strong_comp(G, offsetof(v_data, num));
|
alpar@1
|
919 |
printf("nc = %d\n", nc);
|
alpar@1
|
920 |
for (i = 1; i <= G->nv; i++)
|
alpar@1
|
921 |
printf("num[%d] = %d\n", i, vertex(G->v[i])->num);
|
alpar@1
|
922 |
glp_delete_graph(G);
|
alpar@1
|
923 |
return 0;
|
alpar@1
|
924 |
}
|
alpar@1
|
925 |
\end{verbatim}
|
alpar@1
|
926 |
\end{footnotesize}
|
alpar@1
|
927 |
|
alpar@1
|
928 |
\noindent
|
alpar@1
|
929 |
If the file `\verb|graph.txt|' contains the graph shown below:
|
alpar@1
|
930 |
|
alpar@1
|
931 |
\bigskip
|
alpar@1
|
932 |
|
alpar@1
|
933 |
\noindent\hfil
|
alpar@1
|
934 |
\xymatrix
|
alpar@1
|
935 |
{1\ar[r]&2\ar[r]&3\ar[r]\ar[dd]&4\ar[dd]\\
|
alpar@1
|
936 |
5\ar[u]&6\ar[l]\\
|
alpar@1
|
937 |
7\ar[u]&&8\ar[lu]\ar[ll]\ar[r]&9\ar[r]&10\ar[r]\ar[d]&11\ar[d]\\
|
alpar@1
|
938 |
12\ar[u]\ar[rru]\ar@/_/[rr]&&13\ar[ll]\ar[u]\ar[rr]&&14\ar[lu]&15\ar[l]
|
alpar@1
|
939 |
\\
|
alpar@1
|
940 |
}
|
alpar@1
|
941 |
|
alpar@1
|
942 |
\bigskip\bigskip
|
alpar@1
|
943 |
|
alpar@1
|
944 |
\noindent
|
alpar@1
|
945 |
the program output may look like follows:
|
alpar@1
|
946 |
|
alpar@1
|
947 |
\begin{footnotesize}
|
alpar@1
|
948 |
\begin{verbatim}
|
alpar@1
|
949 |
Reading graph from `graph.txt'...
|
alpar@1
|
950 |
Graph has 15 vertices and 30 arcs
|
alpar@1
|
951 |
31 lines were read
|
alpar@1
|
952 |
nc = 4
|
alpar@1
|
953 |
num[1] = 3
|
alpar@1
|
954 |
num[2] = 3
|
alpar@1
|
955 |
num[3] = 3
|
alpar@1
|
956 |
num[4] = 2
|
alpar@1
|
957 |
num[5] = 3
|
alpar@1
|
958 |
num[6] = 3
|
alpar@1
|
959 |
num[7] = 3
|
alpar@1
|
960 |
num[8] = 3
|
alpar@1
|
961 |
num[9] = 1
|
alpar@1
|
962 |
num[10] = 1
|
alpar@1
|
963 |
num[11] = 1
|
alpar@1
|
964 |
num[12] = 4
|
alpar@1
|
965 |
num[13] = 4
|
alpar@1
|
966 |
num[14] = 1
|
alpar@1
|
967 |
num[15] = 1
|
alpar@1
|
968 |
\end{verbatim}
|
alpar@1
|
969 |
\end{footnotesize}
|
alpar@1
|
970 |
|
alpar@1
|
971 |
\subsection{glp\_top\_sort---topological sorting of acyclic digraph}
|
alpar@1
|
972 |
|
alpar@1
|
973 |
\subsubsection*{Synopsis}
|
alpar@1
|
974 |
|
alpar@1
|
975 |
\begin{verbatim}
|
alpar@1
|
976 |
int glp_top_sort(glp_graph *G, int v_num);
|
alpar@1
|
977 |
\end{verbatim}
|
alpar@1
|
978 |
|
alpar@1
|
979 |
\subsubsection*{Description}
|
alpar@1
|
980 |
|
alpar@1
|
981 |
The routine \verb|glp_top_sort| performs topological sorting of
|
alpar@1
|
982 |
vertices of the specified acyclic digraph.
|
alpar@1
|
983 |
|
alpar@1
|
984 |
The parameter \verb|v_num| specifies an offset of the field of type
|
alpar@1
|
985 |
\verb|int| in the vertex data block, to which the routine stores the
|
alpar@1
|
986 |
vertex number assigned. If \verb|v_num| $<0$, vertex numbers are not
|
alpar@1
|
987 |
stored.
|
alpar@1
|
988 |
|
alpar@1
|
989 |
The vertices are numbered from 1 to $n$, where $n$ is the total number
|
alpar@1
|
990 |
of vertices in the graph. The vertex numbering has the property that
|
alpar@1
|
991 |
for every arc $(i\rightarrow j)$ in the graph the condition
|
alpar@1
|
992 |
$num(i)<num(j)$ holds. Special case $num(i)=0$ means that vertex $i$ is
|
alpar@1
|
993 |
not assigned a number, because the graph is {\it not} acyclic.
|
alpar@1
|
994 |
|
alpar@1
|
995 |
\subsubsection*{Returns}
|
alpar@1
|
996 |
|
alpar@1
|
997 |
If the graph is acyclic and therefore all the vertices have been
|
alpar@1
|
998 |
assigned numbers, the routine \verb|glp_top_sort| returns zero.
|
alpar@1
|
999 |
Otherwise, if the graph is not acyclic, the routine returns the number
|
alpar@1
|
1000 |
of vertices which have not been numbered, i.e. for which $num(i)=0$.
|
alpar@1
|
1001 |
|
alpar@1
|
1002 |
\subsubsection*{Example}
|
alpar@1
|
1003 |
|
alpar@1
|
1004 |
The following program reads a digraph from a plain text file
|
alpar@1
|
1005 |
`\verb|graph.txt|' and performs topological sorting of its vertices.
|
alpar@1
|
1006 |
|
alpar@1
|
1007 |
\begin{footnotesize}
|
alpar@1
|
1008 |
\begin{verbatim}
|
alpar@1
|
1009 |
#include <stddef.h>
|
alpar@1
|
1010 |
#include <stdio.h>
|
alpar@1
|
1011 |
#include <stdlib.h>
|
alpar@1
|
1012 |
#include <glpk.h>
|
alpar@1
|
1013 |
|
alpar@1
|
1014 |
typedef struct { int num; } v_data;
|
alpar@1
|
1015 |
|
alpar@1
|
1016 |
#define vertex(v) ((v_data *)((v)->data))
|
alpar@1
|
1017 |
|
alpar@1
|
1018 |
int main(void)
|
alpar@1
|
1019 |
{ glp_graph *G;
|
alpar@1
|
1020 |
int i, cnt;
|
alpar@1
|
1021 |
G = glp_create_graph(sizeof(v_data), 0);
|
alpar@1
|
1022 |
glp_read_graph(G, "graph.txt");
|
alpar@1
|
1023 |
cnt = glp_top_sort(G, offsetof(v_data, num));
|
alpar@1
|
1024 |
printf("cnt = %d\n", cnt);
|
alpar@1
|
1025 |
for (i = 1; i <= G->nv; i++)
|
alpar@1
|
1026 |
printf("num[%d] = %d\n", i, vertex(G->v[i])->num);
|
alpar@1
|
1027 |
glp_delete_graph(G);
|
alpar@1
|
1028 |
return 0;
|
alpar@1
|
1029 |
}
|
alpar@1
|
1030 |
\end{verbatim}
|
alpar@1
|
1031 |
\end{footnotesize}
|
alpar@1
|
1032 |
|
alpar@1
|
1033 |
\noindent
|
alpar@1
|
1034 |
If the file `\verb|graph.txt|' contains the graph shown below:
|
alpar@1
|
1035 |
|
alpar@1
|
1036 |
\bigskip
|
alpar@1
|
1037 |
|
alpar@1
|
1038 |
\noindent\hfil
|
alpar@1
|
1039 |
\xymatrix @=20pt
|
alpar@1
|
1040 |
{
|
alpar@1
|
1041 |
1\ar[rrr]&&&2\ar[r]\ar[rddd]&3\ar[rd]&&&&\\
|
alpar@1
|
1042 |
&&&4\ar[ru]&&5\ar[r]&6\ar[rd]\ar[dd]&&\\
|
alpar@1
|
1043 |
7\ar[r]&8\ar[r]&9\ar[ruu]\ar[ru]\ar[r]\ar[rd]&10\ar[rr]\ar[rru]&&
|
alpar@1
|
1044 |
11\ar[ru]&&12\ar[r]&13\\
|
alpar@1
|
1045 |
&&&14\ar[r]&15\ar[rrru]\ar[rr]&&16\ar[rru]\ar[rr]&&17\\
|
alpar@1
|
1046 |
}
|
alpar@1
|
1047 |
|
alpar@1
|
1048 |
\bigskip\bigskip
|
alpar@1
|
1049 |
|
alpar@1
|
1050 |
\noindent
|
alpar@1
|
1051 |
the program output may look like follows:
|
alpar@1
|
1052 |
|
alpar@1
|
1053 |
\begin{footnotesize}
|
alpar@1
|
1054 |
\begin{verbatim}
|
alpar@1
|
1055 |
Reading graph from `graph.txt'...
|
alpar@1
|
1056 |
Graph has 17 vertices and 23 arcs
|
alpar@1
|
1057 |
24 lines were read
|
alpar@1
|
1058 |
cnt = 0
|
alpar@1
|
1059 |
num[1] = 8
|
alpar@1
|
1060 |
num[2] = 9
|
alpar@1
|
1061 |
num[3] = 10
|
alpar@1
|
1062 |
num[4] = 4
|
alpar@1
|
1063 |
num[5] = 11
|
alpar@1
|
1064 |
num[6] = 12
|
alpar@1
|
1065 |
num[7] = 1
|
alpar@1
|
1066 |
num[8] = 2
|
alpar@1
|
1067 |
num[9] = 3
|
alpar@1
|
1068 |
num[10] = 5
|
alpar@1
|
1069 |
num[11] = 6
|
alpar@1
|
1070 |
num[12] = 14
|
alpar@1
|
1071 |
num[13] = 16
|
alpar@1
|
1072 |
num[14] = 7
|
alpar@1
|
1073 |
num[15] = 13
|
alpar@1
|
1074 |
num[16] = 15
|
alpar@1
|
1075 |
num[17] = 17
|
alpar@1
|
1076 |
\end{verbatim}
|
alpar@1
|
1077 |
\end{footnotesize}
|
alpar@1
|
1078 |
|
alpar@1
|
1079 |
\noindent
|
alpar@1
|
1080 |
The output corresponds to the following vertex numbering:
|
alpar@1
|
1081 |
|
alpar@1
|
1082 |
\bigskip
|
alpar@1
|
1083 |
|
alpar@1
|
1084 |
\noindent\hfil
|
alpar@1
|
1085 |
\xymatrix @=20pt
|
alpar@1
|
1086 |
{
|
alpar@1
|
1087 |
8\ar[rrr]&&&9\ar[r]\ar[rddd]&10\ar[rd]&&&&\\
|
alpar@1
|
1088 |
&&&4\ar[ru]&&11\ar[r]&12\ar[rd]\ar[dd]&&\\
|
alpar@1
|
1089 |
1\ar[r]&2\ar[r]&3\ar[ruu]\ar[ru]\ar[r]\ar[rd]&5\ar[rr]\ar[rru]&&
|
alpar@1
|
1090 |
6\ar[ru]&&14\ar[r]&16\\
|
alpar@1
|
1091 |
&&&7\ar[r]&13\ar[rrru]\ar[rr]&&15\ar[rru]\ar[rr]&&17\\
|
alpar@1
|
1092 |
}
|
alpar@1
|
1093 |
|
alpar@1
|
1094 |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
alpar@1
|
1095 |
|
alpar@1
|
1096 |
\chapter{Network optimization API routines}
|
alpar@1
|
1097 |
|
alpar@1
|
1098 |
\section{Minimum cost flow problem}
|
alpar@1
|
1099 |
|
alpar@1
|
1100 |
\subsection{Background}
|
alpar@1
|
1101 |
|
alpar@1
|
1102 |
The {\it minimum cost flow problem} (MCFP) is stated as follows. Let
|
alpar@1
|
1103 |
there be given a directed graph (flow network) $G=(V,A)$, where $V$ is
|
alpar@1
|
1104 |
a set of vertices (nodes), and $A\subseteq V\times V$ is a set of arcs.
|
alpar@1
|
1105 |
Let for each node $i\in V$ there be given a quantity $b_i$ having the
|
alpar@1
|
1106 |
following meaning:
|
alpar@1
|
1107 |
|
alpar@1
|
1108 |
if $b_i>0$, then $|b_i|$ is a {\it supply} at node $i$, which shows
|
alpar@1
|
1109 |
how many flow units are {\it generated} at node $i$ (or, equivalently,
|
alpar@1
|
1110 |
entering the network through node $i$ from the outside);
|
alpar@1
|
1111 |
|
alpar@1
|
1112 |
if $b_i<0$, then $|b_i|$ is a {\it demand} at node $i$, which shows how
|
alpar@1
|
1113 |
many flow units are {\it lost} at node $i$ (or, equivalently, leaving
|
alpar@1
|
1114 |
the network through node $i$ to the outside);
|
alpar@1
|
1115 |
|
alpar@1
|
1116 |
if $b_i=0$, then $i$ is a {\it transshipment} node, at which the flow
|
alpar@1
|
1117 |
is conserved, i.e. neither generated nor lost.
|
alpar@1
|
1118 |
|
alpar@1
|
1119 |
Let also for each arc $a=(i,j)\in A$ there be given the following three
|
alpar@1
|
1120 |
quantities:
|
alpar@1
|
1121 |
|
alpar@1
|
1122 |
$l_{ij}$, a (non-negative) lower bound to the flow through arc $(i,j)$;
|
alpar@1
|
1123 |
|
alpar@1
|
1124 |
$u_{ij}$, an upper bound to the flow through arc $(i,j)$, which is the
|
alpar@1
|
1125 |
{\it arc capacity};
|
alpar@1
|
1126 |
|
alpar@1
|
1127 |
$c_{ij}$, a per-unit cost of the flow through arc $(i,j)$.
|
alpar@1
|
1128 |
|
alpar@1
|
1129 |
The problem is to find flows $x_{ij}$ through every arc of the network,
|
alpar@1
|
1130 |
which satisfy the specified bounds and the conservation constraints at
|
alpar@1
|
1131 |
all nodes, and minimize the total flow cost. Here the conservation
|
alpar@1
|
1132 |
constraint at a node means that the total flow entering this node
|
alpar@1
|
1133 |
through its incoming arcs plus the supply at this node must be equal to
|
alpar@1
|
1134 |
the total flow leaving this node through its outgoing arcs plus the
|
alpar@1
|
1135 |
demand at this node.
|
alpar@1
|
1136 |
|
alpar@1
|
1137 |
An example of the minimum cost flow problem is shown on Fig.~1.
|
alpar@1
|
1138 |
|
alpar@1
|
1139 |
\bigskip
|
alpar@1
|
1140 |
|
alpar@1
|
1141 |
\noindent\hfil
|
alpar@1
|
1142 |
\xymatrix @C=48pt
|
alpar@1
|
1143 |
{_{20}\ar@{~>}[d]&
|
alpar@1
|
1144 |
v_2\ar[r]|{_{0,10,\$2}}\ar[dd]|{_{0,9,\$3}}&
|
alpar@1
|
1145 |
v_3\ar[dd]|{_{2,12,\$1}}\ar[r]|{_{0,18,\$0}}&
|
alpar@1
|
1146 |
v_8\ar[rd]|{_{0,20,\$9}}&\\
|
alpar@1
|
1147 |
v_1\ar[ru]|{_{0,14,\$0}}\ar[rd]|{_{0,23,\$0}}&&&
|
alpar@1
|
1148 |
v_6\ar[d]|{_{0,7,\$0}}\ar[u]|{_{4,8,\$0}}&
|
alpar@1
|
1149 |
v_9\ar@{~>}[d]\\
|
alpar@1
|
1150 |
&v_4\ar[r]|{_{0,26,\$0}}&
|
alpar@1
|
1151 |
v_5\ar[luu]|{_{0,11,\$1}}\ar[ru]|{_{0,25,\$5}}\ar[r]|{_{0,4,\$7}}&
|
alpar@1
|
1152 |
v_7\ar[ru]|{_{0,15,\$3}}&_{20}\\
|
alpar@1
|
1153 |
}
|
alpar@1
|
1154 |
|
alpar@1
|
1155 |
\medskip
|
alpar@1
|
1156 |
|
alpar@1
|
1157 |
\noindent\hfil
|
alpar@1
|
1158 |
\begin{tabular}{ccc}
|
alpar@1
|
1159 |
\xymatrix @C=48pt{v_i\ar[r]|{\ l,u,\$c\ }&v_j\\}&
|
alpar@1
|
1160 |
\xymatrix{\hbox{\footnotesize supply}\ar@{~>}[r]&v_i\\}&
|
alpar@1
|
1161 |
\xymatrix{v_i\ar@{~>}[r]&\hbox{\footnotesize demand}\\}\\
|
alpar@1
|
1162 |
\end{tabular}
|
alpar@1
|
1163 |
|
alpar@1
|
1164 |
\bigskip
|
alpar@1
|
1165 |
|
alpar@1
|
1166 |
\noindent\hfil
|
alpar@1
|
1167 |
Fig.~1. An example of the minimum cost flow problem.
|
alpar@1
|
1168 |
|
alpar@1
|
1169 |
\bigskip
|
alpar@1
|
1170 |
|
alpar@1
|
1171 |
The minimum cost flow problem can be naturally formulated as the
|
alpar@1
|
1172 |
following LP problem:
|
alpar@1
|
1173 |
|
alpar@1
|
1174 |
\medskip
|
alpar@1
|
1175 |
|
alpar@1
|
1176 |
\noindent
|
alpar@1
|
1177 |
\hspace{.5in}minimize
|
alpar@1
|
1178 |
$$z=\sum_{(i,j)\in A}c_{ij}x_{ij}\eqno(1)$$
|
alpar@1
|
1179 |
\hspace{.5in}subject to
|
alpar@1
|
1180 |
$$\sum_{(i,j)\in A}x_{ij}-\sum_{(j,i)\in A}x_{ji}=b_i\ \ \ \hbox
|
alpar@1
|
1181 |
{for all}\ i\in V\eqno(2)$$
|
alpar@1
|
1182 |
$$l_{ij}\leq x_{ij}\leq u_{ij}\ \ \ \hbox{for all}\ (i,j)\in A
|
alpar@1
|
1183 |
\eqno(3)$$
|
alpar@1
|
1184 |
|
alpar@1
|
1185 |
\newpage
|
alpar@1
|
1186 |
|
alpar@1
|
1187 |
\subsection{glp\_read\_mincost---read minimum cost flow problem\\data
|
alpar@1
|
1188 |
in DIMACS format}
|
alpar@1
|
1189 |
|
alpar@1
|
1190 |
\subsubsection*{Synopsis}
|
alpar@1
|
1191 |
|
alpar@1
|
1192 |
\begin{verbatim}
|
alpar@1
|
1193 |
int glp_read_mincost(glp_graph *G, int v_rhs, int a_low,
|
alpar@1
|
1194 |
int a_cap, int a_cost, const char *fname);
|
alpar@1
|
1195 |
\end{verbatim}
|
alpar@1
|
1196 |
|
alpar@1
|
1197 |
\subsubsection*{Description}
|
alpar@1
|
1198 |
|
alpar@1
|
1199 |
The routine \verb|glp_read_mincost| reads the minimum cost flow problem
|
alpar@1
|
1200 |
data from a text file in DIMACS format.
|
alpar@1
|
1201 |
|
alpar@1
|
1202 |
The parameter \verb|G| specifies the graph object, to which the problem
|
alpar@1
|
1203 |
data have to be stored. Note that before reading data the current
|
alpar@1
|
1204 |
content of the graph object is completely erased with the routine
|
alpar@1
|
1205 |
\verb|glp_erase_graph|.
|
alpar@1
|
1206 |
|
alpar@1
|
1207 |
The parameter \verb|v_rhs| specifies an offset of the field of type
|
alpar@1
|
1208 |
\verb|double| in the vertex data block, to which the routine stores
|
alpar@1
|
1209 |
$b_i$, the supply/demand value. If \verb|v_rhs| $<0$, the value is not
|
alpar@1
|
1210 |
stored.
|
alpar@1
|
1211 |
|
alpar@1
|
1212 |
The parameter \verb|a_low| specifies an offset of the field of type
|
alpar@1
|
1213 |
\verb|double| in the arc data block, to which the routine stores
|
alpar@1
|
1214 |
$l_{ij}$, the lower bound to the arc flow. If \verb|a_low| $<0$, the
|
alpar@1
|
1215 |
lower bound is not stored.
|
alpar@1
|
1216 |
|
alpar@1
|
1217 |
The parameter \verb|a_cap| specifies an offset of the field of type
|
alpar@1
|
1218 |
\verb|double| in the arc data block, to which the routine stores
|
alpar@1
|
1219 |
$u_{ij}$, the upper bound to the arc flow (the arc capacity). If
|
alpar@1
|
1220 |
\verb|a_cap| $<0$, the upper bound is not stored.
|
alpar@1
|
1221 |
|
alpar@1
|
1222 |
The parameter \verb|a_cost| specifies an offset of the field of type
|
alpar@1
|
1223 |
\verb|double| in the arc data block, to which the routine stores
|
alpar@1
|
1224 |
$c_{ij}$, the per-unit cost of the arc flow. If \verb|a_cost| $<0$, the
|
alpar@1
|
1225 |
cost is not stored.
|
alpar@1
|
1226 |
|
alpar@1
|
1227 |
The character string \verb|fname| specifies the name of a text file to
|
alpar@1
|
1228 |
be read in. (If the file name name ends with the suffix `\verb|.gz|',
|
alpar@1
|
1229 |
the file is assumed to be compressed, in which case the routine
|
alpar@1
|
1230 |
decompresses it ``on the fly''.)
|
alpar@1
|
1231 |
|
alpar@1
|
1232 |
\subsubsection*{Returns}
|
alpar@1
|
1233 |
|
alpar@1
|
1234 |
If the operation was successful, the routine returns zero. Otherwise,
|
alpar@1
|
1235 |
it prints an error message and returns non-zero.
|
alpar@1
|
1236 |
|
alpar@1
|
1237 |
\newpage
|
alpar@1
|
1238 |
|
alpar@1
|
1239 |
\subsubsection*{Example}
|
alpar@1
|
1240 |
|
alpar@1
|
1241 |
\begin{footnotesize}
|
alpar@1
|
1242 |
\begin{verbatim}
|
alpar@1
|
1243 |
typedef struct
|
alpar@1
|
1244 |
{ /* vertex data block */
|
alpar@1
|
1245 |
...
|
alpar@1
|
1246 |
double rhs;
|
alpar@1
|
1247 |
...
|
alpar@1
|
1248 |
} v_data;
|
alpar@1
|
1249 |
|
alpar@1
|
1250 |
typedef struct
|
alpar@1
|
1251 |
{ /* arc data block */
|
alpar@1
|
1252 |
...
|
alpar@1
|
1253 |
double low, cap, cost;
|
alpar@1
|
1254 |
...
|
alpar@1
|
1255 |
} a_data;
|
alpar@1
|
1256 |
|
alpar@1
|
1257 |
int main(void)
|
alpar@1
|
1258 |
{ glp_graph *G;
|
alpar@1
|
1259 |
int ret;
|
alpar@1
|
1260 |
G = glp_create_graph(sizeof(v_data), sizeof(a_data));
|
alpar@1
|
1261 |
ret = glp_read_mincost(G, offsetof(v_data, rhs),
|
alpar@1
|
1262 |
offsetof(a_data, low), offsetof(a_data, cap),
|
alpar@1
|
1263 |
offsetof(a_data, cost), "sample.min");
|
alpar@1
|
1264 |
if (ret != 0) goto ...
|
alpar@1
|
1265 |
...
|
alpar@1
|
1266 |
}
|
alpar@1
|
1267 |
\end{verbatim}
|
alpar@1
|
1268 |
\end{footnotesize}
|
alpar@1
|
1269 |
|
alpar@1
|
1270 |
\subsubsection*{DIMACS minimum cost flow problem format\footnote{This
|
alpar@1
|
1271 |
material is based on the paper ``The First DIMACS International
|
alpar@1
|
1272 |
Algorithm Implementation Challenge: Problem Definitions and
|
alpar@1
|
1273 |
Specifications'', which is publically available at
|
alpar@1
|
1274 |
{\tt http://dimacs.rutgers.edu/Challenges/}.}}
|
alpar@1
|
1275 |
\label{subsecmincost}
|
alpar@1
|
1276 |
|
alpar@1
|
1277 |
The DIMACS input file is a plain ASCII text file. It contains
|
alpar@1
|
1278 |
{\it lines} of several types described below. A line is terminated with
|
alpar@1
|
1279 |
an end-of-line character. Fields in each line are separated by at least
|
alpar@1
|
1280 |
one blank space. Each line begins with a one-character designator to
|
alpar@1
|
1281 |
identify the line type.
|
alpar@1
|
1282 |
|
alpar@1
|
1283 |
Note that DIMACS requires all numerical quantities to be integers in
|
alpar@1
|
1284 |
the range $[-2^{31},\ 2^{31}-1]$ while GLPK allows the quantities to be
|
alpar@1
|
1285 |
floating-point numbers.
|
alpar@1
|
1286 |
|
alpar@1
|
1287 |
\newpage
|
alpar@1
|
1288 |
|
alpar@1
|
1289 |
\paragraph{Comment lines.} Comment lines give human-readable information
|
alpar@1
|
1290 |
about the file and are ignored by programs. Comment lines can appear
|
alpar@1
|
1291 |
anywhere in the file. Each comment line begins with a lower-case
|
alpar@1
|
1292 |
character \verb|c|.
|
alpar@1
|
1293 |
|
alpar@1
|
1294 |
\begin{verbatim}
|
alpar@1
|
1295 |
c This is a comment line
|
alpar@1
|
1296 |
\end{verbatim}
|
alpar@1
|
1297 |
|
alpar@1
|
1298 |
\paragraph{Problem line.} There is one problem line per data file. The
|
alpar@1
|
1299 |
problem line must appear before any node or arc descriptor lines. It has
|
alpar@1
|
1300 |
the following format:
|
alpar@1
|
1301 |
|
alpar@1
|
1302 |
\begin{verbatim}
|
alpar@1
|
1303 |
p min NODES ARCS
|
alpar@1
|
1304 |
\end{verbatim}
|
alpar@1
|
1305 |
|
alpar@1
|
1306 |
\noindent
|
alpar@1
|
1307 |
The lower-case character \verb|p| signifies that this is a problem line.
|
alpar@1
|
1308 |
The three-character problem designator \verb|min| identifies the file as
|
alpar@1
|
1309 |
containing specification information for the minimum cost flow problem.
|
alpar@1
|
1310 |
The \verb|NODES| field contains an integer value specifying the number
|
alpar@1
|
1311 |
of nodes in the network. The \verb|ARCS| field contains an integer value
|
alpar@1
|
1312 |
specifying the number of arcs in the network.
|
alpar@1
|
1313 |
|
alpar@1
|
1314 |
\paragraph{Node descriptors.} All node descriptor lines must appear
|
alpar@1
|
1315 |
before all arc descriptor lines. The node descriptor lines describe
|
alpar@1
|
1316 |
supply and demand nodes, but not transshipment nodes. That is, only
|
alpar@1
|
1317 |
nodes with non-zero node supply/demand values appear. There is one node
|
alpar@1
|
1318 |
descriptor line for each such node, with the following format:
|
alpar@1
|
1319 |
|
alpar@1
|
1320 |
\begin{verbatim}
|
alpar@1
|
1321 |
n ID FLOW
|
alpar@1
|
1322 |
\end{verbatim}
|
alpar@1
|
1323 |
|
alpar@1
|
1324 |
\noindent
|
alpar@1
|
1325 |
The lower-case character \verb|n| signifies that this is a node
|
alpar@1
|
1326 |
descriptor line. The \verb|ID| field gives a node identification number,
|
alpar@1
|
1327 |
an integer between 1 and \verb|NODES|. The \verb|FLOW| field gives the
|
alpar@1
|
1328 |
amount of supply (if positive) or demand (if negative) at node
|
alpar@1
|
1329 |
\verb|ID|.
|
alpar@1
|
1330 |
|
alpar@1
|
1331 |
\paragraph{Arc descriptors.} There is one arc descriptor line for each
|
alpar@1
|
1332 |
arc in the network. Arc descriptor lines are of the following format:
|
alpar@1
|
1333 |
|
alpar@1
|
1334 |
\begin{verbatim}
|
alpar@1
|
1335 |
a SRC DST LOW CAP COST
|
alpar@1
|
1336 |
\end{verbatim}
|
alpar@1
|
1337 |
|
alpar@1
|
1338 |
\noindent
|
alpar@1
|
1339 |
The lower-case character \verb|a| signifies that this is an arc
|
alpar@1
|
1340 |
descriptor line. For a directed arc $(i,j)$ the \verb|SRC| field gives
|
alpar@1
|
1341 |
the identification number $i$ for the tail endpoint, and the \verb|DST|
|
alpar@1
|
1342 |
field gives the identification number $j$ for the head endpoint.
|
alpar@1
|
1343 |
Identification numbers are integers between 1 and \verb|NODES|. The
|
alpar@1
|
1344 |
\verb|LOW| field specifies the minimum amount of flow that can be sent
|
alpar@1
|
1345 |
along arc $(i,j)$, and the \verb|CAP| field gives the maximum amount of
|
alpar@1
|
1346 |
flow that can be sent along arc $(i,j)$ in a feasible flow. The
|
alpar@1
|
1347 |
\verb|COST| field contains the per-unit cost of flow sent along arc
|
alpar@1
|
1348 |
$(i,j)$.
|
alpar@1
|
1349 |
|
alpar@1
|
1350 |
\paragraph{Example.} Below here is an example of the data file in
|
alpar@1
|
1351 |
DIMACS format corresponding to the minimum cost flow problem shown on
|
alpar@1
|
1352 |
Fig~1.
|
alpar@1
|
1353 |
|
alpar@1
|
1354 |
\begin{footnotesize}
|
alpar@1
|
1355 |
\begin{verbatim}
|
alpar@1
|
1356 |
c sample.min
|
alpar@1
|
1357 |
c
|
alpar@1
|
1358 |
c This is an example of the minimum cost flow problem data
|
alpar@1
|
1359 |
c in DIMACS format.
|
alpar@1
|
1360 |
c
|
alpar@1
|
1361 |
p min 9 14
|
alpar@1
|
1362 |
c
|
alpar@1
|
1363 |
n 1 20
|
alpar@1
|
1364 |
n 9 -20
|
alpar@1
|
1365 |
c
|
alpar@1
|
1366 |
a 1 2 0 14 0
|
alpar@1
|
1367 |
a 1 4 0 23 0
|
alpar@1
|
1368 |
a 2 3 0 10 2
|
alpar@1
|
1369 |
a 2 4 0 9 3
|
alpar@1
|
1370 |
a 3 5 2 12 1
|
alpar@1
|
1371 |
a 3 8 0 18 0
|
alpar@1
|
1372 |
a 4 5 0 26 0
|
alpar@1
|
1373 |
a 5 2 0 11 1
|
alpar@1
|
1374 |
a 5 6 0 25 5
|
alpar@1
|
1375 |
a 5 7 0 4 7
|
alpar@1
|
1376 |
a 6 7 0 7 0
|
alpar@1
|
1377 |
a 6 8 4 8 0
|
alpar@1
|
1378 |
a 7 9 0 15 3
|
alpar@1
|
1379 |
a 8 9 0 20 9
|
alpar@1
|
1380 |
c
|
alpar@1
|
1381 |
c eof
|
alpar@1
|
1382 |
\end{verbatim}
|
alpar@1
|
1383 |
\end{footnotesize}
|
alpar@1
|
1384 |
|
alpar@1
|
1385 |
\newpage
|
alpar@1
|
1386 |
|
alpar@1
|
1387 |
\subsection{glp\_write\_mincost---write minimum cost flow problem\\data
|
alpar@1
|
1388 |
in DIMACS format}
|
alpar@1
|
1389 |
|
alpar@1
|
1390 |
\subsubsection*{Synopsis}
|
alpar@1
|
1391 |
|
alpar@1
|
1392 |
\begin{verbatim}
|
alpar@1
|
1393 |
int glp_write_mincost(glp_graph *G, int v_rhs, int a_low,
|
alpar@1
|
1394 |
int a_cap, int a_cost, const char *fname);
|
alpar@1
|
1395 |
\end{verbatim}
|
alpar@1
|
1396 |
|
alpar@1
|
1397 |
\subsubsection*{Description}
|
alpar@1
|
1398 |
|
alpar@1
|
1399 |
The routine \verb|glp_write_mincost| writes the minimum cost flow
|
alpar@1
|
1400 |
problem data to a text file in DIMACS format.
|
alpar@1
|
1401 |
|
alpar@1
|
1402 |
The parameter \verb|G| is the graph (network) program object, which
|
alpar@1
|
1403 |
specifies the minimum cost flow problem instance.
|
alpar@1
|
1404 |
|
alpar@1
|
1405 |
The parameter \verb|v_rhs| specifies an offset of the field of type
|
alpar@1
|
1406 |
\verb|double| in the vertex data block, which contains $b_i$, the
|
alpar@1
|
1407 |
supply/demand value. If \verb|v_rhs| $<0$, it is assumed that $b_i=0$
|
alpar@1
|
1408 |
for all nodes.
|
alpar@1
|
1409 |
|
alpar@1
|
1410 |
The parameter \verb|a_low| specifies an offset of the field of type
|
alpar@1
|
1411 |
\verb|double| in the arc data block, which contains $l_{ij}$, the lower
|
alpar@1
|
1412 |
bound to the arc flow. If \verb|a_low| $<0$, it is assumed that
|
alpar@1
|
1413 |
$l_{ij}=0$ for all arcs.
|
alpar@1
|
1414 |
|
alpar@1
|
1415 |
The parameter \verb|a_cap| specifies an offset of the field of type
|
alpar@1
|
1416 |
\verb|double| in the arc data block, which contains $u_{ij}$, the upper
|
alpar@1
|
1417 |
bound to the arc flow (the arc capacity). If the upper bound is
|
alpar@1
|
1418 |
specified as \verb|DBL_MAX|, it is assumed that $u_{ij}=\infty$, i.e.
|
alpar@1
|
1419 |
the arc is uncapacitated. If \verb|a_cap| $<0$, it is assumed that
|
alpar@1
|
1420 |
$u_{ij}=1$ for all arcs.
|
alpar@1
|
1421 |
|
alpar@1
|
1422 |
The parameter \verb|a_cost| specifies an offset of the field of type
|
alpar@1
|
1423 |
\verb|double| in the arc data block, which contains $c_{ij}$, the
|
alpar@1
|
1424 |
per-unit cost of the arc flow. If \verb|a_cost| $<0$, it is assumed that
|
alpar@1
|
1425 |
$c_{ij}=0$ for all arcs.
|
alpar@1
|
1426 |
|
alpar@1
|
1427 |
The character string \verb|fname| specifies a name of the text file to
|
alpar@1
|
1428 |
be written out. (If the file name ends with suffix `\verb|.gz|', the
|
alpar@1
|
1429 |
file is assumed to be compressed, in which case the routine performs
|
alpar@1
|
1430 |
automatic compression on writing it.)
|
alpar@1
|
1431 |
|
alpar@1
|
1432 |
\subsubsection*{Returns}
|
alpar@1
|
1433 |
|
alpar@1
|
1434 |
If the operation was successful, the routine returns zero. Otherwise,
|
alpar@1
|
1435 |
it prints an error message and returns non-zero.
|
alpar@1
|
1436 |
|
alpar@1
|
1437 |
\newpage
|
alpar@1
|
1438 |
|
alpar@1
|
1439 |
\subsection{glp\_mincost\_lp---convert minimum cost flow problem\\to LP}
|
alpar@1
|
1440 |
|
alpar@1
|
1441 |
\subsubsection*{Synopsis}
|
alpar@1
|
1442 |
|
alpar@1
|
1443 |
\begin{verbatim}
|
alpar@1
|
1444 |
void glp_mincost_lp(glp_prob *lp, glp_graph *G, int names,
|
alpar@1
|
1445 |
int v_rhs, int a_low, int a_cap, int a_cost);
|
alpar@1
|
1446 |
\end{verbatim}
|
alpar@1
|
1447 |
|
alpar@1
|
1448 |
\subsubsection*{Description}
|
alpar@1
|
1449 |
|
alpar@1
|
1450 |
The routine \verb|glp_mincost_lp| builds LP problem (1)---(3), which
|
alpar@1
|
1451 |
corresponds to the specified minimum cost flow problem.
|
alpar@1
|
1452 |
|
alpar@1
|
1453 |
The parameter \verb|lp| is the resultant LP problem object to be built.
|
alpar@1
|
1454 |
Note that on entry its current content is erased with the routine
|
alpar@1
|
1455 |
\verb|glp_erase_prob|.
|
alpar@1
|
1456 |
|
alpar@1
|
1457 |
The parameter \verb|G| is the graph (network) program object, which
|
alpar@1
|
1458 |
specifies the minimum cost flow problem instance.
|
alpar@1
|
1459 |
|
alpar@1
|
1460 |
The parameter \verb|names| is a flag. If it is \verb|GLP_ON|, the
|
alpar@1
|
1461 |
routine uses symbolic names of the graph object components to assign
|
alpar@1
|
1462 |
symbolic names to the LP problem object components. If the flag is
|
alpar@1
|
1463 |
\verb|GLP_OFF|, no symbolic names are assigned.
|
alpar@1
|
1464 |
|
alpar@1
|
1465 |
The parameter \verb|v_rhs| specifies an offset of the field of type
|
alpar@1
|
1466 |
\verb|double| in the vertex data block, which contains $b_i$, the
|
alpar@1
|
1467 |
supply/demand value. If \verb|v_rhs| $<0$, it is assumed that $b_i=0$
|
alpar@1
|
1468 |
for all nodes.
|
alpar@1
|
1469 |
|
alpar@1
|
1470 |
The parameter \verb|a_low| specifies an offset of the field of type
|
alpar@1
|
1471 |
\verb|double| in the arc data block, which contains $l_{ij}$, the lower
|
alpar@1
|
1472 |
bound to the arc flow. If \verb|a_low| $<0$, it is assumed that
|
alpar@1
|
1473 |
$l_{ij}=0$ for all arcs.
|
alpar@1
|
1474 |
|
alpar@1
|
1475 |
The parameter \verb|a_cap| specifies an offset of the field of type
|
alpar@1
|
1476 |
\verb|double| in the arc data block, which contains $u_{ij}$, the upper
|
alpar@1
|
1477 |
bound to the arc flow (the arc capacity). If the upper bound is
|
alpar@1
|
1478 |
specified as \verb|DBL_MAX|, it is assumed that $u_{ij}=\infty$, i.e.
|
alpar@1
|
1479 |
the arc is uncapacitated. If \verb|a_cap| $<0$, it is assumed that
|
alpar@1
|
1480 |
$u_{ij}=1$ for all arcs.
|
alpar@1
|
1481 |
|
alpar@1
|
1482 |
The parameter \verb|a_cost| specifies an offset of the field of type
|
alpar@1
|
1483 |
\verb|double| in the arc data block, which contains $c_{ij}$, the
|
alpar@1
|
1484 |
per-unit cost of the arc flow. If \verb|a_cost| $<0$, it is assumed that
|
alpar@1
|
1485 |
$c_{ij}=0$ for all arcs.
|
alpar@1
|
1486 |
|
alpar@1
|
1487 |
\subsubsection*{Example}
|
alpar@1
|
1488 |
|
alpar@1
|
1489 |
The example program below reads the minimum cost problem instance in
|
alpar@1
|
1490 |
DIMACS format from file `\verb|sample.min|', converts the instance to
|
alpar@1
|
1491 |
LP, and then writes the resultant LP in CPLEX format to file
|
alpar@1
|
1492 |
`\verb|mincost.lp|'.
|
alpar@1
|
1493 |
|
alpar@1
|
1494 |
\newpage
|
alpar@1
|
1495 |
|
alpar@1
|
1496 |
\begin{footnotesize}
|
alpar@1
|
1497 |
\begin{verbatim}
|
alpar@1
|
1498 |
#include <stddef.h>
|
alpar@1
|
1499 |
#include <glpk.h>
|
alpar@1
|
1500 |
|
alpar@1
|
1501 |
typedef struct { double rhs; } v_data;
|
alpar@1
|
1502 |
typedef struct { double low, cap, cost; } a_data;
|
alpar@1
|
1503 |
|
alpar@1
|
1504 |
int main(void)
|
alpar@1
|
1505 |
{ glp_graph *G;
|
alpar@1
|
1506 |
glp_prob *lp;
|
alpar@1
|
1507 |
G = glp_create_graph(sizeof(v_data), sizeof(a_data));
|
alpar@1
|
1508 |
glp_read_mincost(G, offsetof(v_data, rhs),
|
alpar@1
|
1509 |
offsetof(a_data, low), offsetof(a_data, cap),
|
alpar@1
|
1510 |
offsetof(a_data, cost), "sample.min");
|
alpar@1
|
1511 |
lp = glp_create_prob();
|
alpar@1
|
1512 |
glp_mincost_lp(lp, G, GLP_ON, offsetof(v_data, rhs),
|
alpar@1
|
1513 |
offsetof(a_data, low), offsetof(a_data, cap),
|
alpar@1
|
1514 |
offsetof(a_data, cost));
|
alpar@1
|
1515 |
glp_delete_graph(G);
|
alpar@1
|
1516 |
glp_write_lp(lp, NULL, "mincost.lp");
|
alpar@1
|
1517 |
glp_delete_prob(lp);
|
alpar@1
|
1518 |
return 0;
|
alpar@1
|
1519 |
}
|
alpar@1
|
1520 |
\end{verbatim}
|
alpar@1
|
1521 |
\end{footnotesize}
|
alpar@1
|
1522 |
|
alpar@1
|
1523 |
If `\verb|sample.min|' is the example data file from the subsection
|
alpar@1
|
1524 |
describing the routine \verb|glp_read_mincost|, file `\verb|mincost.lp|'
|
alpar@1
|
1525 |
may look like follows:
|
alpar@1
|
1526 |
|
alpar@1
|
1527 |
\begin{footnotesize}
|
alpar@1
|
1528 |
\begin{verbatim}
|
alpar@1
|
1529 |
Minimize
|
alpar@1
|
1530 |
obj: + 3 x(2,4) + 2 x(2,3) + x(3,5) + 7 x(5,7) + 5 x(5,6)
|
alpar@1
|
1531 |
+ x(5,2) + 3 x(7,9) + 9 x(8,9)
|
alpar@1
|
1532 |
|
alpar@1
|
1533 |
Subject To
|
alpar@1
|
1534 |
r_1: + x(1,2) + x(1,4) = 20
|
alpar@1
|
1535 |
r_2: - x(5,2) + x(2,3) + x(2,4) - x(1,2) = 0
|
alpar@1
|
1536 |
r_3: + x(3,5) + x(3,8) - x(2,3) = 0
|
alpar@1
|
1537 |
r_4: + x(4,5) - x(2,4) - x(1,4) = 0
|
alpar@1
|
1538 |
r_5: + x(5,2) + x(5,6) + x(5,7) - x(4,5) - x(3,5) = 0
|
alpar@1
|
1539 |
r_6: + x(6,7) + x(6,8) - x(5,6) = 0
|
alpar@1
|
1540 |
r_7: + x(7,9) - x(6,7) - x(5,7) = 0
|
alpar@1
|
1541 |
r_8: + x(8,9) - x(6,8) - x(3,8) = 0
|
alpar@1
|
1542 |
r_9: - x(8,9) - x(7,9) = -20
|
alpar@1
|
1543 |
|
alpar@1
|
1544 |
Bounds
|
alpar@1
|
1545 |
0 <= x(1,4) <= 23
|
alpar@1
|
1546 |
0 <= x(1,2) <= 14
|
alpar@1
|
1547 |
0 <= x(2,4) <= 9
|
alpar@1
|
1548 |
0 <= x(2,3) <= 10
|
alpar@1
|
1549 |
0 <= x(3,8) <= 18
|
alpar@1
|
1550 |
2 <= x(3,5) <= 12
|
alpar@1
|
1551 |
0 <= x(4,5) <= 26
|
alpar@1
|
1552 |
0 <= x(5,7) <= 4
|
alpar@1
|
1553 |
0 <= x(5,6) <= 25
|
alpar@1
|
1554 |
0 <= x(5,2) <= 11
|
alpar@1
|
1555 |
4 <= x(6,8) <= 8
|
alpar@1
|
1556 |
0 <= x(6,7) <= 7
|
alpar@1
|
1557 |
0 <= x(7,9) <= 15
|
alpar@1
|
1558 |
0 <= x(8,9) <= 20
|
alpar@1
|
1559 |
|
alpar@1
|
1560 |
End
|
alpar@1
|
1561 |
\end{verbatim}
|
alpar@1
|
1562 |
\end{footnotesize}
|
alpar@1
|
1563 |
|
alpar@1
|
1564 |
\subsection{glp\_mincost\_okalg---solve minimum cost flow problem with
|
alpar@1
|
1565 |
out-of-kilter algorithm}
|
alpar@1
|
1566 |
|
alpar@1
|
1567 |
\subsubsection*{Synopsis}
|
alpar@1
|
1568 |
|
alpar@1
|
1569 |
\begin{verbatim}
|
alpar@1
|
1570 |
int glp_mincost_okalg(glp_graph *G, int v_rhs, int a_low,
|
alpar@1
|
1571 |
int a_cap, int a_cost, double *sol, int a_x, int v_pi);
|
alpar@1
|
1572 |
\end{verbatim}
|
alpar@1
|
1573 |
|
alpar@1
|
1574 |
\subsubsection*{Description}
|
alpar@1
|
1575 |
|
alpar@1
|
1576 |
The routine \verb|glp_mincost_okalg| finds optimal solution to the
|
alpar@1
|
1577 |
minimum cost flow problem with the out-of-kilter
|
alpar@1
|
1578 |
algorithm.\footnote{GLPK implementation of the out-of-kilter algorithm
|
alpar@1
|
1579 |
is based on the following book: L.~R.~Ford,~Jr., and D.~R.~Fulkerson,
|
alpar@1
|
1580 |
``Flows in Networks,'' The RAND Corp., Report R-375-PR (August 1962),
|
alpar@1
|
1581 |
Chap. III ``Minimal Cost Flow Problems,'' pp.~113-26.} Note that this
|
alpar@1
|
1582 |
routine requires all the problem data to be integer-valued.
|
alpar@1
|
1583 |
|
alpar@1
|
1584 |
The parameter \verb|G| is a graph (network) program object which
|
alpar@1
|
1585 |
specifies the minimum cost flow problem instance to be solved.
|
alpar@1
|
1586 |
|
alpar@1
|
1587 |
The parameter \verb|v_rhs| specifies an offset of the field of type
|
alpar@1
|
1588 |
\verb|double| in the vertex data block, which contains $b_i$, the
|
alpar@1
|
1589 |
supply/demand value. This value must be integer in the range
|
alpar@1
|
1590 |
[$-$\verb|INT_MAX|, $+$\verb|INT_MAX|]. If \verb|v_rhs| $<0$, it is
|
alpar@1
|
1591 |
assumed that $b_i=0$ for all nodes.
|
alpar@1
|
1592 |
|
alpar@1
|
1593 |
The parameter \verb|a_low| specifies an offset of the field of type
|
alpar@1
|
1594 |
\verb|double| in the arc data block, which contains $l_{ij}$, the lower
|
alpar@1
|
1595 |
bound to the arc flow. This bound must be integer in the range
|
alpar@1
|
1596 |
[$0$, \verb|INT_MAX|]. If \verb|a_low| $<0$, it is assumed that
|
alpar@1
|
1597 |
$l_{ij}=0$ for all arcs.
|
alpar@1
|
1598 |
|
alpar@1
|
1599 |
The parameter \verb|a_cap| specifies an offset of the field of type
|
alpar@1
|
1600 |
\verb|double| in the arc data block, which contains $u_{ij}$, the upper
|
alpar@1
|
1601 |
bound to the arc flow (the arc capacity). This bound must be integer in
|
alpar@1
|
1602 |
the range [$l_{ij}$, \verb|INT_MAX|]. If \verb|a_cap| $<0$, it is
|
alpar@1
|
1603 |
assumed that $u_{ij}=1$ for all arcs.
|
alpar@1
|
1604 |
|
alpar@1
|
1605 |
The parameter \verb|a_cost| specifies an offset of the field of type
|
alpar@1
|
1606 |
\verb|double| in the arc data block, which contains $c_{ij}$, the
|
alpar@1
|
1607 |
per-unit cost of the arc flow. This value must be integer in the range
|
alpar@1
|
1608 |
[$-$\verb|INT_MAX|, $+$\verb|INT_MAX|]. If \verb|a_cost| $<0$, it is
|
alpar@1
|
1609 |
assumed that $c_{ij}=0$ for all arcs.
|
alpar@1
|
1610 |
|
alpar@1
|
1611 |
The parameter \verb|sol| specifies a location, to which the routine
|
alpar@1
|
1612 |
stores the objective value (that is, the total cost) found. If
|
alpar@1
|
1613 |
\verb|sol| is NULL, the objective value is not stored.
|
alpar@1
|
1614 |
|
alpar@1
|
1615 |
The parameter \verb|a_x| specifies an offset of the field of type
|
alpar@1
|
1616 |
\verb|double| in the arc data block, to which the routine stores
|
alpar@1
|
1617 |
$x_{ij}$, the arc flow found. If \verb|a_x| $<0$, the arc flow value is
|
alpar@1
|
1618 |
not stored.
|
alpar@1
|
1619 |
|
alpar@1
|
1620 |
The parameter \verb|v_pi| specifies an offset of the field of type
|
alpar@1
|
1621 |
\verb|double| in the vertex data block, to which the routine stores
|
alpar@1
|
1622 |
$\pi_i$, the node potential, which is the Lagrange multiplier for the
|
alpar@1
|
1623 |
corresponding flow conservation equality constraint (see (2) in
|
alpar@1
|
1624 |
Subsection ``Background''). If necessary, the application program may
|
alpar@1
|
1625 |
use the node potentials to compute $\lambda_{ij}$, reduced costs of the
|
alpar@1
|
1626 |
arc flows $x_{ij}$, which are the Lagrange multipliers for the arc flow
|
alpar@1
|
1627 |
bound constraints (see (3) ibid.), using the following formula:
|
alpar@1
|
1628 |
$$\lambda_{ij}=c_{ij}-(\pi_i-\pi_j),$$
|
alpar@1
|
1629 |
where $c_{ij}$ is the per-unit cost for arc $(i,j)$.
|
alpar@1
|
1630 |
|
alpar@1
|
1631 |
Note that all solution components (the objective value, arc flows, and
|
alpar@1
|
1632 |
node potentials) computed by the routine are always integer-valued.
|
alpar@1
|
1633 |
|
alpar@1
|
1634 |
\subsubsection*{Returns}
|
alpar@1
|
1635 |
|
alpar@1
|
1636 |
\def\arraystretch{1}
|
alpar@1
|
1637 |
|
alpar@1
|
1638 |
\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
|
alpar@1
|
1639 |
0 & Optimal solution found.\\
|
alpar@1
|
1640 |
\verb|GLP_ENOPFS| & No (primal) feasible solution exists.\\
|
alpar@1
|
1641 |
\verb|GLP_EDATA| & Unable to start the search, because some problem
|
alpar@1
|
1642 |
data are either not integer-valued or out of range. This code is also
|
alpar@1
|
1643 |
returned if the total supply, which is the sum of $b_i$ over all source
|
alpar@1
|
1644 |
nodes (nodes with $b_i>0$), exceeds \verb|INT_MAX|.\\
|
alpar@1
|
1645 |
\end{tabular}
|
alpar@1
|
1646 |
|
alpar@1
|
1647 |
\noindent
|
alpar@1
|
1648 |
\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
|
alpar@1
|
1649 |
\verb|GLP_ERANGE| & The search was prematurely terminated because of
|
alpar@1
|
1650 |
integer overflow.\\
|
alpar@1
|
1651 |
\verb|GLP_EFAIL| & An error has been detected in the program logic.
|
alpar@1
|
1652 |
(If this code is returned for your problem instance, please report to
|
alpar@1
|
1653 |
\verb|<bug-glpk@gnu.org>|.)\\
|
alpar@1
|
1654 |
\end{tabular}
|
alpar@1
|
1655 |
|
alpar@1
|
1656 |
\subsubsection*{Comments}
|
alpar@1
|
1657 |
|
alpar@1
|
1658 |
By design the out-of-kilter algorithm is applicable only to networks,
|
alpar@1
|
1659 |
where $b_i=0$ for {\it all} nodes, i.e. actually this algorithm finds a
|
alpar@1
|
1660 |
minimal cost {\it circulation}. Due to this requirement the routine
|
alpar@1
|
1661 |
\verb|glp_mincost_okalg| converts the original network to a network
|
alpar@1
|
1662 |
suitable for the out-of-kilter algorithm in the following
|
alpar@1
|
1663 |
way:\footnote{The conversion is performed internally and does not change
|
alpar@1
|
1664 |
the original network program object passed to the routine.}
|
alpar@1
|
1665 |
|
alpar@1
|
1666 |
1) it adds two auxiliary nodes $s$ and $t$;
|
alpar@1
|
1667 |
|
alpar@1
|
1668 |
2) for each original node $i$ with $b_i>0$ the routine adds auxiliary
|
alpar@1
|
1669 |
supply arc $(s\rightarrow i)$, flow $x_{si}$ through which is costless
|
alpar@1
|
1670 |
($c_{si}=0$) and fixed to $+b_i$ ($l_{si}=u_{si}=+b_i$);
|
alpar@1
|
1671 |
|
alpar@1
|
1672 |
3) for each original node $i$ with $b_i<0$ the routine adds auxiliary
|
alpar@1
|
1673 |
demand arc $(i\rightarrow t)$, flow $x_{it}$ through which is costless
|
alpar@1
|
1674 |
($c_{it}=0$) and fixed to $-b_i$ ($l_{it}=u_{it}=-b_i$);
|
alpar@1
|
1675 |
|
alpar@1
|
1676 |
4) finally, the routine adds auxiliary feedback arc $(t\rightarrow s)$,
|
alpar@1
|
1677 |
flow $x_{ts}$ through which is also costless ($c_{ts}=0$) and fixed to
|
alpar@1
|
1678 |
$F$ ($l_{ts}=u_{ts}=F$), where $\displaystyle F=\sum_{b_i>0}b_i$ is the
|
alpar@1
|
1679 |
total supply.
|
alpar@1
|
1680 |
|
alpar@1
|
1681 |
\subsubsection*{Example}
|
alpar@1
|
1682 |
|
alpar@1
|
1683 |
The example program below reads the minimum cost problem instance in
|
alpar@1
|
1684 |
DIMACS format from file `\verb|sample.min|', solves it by using the
|
alpar@1
|
1685 |
routine \verb|glp_mincost_okalg|, and writes the solution found to the
|
alpar@1
|
1686 |
standard output.
|
alpar@1
|
1687 |
|
alpar@1
|
1688 |
\begin{footnotesize}
|
alpar@1
|
1689 |
\begin{verbatim}
|
alpar@1
|
1690 |
#include <stddef.h>
|
alpar@1
|
1691 |
#include <stdio.h>
|
alpar@1
|
1692 |
#include <stdlib.h>
|
alpar@1
|
1693 |
#include <glpk.h>
|
alpar@1
|
1694 |
|
alpar@1
|
1695 |
typedef struct { double rhs, pi; } v_data;
|
alpar@1
|
1696 |
typedef struct { double low, cap, cost, x; } a_data;
|
alpar@1
|
1697 |
|
alpar@1
|
1698 |
#define node(v) ((v_data *)((v)->data))
|
alpar@1
|
1699 |
#define arc(a) ((a_data *)((a)->data))
|
alpar@1
|
1700 |
|
alpar@1
|
1701 |
int main(void)
|
alpar@1
|
1702 |
{ glp_graph *G;
|
alpar@1
|
1703 |
glp_vertex *v, *w;
|
alpar@1
|
1704 |
glp_arc *a;
|
alpar@1
|
1705 |
int i, ret;
|
alpar@1
|
1706 |
double sol;
|
alpar@1
|
1707 |
G = glp_create_graph(sizeof(v_data), sizeof(a_data));
|
alpar@1
|
1708 |
glp_read_mincost(G, offsetof(v_data, rhs),
|
alpar@1
|
1709 |
offsetof(a_data, low), offsetof(a_data, cap),
|
alpar@1
|
1710 |
offsetof(a_data, cost), "sample.min");
|
alpar@1
|
1711 |
ret = glp_mincost_okalg(G, offsetof(v_data, rhs),
|
alpar@1
|
1712 |
offsetof(a_data, low), offsetof(a_data, cap),
|
alpar@1
|
1713 |
offsetof(a_data, cost), &sol, offsetof(a_data, x),
|
alpar@1
|
1714 |
offsetof(v_data, pi));
|
alpar@1
|
1715 |
printf("ret = %d; sol = %5g\n", ret, sol);
|
alpar@1
|
1716 |
for (i = 1; i <= G->nv; i++)
|
alpar@1
|
1717 |
{ v = G->v[i];
|
alpar@1
|
1718 |
printf("node %d: pi = %5g\n", i, node(v)->pi);
|
alpar@1
|
1719 |
for (a = v->out; a != NULL; a = a->t_next)
|
alpar@1
|
1720 |
{ w = a->head;
|
alpar@1
|
1721 |
printf("arc %d->%d: x = %5g; lambda = %5g\n",
|
alpar@1
|
1722 |
v->i, w->i, arc(a)->x,
|
alpar@1
|
1723 |
arc(a)->cost - (node(v)->pi - node(w)->pi));
|
alpar@1
|
1724 |
}
|
alpar@1
|
1725 |
}
|
alpar@1
|
1726 |
glp_delete_graph(G);
|
alpar@1
|
1727 |
return 0;
|
alpar@1
|
1728 |
}
|
alpar@1
|
1729 |
\end{verbatim}
|
alpar@1
|
1730 |
\end{footnotesize}
|
alpar@1
|
1731 |
|
alpar@1
|
1732 |
If `\verb|sample.min|' is the example data file from the subsection
|
alpar@1
|
1733 |
describing the routine \verb|glp_read_mincost|, the output may look like
|
alpar@1
|
1734 |
follows:
|
alpar@1
|
1735 |
|
alpar@1
|
1736 |
\begin{footnotesize}
|
alpar@1
|
1737 |
\begin{verbatim}
|
alpar@1
|
1738 |
Reading min-cost flow problem data from `sample.min'...
|
alpar@1
|
1739 |
Flow network has 9 nodes and 14 arcs
|
alpar@1
|
1740 |
24 lines were read
|
alpar@1
|
1741 |
ret = 0; sol = 213
|
alpar@1
|
1742 |
node 1: pi = -12
|
alpar@1
|
1743 |
arc 1->4: x = 13; lambda = 0
|
alpar@1
|
1744 |
arc 1->2: x = 7; lambda = 0
|
alpar@1
|
1745 |
node 2: pi = -12
|
alpar@1
|
1746 |
arc 2->4: x = 0; lambda = 3
|
alpar@1
|
1747 |
arc 2->3: x = 7; lambda = 0
|
alpar@1
|
1748 |
node 3: pi = -14
|
alpar@1
|
1749 |
arc 3->8: x = 5; lambda = 0
|
alpar@1
|
1750 |
arc 3->5: x = 2; lambda = 3
|
alpar@1
|
1751 |
node 4: pi = -12
|
alpar@1
|
1752 |
arc 4->5: x = 13; lambda = 0
|
alpar@1
|
1753 |
node 5: pi = -12
|
alpar@1
|
1754 |
arc 5->7: x = 4; lambda = -1
|
alpar@1
|
1755 |
arc 5->6: x = 11; lambda = 0
|
alpar@1
|
1756 |
arc 5->2: x = 0; lambda = 1
|
alpar@1
|
1757 |
node 6: pi = -17
|
alpar@1
|
1758 |
arc 6->8: x = 4; lambda = 3
|
alpar@1
|
1759 |
arc 6->7: x = 7; lambda = -3
|
alpar@1
|
1760 |
node 7: pi = -20
|
alpar@1
|
1761 |
arc 7->9: x = 11; lambda = 0
|
alpar@1
|
1762 |
node 8: pi = -14
|
alpar@1
|
1763 |
arc 8->9: x = 9; lambda = 0
|
alpar@1
|
1764 |
node 9: pi = -23
|
alpar@1
|
1765 |
\end{verbatim}
|
alpar@1
|
1766 |
\end{footnotesize}
|
alpar@1
|
1767 |
|
alpar@1
|
1768 |
\subsection{glp\_netgen---Klingman's network problem generator}
|
alpar@1
|
1769 |
|
alpar@1
|
1770 |
\subsubsection*{Synopsis}
|
alpar@1
|
1771 |
|
alpar@1
|
1772 |
\begin{verbatim}
|
alpar@1
|
1773 |
int glp_netgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
|
alpar@1
|
1774 |
const int parm[1+15]);
|
alpar@1
|
1775 |
\end{verbatim}
|
alpar@1
|
1776 |
|
alpar@1
|
1777 |
\subsubsection*{Description}
|
alpar@1
|
1778 |
|
alpar@1
|
1779 |
The routine \verb|glp_netgen| is a GLPK version of the network problem
|
alpar@1
|
1780 |
generator developed by Dr.~Darwin~Klingman.\footnote{D.~Klingman,
|
alpar@1
|
1781 |
A.~Napier, and J.~Stutz. NETGEN: A program for generating large scale
|
alpar@1
|
1782 |
capacitated assignment, transportation, and minimum cost flow networks.
|
alpar@1
|
1783 |
Management Science 20 (1974), 814-20.} It can create capacitated and
|
alpar@1
|
1784 |
uncapacitated minimum cost flow (or transshipment), transportation, and
|
alpar@1
|
1785 |
assignment problems.
|
alpar@1
|
1786 |
|
alpar@1
|
1787 |
The parameter \verb|G| specifies the graph object, to which the
|
alpar@1
|
1788 |
generated problem data have to be stored. Note that on entry the graph
|
alpar@1
|
1789 |
object is erased with the routine \verb|glp_erase_graph|.
|
alpar@1
|
1790 |
|
alpar@1
|
1791 |
The parameter \verb|v_rhs| specifies an offset of the field of type
|
alpar@1
|
1792 |
\verb|double| in the vertex data block, to which the routine stores the
|
alpar@1
|
1793 |
supply or demand value. If \verb|v_rhs| $<0$, the value is not stored.
|
alpar@1
|
1794 |
|
alpar@1
|
1795 |
The parameter \verb|a_cap| specifies an offset of the field of type
|
alpar@1
|
1796 |
\verb|double| in the arc data block, to which the routine stores the
|
alpar@1
|
1797 |
arc capacity. If \verb|a_cap| $<0$, the capacity is not stored.
|
alpar@1
|
1798 |
|
alpar@1
|
1799 |
The parameter \verb|a_cost| specifies an offset of the field of type
|
alpar@1
|
1800 |
\verb|double| in the arc data block, to which the routine stores the
|
alpar@1
|
1801 |
per-unit cost if the arc flow. If \verb|a_cost| $<0$, the cost is not
|
alpar@1
|
1802 |
stored.
|
alpar@1
|
1803 |
|
alpar@1
|
1804 |
The array \verb|parm| contains description of the network to be
|
alpar@1
|
1805 |
generated:
|
alpar@1
|
1806 |
|
alpar@1
|
1807 |
\begin{tabular}{@{}lll@{}}
|
alpar@1
|
1808 |
\verb|parm[0] |& ¬ used\\
|
alpar@1
|
1809 |
\verb|parm[1] |&\verb|iseed |&8-digit positive random number seed\\
|
alpar@1
|
1810 |
\verb|parm[2] |&\verb|nprob |&8-digit problem id number\\
|
alpar@1
|
1811 |
\verb|parm[3] |&\verb|nodes |&total number of nodes\\
|
alpar@1
|
1812 |
\verb|parm[4] |&\verb|nsorc |&total number of source nodes\\
|
alpar@1
|
1813 |
&&(including transshipment nodes)\\
|
alpar@1
|
1814 |
\verb|parm[5] |&\verb|nsink |&total number of sink nodes\\
|
alpar@1
|
1815 |
&&(including transshipment nodes)\\
|
alpar@1
|
1816 |
\verb|parm[6] |&\verb|iarcs |&number of arc\\
|
alpar@1
|
1817 |
\verb|parm[7] |&\verb|mincst|&minimum cost for arcs\\
|
alpar@1
|
1818 |
\verb|parm[8] |&\verb|maxcst|&maximum cost for arcs\\
|
alpar@1
|
1819 |
\verb|parm[9] |&\verb|itsup |&total supply\\
|
alpar@1
|
1820 |
\end{tabular}
|
alpar@1
|
1821 |
|
alpar@1
|
1822 |
\begin{tabular}{@{}lll@{}}
|
alpar@1
|
1823 |
\verb|parm[10]|&\verb|ntsorc|&number of transshipment source nodes\\
|
alpar@1
|
1824 |
\verb|parm[11]|&\verb|ntsink|&number of transshipment sink nodes\\
|
alpar@1
|
1825 |
\verb|parm[12]|&\verb|iphic |&percentage of skeleton arcs to be given
|
alpar@1
|
1826 |
the maxi-\\&&mum cost\\
|
alpar@1
|
1827 |
\verb|parm[13]|&\verb|ipcap |&percentage of arcs to be capacitated\\
|
alpar@1
|
1828 |
\verb|parm[14]|&\verb|mincap|&minimum upper bound for capacitated arcs\\
|
alpar@1
|
1829 |
\verb|parm[15]|&\verb|maxcap|&maximum upper bound for capacitated arcs\\
|
alpar@1
|
1830 |
\end{tabular}
|
alpar@1
|
1831 |
|
alpar@1
|
1832 |
\subsubsection*{Notes}
|
alpar@1
|
1833 |
|
alpar@1
|
1834 |
\noindent\indent
|
alpar@1
|
1835 |
1. The routine generates a transportation problem if:
|
alpar@1
|
1836 |
$${\tt nsorc}+{\tt nsink}={\tt nodes},
|
alpar@1
|
1837 |
\ {\tt ntsorc}=0,\ \mbox{and}\ {\tt ntsink}=0.$$
|
alpar@1
|
1838 |
|
alpar@1
|
1839 |
2. The routine generates an assignment problem if the requirements for
|
alpar@1
|
1840 |
a transportation problem are met and:
|
alpar@1
|
1841 |
$${\tt nsorc}={\tt nsink}\ \mbox{and}\ {\tt itsup}={\tt nsorc}.$$
|
alpar@1
|
1842 |
|
alpar@1
|
1843 |
3. The routine always generates connected graphs. So, if the number of
|
alpar@1
|
1844 |
requested arcs has been reached and the generated instance is not fully
|
alpar@1
|
1845 |
connected, the routine generates a few remaining arcs to ensure
|
alpar@1
|
1846 |
connectedness. Thus, the actual number of arcs generated by the routine
|
alpar@1
|
1847 |
may be greater than the requested number of arcs.
|
alpar@1
|
1848 |
|
alpar@1
|
1849 |
\subsubsection*{Returns}
|
alpar@1
|
1850 |
|
alpar@1
|
1851 |
If the instance was successfully generated, the routine
|
alpar@1
|
1852 |
\verb|glp_netgen| returns zero; otherwise, if specified parameters are
|
alpar@1
|
1853 |
inconsistent, the routine returns a non-zero error code.
|
alpar@1
|
1854 |
|
alpar@1
|
1855 |
\subsection{glp\_gridgen---grid-like network problem generator}
|
alpar@1
|
1856 |
|
alpar@1
|
1857 |
\subsubsection*{Synopsis}
|
alpar@1
|
1858 |
|
alpar@1
|
1859 |
\begin{verbatim}
|
alpar@1
|
1860 |
int glp_gridgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
|
alpar@1
|
1861 |
const int parm[1+14]);
|
alpar@1
|
1862 |
\end{verbatim}
|
alpar@1
|
1863 |
|
alpar@1
|
1864 |
\subsubsection*{Description}
|
alpar@1
|
1865 |
|
alpar@1
|
1866 |
The routine \verb|glp_gridgen| is a GLPK version of the grid-like
|
alpar@1
|
1867 |
network problem generator developed by Yusin Lee and Jim
|
alpar@1
|
1868 |
Orlin.\footnote{Y.~Lee and J.~Orlin. GRIDGEN generator., 1991. The
|
alpar@1
|
1869 |
original code is publically available from
|
alpar@1
|
1870 |
{\tt<ftp://dimacs.rutgers.edu/pub/netflow/generators/network/gridgen>}.}
|
alpar@1
|
1871 |
|
alpar@1
|
1872 |
The parameter \verb|G| specifies the graph object, to which the
|
alpar@1
|
1873 |
generated problem data have to be stored. Note that on entry the graph
|
alpar@1
|
1874 |
object is erased with the routine \verb|glp_erase_graph|.
|
alpar@1
|
1875 |
|
alpar@1
|
1876 |
The parameter \verb|v_rhs| specifies an offset of the field of type
|
alpar@1
|
1877 |
\verb|double| in the vertex data block, to which the routine stores the
|
alpar@1
|
1878 |
supply or demand value. If \verb|v_rhs| $<0$, the value is not stored.
|
alpar@1
|
1879 |
|
alpar@1
|
1880 |
The parameter \verb|a_cap| specifies an offset of the field of type
|
alpar@1
|
1881 |
\verb|double| in the arc data block, to which the routine stores the
|
alpar@1
|
1882 |
arc capacity. If \verb|a_cap| $<0$, the capacity is not stored.
|
alpar@1
|
1883 |
|
alpar@1
|
1884 |
The parameter \verb|a_cost| specifies an offset of the field of type
|
alpar@1
|
1885 |
\verb|double| in the arc data block, to which the routine stores the
|
alpar@1
|
1886 |
per-unit cost if the arc flow. If \verb|a_cost| $<0$, the cost is not
|
alpar@1
|
1887 |
stored.
|
alpar@1
|
1888 |
|
alpar@1
|
1889 |
The array \verb|parm| contains parameters of the network to be
|
alpar@1
|
1890 |
generated:
|
alpar@1
|
1891 |
|
alpar@1
|
1892 |
\begin{tabular}{@{}ll@{}}
|
alpar@1
|
1893 |
\verb|parm[0] |¬ used\\
|
alpar@1
|
1894 |
\verb|parm[1] |&two-ways arcs indicator:\\
|
alpar@1
|
1895 |
&1 --- if links in both direction should be generated\\
|
alpar@1
|
1896 |
&0 --- otherwise\\
|
alpar@1
|
1897 |
\verb|parm[2] |&random number seed (a positive integer)\\
|
alpar@1
|
1898 |
\verb|parm[3] |&number of nodes (the number of nodes generated might
|
alpar@1
|
1899 |
be\\&slightly different to make the network a grid)\\
|
alpar@1
|
1900 |
\verb|parm[4] |&grid width\\
|
alpar@1
|
1901 |
\verb|parm[5] |&number of sources\\
|
alpar@1
|
1902 |
\verb|parm[6] |&number of sinks\\
|
alpar@1
|
1903 |
\verb|parm[7] |&average degree\\
|
alpar@1
|
1904 |
\verb|parm[8] |&total flow\\
|
alpar@1
|
1905 |
\verb|parm[9] |&distribution of arc costs:\\
|
alpar@1
|
1906 |
&1 --- uniform\\
|
alpar@1
|
1907 |
&2 --- exponential\\
|
alpar@1
|
1908 |
\verb|parm[10]|&lower bound for arc cost (uniform)\\
|
alpar@1
|
1909 |
&$100\lambda$ (exponential)\\
|
alpar@1
|
1910 |
\verb|parm[11]|&upper bound for arc cost (uniform)\\
|
alpar@1
|
1911 |
¬ used (exponential)\\
|
alpar@1
|
1912 |
\verb|parm[12]|&distribution of arc capacities:\\
|
alpar@1
|
1913 |
&1 --- uniform\\
|
alpar@1
|
1914 |
&2 --- exponential\\
|
alpar@1
|
1915 |
\verb|parm[13]|&lower bound for arc capacity (uniform)\\
|
alpar@1
|
1916 |
&$100\lambda$ (exponential)\\
|
alpar@1
|
1917 |
\verb|parm[14]|&upper bound for arc capacity (uniform)\\
|
alpar@1
|
1918 |
¬ used (exponential)\\
|
alpar@1
|
1919 |
\end{tabular}
|
alpar@1
|
1920 |
|
alpar@1
|
1921 |
\subsubsection*{Returns}
|
alpar@1
|
1922 |
|
alpar@1
|
1923 |
If the instance was successfully generated, the routine
|
alpar@1
|
1924 |
\verb|glp_gridgen| returns zero; otherwise, if specified parameters are
|
alpar@1
|
1925 |
inconsistent, the routine returns a non-zero error code.
|
alpar@1
|
1926 |
|
alpar@1
|
1927 |
\subsubsection*{Comments\footnote{This material is based on comments
|
alpar@1
|
1928 |
to the original version of GRIDGEN.}}
|
alpar@1
|
1929 |
|
alpar@1
|
1930 |
This network generator generates a grid-like network plus a super node.
|
alpar@1
|
1931 |
In additional to the arcs connecting the nodes in the grid, there is an
|
alpar@1
|
1932 |
arc from each supply node to the super node and from the super node to
|
alpar@1
|
1933 |
each demand node to guarantee feasiblity. These arcs have very high
|
alpar@1
|
1934 |
costs and very big capacities.
|
alpar@1
|
1935 |
|
alpar@1
|
1936 |
The idea of this network generator is as follows: First, a grid of
|
alpar@1
|
1937 |
$n_1\times n_2$ is generated. For example, $5\times 3$. The nodes are
|
alpar@1
|
1938 |
numbered as 1 to 15, and the supernode is numbered as $n_1\times n_2+1$.
|
alpar@1
|
1939 |
Then arcs between adjacent nodes are generated. For these arcs, the user
|
alpar@1
|
1940 |
is allowed to specify either to generate two-way arcs or one-way arcs.
|
alpar@1
|
1941 |
If two-way arcs are to be generated, two arcs, one in each direction,
|
alpar@1
|
1942 |
will be generated between each adjacent node pairs. Otherwise, only one
|
alpar@1
|
1943 |
arc will be generated. If this is the case, the arcs will be generated
|
alpar@1
|
1944 |
in alterntive directions as shown below.
|
alpar@1
|
1945 |
|
alpar@1
|
1946 |
\bigskip
|
alpar@1
|
1947 |
|
alpar@1
|
1948 |
\noindent\hfil
|
alpar@1
|
1949 |
\xymatrix
|
alpar@1
|
1950 |
{1\ar[r]\ar[d]&2\ar[r]&3\ar[r]\ar[d]&4\ar[r]&5\ar[d]\\
|
alpar@1
|
1951 |
6\ar[d]&7\ar[l]\ar[u]&8\ar[l]\ar[d]&9\ar[l]\ar[u]&10\ar[l]\ar[d]\\
|
alpar@1
|
1952 |
11\ar[r]&12\ar[r]\ar[u]&13\ar[r]&14\ar[r]\ar[u]&15\\
|
alpar@1
|
1953 |
}
|
alpar@1
|
1954 |
|
alpar@1
|
1955 |
\bigskip
|
alpar@1
|
1956 |
|
alpar@1
|
1957 |
Then the arcs between the super node and the source/sink nodes are added
|
alpar@1
|
1958 |
as mentioned before. If the number of arcs still doesn't reach the
|
alpar@1
|
1959 |
requirement, additional arcs will be added by uniformly picking random
|
alpar@1
|
1960 |
node pairs. There is no checking to prevent multiple arcs between any
|
alpar@1
|
1961 |
pair of nodes. However, there will be no self-arcs (arcs that poins back
|
alpar@1
|
1962 |
to its tail node) in the network.
|
alpar@1
|
1963 |
|
alpar@1
|
1964 |
The source and sink nodes are selected uniformly in the network, and
|
alpar@1
|
1965 |
the imbalances of each source/sink node are also assigned by uniform
|
alpar@1
|
1966 |
distribution.
|
alpar@1
|
1967 |
|
alpar@1
|
1968 |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
alpar@1
|
1969 |
|
alpar@1
|
1970 |
\newpage
|
alpar@1
|
1971 |
|
alpar@1
|
1972 |
\section{Maximum flow problem}
|
alpar@1
|
1973 |
|
alpar@1
|
1974 |
\subsection{Background}
|
alpar@1
|
1975 |
|
alpar@1
|
1976 |
The {\it maximum flow problem} (MAXFLOW) is stated as follows. Let
|
alpar@1
|
1977 |
there be given a directed graph (flow network) $G=(V,A)$, where $V$ is
|
alpar@1
|
1978 |
a set of vertices (nodes), and $A\subseteq V\times V$ is a set of arcs.
|
alpar@1
|
1979 |
Let also for each arc $a=(i,j)\in A$ there be given its capacity
|
alpar@1
|
1980 |
$u_{ij}$. The problem is, for given {\it source} node $s\in V$ and
|
alpar@1
|
1981 |
{\it sink} node $t\in V$, to find flows $x_{ij}$ through every arc of
|
alpar@1
|
1982 |
the network, which satisfy the specified arc capacities and the
|
alpar@1
|
1983 |
conservation constraints at all nodes, and maximize the total flow $F$
|
alpar@1
|
1984 |
through the network from $s$ to $t$. Here the conservation constraint
|
alpar@1
|
1985 |
at a node means that the total flow entering this node through its
|
alpar@1
|
1986 |
incoming arcs (plus $F$, if it is the source node) must be equal to the
|
alpar@1
|
1987 |
total flow leaving this node through its outgoing arcs (plus $F$, if it
|
alpar@1
|
1988 |
is the sink node).
|
alpar@1
|
1989 |
|
alpar@1
|
1990 |
An example of the maximum flow problem, where $s=v_1$ and $t=v_9$, is
|
alpar@1
|
1991 |
shown on Fig.~2.
|
alpar@1
|
1992 |
|
alpar@1
|
1993 |
\bigskip
|
alpar@1
|
1994 |
|
alpar@1
|
1995 |
\noindent\hfil
|
alpar@1
|
1996 |
\xymatrix @C=48pt
|
alpar@1
|
1997 |
{_{F}\ar@{~>}[d]&
|
alpar@1
|
1998 |
v_2\ar[r]|{_{10}}\ar[dd]|{_{9}}&
|
alpar@1
|
1999 |
v_3\ar[dd]|{_{12}}\ar[r]|{_{18}}&
|
alpar@1
|
2000 |
v_8\ar[rd]|{_{20}}&\\
|
alpar@1
|
2001 |
v_1\ar[ru]|{_{14}}\ar[rd]|{_{23}}&&&
|
alpar@1
|
2002 |
v_6\ar[d]|{_{7}}\ar[u]|{_{8}}&
|
alpar@1
|
2003 |
v_9\ar@{~>}[d]\\
|
alpar@1
|
2004 |
&v_4\ar[r]|{_{26}}&
|
alpar@1
|
2005 |
v_5\ar[luu]|{_{11}}\ar[ru]|{_{25}}\ar[r]|{_{4}}&
|
alpar@1
|
2006 |
v_7\ar[ru]|{_{15}}&_{F}\\
|
alpar@1
|
2007 |
}
|
alpar@1
|
2008 |
|
alpar@1
|
2009 |
\bigskip
|
alpar@1
|
2010 |
|
alpar@1
|
2011 |
\noindent\hfil
|
alpar@1
|
2012 |
Fig.~2. An example of the maximum flow problem.
|
alpar@1
|
2013 |
|
alpar@1
|
2014 |
\bigskip
|
alpar@1
|
2015 |
|
alpar@1
|
2016 |
The maximum flow problem can be naturally formulated as the following
|
alpar@1
|
2017 |
LP problem:
|
alpar@1
|
2018 |
|
alpar@1
|
2019 |
\medskip
|
alpar@1
|
2020 |
|
alpar@1
|
2021 |
\noindent
|
alpar@1
|
2022 |
\hspace{.5in}maximize
|
alpar@1
|
2023 |
$$F\eqno(4)$$
|
alpar@1
|
2024 |
\hspace{.5in}subject to
|
alpar@1
|
2025 |
$$\sum_{(i,j)\in A}x_{ij}-\sum_{(j,i)\in A}x_{ji}=\left\{
|
alpar@1
|
2026 |
\begin{array}{@{\ }rl}
|
alpar@1
|
2027 |
+F,&\hbox{for}\ i=s\\
|
alpar@1
|
2028 |
0,&\hbox{for all}\ i\in V\backslash\{s,t\}\\
|
alpar@1
|
2029 |
-F,&\hbox{for}\ i=t\\
|
alpar@1
|
2030 |
\end{array}
|
alpar@1
|
2031 |
\right.\eqno(5)
|
alpar@1
|
2032 |
$$
|
alpar@1
|
2033 |
$$0\leq x_{ij}\leq u_{ij}\ \ \ \hbox{for all}\ (i,j)\in A
|
alpar@1
|
2034 |
\eqno(6)$$
|
alpar@1
|
2035 |
|
alpar@1
|
2036 |
\medskip
|
alpar@1
|
2037 |
|
alpar@1
|
2038 |
\noindent
|
alpar@1
|
2039 |
where $F\geq 0$ is an additional variable playing the role of the
|
alpar@1
|
2040 |
objective.
|
alpar@1
|
2041 |
|
alpar@1
|
2042 |
\newpage
|
alpar@1
|
2043 |
|
alpar@1
|
2044 |
Another LP formulation of the maximum flow problem, which does not
|
alpar@1
|
2045 |
include the variable $F$, is the following:
|
alpar@1
|
2046 |
|
alpar@1
|
2047 |
\medskip
|
alpar@1
|
2048 |
|
alpar@1
|
2049 |
\noindent
|
alpar@1
|
2050 |
\hspace{.5in}maximize
|
alpar@1
|
2051 |
$$z=\sum_{(s,j)\in A}x_{sj}-\sum_{(j,s)\in A}x_{js}\ (=F)\eqno(7)$$
|
alpar@1
|
2052 |
\hspace{.5in}subject to
|
alpar@1
|
2053 |
$$\sum_{(i,j)\in A}x_{ij}-\sum_{(j,i)\in A}x_{ji}\left\{
|
alpar@1
|
2054 |
\begin{array}{@{\ }rl}
|
alpar@1
|
2055 |
\geq 0,&\hbox{for}\ i=s\\
|
alpar@1
|
2056 |
=0,&\hbox{for all}\ i\in V\backslash\{s,t\}\\
|
alpar@1
|
2057 |
\leq 0,&\hbox{for}\ i=t\\
|
alpar@1
|
2058 |
\end{array}
|
alpar@1
|
2059 |
\right.\eqno(8)
|
alpar@1
|
2060 |
$$
|
alpar@1
|
2061 |
$$0\leq x_{ij}\leq u_{ij}\ \ \ \hbox{for all}\ (i,j)\in A
|
alpar@1
|
2062 |
\eqno(9)$$
|
alpar@1
|
2063 |
|
alpar@1
|
2064 |
\subsection{glp\_read\_maxflow---read maximum flow problem data\\in
|
alpar@1
|
2065 |
DIMACS format}
|
alpar@1
|
2066 |
|
alpar@1
|
2067 |
\subsubsection*{Synopsis}
|
alpar@1
|
2068 |
|
alpar@1
|
2069 |
\begin{verbatim}
|
alpar@1
|
2070 |
int glp_read_maxflow(glp_graph *G, int *s, int *t, int a_cap,
|
alpar@1
|
2071 |
const char *fname);
|
alpar@1
|
2072 |
\end{verbatim}
|
alpar@1
|
2073 |
|
alpar@1
|
2074 |
\subsubsection*{Description}
|
alpar@1
|
2075 |
|
alpar@1
|
2076 |
The routine \verb|glp_read_maxflow| reads the maximum flow problem
|
alpar@1
|
2077 |
data from a text file in DIMACS format.
|
alpar@1
|
2078 |
|
alpar@1
|
2079 |
The parameter \verb|G| specifies the graph object, to which the problem
|
alpar@1
|
2080 |
data have to be stored. Note that before reading data the current
|
alpar@1
|
2081 |
content of the graph object is completely erased with the routine
|
alpar@1
|
2082 |
\verb|glp_erase_graph|.
|
alpar@1
|
2083 |
|
alpar@1
|
2084 |
The pointer \verb|s| specifies a location, to which the routine stores
|
alpar@1
|
2085 |
the ordinal number of the source node. If \verb|s| is \verb|NULL|, the
|
alpar@1
|
2086 |
source node number is not stored.
|
alpar@1
|
2087 |
|
alpar@1
|
2088 |
The pointer \verb|t| specifies a location, to which the routine stores
|
alpar@1
|
2089 |
the ordinal number of the sink node. If \verb|t| is \verb|NULL|, the
|
alpar@1
|
2090 |
sink node number is not stored.
|
alpar@1
|
2091 |
|
alpar@1
|
2092 |
The parameter \verb|a_cap| specifies an offset of the field of type
|
alpar@1
|
2093 |
\verb|double| in the arc data block, to which the routine stores
|
alpar@1
|
2094 |
$u_{ij}$, the arc capacity. If \verb|a_cap| $<0$, the arc capacity is
|
alpar@1
|
2095 |
not stored.
|
alpar@1
|
2096 |
|
alpar@1
|
2097 |
The character string \verb|fname| specifies the name of a text file to
|
alpar@1
|
2098 |
be read in. (If the file name name ends with the suffix `\verb|.gz|',
|
alpar@1
|
2099 |
the file is assumed to be compressed, in which case the routine
|
alpar@1
|
2100 |
decompresses it ``on the fly''.)
|
alpar@1
|
2101 |
|
alpar@1
|
2102 |
\subsubsection*{Returns}
|
alpar@1
|
2103 |
|
alpar@1
|
2104 |
If the operation was successful, the routine returns zero. Otherwise,
|
alpar@1
|
2105 |
it prints an error message and returns non-zero.
|
alpar@1
|
2106 |
|
alpar@1
|
2107 |
\subsubsection*{Example}
|
alpar@1
|
2108 |
|
alpar@1
|
2109 |
\begin{footnotesize}
|
alpar@1
|
2110 |
\begin{verbatim}
|
alpar@1
|
2111 |
typedef struct
|
alpar@1
|
2112 |
{ /* arc data block */
|
alpar@1
|
2113 |
...
|
alpar@1
|
2114 |
double cap;
|
alpar@1
|
2115 |
...
|
alpar@1
|
2116 |
} a_data;
|
alpar@1
|
2117 |
|
alpar@1
|
2118 |
int main(void)
|
alpar@1
|
2119 |
{ glp_graph *G;
|
alpar@1
|
2120 |
int s, t, ret;
|
alpar@1
|
2121 |
G = glp_create_graph(..., sizeof(a_data));
|
alpar@1
|
2122 |
ret = glp_read_maxflow(G, &s, &t, offsetof(a_data, cap),
|
alpar@1
|
2123 |
"sample.max");
|
alpar@1
|
2124 |
if (ret != 0) goto ...
|
alpar@1
|
2125 |
...
|
alpar@1
|
2126 |
}
|
alpar@1
|
2127 |
\end{verbatim}
|
alpar@1
|
2128 |
\end{footnotesize}
|
alpar@1
|
2129 |
|
alpar@1
|
2130 |
\subsubsection*{DIMACS maximum flow problem format\footnote{This
|
alpar@1
|
2131 |
material is based on the paper ``The First DIMACS International
|
alpar@1
|
2132 |
Algorithm Implementation Challenge: Problem Definitions and
|
alpar@1
|
2133 |
Specifications'', which is publically available at
|
alpar@1
|
2134 |
{\tt http://dimacs.rutgers.edu/Challenges/}.}}
|
alpar@1
|
2135 |
\label{subsecmaxflow}
|
alpar@1
|
2136 |
|
alpar@1
|
2137 |
The DIMACS input file is a plain ASCII text file. It contains
|
alpar@1
|
2138 |
{\it lines} of several types described below. A line is terminated with
|
alpar@1
|
2139 |
an end-of-line character. Fields in each line are separated by at least
|
alpar@1
|
2140 |
one blank space. Each line begins with a one-character designator to
|
alpar@1
|
2141 |
identify the line type.
|
alpar@1
|
2142 |
|
alpar@1
|
2143 |
Note that DIMACS requires all numerical quantities to be integers in
|
alpar@1
|
2144 |
the range $[-2^{31},\ 2^{31}-1]$ while GLPK allows the quantities to be
|
alpar@1
|
2145 |
floating-point numbers.
|
alpar@1
|
2146 |
|
alpar@1
|
2147 |
\paragraph{Comment lines.} Comment lines give human-readable information
|
alpar@1
|
2148 |
about the file and are ignored by programs. Comment lines can appear
|
alpar@1
|
2149 |
anywhere in the file. Each comment line begins with a lower-case
|
alpar@1
|
2150 |
character \verb|c|.
|
alpar@1
|
2151 |
|
alpar@1
|
2152 |
\begin{verbatim}
|
alpar@1
|
2153 |
c This is a comment line
|
alpar@1
|
2154 |
\end{verbatim}
|
alpar@1
|
2155 |
|
alpar@1
|
2156 |
\newpage
|
alpar@1
|
2157 |
|
alpar@1
|
2158 |
\paragraph{Problem line.} There is one problem line per data file. The
|
alpar@1
|
2159 |
problem line must appear before any node or arc descriptor lines. It has
|
alpar@1
|
2160 |
the following format:
|
alpar@1
|
2161 |
|
alpar@1
|
2162 |
\begin{verbatim}
|
alpar@1
|
2163 |
p max NODES ARCS
|
alpar@1
|
2164 |
\end{verbatim}
|
alpar@1
|
2165 |
|
alpar@1
|
2166 |
\noindent
|
alpar@1
|
2167 |
The lower-case character \verb|p| signifies that this is a problem line.
|
alpar@1
|
2168 |
The three-character problem designator \verb|max| identifies the file as
|
alpar@1
|
2169 |
containing specification information for the maximum flow problem. The
|
alpar@1
|
2170 |
\verb|NODES| field contains an integer value specifying the number of
|
alpar@1
|
2171 |
nodes in the network. The \verb|ARCS| field contains an integer value
|
alpar@1
|
2172 |
specifying the number of arcs in the network.
|
alpar@1
|
2173 |
|
alpar@1
|
2174 |
\paragraph{Node descriptors.} Two node descriptor lines for the source
|
alpar@1
|
2175 |
and sink nodes must appear before all arc descriptor lines. They may
|
alpar@1
|
2176 |
appear in either order, each with the following format:
|
alpar@1
|
2177 |
|
alpar@1
|
2178 |
\begin{verbatim}
|
alpar@1
|
2179 |
n ID WHICH
|
alpar@1
|
2180 |
\end{verbatim}
|
alpar@1
|
2181 |
|
alpar@1
|
2182 |
\noindent
|
alpar@1
|
2183 |
The lower-case character \verb|n| signifies that this a node descriptor
|
alpar@1
|
2184 |
line. The \verb|ID| field gives a node identification number, an integer
|
alpar@1
|
2185 |
between 1 and \verb|NODES|. The \verb|WHICH| field gives either a
|
alpar@1
|
2186 |
lower-case \verb|s| or \verb|t|, designating the source and sink,
|
alpar@1
|
2187 |
respectively.
|
alpar@1
|
2188 |
|
alpar@1
|
2189 |
\paragraph{Arc descriptors.} There is one arc descriptor line for each
|
alpar@1
|
2190 |
arc in the network. Arc descriptor lines are of the following format:
|
alpar@1
|
2191 |
|
alpar@1
|
2192 |
\begin{verbatim}
|
alpar@1
|
2193 |
a SRC DST CAP
|
alpar@1
|
2194 |
\end{verbatim}
|
alpar@1
|
2195 |
|
alpar@1
|
2196 |
\noindent
|
alpar@1
|
2197 |
The lower-case character \verb|a| signifies that this is an arc
|
alpar@1
|
2198 |
descriptor line. For a directed arc $(i,j)$ the \verb|SRC| field gives
|
alpar@1
|
2199 |
the identification number $i$ for the tail endpoint, and the \verb|DST|
|
alpar@1
|
2200 |
field gives the identification number $j$ for the head endpoint.
|
alpar@1
|
2201 |
Identification numbers are integers between 1 and \verb|NODES|. The
|
alpar@1
|
2202 |
\verb|CAP| field gives the arc capacity, i.e. maximum amount of flow
|
alpar@1
|
2203 |
that can be sent along arc $(i,j)$ in a feasible flow.
|
alpar@1
|
2204 |
|
alpar@1
|
2205 |
\paragraph{Example.} Below here is an example of the data file in
|
alpar@1
|
2206 |
DIMACS format corresponding to the maximum flow problem shown on Fig~2.
|
alpar@1
|
2207 |
|
alpar@1
|
2208 |
\newpage
|
alpar@1
|
2209 |
|
alpar@1
|
2210 |
\begin{footnotesize}
|
alpar@1
|
2211 |
\begin{verbatim}
|
alpar@1
|
2212 |
c sample.max
|
alpar@1
|
2213 |
c
|
alpar@1
|
2214 |
c This is an example of the maximum flow problem data
|
alpar@1
|
2215 |
c in DIMACS format.
|
alpar@1
|
2216 |
c
|
alpar@1
|
2217 |
p max 9 14
|
alpar@1
|
2218 |
c
|
alpar@1
|
2219 |
n 1 s
|
alpar@1
|
2220 |
n 9 t
|
alpar@1
|
2221 |
c
|
alpar@1
|
2222 |
a 1 2 14
|
alpar@1
|
2223 |
a 1 4 23
|
alpar@1
|
2224 |
a 2 3 10
|
alpar@1
|
2225 |
a 2 4 9
|
alpar@1
|
2226 |
a 3 5 12
|
alpar@1
|
2227 |
a 3 8 18
|
alpar@1
|
2228 |
a 4 5 26
|
alpar@1
|
2229 |
a 5 2 11
|
alpar@1
|
2230 |
a 5 6 25
|
alpar@1
|
2231 |
a 5 7 4
|
alpar@1
|
2232 |
a 6 7 7
|
alpar@1
|
2233 |
a 6 8 8
|
alpar@1
|
2234 |
a 7 9 15
|
alpar@1
|
2235 |
a 8 9 20
|
alpar@1
|
2236 |
c
|
alpar@1
|
2237 |
c eof
|
alpar@1
|
2238 |
\end{verbatim}
|
alpar@1
|
2239 |
\end{footnotesize}
|
alpar@1
|
2240 |
|
alpar@1
|
2241 |
\subsection{glp\_write\_maxflow---write maximum flow problem data\\
|
alpar@1
|
2242 |
in DIMACS format}
|
alpar@1
|
2243 |
|
alpar@1
|
2244 |
\subsubsection*{Synopsis}
|
alpar@1
|
2245 |
|
alpar@1
|
2246 |
\begin{verbatim}
|
alpar@1
|
2247 |
int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap,
|
alpar@1
|
2248 |
const char *fname);
|
alpar@1
|
2249 |
\end{verbatim}
|
alpar@1
|
2250 |
|
alpar@1
|
2251 |
\subsubsection*{Description}
|
alpar@1
|
2252 |
|
alpar@1
|
2253 |
The routine \verb|glp_write_maxflow| writes the maximum flow problem
|
alpar@1
|
2254 |
data to a text file in DIMACS format.
|
alpar@1
|
2255 |
|
alpar@1
|
2256 |
The parameter \verb|G| is the graph (network) program object, which
|
alpar@1
|
2257 |
specifies the maximum flow problem instance.
|
alpar@1
|
2258 |
|
alpar@1
|
2259 |
The parameter \verb|s| specifies the ordinal number of the source node.
|
alpar@1
|
2260 |
|
alpar@1
|
2261 |
The parameter \verb|t| specifies the ordinal number of the sink node.
|
alpar@1
|
2262 |
|
alpar@1
|
2263 |
The parameter \verb|a_cap| specifies an offset of the field of type
|
alpar@1
|
2264 |
\verb|double| in the arc data block, which contains $u_{ij}$, the upper
|
alpar@1
|
2265 |
bound to the arc flow (the arc capacity). If the upper bound is
|
alpar@1
|
2266 |
specified as \verb|DBL_MAX|, it is assumed that $u_{ij}=\infty$, i.e.
|
alpar@1
|
2267 |
the arc is uncapacitated. If \verb|a_cap| $<0$, it is assumed that
|
alpar@1
|
2268 |
$u_{ij}=1$ for all arcs.
|
alpar@1
|
2269 |
|
alpar@1
|
2270 |
The character string \verb|fname| specifies a name of the text file to
|
alpar@1
|
2271 |
be written out. (If the file name ends with suffix `\verb|.gz|', the
|
alpar@1
|
2272 |
file is assumed to be compressed, in which case the routine performs
|
alpar@1
|
2273 |
automatic compression on writing it.)
|
alpar@1
|
2274 |
|
alpar@1
|
2275 |
\subsubsection*{Returns}
|
alpar@1
|
2276 |
|
alpar@1
|
2277 |
If the operation was successful, the routine returns zero. Otherwise,
|
alpar@1
|
2278 |
it prints an error message and returns non-zero.
|
alpar@1
|
2279 |
|
alpar@1
|
2280 |
\subsection{glp\_maxflow\_lp---convert maximum flow problem to LP}
|
alpar@1
|
2281 |
|
alpar@1
|
2282 |
\subsubsection*{Synopsis}
|
alpar@1
|
2283 |
|
alpar@1
|
2284 |
\begin{verbatim}
|
alpar@1
|
2285 |
void glp_maxflow_lp(glp_prob *lp, glp_graph *G, int names,
|
alpar@1
|
2286 |
int s, int t, int a_cap);
|
alpar@1
|
2287 |
\end{verbatim}
|
alpar@1
|
2288 |
|
alpar@1
|
2289 |
\subsubsection*{Description}
|
alpar@1
|
2290 |
|
alpar@1
|
2291 |
The routine \verb|glp_maxflow_lp| builds LP problem (7)---(9), which
|
alpar@1
|
2292 |
corresponds to the specified maximum flow problem.
|
alpar@1
|
2293 |
|
alpar@1
|
2294 |
The parameter \verb|lp| is the resultant LP problem object to be built.
|
alpar@1
|
2295 |
Note that on entry its current content is erased with the routine
|
alpar@1
|
2296 |
\verb|glp_erase_prob|.
|
alpar@1
|
2297 |
|
alpar@1
|
2298 |
The parameter \verb|G| is the graph (network) program object, which
|
alpar@1
|
2299 |
specifies the maximum flow problem instance.
|
alpar@1
|
2300 |
|
alpar@1
|
2301 |
The parameter \verb|names| is a flag. If it is \verb|GLP_ON|, the
|
alpar@1
|
2302 |
routine uses symbolic names of the graph object components to assign
|
alpar@1
|
2303 |
symbolic names to the LP problem object components. If the flag is
|
alpar@1
|
2304 |
\verb|GLP_OFF|, no symbolic names are assigned.
|
alpar@1
|
2305 |
|
alpar@1
|
2306 |
The parameter \verb|s| specifies the ordinal number of the source node.
|
alpar@1
|
2307 |
|
alpar@1
|
2308 |
The parameter \verb|t| specifies the ordinal number of the sink node.
|
alpar@1
|
2309 |
|
alpar@1
|
2310 |
The parameter \verb|a_cap| specifies an offset of the field of type
|
alpar@1
|
2311 |
\verb|double| in the arc data block, which contains $u_{ij}$, the upper
|
alpar@1
|
2312 |
bound to the arc flow (the arc capacity). If the upper bound is
|
alpar@1
|
2313 |
specified as \verb|DBL_MAX|, it is assumed that $u_{ij}=\infty$, i.e.
|
alpar@1
|
2314 |
the arc is uncapacitated. If \verb|a_cap| $<0$, it is assumed that
|
alpar@1
|
2315 |
$u_{ij}=1$ for all arcs.
|
alpar@1
|
2316 |
|
alpar@1
|
2317 |
\subsubsection*{Example}
|
alpar@1
|
2318 |
|
alpar@1
|
2319 |
The example program below reads the maximum flow problem in DIMACS
|
alpar@1
|
2320 |
format from file `\verb|sample.max|', converts the instance to LP, and
|
alpar@1
|
2321 |
then writes the resultant LP in CPLEX format to file
|
alpar@1
|
2322 |
`\verb|maxflow.lp|'.
|
alpar@1
|
2323 |
|
alpar@1
|
2324 |
\begin{footnotesize}
|
alpar@1
|
2325 |
\begin{verbatim}
|
alpar@1
|
2326 |
#include <stddef.h>
|
alpar@1
|
2327 |
#include <glpk.h>
|
alpar@1
|
2328 |
|
alpar@1
|
2329 |
int main(void)
|
alpar@1
|
2330 |
{ glp_graph *G;
|
alpar@1
|
2331 |
glp_prob *lp;
|
alpar@1
|
2332 |
int s, t;
|
alpar@1
|
2333 |
G = glp_create_graph(0, sizeof(double));
|
alpar@1
|
2334 |
glp_read_maxflow(G, &s, &t, 0, "sample.max");
|
alpar@1
|
2335 |
lp = glp_create_prob();
|
alpar@1
|
2336 |
glp_maxflow_lp(lp, G, GLP_ON, s, t, 0);
|
alpar@1
|
2337 |
glp_delete_graph(G);
|
alpar@1
|
2338 |
glp_write_lp(lp, NULL, "maxflow.lp");
|
alpar@1
|
2339 |
glp_delete_prob(lp);
|
alpar@1
|
2340 |
return 0;
|
alpar@1
|
2341 |
}
|
alpar@1
|
2342 |
\end{verbatim}
|
alpar@1
|
2343 |
\end{footnotesize}
|
alpar@1
|
2344 |
|
alpar@1
|
2345 |
If `\verb|sample.max|' is the example data file from the previous
|
alpar@1
|
2346 |
subsection, the output `\verb|maxflow.lp|' may look like follows:
|
alpar@1
|
2347 |
|
alpar@1
|
2348 |
\begin{footnotesize}
|
alpar@1
|
2349 |
\begin{verbatim}
|
alpar@1
|
2350 |
Maximize
|
alpar@1
|
2351 |
obj: + x(1,4) + x(1,2)
|
alpar@1
|
2352 |
|
alpar@1
|
2353 |
Subject To
|
alpar@1
|
2354 |
r_1: + x(1,2) + x(1,4) >= 0
|
alpar@1
|
2355 |
r_2: - x(5,2) + x(2,3) + x(2,4) - x(1,2) = 0
|
alpar@1
|
2356 |
r_3: + x(3,5) + x(3,8) - x(2,3) = 0
|
alpar@1
|
2357 |
r_4: + x(4,5) - x(2,4) - x(1,4) = 0
|
alpar@1
|
2358 |
r_5: + x(5,2) + x(5,6) + x(5,7) - x(4,5) - x(3,5) = 0
|
alpar@1
|
2359 |
r_6: + x(6,7) + x(6,8) - x(5,6) = 0
|
alpar@1
|
2360 |
r_7: + x(7,9) - x(6,7) - x(5,7) = 0
|
alpar@1
|
2361 |
r_8: + x(8,9) - x(6,8) - x(3,8) = 0
|
alpar@1
|
2362 |
r_9: - x(8,9) - x(7,9) <= 0
|
alpar@1
|
2363 |
|
alpar@1
|
2364 |
Bounds
|
alpar@1
|
2365 |
0 <= x(1,4) <= 23
|
alpar@1
|
2366 |
0 <= x(1,2) <= 14
|
alpar@1
|
2367 |
0 <= x(2,4) <= 9
|
alpar@1
|
2368 |
0 <= x(2,3) <= 10
|
alpar@1
|
2369 |
0 <= x(3,8) <= 18
|
alpar@1
|
2370 |
0 <= x(3,5) <= 12
|
alpar@1
|
2371 |
0 <= x(4,5) <= 26
|
alpar@1
|
2372 |
0 <= x(5,7) <= 4
|
alpar@1
|
2373 |
0 <= x(5,6) <= 25
|
alpar@1
|
2374 |
0 <= x(5,2) <= 11
|
alpar@1
|
2375 |
0 <= x(6,8) <= 8
|
alpar@1
|
2376 |
0 <= x(6,7) <= 7
|
alpar@1
|
2377 |
0 <= x(7,9) <= 15
|
alpar@1
|
2378 |
0 <= x(8,9) <= 20
|
alpar@1
|
2379 |
|
alpar@1
|
2380 |
End
|
alpar@1
|
2381 |
\end{verbatim}
|
alpar@1
|
2382 |
\end{footnotesize}
|
alpar@1
|
2383 |
|
alpar@1
|
2384 |
\subsection{glp\_maxflow\_ffalg---solve maximum flow problem with
|
alpar@1
|
2385 |
Ford-Fulkerson algorithm}
|
alpar@1
|
2386 |
|
alpar@1
|
2387 |
\subsubsection*{Synopsis}
|
alpar@1
|
2388 |
|
alpar@1
|
2389 |
\begin{verbatim}
|
alpar@1
|
2390 |
int glp_maxflow_ffalg(glp_graph *G, int s, int t, int a_cap,
|
alpar@1
|
2391 |
double *sol, int a_x, int v_cut);
|
alpar@1
|
2392 |
\end{verbatim}
|
alpar@1
|
2393 |
|
alpar@1
|
2394 |
\subsubsection*{Description}
|
alpar@1
|
2395 |
|
alpar@1
|
2396 |
The routine \verb|glp_mincost_ffalg| finds optimal solution to the
|
alpar@1
|
2397 |
maximum flow problem with the Ford-Fulkerson algorithm.\footnote{GLPK
|
alpar@1
|
2398 |
implementation of the Ford-Fulkerson algorithm is based on the following
|
alpar@1
|
2399 |
book: L.~R.~Ford,~Jr., and D.~R.~Fulkerson, ``Flows in Networks,'' The
|
alpar@1
|
2400 |
RAND Corp., Report\linebreak R-375-PR (August 1962), Chap. I
|
alpar@1
|
2401 |
``Static Maximal Flow,'' pp.~30-33.} Note that this routine requires all
|
alpar@1
|
2402 |
the problem data to be integer-valued.
|
alpar@1
|
2403 |
|
alpar@1
|
2404 |
The parameter \verb|G| is a graph (network) program object which
|
alpar@1
|
2405 |
specifies the maximum flow problem instance to be solved.
|
alpar@1
|
2406 |
|
alpar@1
|
2407 |
The parameter $s$ specifies the ordinal number of the source node.
|
alpar@1
|
2408 |
|
alpar@1
|
2409 |
The parameter $t$ specifies the ordinal number of the sink node.
|
alpar@1
|
2410 |
|
alpar@1
|
2411 |
The parameter \verb|a_cap| specifies an offset of the field of type
|
alpar@1
|
2412 |
\verb|double| in the arc data block, which contains $u_{ij}$, the upper
|
alpar@1
|
2413 |
bound to the arc flow (the arc capacity). This bound must be integer in
|
alpar@1
|
2414 |
the range [0, \verb|INT_MAX|]. If \verb|a_cap| $<0$, it is assumed that
|
alpar@1
|
2415 |
$u_{ij}=1$ for all arcs.
|
alpar@1
|
2416 |
|
alpar@1
|
2417 |
The parameter \verb|sol| specifies a location, to which the routine
|
alpar@1
|
2418 |
stores the objective value (that is, the total flow from $s$ to $t$)
|
alpar@1
|
2419 |
found. If \verb|sol| is NULL, the objective value is not stored.
|
alpar@1
|
2420 |
|
alpar@1
|
2421 |
The parameter \verb|a_x| specifies an offset of the field of type
|
alpar@1
|
2422 |
\verb|double| in the arc data block, to which the routine stores
|
alpar@1
|
2423 |
$x_{ij}$, the arc flow found. If \verb|a_x| $<0$, the arc flow values
|
alpar@1
|
2424 |
are not stored.
|
alpar@1
|
2425 |
|
alpar@1
|
2426 |
The parameter \verb|v_cut| specifies an offset of the field of type
|
alpar@1
|
2427 |
\verb|int| in the vertex data block, to which the routine stores node
|
alpar@1
|
2428 |
flags corresponding to the optimal solution found: if the node flag is
|
alpar@1
|
2429 |
1, the node is labelled, and if the node flag is 0, the node is
|
alpar@1
|
2430 |
unlabelled. The calling program may use these node flags to determine
|
alpar@1
|
2431 |
the {\it minimal cut}, which is a subset of arcs whose one endpoint is
|
alpar@1
|
2432 |
labelled and other is not. If \verb|v_cut| $<0$, the node flags are not
|
alpar@1
|
2433 |
stored.
|
alpar@1
|
2434 |
|
alpar@1
|
2435 |
Note that all solution components (the objective value and arc flows)
|
alpar@1
|
2436 |
computed by the routine are always integer-valued.
|
alpar@1
|
2437 |
|
alpar@1
|
2438 |
\subsubsection*{Returns}
|
alpar@1
|
2439 |
|
alpar@1
|
2440 |
\def\arraystretch{1}
|
alpar@1
|
2441 |
|
alpar@1
|
2442 |
\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
|
alpar@1
|
2443 |
0 & Optimal solution found.\\
|
alpar@1
|
2444 |
\verb|GLP_EDATA| & Unable to start the search, because some problem
|
alpar@1
|
2445 |
data are either not integer-valued or out of range.\\
|
alpar@1
|
2446 |
\end{tabular}
|
alpar@1
|
2447 |
|
alpar@1
|
2448 |
\subsubsection*{Example}
|
alpar@1
|
2449 |
|
alpar@1
|
2450 |
The example program shown below reads the maximum flow problem instance
|
alpar@1
|
2451 |
in DIMACS format from file `\verb|sample.max|', solves it using the
|
alpar@1
|
2452 |
routine \verb|glp_maxflow_ffalg|, and write the solution found to the
|
alpar@1
|
2453 |
standard output.
|
alpar@1
|
2454 |
|
alpar@1
|
2455 |
\begin{footnotesize}
|
alpar@1
|
2456 |
\begin{verbatim}
|
alpar@1
|
2457 |
#include <stddef.h>
|
alpar@1
|
2458 |
#include <stdio.h>
|
alpar@1
|
2459 |
#include <stdlib.h>
|
alpar@1
|
2460 |
#include <glpk.h>
|
alpar@1
|
2461 |
|
alpar@1
|
2462 |
typedef struct { int cut; } v_data;
|
alpar@1
|
2463 |
typedef struct { double cap, x; } a_data;
|
alpar@1
|
2464 |
|
alpar@1
|
2465 |
#define node(v) ((v_data *)((v)->data))
|
alpar@1
|
2466 |
#define arc(a) ((a_data *)((a)->data))
|
alpar@1
|
2467 |
|
alpar@1
|
2468 |
int main(void)
|
alpar@1
|
2469 |
{ glp_graph *G;
|
alpar@1
|
2470 |
glp_vertex *v, *w;
|
alpar@1
|
2471 |
glp_arc *a;
|
alpar@1
|
2472 |
int i, s, t, ret;
|
alpar@1
|
2473 |
double sol;
|
alpar@1
|
2474 |
G = glp_create_graph(sizeof(v_data), sizeof(a_data));
|
alpar@1
|
2475 |
glp_read_maxflow(G, &s, &t, offsetof(a_data, cap),
|
alpar@1
|
2476 |
"sample.max");
|
alpar@1
|
2477 |
ret = glp_maxflow_ffalg(G, s, t, offsetof(a_data, cap),
|
alpar@1
|
2478 |
&sol, offsetof(a_data, x), offsetof(v_data, cut));
|
alpar@1
|
2479 |
printf("ret = %d; sol = %5g\n", ret, sol);
|
alpar@1
|
2480 |
for (i = 1; i <= G->nv; i++)
|
alpar@1
|
2481 |
{ v = G->v[i];
|
alpar@1
|
2482 |
for (a = v->out; a != NULL; a = a->t_next)
|
alpar@1
|
2483 |
{ w = a->head;
|
alpar@1
|
2484 |
printf("x[%d->%d] = %5g (%d)\n", v->i, w->i,
|
alpar@1
|
2485 |
arc(a)->x, node(v)->cut ^ node(w)->cut);
|
alpar@1
|
2486 |
}
|
alpar@1
|
2487 |
}
|
alpar@1
|
2488 |
glp_delete_graph(G);
|
alpar@1
|
2489 |
return 0;
|
alpar@1
|
2490 |
}
|
alpar@1
|
2491 |
\end{verbatim}
|
alpar@1
|
2492 |
\end{footnotesize}
|
alpar@1
|
2493 |
|
alpar@1
|
2494 |
If `\verb|sample.max|' is the example data file from the subsection
|
alpar@1
|
2495 |
describing the routine \verb|glp_read_maxflow|, the output may look like
|
alpar@1
|
2496 |
follows:
|
alpar@1
|
2497 |
|
alpar@1
|
2498 |
\begin{footnotesize}
|
alpar@1
|
2499 |
\begin{verbatim}
|
alpar@1
|
2500 |
Reading maximum flow problem data from `sample.max'...
|
alpar@1
|
2501 |
Flow network has 9 nodes and 14 arcs
|
alpar@1
|
2502 |
24 lines were read
|
alpar@1
|
2503 |
ret = 0; sol = 29
|
alpar@1
|
2504 |
x[1->4] = 19 (0)
|
alpar@1
|
2505 |
x[1->2] = 10 (0)
|
alpar@1
|
2506 |
x[2->4] = 0 (0)
|
alpar@1
|
2507 |
x[2->3] = 10 (1)
|
alpar@1
|
2508 |
x[3->8] = 10 (0)
|
alpar@1
|
2509 |
x[3->5] = 0 (1)
|
alpar@1
|
2510 |
x[4->5] = 19 (0)
|
alpar@1
|
2511 |
x[5->7] = 4 (1)
|
alpar@1
|
2512 |
x[5->6] = 15 (0)
|
alpar@1
|
2513 |
x[5->2] = 0 (0)
|
alpar@1
|
2514 |
x[6->8] = 8 (1)
|
alpar@1
|
2515 |
x[6->7] = 7 (1)
|
alpar@1
|
2516 |
x[7->9] = 11 (0)
|
alpar@1
|
2517 |
x[8->9] = 18 (0)
|
alpar@1
|
2518 |
\end{verbatim}
|
alpar@1
|
2519 |
\end{footnotesize}
|
alpar@1
|
2520 |
|
alpar@1
|
2521 |
\newpage
|
alpar@1
|
2522 |
|
alpar@1
|
2523 |
\subsection{glp\_rmfgen---Goldfarb's maximum flow problem generator}
|
alpar@1
|
2524 |
|
alpar@1
|
2525 |
\subsubsection*{Synopsis}
|
alpar@1
|
2526 |
|
alpar@1
|
2527 |
\begin{verbatim}
|
alpar@1
|
2528 |
int glp_rmfgen(glp_graph *G, int *s, int *t, int a_cap,
|
alpar@1
|
2529 |
const int parm[1+5]);
|
alpar@1
|
2530 |
\end{verbatim}
|
alpar@1
|
2531 |
|
alpar@1
|
2532 |
\subsubsection*{Description}
|
alpar@1
|
2533 |
|
alpar@1
|
2534 |
The routine \verb|glp_rmfgen| is a GLPK version of the maximum flow
|
alpar@1
|
2535 |
problem generator developed by D.~Goldfarb and
|
alpar@1
|
2536 |
M.~Grigoriadis.\footnote{D.~Goldfarb and M.~D.~Grigoriadis,
|
alpar@1
|
2537 |
``A computational comparison of the Dinic and network simplex methods
|
alpar@1
|
2538 |
for maximum flow.'' Annals of Op. Res. 13 (1988),
|
alpar@1
|
2539 |
pp.~83-123.}$^{,}$\footnote{U.~Derigs and W.~Meier, ``Implementing
|
alpar@1
|
2540 |
Goldberg's max-flow algorithm: A computational investigation.''
|
alpar@1
|
2541 |
Zeitschrift f\"ur Operations Research 33 (1989),
|
alpar@1
|
2542 |
pp.~383-403.}$^{,}$\footnote{The original code of RMFGEN implemented by
|
alpar@1
|
2543 |
Tamas Badics is publically available from
|
alpar@1
|
2544 |
{\tt <ftp://dimacs.rutgers.edu/pub/netflow/generators/network/genrmf>}.}
|
alpar@1
|
2545 |
|
alpar@1
|
2546 |
The parameter \verb|G| specifies the graph object, to which the
|
alpar@1
|
2547 |
generated problem data have to be stored. Note that on entry the graph
|
alpar@1
|
2548 |
object is erased with the routine \verb|glp_erase_graph|.
|
alpar@1
|
2549 |
|
alpar@1
|
2550 |
The pointers \verb|s| and \verb|t| specify locations, to which the
|
alpar@1
|
2551 |
routine stores the source and sink node numbers, respectively. If
|
alpar@1
|
2552 |
\verb|s| or \verb|t| is \verb|NULL|, corresponding node number is not
|
alpar@1
|
2553 |
stored.
|
alpar@1
|
2554 |
|
alpar@1
|
2555 |
The parameter \verb|a_cap| specifies an offset of the field of type
|
alpar@1
|
2556 |
\verb|double| in the arc data block, to which the routine stores the arc
|
alpar@1
|
2557 |
capacity. If \verb|a_cap| $<0$, the capacity is not stored.
|
alpar@1
|
2558 |
|
alpar@1
|
2559 |
The array \verb|parm| contains description of the network to be
|
alpar@1
|
2560 |
generated:
|
alpar@1
|
2561 |
|
alpar@1
|
2562 |
\begin{tabular}{@{}lll@{}}
|
alpar@1
|
2563 |
\verb|parm[0]|& ¬ used\\
|
alpar@1
|
2564 |
\verb|parm[1]|&\verb|seed|&random number seed (a positive integer)\\
|
alpar@1
|
2565 |
\verb|parm[2]|&\verb|a |&frame size\\
|
alpar@1
|
2566 |
\verb|parm[3]|&\verb|b |&depth\\
|
alpar@1
|
2567 |
\verb|parm[4]|&\verb|c1 |&minimal arc capacity\\
|
alpar@1
|
2568 |
\verb|parm[5]|&\verb|c2 |&maximal arc capacity\\
|
alpar@1
|
2569 |
\end{tabular}
|
alpar@1
|
2570 |
|
alpar@1
|
2571 |
\subsubsection*{Returns}
|
alpar@1
|
2572 |
|
alpar@1
|
2573 |
If the instance was successfully generated, the routine
|
alpar@1
|
2574 |
\verb|glp_netgen| returns zero; otherwise, if specified parameters are
|
alpar@1
|
2575 |
inconsistent, the routine returns a non-zero error code.
|
alpar@1
|
2576 |
|
alpar@1
|
2577 |
\newpage
|
alpar@1
|
2578 |
|
alpar@1
|
2579 |
\subsubsection*{Comments\footnote{This material is based on comments
|
alpar@1
|
2580 |
to the original version of RMFGEN.}}
|
alpar@1
|
2581 |
|
alpar@1
|
2582 |
The generated network is as follows. It has $b$ pieces of frames of
|
alpar@1
|
2583 |
size $a\times a$. (So alltogether the number of vertices is
|
alpar@1
|
2584 |
$a\times a\times b$.)
|
alpar@1
|
2585 |
|
alpar@1
|
2586 |
In each frame all the vertices are connected with their neighbours
|
alpar@1
|
2587 |
(forth and back). In addition the vertices of a frame are connected
|
alpar@1
|
2588 |
one to one with the vertices of next frame using a random permutation
|
alpar@1
|
2589 |
of those vertices.
|
alpar@1
|
2590 |
|
alpar@1
|
2591 |
The source is the lower left vertex of the first frame, the sink is
|
alpar@1
|
2592 |
the upper right vertex of the $b$-th frame.
|
alpar@1
|
2593 |
|
alpar@1
|
2594 |
\begin{verbatim}
|
alpar@1
|
2595 |
t
|
alpar@1
|
2596 |
+-------+
|
alpar@1
|
2597 |
| .|
|
alpar@1
|
2598 |
| . |
|
alpar@1
|
2599 |
/ | / |
|
alpar@1
|
2600 |
+-------+/ -+ b
|
alpar@1
|
2601 |
| | |/.
|
alpar@1
|
2602 |
a | -v- |/
|
alpar@1
|
2603 |
| | |/
|
alpar@1
|
2604 |
+-------+ 1
|
alpar@1
|
2605 |
s a
|
alpar@1
|
2606 |
\end{verbatim}
|
alpar@1
|
2607 |
|
alpar@1
|
2608 |
The capacities are randomly chosen integers from the range of
|
alpar@1
|
2609 |
$[c_1,c_2]$ in the case of interconnecting edges, and $c_2\cdot a^2$
|
alpar@1
|
2610 |
for the in-frame edges.
|
alpar@1
|
2611 |
|
alpar@1
|
2612 |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
alpar@1
|
2613 |
|
alpar@1
|
2614 |
\newpage
|
alpar@1
|
2615 |
|
alpar@1
|
2616 |
\section{Assignment problem}
|
alpar@1
|
2617 |
|
alpar@1
|
2618 |
\subsection{Background}
|
alpar@1
|
2619 |
|
alpar@1
|
2620 |
Let there be given an undirected bipartite graph $G=(R\cup S,E)$, where
|
alpar@1
|
2621 |
$R$ and $S$ are disjoint sets of vertices (nodes), and
|
alpar@1
|
2622 |
$E\subseteq R\times S$ is a set of edges. Let also for each edge
|
alpar@1
|
2623 |
$e=(i,j)\in E$ there be given its cost $c_{ij}$. A {\it matching}
|
alpar@1
|
2624 |
(which in case of bipartite graph is also called {\it assignment})
|
alpar@1
|
2625 |
$M\subseteq E$ in $G$ is a set of pairwise non-adjacent edges, that is,
|
alpar@1
|
2626 |
no two edges in $M$ share a common vertex. A matching, which matches
|
alpar@1
|
2627 |
all vertices of the graph, is called a {\it perfect matching}.
|
alpar@1
|
2628 |
Obviously, a perfect matching in bipartite graph $G=(R\cup S,E)$
|
alpar@1
|
2629 |
defines some bijection $R\leftrightarrow S$.
|
alpar@1
|
2630 |
|
alpar@1
|
2631 |
The {\it assignment problem} has two different variants. In the first
|
alpar@1
|
2632 |
variant the problem is to find matching (assignment) $M$, which
|
alpar@1
|
2633 |
maximizes the sum:
|
alpar@1
|
2634 |
$$\sum_{(i,j)\in M}c_{ij}\eqno(10)$$
|
alpar@1
|
2635 |
(so this variant is also called the {\it maximum weighted bipartite
|
alpar@1
|
2636 |
matching problem} or, if all $c_{ij}=1$, the {\it maximum cardinality
|
alpar@1
|
2637 |
bipartite matching problem}). In the second, classic variant the
|
alpar@1
|
2638 |
problem is to find {\it perfect} matching (assignment) $M$, which
|
alpar@1
|
2639 |
minimizes or maximizes the sum (10).
|
alpar@1
|
2640 |
|
alpar@1
|
2641 |
An example of the assignment problem, which is the maximum weighted
|
alpar@1
|
2642 |
bipartite matching problem, is shown on Fig. 3.
|
alpar@1
|
2643 |
|
alpar@1
|
2644 |
The maximum weighted bipartite matching problem can be naturally
|
alpar@1
|
2645 |
formulated as the following LP problem:
|
alpar@1
|
2646 |
|
alpar@1
|
2647 |
\medskip
|
alpar@1
|
2648 |
|
alpar@1
|
2649 |
\noindent
|
alpar@1
|
2650 |
\hspace{.5in}maximize
|
alpar@1
|
2651 |
$$z=\sum_{(i,j)\in E}c_{ij}x_{ij}\eqno(11)$$
|
alpar@1
|
2652 |
\hspace{.5in}subject to
|
alpar@1
|
2653 |
$$\sum_{(i,j)\in E}x_{ij}\leq 1\ \ \ \hbox{for all}\ i\in R\eqno(12)$$
|
alpar@1
|
2654 |
$$\sum_{(i,j)\in E}x_{ij}\leq 1\ \ \ \hbox{for all}\ j\in S\eqno(13)$$
|
alpar@1
|
2655 |
$$\ \ \ \ \ \ \ \ 0\leq x_{ij}\leq 1\ \ \ \hbox{for all}\ (i,j)\in E
|
alpar@1
|
2656 |
\eqno(14)$$
|
alpar@1
|
2657 |
|
alpar@1
|
2658 |
\medskip
|
alpar@1
|
2659 |
|
alpar@1
|
2660 |
\noindent
|
alpar@1
|
2661 |
where $x_{ij}=1$ means that $(i,j)\in M$, and $x_{ij}=0$ means that
|
alpar@1
|
2662 |
$(i,j)\notin M$.\footnote{The constraint matrix of LP formulation
|
alpar@1
|
2663 |
(11)---(14) is totally unimodular, due to which $x_{ij}\in\{0,1\}$ for
|
alpar@1
|
2664 |
any basic solution.}
|
alpar@1
|
2665 |
|
alpar@1
|
2666 |
\newpage
|
alpar@1
|
2667 |
|
alpar@1
|
2668 |
\bigskip
|
alpar@1
|
2669 |
|
alpar@1
|
2670 |
\noindent\hfil
|
alpar@1
|
2671 |
\xymatrix @C=48pt
|
alpar@1
|
2672 |
{v_1\ar@{-}[rr]|{_{13}}\ar@{-}[rrd]|{_{21}}\ar@{-}[rrddd]|(.2){_{20}}&&
|
alpar@1
|
2673 |
v_9\\
|
alpar@1
|
2674 |
v_2\ar@{-}[rr]|{_{12}}\ar@{-}[rrdd]|(.3){_{8}}
|
alpar@1
|
2675 |
\ar@{-}[rrddd]|(.4){_{26}}&&v_{10}\\
|
alpar@1
|
2676 |
v_3\ar@{-}[rr]|(.2){_{22}}\ar@{-}[rrdd]|(.3){_{11}}&&v_{11}\\
|
alpar@1
|
2677 |
v_4\ar@{-}[rruuu]|(.6){_{12}}\ar@{-}[rr]|(.2){_{36}}
|
alpar@1
|
2678 |
\ar@{-}[rrdd]|(.7){_{25}}&&v_{12}\\
|
alpar@1
|
2679 |
v_5\ar@{-}[rruu]|(.42){_{41}}\ar@{-}[rru]|(.4){_{40}}
|
alpar@1
|
2680 |
\ar@{-}[rr]|(.75){_{11}}\ar@{-}[rrd]|(.6){_{4}}\ar@{-}[rrdd]|{_{8}}
|
alpar@1
|
2681 |
\ar@{-}[rrddd]|{_{35}}\ar@{-}[rrdddd]|{_{32}}&&v_{13}\\
|
alpar@1
|
2682 |
v_6\ar@{-}[rruuuuu]|(.7){_{13}}&&v_{14}\\
|
alpar@1
|
2683 |
v_7\ar@{-}[rruuuuu]|(.15){_{19}}&&v_{15}\\
|
alpar@1
|
2684 |
v_8\ar@{-}[rruuuuuu]|(.25){_{39}}\ar@{-}[rruuuuu]|(.65){_{15}}&&
|
alpar@1
|
2685 |
v_{16}\\
|
alpar@1
|
2686 |
&&v_{17}\\
|
alpar@1
|
2687 |
}
|
alpar@1
|
2688 |
|
alpar@1
|
2689 |
\bigskip
|
alpar@1
|
2690 |
|
alpar@1
|
2691 |
\noindent\hfil
|
alpar@1
|
2692 |
Fig.~3. An example of the assignment problem.
|
alpar@1
|
2693 |
|
alpar@1
|
2694 |
\bigskip
|
alpar@1
|
2695 |
|
alpar@1
|
2696 |
Similarly, the perfect assignment problem can be naturally formulated
|
alpar@1
|
2697 |
as the following LP problem:
|
alpar@1
|
2698 |
|
alpar@1
|
2699 |
\medskip
|
alpar@1
|
2700 |
|
alpar@1
|
2701 |
\noindent
|
alpar@1
|
2702 |
\hspace{.5in}minimize (or maximize)
|
alpar@1
|
2703 |
$$z=\sum_{(i,j)\in E}c_{ij}x_{ij}\eqno(15)$$
|
alpar@1
|
2704 |
\hspace{.5in}subject to
|
alpar@1
|
2705 |
$$\sum_{(i,j)\in E}x_{ij}=1\ \ \ \hbox{for all}\ i\in R\eqno(16)$$
|
alpar@1
|
2706 |
$$\sum_{(i,j)\in E}x_{ij}=1\ \ \ \hbox{for all}\ j\in S\eqno(17)$$
|
alpar@1
|
2707 |
$$\ \ \ \ \ \ \ \ 0\leq x_{ij}\leq 1\ \ \ \hbox{for all}\ (i,j)\in E
|
alpar@1
|
2708 |
\eqno(18)$$
|
alpar@1
|
2709 |
|
alpar@1
|
2710 |
\medskip
|
alpar@1
|
2711 |
|
alpar@1
|
2712 |
\noindent
|
alpar@1
|
2713 |
where variables $x_{ij}$ have the same meaning as for (11)---(14)
|
alpar@1
|
2714 |
above.
|
alpar@1
|
2715 |
|
alpar@1
|
2716 |
\newpage
|
alpar@1
|
2717 |
|
alpar@1
|
2718 |
In GLPK an undirected bipartite graph $G=(R\cup S,E)$ is represented as
|
alpar@1
|
2719 |
directed graph $\overline{G}=(V,A)$, where $V=R\cup S$ and
|
alpar@1
|
2720 |
$A=\{(i,j):(i,j)\in E\}$, i.e. every edge $(i,j)\in E$ in $G$
|
alpar@1
|
2721 |
corresponds to arc $(i\rightarrow j)\in A$ in $\overline{G}$.
|
alpar@1
|
2722 |
|
alpar@1
|
2723 |
\subsection{glp\_read\_asnprob---read assignment problem data in\\DIMACS
|
alpar@1
|
2724 |
format}
|
alpar@1
|
2725 |
|
alpar@1
|
2726 |
\subsubsection*{Synopsis}
|
alpar@1
|
2727 |
|
alpar@1
|
2728 |
\begin{verbatim}
|
alpar@1
|
2729 |
int glp_read_asnprob(glp_graph *G, int v_set, int a_cost,
|
alpar@1
|
2730 |
const char *fname);
|
alpar@1
|
2731 |
\end{verbatim}
|
alpar@1
|
2732 |
|
alpar@1
|
2733 |
\subsubsection*{Description}
|
alpar@1
|
2734 |
|
alpar@1
|
2735 |
The routine \verb|glp_read_asnprob| reads the assignment problem data
|
alpar@1
|
2736 |
from a text file in DIMACS format.
|
alpar@1
|
2737 |
|
alpar@1
|
2738 |
The parameter \verb|G| specifies the graph object, to which the problem
|
alpar@1
|
2739 |
data have to be stored. Note that before reading data the current
|
alpar@1
|
2740 |
content of the graph object is completely erased with the routine
|
alpar@1
|
2741 |
\verb|glp_erase_graph|.
|
alpar@1
|
2742 |
|
alpar@1
|
2743 |
The parameter \verb|v_set| specifies an offset of the field of type
|
alpar@1
|
2744 |
\verb|int| in the vertex data block, to which the routine stores the
|
alpar@1
|
2745 |
node set indicator:
|
alpar@1
|
2746 |
|
alpar@1
|
2747 |
0 --- the node is in set $R$;
|
alpar@1
|
2748 |
|
alpar@1
|
2749 |
1 --- the node is in set $S$.
|
alpar@1
|
2750 |
|
alpar@1
|
2751 |
\noindent
|
alpar@1
|
2752 |
If \verb|v_set| $<0$, the node set indicator is not stored.
|
alpar@1
|
2753 |
|
alpar@1
|
2754 |
The parameter \verb|a_cost| specifies an offset of the field of type
|
alpar@1
|
2755 |
\verb|double| in the arc data block, to which the routine stores the
|
alpar@1
|
2756 |
edge cost $c_{ij}$. If \verb|a_cost| $<0$, the edge cost is not stored.
|
alpar@1
|
2757 |
|
alpar@1
|
2758 |
The character string \verb|fname| specifies the name of a text file to
|
alpar@1
|
2759 |
be read in. (If the file name name ends with the suffix `\verb|.gz|',
|
alpar@1
|
2760 |
the file is assumed to be compressed, in which case the routine
|
alpar@1
|
2761 |
decompresses it ``on the fly''.)
|
alpar@1
|
2762 |
|
alpar@1
|
2763 |
\subsubsection*{Returns}
|
alpar@1
|
2764 |
|
alpar@1
|
2765 |
If the operation was successful, the routine returns zero. Otherwise,
|
alpar@1
|
2766 |
it prints an error message and returns non-zero.
|
alpar@1
|
2767 |
|
alpar@1
|
2768 |
\newpage
|
alpar@1
|
2769 |
|
alpar@1
|
2770 |
\subsubsection*{Example}
|
alpar@1
|
2771 |
|
alpar@1
|
2772 |
\begin{footnotesize}
|
alpar@1
|
2773 |
\begin{verbatim}
|
alpar@1
|
2774 |
typedef struct
|
alpar@1
|
2775 |
{ /* vertex data block */
|
alpar@1
|
2776 |
...
|
alpar@1
|
2777 |
int set;
|
alpar@1
|
2778 |
...
|
alpar@1
|
2779 |
} v_data;
|
alpar@1
|
2780 |
|
alpar@1
|
2781 |
typedef struct
|
alpar@1
|
2782 |
{ /* arc data block */
|
alpar@1
|
2783 |
...
|
alpar@1
|
2784 |
double cost;
|
alpar@1
|
2785 |
...
|
alpar@1
|
2786 |
} a_data;
|
alpar@1
|
2787 |
|
alpar@1
|
2788 |
int main(void)
|
alpar@1
|
2789 |
{ glp_graph *G;
|
alpar@1
|
2790 |
int ret;
|
alpar@1
|
2791 |
G = glp_create_graph(sizeof(v_data), sizeof(a_data));
|
alpar@1
|
2792 |
ret = glp_read_asnprob(G, offsetof(v_data, set),
|
alpar@1
|
2793 |
offsetof(a_data, cost), "sample.asn");
|
alpar@1
|
2794 |
if (ret != 0) goto ...
|
alpar@1
|
2795 |
...
|
alpar@1
|
2796 |
}
|
alpar@1
|
2797 |
\end{verbatim}
|
alpar@1
|
2798 |
\end{footnotesize}
|
alpar@1
|
2799 |
|
alpar@1
|
2800 |
\subsubsection*{DIMACS assignment problem format\footnote{This
|
alpar@1
|
2801 |
material is based on the paper ``The First DIMACS International
|
alpar@1
|
2802 |
Algorithm Implementation Challenge: Problem Definitions and
|
alpar@1
|
2803 |
Specifications'', which is publically available at
|
alpar@1
|
2804 |
{\tt http://dimacs.rutgers.edu/Challenges/}.}}
|
alpar@1
|
2805 |
\label{subsecasnprob}
|
alpar@1
|
2806 |
|
alpar@1
|
2807 |
The DIMACS input file is a plain ASCII text file. It contains
|
alpar@1
|
2808 |
{\it lines} of several types described below. A line is terminated with
|
alpar@1
|
2809 |
an end-of-line character. Fields in each line are separated by at least
|
alpar@1
|
2810 |
one blank space. Each line begins with a one-character designator to
|
alpar@1
|
2811 |
identify the line type.
|
alpar@1
|
2812 |
|
alpar@1
|
2813 |
Note that DIMACS requires all numerical quantities to be integers in
|
alpar@1
|
2814 |
the range $[-2^{31},\ 2^{31}-1]$ while GLPK allows the quantities to be
|
alpar@1
|
2815 |
floating-point numbers.
|
alpar@1
|
2816 |
|
alpar@1
|
2817 |
\paragraph{Comment lines.} Comment lines give human-readable information
|
alpar@1
|
2818 |
about the file and are ignored by programs. Comment lines can appear
|
alpar@1
|
2819 |
anywhere in the file. Each comment line begins with a lower-case
|
alpar@1
|
2820 |
character \verb|c|.
|
alpar@1
|
2821 |
|
alpar@1
|
2822 |
\begin{verbatim}
|
alpar@1
|
2823 |
c This is a comment line
|
alpar@1
|
2824 |
\end{verbatim}
|
alpar@1
|
2825 |
|
alpar@1
|
2826 |
\newpage
|
alpar@1
|
2827 |
|
alpar@1
|
2828 |
\paragraph{Problem line.} There is one problem line per data file. The
|
alpar@1
|
2829 |
problem line must appear before any node or arc descriptor lines. It has
|
alpar@1
|
2830 |
the following format:
|
alpar@1
|
2831 |
|
alpar@1
|
2832 |
\begin{verbatim}
|
alpar@1
|
2833 |
p asn NODES EDGES
|
alpar@1
|
2834 |
\end{verbatim}
|
alpar@1
|
2835 |
|
alpar@1
|
2836 |
\noindent
|
alpar@1
|
2837 |
The lower-case character \verb|p| signifies that this is a problem line.
|
alpar@1
|
2838 |
The three-character problem designator \verb|asn| identifies the file as
|
alpar@1
|
2839 |
containing specification information for the assignment problem.
|
alpar@1
|
2840 |
The \verb|NODES| field contains an integer value specifying the total
|
alpar@1
|
2841 |
number of nodes in the graph (i.e. in both sets $R$ and $S$). The
|
alpar@1
|
2842 |
\verb|EDGES| field contains an integer value specifying the number of
|
alpar@1
|
2843 |
edges in the graph.
|
alpar@1
|
2844 |
|
alpar@1
|
2845 |
\paragraph{Node descriptors.} All node descriptor lines must appear
|
alpar@1
|
2846 |
before all edge descriptor lines. The node descriptor lines lists the
|
alpar@1
|
2847 |
nodes in set $R$ only, and all other nodes are assumed to be in set
|
alpar@1
|
2848 |
$S$. There is one node descriptor line for each such node, with the
|
alpar@1
|
2849 |
following format:
|
alpar@1
|
2850 |
|
alpar@1
|
2851 |
\begin{verbatim}
|
alpar@1
|
2852 |
n ID
|
alpar@1
|
2853 |
\end{verbatim}
|
alpar@1
|
2854 |
|
alpar@1
|
2855 |
\noindent
|
alpar@1
|
2856 |
The lower-case character \verb|n| signifies that this is a node
|
alpar@1
|
2857 |
descriptor line. The \verb|ID| field gives a node identification number,
|
alpar@1
|
2858 |
an integer between 1 and \verb|NODES|.
|
alpar@1
|
2859 |
|
alpar@1
|
2860 |
\paragraph{Edge descriptors.} There is one edge descriptor line for
|
alpar@1
|
2861 |
each edge in the graph. Edge descriptor lines are of the following
|
alpar@1
|
2862 |
format:
|
alpar@1
|
2863 |
|
alpar@1
|
2864 |
\begin{verbatim}
|
alpar@1
|
2865 |
a SRC DST COST
|
alpar@1
|
2866 |
\end{verbatim}
|
alpar@1
|
2867 |
|
alpar@1
|
2868 |
\noindent
|
alpar@1
|
2869 |
The lower-case character \verb|a| signifies that this is an edge
|
alpar@1
|
2870 |
descriptor line. For each edge $(i,j)$, where $i\in R$ and $j\in S$,
|
alpar@1
|
2871 |
the \verb|SRC| field gives the identification number of vertex $i$, and
|
alpar@1
|
2872 |
the \verb|DST| field gives the identification number of vertex $j$.
|
alpar@1
|
2873 |
Identification numbers are integers between 1 and \verb|NODES|. The
|
alpar@1
|
2874 |
\verb|COST| field contains the cost of edge $(i,j)$.
|
alpar@1
|
2875 |
|
alpar@1
|
2876 |
\paragraph{Example.} Below here is an example of the data file in
|
alpar@1
|
2877 |
DIMACS format corresponding to the assignment problem shown on Fig~3.
|
alpar@1
|
2878 |
|
alpar@1
|
2879 |
\newpage
|
alpar@1
|
2880 |
|
alpar@1
|
2881 |
\begin{footnotesize}
|
alpar@1
|
2882 |
\begin{verbatim}
|
alpar@1
|
2883 |
c sample.asn
|
alpar@1
|
2884 |
c
|
alpar@1
|
2885 |
c This is an example of the assignment problem data
|
alpar@1
|
2886 |
c in DIMACS format.
|
alpar@1
|
2887 |
c
|
alpar@1
|
2888 |
p asn 17 22
|
alpar@1
|
2889 |
c
|
alpar@1
|
2890 |
n 1
|
alpar@1
|
2891 |
n 2
|
alpar@1
|
2892 |
n 3
|
alpar@1
|
2893 |
n 4
|
alpar@1
|
2894 |
n 5
|
alpar@1
|
2895 |
n 6
|
alpar@1
|
2896 |
n 7
|
alpar@1
|
2897 |
n 8
|
alpar@1
|
2898 |
c
|
alpar@1
|
2899 |
a 1 9 13
|
alpar@1
|
2900 |
a 1 10 21
|
alpar@1
|
2901 |
a 1 12 20
|
alpar@1
|
2902 |
a 2 10 12
|
alpar@1
|
2903 |
a 2 12 8
|
alpar@1
|
2904 |
a 2 13 26
|
alpar@1
|
2905 |
a 3 11 22
|
alpar@1
|
2906 |
a 3 13 11
|
alpar@1
|
2907 |
a 4 9 12
|
alpar@1
|
2908 |
a 4 12 36
|
alpar@1
|
2909 |
a 4 14 25
|
alpar@1
|
2910 |
a 5 11 41
|
alpar@1
|
2911 |
a 5 12 40
|
alpar@1
|
2912 |
a 5 13 11
|
alpar@1
|
2913 |
a 5 14 4
|
alpar@1
|
2914 |
a 5 15 8
|
alpar@1
|
2915 |
a 5 16 35
|
alpar@1
|
2916 |
a 5 17 32
|
alpar@1
|
2917 |
a 6 9 13
|
alpar@1
|
2918 |
a 7 10 19
|
alpar@1
|
2919 |
a 8 10 39
|
alpar@1
|
2920 |
a 8 11 15
|
alpar@1
|
2921 |
c
|
alpar@1
|
2922 |
c eof
|
alpar@1
|
2923 |
\end{verbatim}
|
alpar@1
|
2924 |
\end{footnotesize}
|
alpar@1
|
2925 |
|
alpar@1
|
2926 |
\newpage
|
alpar@1
|
2927 |
|
alpar@1
|
2928 |
\subsection{glp\_write\_asnprob---write assignment problem data in\\
|
alpar@1
|
2929 |
DIMACS format}
|
alpar@1
|
2930 |
|
alpar@1
|
2931 |
\subsubsection*{Synopsis}
|
alpar@1
|
2932 |
|
alpar@1
|
2933 |
\begin{verbatim}
|
alpar@1
|
2934 |
int glp_write_asnprob(glp_graph *G, int v_set, int a_cost,
|
alpar@1
|
2935 |
const char *fname);
|
alpar@1
|
2936 |
\end{verbatim}
|
alpar@1
|
2937 |
|
alpar@1
|
2938 |
\subsubsection*{Description}
|
alpar@1
|
2939 |
|
alpar@1
|
2940 |
The routine \verb|glp_write_asnprob| writes the assignment problem data
|
alpar@1
|
2941 |
to a text file in DIMACS format.
|
alpar@1
|
2942 |
|
alpar@1
|
2943 |
The parameter \verb|G| is the graph program object, which specifies the
|
alpar@1
|
2944 |
assignment problem instance.
|
alpar@1
|
2945 |
|
alpar@1
|
2946 |
The parameter \verb|v_set| specifies an offset of the field of type
|
alpar@1
|
2947 |
\verb|int| in the vertex data block, which contains the node set
|
alpar@1
|
2948 |
indicator:
|
alpar@1
|
2949 |
|
alpar@1
|
2950 |
0 --- the node is in set $R$;
|
alpar@1
|
2951 |
|
alpar@1
|
2952 |
1 --- the node is in set $S$.
|
alpar@1
|
2953 |
|
alpar@1
|
2954 |
\noindent
|
alpar@1
|
2955 |
If \verb|v_set| $<0$, it is assumed that a node having no incoming arcs
|
alpar@1
|
2956 |
is in set $R$, and a node having no outgoing arcs is in set $S$.
|
alpar@1
|
2957 |
|
alpar@1
|
2958 |
The parameter \verb|a_cost| specifies an offset of the field of type
|
alpar@1
|
2959 |
\verb|double| in the arc data block, which contains $c_{ij}$, the edge
|
alpar@1
|
2960 |
cost. If \verb|a_cost| $<0$, it is assumed that $c_{ij}=1$ for all
|
alpar@1
|
2961 |
edges.
|
alpar@1
|
2962 |
|
alpar@1
|
2963 |
The character string \verb|fname| specifies a name of the text file to
|
alpar@1
|
2964 |
be written out. (If the file name ends with suffix `\verb|.gz|', the
|
alpar@1
|
2965 |
file is assumed to be compressed, in which case the routine performs
|
alpar@1
|
2966 |
automatic compression on writing it.)
|
alpar@1
|
2967 |
|
alpar@1
|
2968 |
\subsubsection*{Note}
|
alpar@1
|
2969 |
|
alpar@1
|
2970 |
The routine \verb|glp_write_asnprob| does not check that the specified
|
alpar@1
|
2971 |
graph object correctly represents a bipartite graph. To make sure that
|
alpar@1
|
2972 |
the problem data are correct, use the routine \verb|glp_check_asnprob|.
|
alpar@1
|
2973 |
|
alpar@1
|
2974 |
\subsubsection*{Returns}
|
alpar@1
|
2975 |
|
alpar@1
|
2976 |
If the operation was successful, the routine returns zero. Otherwise,
|
alpar@1
|
2977 |
it prints an error message and returns non-zero.
|
alpar@1
|
2978 |
|
alpar@1
|
2979 |
\newpage
|
alpar@1
|
2980 |
|
alpar@1
|
2981 |
\subsection{glp\_check\_asnprob---check correctness of assignment
|
alpar@1
|
2982 |
problem data}
|
alpar@1
|
2983 |
|
alpar@1
|
2984 |
\subsubsection*{Synopsis}
|
alpar@1
|
2985 |
|
alpar@1
|
2986 |
\begin{verbatim}
|
alpar@1
|
2987 |
int glp_check_asnprob(glp_graph *G, int v_set);
|
alpar@1
|
2988 |
\end{verbatim}
|
alpar@1
|
2989 |
|
alpar@1
|
2990 |
\subsubsection*{Description}
|
alpar@1
|
2991 |
|
alpar@1
|
2992 |
The routine \verb|glp_check_asnprob| checks that the specified graph
|
alpar@1
|
2993 |
object \verb|G| correctly represents a bipartite graph.
|
alpar@1
|
2994 |
|
alpar@1
|
2995 |
The parameter \verb|v_set| specifies an offset of the field of type
|
alpar@1
|
2996 |
\verb|int| in the vertex data block, which contains the node set
|
alpar@1
|
2997 |
indicator:
|
alpar@1
|
2998 |
|
alpar@1
|
2999 |
0 --- the node is in set $R$;
|
alpar@1
|
3000 |
|
alpar@1
|
3001 |
1 --- the node is in set $S$.
|
alpar@1
|
3002 |
|
alpar@1
|
3003 |
\noindent
|
alpar@1
|
3004 |
If \verb|v_set| $<0$, it is assumed that a node having no incoming arcs
|
alpar@1
|
3005 |
is in set $R$, and a node having no outgoing arcs is in set $S$.
|
alpar@1
|
3006 |
|
alpar@1
|
3007 |
\subsubsection*{Returns}
|
alpar@1
|
3008 |
|
alpar@1
|
3009 |
The routine \verb|glp_check_asnprob| may return the following codes:
|
alpar@1
|
3010 |
|
alpar@1
|
3011 |
0 --- the data are correct;
|
alpar@1
|
3012 |
|
alpar@1
|
3013 |
1 --- the set indicator of some node is 0, however, that node has one
|
alpar@1
|
3014 |
or more incoming arcs;
|
alpar@1
|
3015 |
|
alpar@1
|
3016 |
2 --- the set indicator of some node is 1, however, that node has one
|
alpar@1
|
3017 |
or more outgoing arcs;
|
alpar@1
|
3018 |
|
alpar@1
|
3019 |
3 --- the set indicator of some node is invalid (neither 0 nor 1);
|
alpar@1
|
3020 |
|
alpar@1
|
3021 |
4 --- some node has both incoming and outgoing arcs.
|
alpar@1
|
3022 |
|
alpar@1
|
3023 |
\subsection{glp\_asnprob\_lp---convert assignment problem to LP}
|
alpar@1
|
3024 |
|
alpar@1
|
3025 |
\subsubsection*{Synopsis}
|
alpar@1
|
3026 |
|
alpar@1
|
3027 |
\begin{verbatim}
|
alpar@1
|
3028 |
int glp_asnprob_lp(glp_prob *P, int form, glp_graph *G,
|
alpar@1
|
3029 |
int names, int v_set, int a_cost);
|
alpar@1
|
3030 |
\end{verbatim}
|
alpar@1
|
3031 |
|
alpar@1
|
3032 |
\subsubsection*{Description}
|
alpar@1
|
3033 |
|
alpar@1
|
3034 |
The routine \verb|glp_asnprob_lp| builds LP problem, which corresponds
|
alpar@1
|
3035 |
to the specified assignment problem.
|
alpar@1
|
3036 |
|
alpar@1
|
3037 |
The parameter \verb|lp| is the resultant LP problem object to be built.
|
alpar@1
|
3038 |
Note that on entry its current content is erased with the routine
|
alpar@1
|
3039 |
\verb|glp_erase_prob|.
|
alpar@1
|
3040 |
|
alpar@1
|
3041 |
The parameter \verb|form| defines which LP formulation should be used:
|
alpar@1
|
3042 |
|
alpar@1
|
3043 |
\verb|GLP_ASN_MIN| --- perfect matching (15)---(18), minimization;
|
alpar@1
|
3044 |
|
alpar@1
|
3045 |
\verb|GLP_ASN_MAX| --- perfect matching (15)---(18), maximization;
|
alpar@1
|
3046 |
|
alpar@1
|
3047 |
\verb|GLP_ASN_MMP| --- maximum weighted matching (11)---(14).
|
alpar@1
|
3048 |
|
alpar@1
|
3049 |
The parameter \verb|G| is the graph program object, which specifies the
|
alpar@1
|
3050 |
assignment problem instance.
|
alpar@1
|
3051 |
|
alpar@1
|
3052 |
The parameter \verb|names| is a flag. If it is \verb|GLP_ON|, the
|
alpar@1
|
3053 |
routine uses symbolic names of the graph object components to assign
|
alpar@1
|
3054 |
symbolic names to the LP problem object components. If the \verb|flag|
|
alpar@1
|
3055 |
is \verb|GLP_OFF|, no symbolic names are assigned.
|
alpar@1
|
3056 |
|
alpar@1
|
3057 |
The parameter \verb|v_set| specifies an offset of the field of type
|
alpar@1
|
3058 |
\verb|int| in the vertex data block, which contains the node set
|
alpar@1
|
3059 |
indicator:
|
alpar@1
|
3060 |
|
alpar@1
|
3061 |
0 --- the node is in set $R$;
|
alpar@1
|
3062 |
|
alpar@1
|
3063 |
1 --- the node is in set $S$.
|
alpar@1
|
3064 |
|
alpar@1
|
3065 |
\noindent
|
alpar@1
|
3066 |
If \verb|v_set| $<0$, it is assumed that a node having no incoming arcs
|
alpar@1
|
3067 |
is in set $R$, and a node having no outgoing arcs is in set $S$.
|
alpar@1
|
3068 |
|
alpar@1
|
3069 |
The parameter \verb|a_cost| specifies an offset of the field of type
|
alpar@1
|
3070 |
\verb|double| in the arc data block, which contains $c_{ij}$, the edge
|
alpar@1
|
3071 |
cost. If \verb|a_cost| $<0$, it is assumed that $c_{ij}=1$ for all
|
alpar@1
|
3072 |
edges.
|
alpar@1
|
3073 |
|
alpar@1
|
3074 |
\subsubsection*{Returns}
|
alpar@1
|
3075 |
|
alpar@1
|
3076 |
If the LP problem has been successfully built, the routine
|
alpar@1
|
3077 |
\verb|glp_asnprob_lp| returns zero, otherwise, non-zero (see the
|
alpar@1
|
3078 |
routine \verb|glp_check_asnprob|).
|
alpar@1
|
3079 |
|
alpar@1
|
3080 |
\subsubsection*{Example}
|
alpar@1
|
3081 |
|
alpar@1
|
3082 |
The example program below reads the assignment problem instance in
|
alpar@1
|
3083 |
DIMACS format from file `\verb|sample.asn|', converts the instance to
|
alpar@1
|
3084 |
LP (11)---(14), and writes the resultant LP in CPLEX format to file
|
alpar@1
|
3085 |
`\verb|matching.lp|'.
|
alpar@1
|
3086 |
|
alpar@1
|
3087 |
\begin{footnotesize}
|
alpar@1
|
3088 |
\begin{verbatim}
|
alpar@1
|
3089 |
#include <stddef.h>
|
alpar@1
|
3090 |
#include <glpk.h>
|
alpar@1
|
3091 |
|
alpar@1
|
3092 |
typedef struct { int set; } v_data;
|
alpar@1
|
3093 |
typedef struct { double cost; } a_data;
|
alpar@1
|
3094 |
|
alpar@1
|
3095 |
int main(void)
|
alpar@1
|
3096 |
{ glp_graph *G;
|
alpar@1
|
3097 |
glp_prob *P;
|
alpar@1
|
3098 |
G = glp_create_graph(sizeof(v_data), sizeof(a_data));
|
alpar@1
|
3099 |
glp_read_asnprob(G, offsetof(v_data, set),
|
alpar@1
|
3100 |
offsetof(a_data, cost), "sample.asn");
|
alpar@1
|
3101 |
P = glp_create_prob();
|
alpar@1
|
3102 |
glp_asnprob_lp(P, GLP_ASN_MMP, G, GLP_ON,
|
alpar@1
|
3103 |
offsetof(v_data, set), offsetof(a_data, cost));
|
alpar@1
|
3104 |
glp_delete_graph(G);
|
alpar@1
|
3105 |
glp_write_lp(P, NULL, "matching.lp");
|
alpar@1
|
3106 |
glp_delete_prob(P);
|
alpar@1
|
3107 |
return 0;
|
alpar@1
|
3108 |
}
|
alpar@1
|
3109 |
\end{verbatim}
|
alpar@1
|
3110 |
\end{footnotesize}
|
alpar@1
|
3111 |
|
alpar@1
|
3112 |
If `\verb|sample.asn|' is the example data file from the subsection
|
alpar@1
|
3113 |
describing the routine \verb|glp_read_asnprob|, file
|
alpar@1
|
3114 |
`\verb|matching.lp|' may look like follows:
|
alpar@1
|
3115 |
|
alpar@1
|
3116 |
\begin{footnotesize}
|
alpar@1
|
3117 |
\begin{verbatim}
|
alpar@1
|
3118 |
Maximize
|
alpar@1
|
3119 |
obj: + 20 x(1,12) + 21 x(1,10) + 13 x(1,9) + 26 x(2,13) + 8 x(2,12)
|
alpar@1
|
3120 |
+ 12 x(2,10) + 11 x(3,13) + 22 x(3,11) + 25 x(4,14) + 36 x(4,12)
|
alpar@1
|
3121 |
+ 12 x(4,9) + 32 x(5,17) + 35 x(5,16) + 8 x(5,15) + 4 x(5,14)
|
alpar@1
|
3122 |
+ 11 x(5,13) + 40 x(5,12) + 41 x(5,11) + 13 x(6,9) + 19 x(7,10)
|
alpar@1
|
3123 |
+ 15 x(8,11) + 39 x(8,10)
|
alpar@1
|
3124 |
|
alpar@1
|
3125 |
Subject To
|
alpar@1
|
3126 |
r_1: + x(1,9) + x(1,10) + x(1,12) <= 1
|
alpar@1
|
3127 |
r_2: + x(2,10) + x(2,12) + x(2,13) <= 1
|
alpar@1
|
3128 |
r_3: + x(3,11) + x(3,13) <= 1
|
alpar@1
|
3129 |
r_4: + x(4,9) + x(4,12) + x(4,14) <= 1
|
alpar@1
|
3130 |
r_5: + x(5,11) + x(5,12) + x(5,13) + x(5,14) + x(5,15) + x(5,16)
|
alpar@1
|
3131 |
+ x(5,17) <= 1
|
alpar@1
|
3132 |
r_6: + x(6,9) <= 1
|
alpar@1
|
3133 |
r_7: + x(7,10) <= 1
|
alpar@1
|
3134 |
r_8: + x(8,10) + x(8,11) <= 1
|
alpar@1
|
3135 |
r_9: + x(6,9) + x(4,9) + x(1,9) <= 1
|
alpar@1
|
3136 |
r_10: + x(8,10) + x(7,10) + x(2,10) + x(1,10) <= 1
|
alpar@1
|
3137 |
r_11: + x(8,11) + x(5,11) + x(3,11) <= 1
|
alpar@1
|
3138 |
r_12: + x(5,12) + x(4,12) + x(2,12) + x(1,12) <= 1
|
alpar@1
|
3139 |
r_13: + x(5,13) + x(3,13) + x(2,13) <= 1
|
alpar@1
|
3140 |
r_14: + x(5,14) + x(4,14) <= 1
|
alpar@1
|
3141 |
r_15: + x(5,15) <= 1
|
alpar@1
|
3142 |
r_16: + x(5,16) <= 1
|
alpar@1
|
3143 |
r_17: + x(5,17) <= 1
|
alpar@1
|
3144 |
|
alpar@1
|
3145 |
Bounds
|
alpar@1
|
3146 |
0 <= x(1,12) <= 1
|
alpar@1
|
3147 |
0 <= x(1,10) <= 1
|
alpar@1
|
3148 |
0 <= x(1,9) <= 1
|
alpar@1
|
3149 |
0 <= x(2,13) <= 1
|
alpar@1
|
3150 |
0 <= x(2,12) <= 1
|
alpar@1
|
3151 |
0 <= x(2,10) <= 1
|
alpar@1
|
3152 |
0 <= x(3,13) <= 1
|
alpar@1
|
3153 |
0 <= x(3,11) <= 1
|
alpar@1
|
3154 |
0 <= x(4,14) <= 1
|
alpar@1
|
3155 |
0 <= x(4,12) <= 1
|
alpar@1
|
3156 |
0 <= x(4,9) <= 1
|
alpar@1
|
3157 |
0 <= x(5,17) <= 1
|
alpar@1
|
3158 |
0 <= x(5,16) <= 1
|
alpar@1
|
3159 |
0 <= x(5,15) <= 1
|
alpar@1
|
3160 |
0 <= x(5,14) <= 1
|
alpar@1
|
3161 |
0 <= x(5,13) <= 1
|
alpar@1
|
3162 |
0 <= x(5,12) <= 1
|
alpar@1
|
3163 |
0 <= x(5,11) <= 1
|
alpar@1
|
3164 |
0 <= x(6,9) <= 1
|
alpar@1
|
3165 |
0 <= x(7,10) <= 1
|
alpar@1
|
3166 |
0 <= x(8,11) <= 1
|
alpar@1
|
3167 |
0 <= x(8,10) <= 1
|
alpar@1
|
3168 |
|
alpar@1
|
3169 |
End
|
alpar@1
|
3170 |
\end{verbatim}
|
alpar@1
|
3171 |
\end{footnotesize}
|
alpar@1
|
3172 |
|
alpar@1
|
3173 |
\subsection{glp\_asnprob\_okalg---solve assignment problem with
|
alpar@1
|
3174 |
out-of-kilter algorithm}
|
alpar@1
|
3175 |
|
alpar@1
|
3176 |
\subsubsection*{Synopsis}
|
alpar@1
|
3177 |
|
alpar@1
|
3178 |
\begin{verbatim}
|
alpar@1
|
3179 |
int glp_asnprob_okalg(int form, glp_graph *G, int v_set,
|
alpar@1
|
3180 |
int a_cost, double *sol, int a_x);
|
alpar@1
|
3181 |
\end{verbatim}
|
alpar@1
|
3182 |
|
alpar@1
|
3183 |
\subsubsection*{Description}
|
alpar@1
|
3184 |
|
alpar@1
|
3185 |
The routine \verb|glp_mincost_okalg| finds optimal solution to the
|
alpar@1
|
3186 |
assignment problem with the out-of-kilter
|
alpar@1
|
3187 |
algorithm.\footnote{GLPK implementation of the out-of-kilter algorithm
|
alpar@1
|
3188 |
is based on the following book: L.~R.~Ford,~Jr., and D.~R.~Fulkerson,
|
alpar@1
|
3189 |
``Flows in Networks,'' The RAND Corp., Report R-375-PR (August 1962),
|
alpar@1
|
3190 |
Chap. III ``Minimal Cost Flow Problems,'' pp.~113-26.} Note that this
|
alpar@1
|
3191 |
routine requires all the problem data to be integer-valued.
|
alpar@1
|
3192 |
|
alpar@1
|
3193 |
The parameter \verb|form| defines which LP formulation should be used:
|
alpar@1
|
3194 |
|
alpar@1
|
3195 |
\verb|GLP_ASN_MIN| --- perfect matching (15)---(18), minimization;
|
alpar@1
|
3196 |
|
alpar@1
|
3197 |
\verb|GLP_ASN_MAX| --- perfect matching (15)---(18), maximization;
|
alpar@1
|
3198 |
|
alpar@1
|
3199 |
\verb|GLP_ASN_MMP| --- maximum weighted matching (11)---(14).
|
alpar@1
|
3200 |
|
alpar@1
|
3201 |
The parameter \verb|G| is the graph program object, which specifies the
|
alpar@1
|
3202 |
assignment problem instance.
|
alpar@1
|
3203 |
|
alpar@1
|
3204 |
The parameter \verb|v_set| specifies an offset of the field of type
|
alpar@1
|
3205 |
\verb|int| in the vertex data block, which contains the node set
|
alpar@1
|
3206 |
indicator:
|
alpar@1
|
3207 |
|
alpar@1
|
3208 |
0 --- the node is in set $R$;
|
alpar@1
|
3209 |
|
alpar@1
|
3210 |
1 --- the node is in set $S$.
|
alpar@1
|
3211 |
|
alpar@1
|
3212 |
\newpage
|
alpar@1
|
3213 |
|
alpar@1
|
3214 |
\noindent
|
alpar@1
|
3215 |
If \verb|v_set| $<0$, it is assumed that a node having no incoming arcs
|
alpar@1
|
3216 |
is in set $R$, and a node having no outgoing arcs is in set $S$.
|
alpar@1
|
3217 |
|
alpar@1
|
3218 |
The parameter \verb|a_cost| specifies an offset of the field of type
|
alpar@1
|
3219 |
\verb|double| in the arc data block, which contains $c_{ij}$, the edge
|
alpar@1
|
3220 |
cost. This value must be integer in the range [\verb|-INT_MAX|,
|
alpar@1
|
3221 |
\verb|+INT_MAX|]. If \verb|a_cost| $<0$, it is assumed that $c_{ij}=1$
|
alpar@1
|
3222 |
for all edges.
|
alpar@1
|
3223 |
|
alpar@1
|
3224 |
The parameter \verb|sol| specifies a location, to which the routine
|
alpar@1
|
3225 |
stores the objective value (that is, the total cost) found.
|
alpar@1
|
3226 |
If \verb|sol| is \verb|NULL|, the objective value is not stored.
|
alpar@1
|
3227 |
|
alpar@1
|
3228 |
The parameter \verb|a_x| specifies an offset of the field of type
|
alpar@1
|
3229 |
\verb|int| in the arc data block, to which the routine stores $x_{ij}$.
|
alpar@1
|
3230 |
If \verb|a_x| $<0$, this value is not stored.
|
alpar@1
|
3231 |
|
alpar@1
|
3232 |
\subsubsection*{Returns}
|
alpar@1
|
3233 |
|
alpar@1
|
3234 |
\def\arraystretch{1}
|
alpar@1
|
3235 |
|
alpar@1
|
3236 |
\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
|
alpar@1
|
3237 |
0 & Optimal solution found.\\
|
alpar@1
|
3238 |
\verb|GLP_ENOPFS| & No (primal) feasible solution exists.\\
|
alpar@1
|
3239 |
\verb|GLP_EDATA| & Unable to start the search, because the assignment
|
alpar@1
|
3240 |
problem data are either incorrect (this error is detected by the
|
alpar@1
|
3241 |
routine \verb|glp_check_asnprob|), not integer-valued or out of range.\\
|
alpar@1
|
3242 |
\verb|GLP_ERANGE| & The search was prematurely terminated because of
|
alpar@1
|
3243 |
integer overflow.\\
|
alpar@1
|
3244 |
\verb|GLP_EFAIL| & An error has been detected in the program logic.
|
alpar@1
|
3245 |
(If this code is returned for your problem instance, please report to
|
alpar@1
|
3246 |
\verb|<bug-glpk@gnu.org>|.)\\
|
alpar@1
|
3247 |
\end{tabular}
|
alpar@1
|
3248 |
|
alpar@1
|
3249 |
\subsubsection*{Comments}
|
alpar@1
|
3250 |
|
alpar@1
|
3251 |
Since the out-of-kilter algorithm is designed to find a minimal cost
|
alpar@1
|
3252 |
circulation, the routine \verb|glp_asnprob_okalg| converts the original
|
alpar@1
|
3253 |
graph to a network suitable for this algorithm in the following
|
alpar@1
|
3254 |
way:\footnote{The conversion is performed internally and does not change
|
alpar@1
|
3255 |
the original graph program object passed to the routine.}
|
alpar@1
|
3256 |
|
alpar@1
|
3257 |
1) it replaces each edge $(i,j)$ by arc $(i\rightarrow j)$,
|
alpar@1
|
3258 |
flow $x_{ij}$ through which has zero lower bound ($l_{ij}=0$), unity
|
alpar@1
|
3259 |
upper bound ($u_{ij}=1$), and per-unit cost $+c_{ij}$ (in case of
|
alpar@1
|
3260 |
\verb|GLP_ASN_MIN|), or $-c_{ij}$ (in case of \verb|GLP_ASN_MAX| and
|
alpar@1
|
3261 |
\verb|GLP_ASN_MMP|);
|
alpar@1
|
3262 |
|
alpar@1
|
3263 |
2) then it adds one auxiliary feedback node $k$;
|
alpar@1
|
3264 |
|
alpar@1
|
3265 |
\newpage
|
alpar@1
|
3266 |
|
alpar@1
|
3267 |
3) for each original node $i\in R$ the routine adds auxiliary supply
|
alpar@1
|
3268 |
arc $(k\rightarrow i)$, flow $x_{ki}$ through which is costless
|
alpar@1
|
3269 |
($c_{ki}=0$) and either fixed at 1 ($l_{ki}=u_{ki}=1$, in case of
|
alpar@1
|
3270 |
\verb|GLP_ASN_MIN| and \verb|GLP_ASN_MAX|) or has zero lower bound and
|
alpar@1
|
3271 |
unity upper bound ($l_{ij}=0$, $u_{ij}=1$, in case of
|
alpar@1
|
3272 |
\verb|GLP_ASN_MMP|);
|
alpar@1
|
3273 |
|
alpar@1
|
3274 |
4) similarly, for each original node $j\in S$ the routine adds
|
alpar@1
|
3275 |
auxiliary demand arc $(j\rightarrow k)$, flow $x_{jk}$ through which is
|
alpar@1
|
3276 |
costless ($c_{jk}=0$) and either fixed at 1 ($l_{jk}=u_{jk}=1$, in case
|
alpar@1
|
3277 |
of \verb|GLP_ASN_MIN| and \verb|GLP_ASN_MAX|) or has zero lower bound
|
alpar@1
|
3278 |
and unity upper bound ($l_{jk}=0$, $u_{jk}=1$, in case of
|
alpar@1
|
3279 |
\verb|GLP_ASN_MMP|).
|
alpar@1
|
3280 |
|
alpar@1
|
3281 |
\subsubsection*{Example}
|
alpar@1
|
3282 |
|
alpar@1
|
3283 |
The example program shown below reads the assignment problem instance
|
alpar@1
|
3284 |
in DIMACS format from file `\verb|sample.asn|', solves it by using the
|
alpar@1
|
3285 |
routine \verb|glp_asnprob_okalg|, and writes the solution found to the
|
alpar@1
|
3286 |
standard output.
|
alpar@1
|
3287 |
|
alpar@1
|
3288 |
\begin{footnotesize}
|
alpar@1
|
3289 |
\begin{verbatim}
|
alpar@1
|
3290 |
#include <stddef.h>
|
alpar@1
|
3291 |
#include <stdio.h>
|
alpar@1
|
3292 |
#include <stdlib.h>
|
alpar@1
|
3293 |
#include <glpk.h>
|
alpar@1
|
3294 |
|
alpar@1
|
3295 |
typedef struct { int set; } v_data;
|
alpar@1
|
3296 |
typedef struct { double cost; int x; } e_data;
|
alpar@1
|
3297 |
|
alpar@1
|
3298 |
#define node(v) ((v_data *)((v)->data))
|
alpar@1
|
3299 |
#define edge(e) ((e_data *)((e)->data))
|
alpar@1
|
3300 |
|
alpar@1
|
3301 |
int main(void)
|
alpar@1
|
3302 |
{ glp_graph *G;
|
alpar@1
|
3303 |
glp_vertex *v;
|
alpar@1
|
3304 |
glp_arc *e;
|
alpar@1
|
3305 |
int i, ret;
|
alpar@1
|
3306 |
double sol;
|
alpar@1
|
3307 |
G = glp_create_graph(sizeof(v_data), sizeof(e_data));
|
alpar@1
|
3308 |
glp_read_asnprob(G, offsetof(v_data, set),
|
alpar@1
|
3309 |
offsetof(e_data, cost), "sample.asn");
|
alpar@1
|
3310 |
ret = glp_asnprob_okalg(GLP_ASN_MMP, G,
|
alpar@1
|
3311 |
offsetof(v_data, set), offsetof(e_data, cost), &sol,
|
alpar@1
|
3312 |
offsetof(e_data, x));
|
alpar@1
|
3313 |
printf("ret = %d; sol = %5g\n", ret, sol);
|
alpar@1
|
3314 |
for (i = 1; i <= G->nv; i++)
|
alpar@1
|
3315 |
{ v = G->v[i];
|
alpar@1
|
3316 |
for (e = v->out; e != NULL; e = e->t_next)
|
alpar@1
|
3317 |
printf("edge %2d %2d: x = %d; c = %g\n",
|
alpar@1
|
3318 |
e->tail->i, e->head->i, edge(e)->x, edge(e)->cost);
|
alpar@1
|
3319 |
}
|
alpar@1
|
3320 |
glp_delete_graph(G);
|
alpar@1
|
3321 |
return 0;
|
alpar@1
|
3322 |
}
|
alpar@1
|
3323 |
\end{verbatim}
|
alpar@1
|
3324 |
\end{footnotesize}
|
alpar@1
|
3325 |
|
alpar@1
|
3326 |
If `\verb|sample.asn|' is the example data file from the subsection
|
alpar@1
|
3327 |
describing the routine \verb|glp_read_asnprob|, the output may look
|
alpar@1
|
3328 |
like follows:
|
alpar@1
|
3329 |
|
alpar@1
|
3330 |
\begin{footnotesize}
|
alpar@1
|
3331 |
\begin{verbatim}
|
alpar@1
|
3332 |
Reading assignment problem data from `sample.asn'...
|
alpar@1
|
3333 |
Assignment problem has 8 + 9 = 17 nodes and 22 arcs
|
alpar@1
|
3334 |
38 lines were read
|
alpar@1
|
3335 |
ret = 0; sol = 180
|
alpar@1
|
3336 |
edge 1 12: x = 1; c = 20
|
alpar@1
|
3337 |
edge 1 10: x = 0; c = 21
|
alpar@1
|
3338 |
edge 1 9: x = 0; c = 13
|
alpar@1
|
3339 |
edge 2 13: x = 1; c = 26
|
alpar@1
|
3340 |
edge 2 12: x = 0; c = 8
|
alpar@1
|
3341 |
edge 2 10: x = 0; c = 12
|
alpar@1
|
3342 |
edge 3 13: x = 0; c = 11
|
alpar@1
|
3343 |
edge 3 11: x = 1; c = 22
|
alpar@1
|
3344 |
edge 4 14: x = 1; c = 25
|
alpar@1
|
3345 |
edge 4 12: x = 0; c = 36
|
alpar@1
|
3346 |
edge 4 9: x = 0; c = 12
|
alpar@1
|
3347 |
edge 5 17: x = 0; c = 32
|
alpar@1
|
3348 |
edge 5 16: x = 1; c = 35
|
alpar@1
|
3349 |
edge 5 15: x = 0; c = 8
|
alpar@1
|
3350 |
edge 5 14: x = 0; c = 4
|
alpar@1
|
3351 |
edge 5 13: x = 0; c = 11
|
alpar@1
|
3352 |
edge 5 12: x = 0; c = 40
|
alpar@1
|
3353 |
edge 5 11: x = 0; c = 41
|
alpar@1
|
3354 |
edge 6 9: x = 1; c = 13
|
alpar@1
|
3355 |
edge 7 10: x = 0; c = 19
|
alpar@1
|
3356 |
edge 8 11: x = 0; c = 15
|
alpar@1
|
3357 |
edge 8 10: x = 1; c = 39
|
alpar@1
|
3358 |
\end{verbatim}
|
alpar@1
|
3359 |
\end{footnotesize}
|
alpar@1
|
3360 |
|
alpar@1
|
3361 |
\newpage
|
alpar@1
|
3362 |
|
alpar@1
|
3363 |
\subsection{glp\_asnprob\_hall---find bipartite matching of maximum
|
alpar@1
|
3364 |
cardinality}
|
alpar@1
|
3365 |
|
alpar@1
|
3366 |
\subsubsection*{Synopsis}
|
alpar@1
|
3367 |
|
alpar@1
|
3368 |
\begin{verbatim}
|
alpar@1
|
3369 |
int glp_asnprob_hall(glp_graph *G, int v_set, int a_x);
|
alpar@1
|
3370 |
\end{verbatim}
|
alpar@1
|
3371 |
|
alpar@1
|
3372 |
\subsubsection*{Description}
|
alpar@1
|
3373 |
|
alpar@1
|
3374 |
The routine \verb|glp_asnprob_hall| finds a matching of maximal
|
alpar@1
|
3375 |
cardinality in the specified bipartite graph. It uses a version of the
|
alpar@1
|
3376 |
Fortran routine \verb|MC21A| developed by
|
alpar@1
|
3377 |
I.~S.~Duff\footnote{I.~S.~Duff, Algorithm 575: Permutations for
|
alpar@1
|
3378 |
zero-free diagonal, ACM Trans. on Math. Softw. 7 (1981), pp.~387-390.},
|
alpar@1
|
3379 |
which implements Hall's algorithm.\footnote{M.~Hall, ``An Algorithm for
|
alpar@1
|
3380 |
Distinct Representatives,'' Am. Math. Monthly 63 (1956), pp.~716-717.}
|
alpar@1
|
3381 |
|
alpar@1
|
3382 |
The parameter \verb|G| is a pointer to the graph program object.
|
alpar@1
|
3383 |
|
alpar@1
|
3384 |
The parameter \verb|v_set| specifies an offset of the field of type
|
alpar@1
|
3385 |
\verb|int| in the vertex data block, which contains the node set
|
alpar@1
|
3386 |
indicator:
|
alpar@1
|
3387 |
|
alpar@1
|
3388 |
0 --- the node is in set $R$;
|
alpar@1
|
3389 |
|
alpar@1
|
3390 |
1 --- the node is in set $S$.
|
alpar@1
|
3391 |
|
alpar@1
|
3392 |
\noindent
|
alpar@1
|
3393 |
If \verb|v_set| $<0$, it is assumed that a node having no incoming arcs
|
alpar@1
|
3394 |
is in set $R$, and a node having no outgoing arcs is in set $S$.
|
alpar@1
|
3395 |
|
alpar@1
|
3396 |
The parameter \verb|a_x| specifies an offset of the field of type
|
alpar@1
|
3397 |
\verb|int| in the arc data block, to which the routine stores $x_{ij}$.
|
alpar@1
|
3398 |
If \verb|a_x| $<0$, this value is not stored.
|
alpar@1
|
3399 |
|
alpar@1
|
3400 |
\subsubsection*{Returns}
|
alpar@1
|
3401 |
|
alpar@1
|
3402 |
The routine \verb|glp_asnprob_hall| returns the cardinality of the
|
alpar@1
|
3403 |
matching found. However, if the specified graph is incorrect (as
|
alpar@1
|
3404 |
detected by the routine \verb|glp_check_asnprob|), this routine returns
|
alpar@1
|
3405 |
a negative value.
|
alpar@1
|
3406 |
|
alpar@1
|
3407 |
\subsubsection*{Comments}
|
alpar@1
|
3408 |
|
alpar@1
|
3409 |
The same solution may be obtained with the routine
|
alpar@1
|
3410 |
\verb|glp_asnprob_okalg| (for LP formulation \verb|GLP_ASN_MMP| and
|
alpar@1
|
3411 |
all edge costs equal to 1). However, the routine \verb|glp_asnprob_hall|
|
alpar@1
|
3412 |
is much faster.
|
alpar@1
|
3413 |
|
alpar@1
|
3414 |
\newpage
|
alpar@1
|
3415 |
|
alpar@1
|
3416 |
\subsubsection*{Example}
|
alpar@1
|
3417 |
|
alpar@1
|
3418 |
The example program shown below reads the assignment problem instance
|
alpar@1
|
3419 |
in DIMACS format from file `\verb|sample.asn|', finds a bipartite
|
alpar@1
|
3420 |
matching of maximal cardinality by using the routine
|
alpar@1
|
3421 |
\verb|glp_asnprob_hall|, and writes the solution found to the standard
|
alpar@1
|
3422 |
output.
|
alpar@1
|
3423 |
|
alpar@1
|
3424 |
\begin{footnotesize}
|
alpar@1
|
3425 |
\begin{verbatim}
|
alpar@1
|
3426 |
#include <stddef.h>
|
alpar@1
|
3427 |
#include <stdio.h>
|
alpar@1
|
3428 |
#include <stdlib.h>
|
alpar@1
|
3429 |
#include <glpk.h>
|
alpar@1
|
3430 |
|
alpar@1
|
3431 |
typedef struct { int set; } v_data;
|
alpar@1
|
3432 |
typedef struct { int x; } e_data;
|
alpar@1
|
3433 |
|
alpar@1
|
3434 |
#define node(v) ((v_data *)((v)->data))
|
alpar@1
|
3435 |
#define edge(e) ((e_data *)((e)->data))
|
alpar@1
|
3436 |
|
alpar@1
|
3437 |
int main(void)
|
alpar@1
|
3438 |
{ glp_graph *G;
|
alpar@1
|
3439 |
glp_vertex *v;
|
alpar@1
|
3440 |
glp_arc *e;
|
alpar@1
|
3441 |
int i, card;
|
alpar@1
|
3442 |
G = glp_create_graph(sizeof(v_data), sizeof(e_data));
|
alpar@1
|
3443 |
glp_read_asnprob(G, offsetof(v_data, set), -1,
|
alpar@1
|
3444 |
"sample.asn");
|
alpar@1
|
3445 |
card = glp_asnprob_hall(G, offsetof(v_data, set),
|
alpar@1
|
3446 |
offsetof(e_data, x));
|
alpar@1
|
3447 |
printf("card = %d\n", card);
|
alpar@1
|
3448 |
for (i = 1; i <= G->nv; i++)
|
alpar@1
|
3449 |
{ v = G->v[i];
|
alpar@1
|
3450 |
for (e = v->out; e != NULL; e = e->t_next)
|
alpar@1
|
3451 |
printf("edge %2d %2d: x = %d\n",
|
alpar@1
|
3452 |
e->tail->i, e->head->i, edge(e)->x);
|
alpar@1
|
3453 |
}
|
alpar@1
|
3454 |
glp_delete_graph(G);
|
alpar@1
|
3455 |
return 0;
|
alpar@1
|
3456 |
}
|
alpar@1
|
3457 |
\end{verbatim}
|
alpar@1
|
3458 |
\end{footnotesize}
|
alpar@1
|
3459 |
|
alpar@1
|
3460 |
If `\verb|sample.asn|' is the example data file from the subsection
|
alpar@1
|
3461 |
describing the routine \verb|glp_read_asnprob|, the output may look
|
alpar@1
|
3462 |
like follows:
|
alpar@1
|
3463 |
|
alpar@1
|
3464 |
\begin{footnotesize}
|
alpar@1
|
3465 |
\begin{verbatim}
|
alpar@1
|
3466 |
Reading assignment problem data from `sample.asn'...
|
alpar@1
|
3467 |
Assignment problem has 8 + 9 = 17 nodes and 22 arcs
|
alpar@1
|
3468 |
38 lines were read
|
alpar@1
|
3469 |
card = 7
|
alpar@1
|
3470 |
edge 1 12: x = 1
|
alpar@1
|
3471 |
edge 1 10: x = 0
|
alpar@1
|
3472 |
edge 1 9: x = 0
|
alpar@1
|
3473 |
edge 2 13: x = 1
|
alpar@1
|
3474 |
edge 2 12: x = 0
|
alpar@1
|
3475 |
edge 2 10: x = 0
|
alpar@1
|
3476 |
edge 3 13: x = 0
|
alpar@1
|
3477 |
edge 3 11: x = 1
|
alpar@1
|
3478 |
edge 4 14: x = 1
|
alpar@1
|
3479 |
edge 4 12: x = 0
|
alpar@1
|
3480 |
edge 4 9: x = 0
|
alpar@1
|
3481 |
edge 5 17: x = 1
|
alpar@1
|
3482 |
edge 5 16: x = 0
|
alpar@1
|
3483 |
edge 5 15: x = 0
|
alpar@1
|
3484 |
edge 5 14: x = 0
|
alpar@1
|
3485 |
edge 5 13: x = 0
|
alpar@1
|
3486 |
edge 5 12: x = 0
|
alpar@1
|
3487 |
edge 5 11: x = 0
|
alpar@1
|
3488 |
edge 6 9: x = 1
|
alpar@1
|
3489 |
edge 7 10: x = 1
|
alpar@1
|
3490 |
edge 8 11: x = 0
|
alpar@1
|
3491 |
edge 8 10: x = 0
|
alpar@1
|
3492 |
\end{verbatim}
|
alpar@1
|
3493 |
\end{footnotesize}
|
alpar@1
|
3494 |
|
alpar@1
|
3495 |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
alpar@1
|
3496 |
|
alpar@1
|
3497 |
\newpage
|
alpar@1
|
3498 |
|
alpar@1
|
3499 |
\section{Critical path problem}
|
alpar@1
|
3500 |
|
alpar@1
|
3501 |
\subsection{Background}
|
alpar@1
|
3502 |
|
alpar@1
|
3503 |
The {\it critical path problem} (CPP) is stated as follows. Let there
|
alpar@1
|
3504 |
be given a project $J$, which a set of jobs (tasks, activities, etc.).
|
alpar@1
|
3505 |
Performing each job $i\in J$ requires time $t_i\geq 0$. Besides, over
|
alpar@1
|
3506 |
the set $J$ there is given a precedence relation $R\subseteq J\times J$,
|
alpar@1
|
3507 |
where $(i,j)\in R$ means that job $i$ immediately precedes job $j$, i.e.
|
alpar@1
|
3508 |
performing job $j$ cannot start until job $i$ has been completely
|
alpar@1
|
3509 |
performed. The problem is to find starting times $x_i$ for each job
|
alpar@1
|
3510 |
$i\in J$, which satisfy to the precedence relation and minimize the
|
alpar@1
|
3511 |
total duration (makespan) of the project.
|
alpar@1
|
3512 |
|
alpar@1
|
3513 |
The following is an example of the critical path problem:
|
alpar@1
|
3514 |
|
alpar@1
|
3515 |
\begin{center}
|
alpar@1
|
3516 |
\begin{tabular}{|c|l|c|c|}
|
alpar@1
|
3517 |
\hline
|
alpar@1
|
3518 |
Job&Desription&Time&Predecessors\\
|
alpar@1
|
3519 |
\hline
|
alpar@1
|
3520 |
A&Excavate&3&---\\
|
alpar@1
|
3521 |
B&Lay foundation&4&A\\
|
alpar@1
|
3522 |
C&Rough plumbing&3&B\\
|
alpar@1
|
3523 |
D&Frame&10&B\\
|
alpar@1
|
3524 |
E&Finish exterior&8&D\\
|
alpar@1
|
3525 |
F&Install HVAC&4&D\\
|
alpar@1
|
3526 |
G&Rough electric&6&D\\
|
alpar@1
|
3527 |
H&Sheet rock&8&C, E, F, G\\
|
alpar@1
|
3528 |
I&Install cabinets&5&H\\
|
alpar@1
|
3529 |
J&Paint&5&H\\
|
alpar@1
|
3530 |
K&Final plumbing&4&I\\
|
alpar@1
|
3531 |
L&Final electric&2&J\\
|
alpar@1
|
3532 |
M&Install flooring&4&K, L\\
|
alpar@1
|
3533 |
\hline
|
alpar@1
|
3534 |
\end{tabular}
|
alpar@1
|
3535 |
\end{center}
|
alpar@1
|
3536 |
|
alpar@1
|
3537 |
Obviously, the project along with the precedence relation can be
|
alpar@1
|
3538 |
represented as a directed graph $G=(J,R)$ called {\it project network},
|
alpar@1
|
3539 |
where each node $i\in J$ corresponds to a job, and arc
|
alpar@1
|
3540 |
$(i\rightarrow j)\in R$ means that job $i$ immediately precedes job
|
alpar@1
|
3541 |
$j$.\footnote{There exists another network representation of the
|
alpar@1
|
3542 |
critical path problem, where jobs correspond to arcs while nodes
|
alpar@1
|
3543 |
correspond to events introduced to express the precedence relation.
|
alpar@1
|
3544 |
That representation, however, is much less convenient than the one,
|
alpar@1
|
3545 |
where jobs are represented as nodes of the network.} The project network
|
alpar@1
|
3546 |
for the example above is shown on Fig.~4.
|
alpar@1
|
3547 |
|
alpar@1
|
3548 |
May note that the project network must be acyclic; otherwise, it would
|
alpar@1
|
3549 |
be impossible to satisfy to the precedence relation for any job that
|
alpar@1
|
3550 |
belongs to a cycle.
|
alpar@1
|
3551 |
|
alpar@1
|
3552 |
\newpage
|
alpar@1
|
3553 |
|
alpar@1
|
3554 |
\xymatrix
|
alpar@1
|
3555 |
{&&&C|3\ar[rd]&&I|5\ar[r]&K|4\ar[rd]&\\
|
alpar@1
|
3556 |
A|3\ar[r]&B|4\ar[rru]\ar[rd]&&E|8\ar[r]&H|8\ar[ru]\ar[rd]&&&M|4\\
|
alpar@1
|
3557 |
&&D|10\ar[ru]\ar[r]\ar[rd]&F|4\ar[ru]&&J|5\ar[r]&L|2\ar[ru]&\\
|
alpar@1
|
3558 |
&&&G|6\ar[ruu]&&&&\\
|
alpar@1
|
3559 |
}
|
alpar@1
|
3560 |
|
alpar@1
|
3561 |
\bigskip
|
alpar@1
|
3562 |
|
alpar@1
|
3563 |
\noindent\hfil
|
alpar@1
|
3564 |
Fig.~4. An example of the project network.
|
alpar@1
|
3565 |
|
alpar@1
|
3566 |
\bigskip
|
alpar@1
|
3567 |
|
alpar@1
|
3568 |
The critical path problem can be naturally formulated as the following
|
alpar@1
|
3569 |
LP problem:
|
alpar@1
|
3570 |
|
alpar@1
|
3571 |
\medskip
|
alpar@1
|
3572 |
|
alpar@1
|
3573 |
\noindent
|
alpar@1
|
3574 |
\hspace{.5in}minimize
|
alpar@1
|
3575 |
$$z\eqno(19)$$
|
alpar@1
|
3576 |
\hspace{.5in}subject to
|
alpar@1
|
3577 |
$$x_i+t_i\leq z\ \ \ \hbox{for all}\ i\in J\ \ \ \ \eqno(20)$$
|
alpar@1
|
3578 |
$$x_i+t_i\leq x_j\ \ \ \hbox{for all}\ (i,j)\in R\eqno(21)$$
|
alpar@1
|
3579 |
$$x_i\geq 0\ \ \ \ \ \ \ \hbox{for all}\ i\in J\ \ \eqno(22)$$
|
alpar@1
|
3580 |
|
alpar@1
|
3581 |
The inequality constraints (21), which are active in the optimal
|
alpar@1
|
3582 |
solution, define so called {\it critical path} having the following
|
alpar@1
|
3583 |
property: the minimal project duration $z$ can be decreased only by
|
alpar@1
|
3584 |
decreasing the times $t_j$ for jobs on the critical path, and delaying
|
alpar@1
|
3585 |
any critical job delays the entire project.
|
alpar@1
|
3586 |
|
alpar@1
|
3587 |
\subsection{glp\_cpp---solve critical path problem}
|
alpar@1
|
3588 |
|
alpar@1
|
3589 |
\subsubsection{Synopsis}
|
alpar@1
|
3590 |
|
alpar@1
|
3591 |
\begin{verbatim}
|
alpar@1
|
3592 |
double glp_cpp(glp_graph *G, int v_t, int v_es, int v_ls);
|
alpar@1
|
3593 |
\end{verbatim}
|
alpar@1
|
3594 |
|
alpar@1
|
3595 |
\subsubsection{Description}
|
alpar@1
|
3596 |
|
alpar@1
|
3597 |
The routine \verb|glp_cpp| solves the critical path problem represented
|
alpar@1
|
3598 |
in the form of the project network.
|
alpar@1
|
3599 |
|
alpar@1
|
3600 |
The parameter \verb|G| is a pointer to the graph object, which
|
alpar@1
|
3601 |
specifies the project network. This graph must be acyclic. Multiple
|
alpar@1
|
3602 |
arcs are allowed being considered as single arcs.
|
alpar@1
|
3603 |
|
alpar@1
|
3604 |
The parameter \verb|v_t| specifies an offset of the field of type
|
alpar@1
|
3605 |
\verb|double| in the vertex data block, which contains time $t_i\geq 0$
|
alpar@1
|
3606 |
needed to perform corresponding job $j\in J$. If \verb|v_t| $<0$, it is
|
alpar@1
|
3607 |
assumed that $t_i=1$ for all jobs.
|
alpar@1
|
3608 |
|
alpar@1
|
3609 |
The parameter \verb|v_es| specifies an offset of the field of type
|
alpar@1
|
3610 |
\verb|double| in the vertex data block, to which the routine stores
|
alpar@1
|
3611 |
the {\it earliest start time} for corresponding job. If \verb|v_es|
|
alpar@1
|
3612 |
$<0$, this time is not stored.
|
alpar@1
|
3613 |
|
alpar@1
|
3614 |
The parameter \verb|v_ls| specifies an offset of the field of type
|
alpar@1
|
3615 |
\verb|double| in the vertex data block, to which the routine stores
|
alpar@1
|
3616 |
the {\it latest start time} for corresponding job. If \verb|v_ls|
|
alpar@1
|
3617 |
$<0$, this time is not stored.
|
alpar@1
|
3618 |
|
alpar@1
|
3619 |
The difference between the latest and earliest start times of some job
|
alpar@1
|
3620 |
is called its {\it time reserve}. Delaying a job within its time reserve
|
alpar@1
|
3621 |
does not affect the project duration, so if the time reserve is zero,
|
alpar@1
|
3622 |
the corresponding job is critical.
|
alpar@1
|
3623 |
|
alpar@1
|
3624 |
\subsubsection{Returns}
|
alpar@1
|
3625 |
|
alpar@1
|
3626 |
The routine \verb|glp_cpp| returns the minimal project duration, i.e.
|
alpar@1
|
3627 |
minimal time needed to perform all jobs in the project.
|
alpar@1
|
3628 |
|
alpar@1
|
3629 |
\subsubsection{Example}
|
alpar@1
|
3630 |
|
alpar@1
|
3631 |
The example program below solves the critical path problem shown on
|
alpar@1
|
3632 |
Fig.~4 by using the routine \verb|glp_cpp| and writes the solution found
|
alpar@1
|
3633 |
to the standard output.
|
alpar@1
|
3634 |
|
alpar@1
|
3635 |
\begin{footnotesize}
|
alpar@1
|
3636 |
\begin{verbatim}
|
alpar@1
|
3637 |
#include <stddef.h>
|
alpar@1
|
3638 |
#include <stdio.h>
|
alpar@1
|
3639 |
#include <stdlib.h>
|
alpar@1
|
3640 |
#include <glpk.h>
|
alpar@1
|
3641 |
|
alpar@1
|
3642 |
typedef struct { double t, es, ls; } v_data;
|
alpar@1
|
3643 |
|
alpar@1
|
3644 |
#define node(v) ((v_data *)((v)->data))
|
alpar@1
|
3645 |
|
alpar@1
|
3646 |
int main(void)
|
alpar@1
|
3647 |
{ glp_graph *G;
|
alpar@1
|
3648 |
int i;
|
alpar@1
|
3649 |
double t, es, ef, ls, lf, total;
|
alpar@1
|
3650 |
G = glp_create_graph(sizeof(v_data), 0);
|
alpar@1
|
3651 |
glp_add_vertices(G, 13);
|
alpar@1
|
3652 |
node(G->v[1])->t = 3; /* A: Excavate */
|
alpar@1
|
3653 |
node(G->v[2])->t = 4; /* B: Lay foundation */
|
alpar@1
|
3654 |
node(G->v[3])->t = 3; /* C: Rough plumbing */
|
alpar@1
|
3655 |
node(G->v[4])->t = 10; /* D: Frame */
|
alpar@1
|
3656 |
node(G->v[5])->t = 8; /* E: Finish exterior */
|
alpar@1
|
3657 |
node(G->v[6])->t = 4; /* F: Install HVAC */
|
alpar@1
|
3658 |
node(G->v[7])->t = 6; /* G: Rough elecrtic */
|
alpar@1
|
3659 |
node(G->v[8])->t = 8; /* H: Sheet rock */
|
alpar@1
|
3660 |
node(G->v[9])->t = 5; /* I: Install cabinets */
|
alpar@1
|
3661 |
node(G->v[10])->t = 5; /* J: Paint */
|
alpar@1
|
3662 |
node(G->v[11])->t = 4; /* K: Final plumbing */
|
alpar@1
|
3663 |
node(G->v[12])->t = 2; /* L: Final electric */
|
alpar@1
|
3664 |
node(G->v[13])->t = 4; /* M: Install flooring */
|
alpar@1
|
3665 |
glp_add_arc(G, 1, 2); /* A precedes B */
|
alpar@1
|
3666 |
glp_add_arc(G, 2, 3); /* B precedes C */
|
alpar@1
|
3667 |
glp_add_arc(G, 2, 4); /* B precedes D */
|
alpar@1
|
3668 |
glp_add_arc(G, 4, 5); /* D precedes E */
|
alpar@1
|
3669 |
glp_add_arc(G, 4, 6); /* D precedes F */
|
alpar@1
|
3670 |
glp_add_arc(G, 4, 7); /* D precedes G */
|
alpar@1
|
3671 |
glp_add_arc(G, 3, 8); /* C precedes H */
|
alpar@1
|
3672 |
glp_add_arc(G, 5, 8); /* E precedes H */
|
alpar@1
|
3673 |
glp_add_arc(G, 6, 8); /* F precedes H */
|
alpar@1
|
3674 |
glp_add_arc(G, 7, 8); /* G precedes H */
|
alpar@1
|
3675 |
glp_add_arc(G, 8, 9); /* H precedes I */
|
alpar@1
|
3676 |
glp_add_arc(G, 8, 10); /* H precedes J */
|
alpar@1
|
3677 |
glp_add_arc(G, 9, 11); /* I precedes K */
|
alpar@1
|
3678 |
glp_add_arc(G, 10, 12); /* J precedes L */
|
alpar@1
|
3679 |
glp_add_arc(G, 11, 13); /* K precedes M */
|
alpar@1
|
3680 |
glp_add_arc(G, 12, 13); /* L precedes M */
|
alpar@1
|
3681 |
total = glp_cpp(G, offsetof(v_data, t), offsetof(v_data, es),
|
alpar@1
|
3682 |
offsetof(v_data, ls));
|
alpar@1
|
3683 |
printf("Minimal project duration is %.2f\n\n", total);
|
alpar@1
|
3684 |
printf("Job Time ES EF LS LF\n");
|
alpar@1
|
3685 |
printf("--- ------ ------ ------ ------ ------\n");
|
alpar@1
|
3686 |
for (i = 1; i <= G->nv; i++)
|
alpar@1
|
3687 |
{ t = node(G->v[i])->t;
|
alpar@1
|
3688 |
es = node(G->v[i])->es;
|
alpar@1
|
3689 |
ef = es + node(G->v[i])->t;
|
alpar@1
|
3690 |
ls = node(G->v[i])->ls;
|
alpar@1
|
3691 |
lf = ls + node(G->v[i])->t;
|
alpar@1
|
3692 |
printf("%3d %6.2f %s %6.2f %6.2f %6.2f %6.2f\n",
|
alpar@1
|
3693 |
i, t, ls - es < 0.001 ? "*" : " ", es, ef, ls, lf);
|
alpar@1
|
3694 |
}
|
alpar@1
|
3695 |
glp_delete_graph(G);
|
alpar@1
|
3696 |
return 0;
|
alpar@1
|
3697 |
}
|
alpar@1
|
3698 |
\end{verbatim}
|
alpar@1
|
3699 |
\end{footnotesize}
|
alpar@1
|
3700 |
|
alpar@1
|
3701 |
The output from the example program shown below includes job number,
|
alpar@1
|
3702 |
the time needed to perform a job, earliest start time (\verb|ES|),
|
alpar@1
|
3703 |
earliest finish time (\verb|EF|), latest start time (\verb|LS|), and
|
alpar@1
|
3704 |
latest finish time (\verb|LF|) for each job in the project. Critical
|
alpar@1
|
3705 |
jobs are marked by asterisks.
|
alpar@1
|
3706 |
|
alpar@1
|
3707 |
\newpage
|
alpar@1
|
3708 |
|
alpar@1
|
3709 |
\begin{footnotesize}
|
alpar@1
|
3710 |
\begin{verbatim}
|
alpar@1
|
3711 |
Minimal project duration is 46.00
|
alpar@1
|
3712 |
|
alpar@1
|
3713 |
Job Time ES EF LS LF
|
alpar@1
|
3714 |
--- ------ ------ ------ ------ ------
|
alpar@1
|
3715 |
1 3.00 * 0.00 3.00 0.00 3.00
|
alpar@1
|
3716 |
2 4.00 * 3.00 7.00 3.00 7.00
|
alpar@1
|
3717 |
3 3.00 7.00 10.00 22.00 25.00
|
alpar@1
|
3718 |
4 10.00 * 7.00 17.00 7.00 17.00
|
alpar@1
|
3719 |
5 8.00 * 17.00 25.00 17.00 25.00
|
alpar@1
|
3720 |
6 4.00 17.00 21.00 21.00 25.00
|
alpar@1
|
3721 |
7 6.00 17.00 23.00 19.00 25.00
|
alpar@1
|
3722 |
8 8.00 * 25.00 33.00 25.00 33.00
|
alpar@1
|
3723 |
9 5.00 * 33.00 38.00 33.00 38.00
|
alpar@1
|
3724 |
10 5.00 33.00 38.00 35.00 40.00
|
alpar@1
|
3725 |
11 4.00 * 38.00 42.00 38.00 42.00
|
alpar@1
|
3726 |
12 2.00 38.00 40.00 40.00 42.00
|
alpar@1
|
3727 |
13 4.00 * 42.00 46.00 42.00 46.00
|
alpar@1
|
3728 |
\end{verbatim}
|
alpar@1
|
3729 |
\end{footnotesize}
|
alpar@1
|
3730 |
|
alpar@1
|
3731 |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
alpar@1
|
3732 |
|
alpar@1
|
3733 |
\chapter{Graph Optimization API Routines}
|
alpar@1
|
3734 |
|
alpar@1
|
3735 |
\section{Maximum clique problem}
|
alpar@1
|
3736 |
|
alpar@1
|
3737 |
\subsection{Background}
|
alpar@1
|
3738 |
|
alpar@1
|
3739 |
The {\it maximum clique problem (MCP)} is a classic combinatorial
|
alpar@1
|
3740 |
optimization problem. Given an undirected graph $G=(V,E)$, where $V$ is
|
alpar@1
|
3741 |
a set of vertices, and $E$ is a set of edges, this problem is to find
|
alpar@1
|
3742 |
the largest {\it clique} $C\subseteq G$, i.e. the largest induced
|
alpar@1
|
3743 |
complete subgraph. A generalization of this problem is the {\it maximum
|
alpar@1
|
3744 |
weight clique problem (MWCP)}, which is to find a clique $C\subseteq G$
|
alpar@1
|
3745 |
of the largest weight $\displaystyle\sum_{v\in C}w(v)\rightarrow\max$,
|
alpar@1
|
3746 |
where $w(v)$ is a weight of vertex $v\in V$.
|
alpar@1
|
3747 |
|
alpar@1
|
3748 |
An example of the maximum weight clique problem is shown on Fig.~5.
|
alpar@1
|
3749 |
|
alpar@1
|
3750 |
\begin{figure}
|
alpar@1
|
3751 |
\noindent\hfil
|
alpar@1
|
3752 |
\begin{tabular}{c}
|
alpar@1
|
3753 |
{\xymatrix %@C=16pt
|
alpar@1
|
3754 |
{&&&{v_1}\ar@{-}[lllddd]\ar@{-}[llddddd]\ar@{-}[dddddd]
|
alpar@1
|
3755 |
\ar@{-}[rrrddd]&&&\\
|
alpar@1
|
3756 |
&{v_2}\ar@{-}[rrrr]\ar@{-}[rrrrdddd]\ar@{-}[rrddddd]\ar@{-}[dddd]&&&&
|
alpar@1
|
3757 |
{v_3}\ar@{-}[llllldd]\ar@{-}[lllldddd]\ar@{-}[dddd]&\\
|
alpar@1
|
3758 |
&&&&&&\\
|
alpar@1
|
3759 |
{v_4}\ar@{-}[rrrrrr]\ar@{-}[rrrddd]&&&&&&{v_5}\ar@{-}[lllddd]
|
alpar@1
|
3760 |
\ar@{-}[ldd]\\
|
alpar@1
|
3761 |
&&&&&&\\
|
alpar@1
|
3762 |
&{v_6}\ar@{-}[rrrr]&&&&{v_7}&\\
|
alpar@1
|
3763 |
&&&{v_8}&&&\\
|
alpar@1
|
3764 |
}}
|
alpar@1
|
3765 |
\end{tabular}
|
alpar@1
|
3766 |
\begin{tabular}{r@{\ }c@{\ }l}
|
alpar@1
|
3767 |
$w(v_1)$&=&3\\$w(v_2)$&=&4\\$w(v_3)$&=&8\\$w(v_4)$&=&1\\
|
alpar@1
|
3768 |
$w(v_5)$&=&5\\$w(v_6)$&=&2\\$w(v_7)$&=&1\\$w(v_8)$&=&3\\
|
alpar@1
|
3769 |
\end{tabular}
|
alpar@1
|
3770 |
|
alpar@1
|
3771 |
\begin{center}
|
alpar@1
|
3772 |
Fig.~5. An example of the maximum weight clique problem.
|
alpar@1
|
3773 |
\end{center}
|
alpar@1
|
3774 |
\end{figure}
|
alpar@1
|
3775 |
|
alpar@1
|
3776 |
\subsection{glp\_wclique\_exact---find maximum weight clique with exact
|
alpar@1
|
3777 |
algorithm}
|
alpar@1
|
3778 |
|
alpar@1
|
3779 |
\subsubsection*{Synopsis}
|
alpar@1
|
3780 |
|
alpar@1
|
3781 |
\begin{verbatim}
|
alpar@1
|
3782 |
int glp_wclique_exact(glp_graph *G, int v_wgt, double *sol,
|
alpar@1
|
3783 |
int v_set);
|
alpar@1
|
3784 |
\end{verbatim}
|
alpar@1
|
3785 |
|
alpar@1
|
3786 |
\subsection*{Description}
|
alpar@1
|
3787 |
|
alpar@1
|
3788 |
The routine {\it glp\_wclique\_exact} finds a maximum weight clique in
|
alpar@1
|
3789 |
the specified undirected graph with the exact algorithm developed by
|
alpar@1
|
3790 |
Patric \"Osterg{\aa}rd.\footnote{P.~R.~J.~\"Osterg{\aa}rd, A new
|
alpar@1
|
3791 |
algorithm for the maximum-weight clique problem, Nordic J. of Computing,
|
alpar@1
|
3792 |
Vol.~8, No.~4, 2001, pp.~424--36.}
|
alpar@1
|
3793 |
|
alpar@1
|
3794 |
The parameter $G$ is the program object, which specifies an undirected
|
alpar@1
|
3795 |
graph. Each arc $(x\rightarrow y)$ in $G$ is considered as edge
|
alpar@1
|
3796 |
$(x,y)$, self-loops are ignored, and multiple edges, if present, are
|
alpar@1
|
3797 |
replaced (internally) by simple edges.
|
alpar@1
|
3798 |
|
alpar@1
|
3799 |
The parameter {\it v\_wgt} specifies an offset of the field of type
|
alpar@1
|
3800 |
{\bf double} in the vertex data block, which contains a weight of
|
alpar@1
|
3801 |
corresponding vertex. Vertex weights must be integer-valued in the
|
alpar@1
|
3802 |
range $[0,$ {\it INT\_MAX}$]$. If {\it v\_wgt} $<0$, it is assumed that
|
alpar@1
|
3803 |
all vertices of the graph have the weight 1.
|
alpar@1
|
3804 |
|
alpar@1
|
3805 |
The parameter {\it sol} specifies a location, to which the routine
|
alpar@1
|
3806 |
stores the weight of the clique found (the clique weight is the sum
|
alpar@1
|
3807 |
of weights of all vertices included in the clique.) If {\it sol} is
|
alpar@1
|
3808 |
{\it NULL}, the solution is not stored.
|
alpar@1
|
3809 |
|
alpar@1
|
3810 |
The parameter {\it v\_set} specifies an offset of the field of type
|
alpar@1
|
3811 |
{\bf int} in the vertex data block, to which the routines stores a
|
alpar@1
|
3812 |
vertex flag: 1 means that the corresponding vertex is included in the
|
alpar@1
|
3813 |
clique found, and 0 otherwise. If {\it v\_set} $<0$, vertex flags are
|
alpar@1
|
3814 |
not stored.
|
alpar@1
|
3815 |
|
alpar@1
|
3816 |
\subsubsection*{Returns}
|
alpar@1
|
3817 |
|
alpar@1
|
3818 |
\def\arraystretch{1}
|
alpar@1
|
3819 |
|
alpar@1
|
3820 |
\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
|
alpar@1
|
3821 |
0 & Optimal solution found.\\
|
alpar@1
|
3822 |
\verb|GLP_EDATA| & Unable to start the search, because some vertex
|
alpar@1
|
3823 |
weights are either not integer-valued or out of range. This code is
|
alpar@1
|
3824 |
also returned if the sum of weights of all vertices exceeds
|
alpar@1
|
3825 |
{\it INT\_MAX}. \\
|
alpar@1
|
3826 |
\end{tabular}
|
alpar@1
|
3827 |
|
alpar@1
|
3828 |
\subsubsection*{Notes}
|
alpar@1
|
3829 |
|
alpar@1
|
3830 |
\noindent\indent
|
alpar@1
|
3831 |
1. The routine {\it glp\_wclique\_exact} finds exact solution. Since
|
alpar@1
|
3832 |
both MCP and MWCP problems are NP-complete, the algorithm may require
|
alpar@1
|
3833 |
exponential time in worst cases.
|
alpar@1
|
3834 |
|
alpar@1
|
3835 |
2. Internally the specified graph is converted to an adjacency matrix
|
alpar@1
|
3836 |
in {\it dense} format. This requires about $|V|^2/16$ bytes of memory,
|
alpar@1
|
3837 |
where $|V|$ is the number of vertices in the graph.
|
alpar@1
|
3838 |
|
alpar@1
|
3839 |
\subsubsection*{Example}
|
alpar@1
|
3840 |
|
alpar@1
|
3841 |
The example program shown below reads a MWCP instance in DIMACS
|
alpar@1
|
3842 |
clique/coloring format from file `\verb|sample.clq|', finds the clique
|
alpar@1
|
3843 |
of largest weight, and writes the solution found to the standard output.
|
alpar@1
|
3844 |
|
alpar@1
|
3845 |
\begin{footnotesize}
|
alpar@1
|
3846 |
\begin{verbatim}
|
alpar@1
|
3847 |
#include <stddef.h>
|
alpar@1
|
3848 |
#include <stdio.h>
|
alpar@1
|
3849 |
#include <stdlib.h>
|
alpar@1
|
3850 |
#include <glpk.h>
|
alpar@1
|
3851 |
|
alpar@1
|
3852 |
typedef struct { double wgt; int set; } v_data;
|
alpar@1
|
3853 |
|
alpar@1
|
3854 |
#define vertex(v) ((v_data *)((v)->data))
|
alpar@1
|
3855 |
|
alpar@1
|
3856 |
int main(void)
|
alpar@1
|
3857 |
{ glp_graph *G;
|
alpar@1
|
3858 |
glp_vertex *v;
|
alpar@1
|
3859 |
int i, ret;
|
alpar@1
|
3860 |
double sol;
|
alpar@1
|
3861 |
G = glp_create_graph(sizeof(v_data), 0);
|
alpar@1
|
3862 |
glp_read_ccdata(G, offsetof(v_data, wgt), "sample.clq");
|
alpar@1
|
3863 |
ret = glp_wclique_exact(G, offsetof(v_data, wgt), &sol,
|
alpar@1
|
3864 |
offsetof(v_data, set));
|
alpar@1
|
3865 |
printf("ret = %d; sol = %g\n", ret, sol);
|
alpar@1
|
3866 |
for (i = 1; i <= G->nv; i++)
|
alpar@1
|
3867 |
{ v = G->v[i];
|
alpar@1
|
3868 |
printf("vertex %d: weight = %g, flag = %d\n",
|
alpar@1
|
3869 |
i, vertex(v)->wgt, vertex(v)->set);
|
alpar@1
|
3870 |
}
|
alpar@1
|
3871 |
glp_delete_graph(G);
|
alpar@1
|
3872 |
return 0;
|
alpar@1
|
3873 |
}
|
alpar@1
|
3874 |
\end{verbatim}
|
alpar@1
|
3875 |
\end{footnotesize}
|
alpar@1
|
3876 |
|
alpar@1
|
3877 |
\noindent
|
alpar@1
|
3878 |
For the example shown on Fig.~5 the data file may look like follows:
|
alpar@1
|
3879 |
|
alpar@1
|
3880 |
\begin{footnotesize}
|
alpar@1
|
3881 |
\begin{verbatim}
|
alpar@1
|
3882 |
c sample.clq
|
alpar@1
|
3883 |
c
|
alpar@1
|
3884 |
c This is an example of the maximum weight clique
|
alpar@1
|
3885 |
c problem in DIMACS clique/coloring format.
|
alpar@1
|
3886 |
c
|
alpar@1
|
3887 |
p edge 8 16
|
alpar@1
|
3888 |
n 1 3
|
alpar@1
|
3889 |
n 2 4
|
alpar@1
|
3890 |
n 3 8
|
alpar@1
|
3891 |
n 5 5
|
alpar@1
|
3892 |
n 6 2
|
alpar@1
|
3893 |
n 8 3
|
alpar@1
|
3894 |
e 1 4
|
alpar@1
|
3895 |
e 1 5
|
alpar@1
|
3896 |
e 1 6
|
alpar@1
|
3897 |
e 1 8
|
alpar@1
|
3898 |
e 2 3
|
alpar@1
|
3899 |
e 2 6
|
alpar@1
|
3900 |
e 2 7
|
alpar@1
|
3901 |
e 2 8
|
alpar@1
|
3902 |
e 3 4
|
alpar@1
|
3903 |
e 3 6
|
alpar@1
|
3904 |
e 3 7
|
alpar@1
|
3905 |
e 4 5
|
alpar@1
|
3906 |
e 4 8
|
alpar@1
|
3907 |
e 5 7
|
alpar@1
|
3908 |
e 5 8
|
alpar@1
|
3909 |
e 6 7
|
alpar@1
|
3910 |
c
|
alpar@1
|
3911 |
c eof
|
alpar@1
|
3912 |
\end{verbatim}
|
alpar@1
|
3913 |
\end{footnotesize}
|
alpar@1
|
3914 |
|
alpar@1
|
3915 |
\noindent
|
alpar@1
|
3916 |
The corresponding output from the example program is the following:
|
alpar@1
|
3917 |
|
alpar@1
|
3918 |
\begin{footnotesize}
|
alpar@1
|
3919 |
\begin{verbatim}
|
alpar@1
|
3920 |
Reading graph from `sample.clq'...
|
alpar@1
|
3921 |
Graph has 8 vertices and 16 edges
|
alpar@1
|
3922 |
28 lines were read
|
alpar@1
|
3923 |
ret = 0; sol = 15
|
alpar@1
|
3924 |
vertex 1: weight = 3, flag = 0
|
alpar@1
|
3925 |
vertex 2: weight = 4, flag = 1
|
alpar@1
|
3926 |
vertex 3: weight = 8, flag = 1
|
alpar@1
|
3927 |
vertex 4: weight = 1, flag = 0
|
alpar@1
|
3928 |
vertex 5: weight = 5, flag = 0
|
alpar@1
|
3929 |
vertex 6: weight = 2, flag = 1
|
alpar@1
|
3930 |
vertex 7: weight = 1, flag = 1
|
alpar@1
|
3931 |
vertex 8: weight = 3, flag = 0
|
alpar@1
|
3932 |
\end{verbatim}
|
alpar@1
|
3933 |
\end{footnotesize}
|
alpar@1
|
3934 |
|
alpar@1
|
3935 |
\end{document}
|