alpar@1
|
1 |
%* glpk05.tex *%
|
alpar@1
|
2 |
|
alpar@1
|
3 |
\chapter{Branch-and-Cut API Routines}
|
alpar@1
|
4 |
|
alpar@1
|
5 |
\section{Introduction}
|
alpar@1
|
6 |
|
alpar@1
|
7 |
\subsection{Using the callback routine}
|
alpar@1
|
8 |
|
alpar@1
|
9 |
The GLPK MIP solver based on the branch-and-cut method allows the
|
alpar@1
|
10 |
application program to control the solution process. This is attained
|
alpar@1
|
11 |
by means of the user-defined callback routine, which is called by the
|
alpar@1
|
12 |
solver at various points of the branch-and-cut algorithm.
|
alpar@1
|
13 |
|
alpar@1
|
14 |
The callback routine passed to the MIP solver should be written by the
|
alpar@1
|
15 |
user and has the following specification:\footnote{The name
|
alpar@1
|
16 |
{\tt foo\_bar} used here is a placeholder for the callback routine
|
alpar@1
|
17 |
name.}
|
alpar@1
|
18 |
|
alpar@1
|
19 |
\begin{verbatim}
|
alpar@1
|
20 |
void foo_bar(glp_tree *tree, void *info);
|
alpar@1
|
21 |
\end{verbatim}
|
alpar@1
|
22 |
|
alpar@1
|
23 |
\noindent
|
alpar@1
|
24 |
where \verb|tree| is a pointer to the data structure \verb|glp_tree|,
|
alpar@1
|
25 |
which should be used on subsequent calls to branch-and-cut interface
|
alpar@1
|
26 |
routines, and \verb|info| is a transit pointer passed to the routine
|
alpar@1
|
27 |
\verb|glp_intopt|, which may be used by the application program to pass
|
alpar@1
|
28 |
some external data to the callback routine.
|
alpar@1
|
29 |
|
alpar@1
|
30 |
The callback routine is passed to the MIP solver through the control
|
alpar@1
|
31 |
parameter structure \verb|glp_iocp| (see Chapter ``Basic API Routines'',
|
alpar@1
|
32 |
Section ``Mixed integer programming routines'', Subsection ``Solve MIP
|
alpar@1
|
33 |
problem with the branch-and-cut method'') as follows:
|
alpar@1
|
34 |
|
alpar@1
|
35 |
\newpage
|
alpar@1
|
36 |
|
alpar@1
|
37 |
\begin{verbatim}
|
alpar@1
|
38 |
glp_prob *mip;
|
alpar@1
|
39 |
glp_iocp parm;
|
alpar@1
|
40 |
. . .
|
alpar@1
|
41 |
glp_init_iocp(&parm);
|
alpar@1
|
42 |
. . .
|
alpar@1
|
43 |
parm.cb_func = foo_bar;
|
alpar@1
|
44 |
parm.cb_info = ... ;
|
alpar@1
|
45 |
ret = glp_intopt(mip, &parm);
|
alpar@1
|
46 |
. . .
|
alpar@1
|
47 |
\end{verbatim}
|
alpar@1
|
48 |
|
alpar@1
|
49 |
To determine why it is being called by the MIP solver the callback
|
alpar@1
|
50 |
routine should use the routine \verb|glp_ios_reason| (described in this
|
alpar@1
|
51 |
section below), which returns a code indicating the reason for calling.
|
alpar@1
|
52 |
Depending on the reason the callback routine may perform necessary
|
alpar@1
|
53 |
actions to control the solution process.
|
alpar@1
|
54 |
|
alpar@1
|
55 |
The reason codes, which correspond to various point of the
|
alpar@1
|
56 |
branch-and-cut algorithm implemented in the MIP solver, are described
|
alpar@1
|
57 |
in Subsection ``Reasons for calling the callback routine'' below.
|
alpar@1
|
58 |
|
alpar@1
|
59 |
To ignore calls for reasons, which are not processed by the callback
|
alpar@1
|
60 |
routine, it should just return to the MIP solver doing nothing. For
|
alpar@1
|
61 |
example:
|
alpar@1
|
62 |
|
alpar@1
|
63 |
\begin{verbatim}
|
alpar@1
|
64 |
void foo_bar(glp_tree *tree, void *info)
|
alpar@1
|
65 |
{ . . .
|
alpar@1
|
66 |
switch (glp_ios_reason(tree))
|
alpar@1
|
67 |
{ case GLP_IBRANCH:
|
alpar@1
|
68 |
. . .
|
alpar@1
|
69 |
break;
|
alpar@1
|
70 |
case GLP_ISELECT:
|
alpar@1
|
71 |
. . .
|
alpar@1
|
72 |
break;
|
alpar@1
|
73 |
default:
|
alpar@1
|
74 |
/* ignore call for other reasons */
|
alpar@1
|
75 |
break;
|
alpar@1
|
76 |
}
|
alpar@1
|
77 |
return;
|
alpar@1
|
78 |
}
|
alpar@1
|
79 |
\end{verbatim}
|
alpar@1
|
80 |
|
alpar@1
|
81 |
To control the solution process as well as to obtain necessary
|
alpar@1
|
82 |
information the callback routine may use the branch-and-cut API
|
alpar@1
|
83 |
routines described in this chapter. Names of all these routines begin
|
alpar@1
|
84 |
with `\verb|glp_ios_|'.
|
alpar@1
|
85 |
|
alpar@1
|
86 |
\subsection{Branch-and-cut algorithm}
|
alpar@1
|
87 |
|
alpar@1
|
88 |
This section gives a schematic description of the branch-and-cut
|
alpar@1
|
89 |
algorithm as it is implemented in the GLPK MIP solver.
|
alpar@1
|
90 |
|
alpar@1
|
91 |
\medskip
|
alpar@1
|
92 |
|
alpar@1
|
93 |
{\it 1. Initialization}
|
alpar@1
|
94 |
|
alpar@1
|
95 |
Set $L:=\{P_0\}$, where $L$ is the {\it active list} (i.e. the list of
|
alpar@1
|
96 |
active subproblems), $P_0$ is the original MIP problem to be solved.
|
alpar@1
|
97 |
|
alpar@1
|
98 |
Set $z^{\it best}:=+\infty$ (in case of minimization) or
|
alpar@1
|
99 |
$z^{\it best}:=-\infty$ (in case of maximization), where $z^{\it best}$
|
alpar@1
|
100 |
is {\it incumbent value}, i.e. an upper (minimization) or lower
|
alpar@1
|
101 |
(maximization) global bound for $z^{\it opt}$, the optimal objective
|
alpar@1
|
102 |
value for $P^0$.
|
alpar@1
|
103 |
|
alpar@1
|
104 |
\medskip
|
alpar@1
|
105 |
|
alpar@1
|
106 |
{\it 2. Subproblem selection}
|
alpar@1
|
107 |
|
alpar@1
|
108 |
If $L=\varnothing$ then GO TO 9.
|
alpar@1
|
109 |
|
alpar@1
|
110 |
Select $P\in L$, i.e. make active subproblem $P$ current.
|
alpar@1
|
111 |
|
alpar@1
|
112 |
\medskip
|
alpar@1
|
113 |
|
alpar@1
|
114 |
{\it 3. Solving LP relaxation}
|
alpar@1
|
115 |
|
alpar@1
|
116 |
Solve $P^{\it LP}$, which is LP relaxation of $P$.
|
alpar@1
|
117 |
|
alpar@1
|
118 |
If $P^{\it LP}$ has no primal feasible solution then GO TO 8.
|
alpar@1
|
119 |
|
alpar@1
|
120 |
Let $z^{\it LP}$ be the optimal objective value for $P^{\it LP}$.
|
alpar@1
|
121 |
|
alpar@1
|
122 |
If $z^{\it LP}\geq z^{\it best}$ (in case of minimization) or
|
alpar@1
|
123 |
$z^{\it LP}\leq z^{\rm best}$ (in case of maximization) then GO TO 8.
|
alpar@1
|
124 |
|
alpar@1
|
125 |
\medskip
|
alpar@1
|
126 |
|
alpar@1
|
127 |
{\it 4. Adding ``lazy'' constraints}
|
alpar@1
|
128 |
|
alpar@1
|
129 |
Let $x^{\it LP}$ be the optimal solution to $P^{\it LP}$.
|
alpar@1
|
130 |
|
alpar@1
|
131 |
If there are ``lazy'' constraints (i.e. essential constraints not
|
alpar@1
|
132 |
included in the original MIP problem $P_0$), which are violated at the
|
alpar@1
|
133 |
optimal point $x^{\it LP}$, add them to $P$, and GO TO 3.
|
alpar@1
|
134 |
|
alpar@1
|
135 |
\medskip
|
alpar@1
|
136 |
|
alpar@1
|
137 |
{\it 5. Check for integrality}
|
alpar@1
|
138 |
|
alpar@1
|
139 |
Let $x_j$ be a variable, which is required to be integer, and let
|
alpar@1
|
140 |
$x^{\it LP}_j\in x^{\it LP}$ be its value in the optimal solution to
|
alpar@1
|
141 |
$P^{\it LP}$.
|
alpar@1
|
142 |
|
alpar@1
|
143 |
If $x^{\it LP}_j$ are integral for all integer variables, then a better
|
alpar@1
|
144 |
integer feasible solution is found. Store its components, set
|
alpar@1
|
145 |
$z^{\it best}:=z^{\it LP}$, and GO TO 8.
|
alpar@1
|
146 |
|
alpar@1
|
147 |
\medskip
|
alpar@1
|
148 |
|
alpar@1
|
149 |
{\it 6. Adding cutting planes}
|
alpar@1
|
150 |
|
alpar@1
|
151 |
If there are cutting planes (i.e. valid constraints for $P$),
|
alpar@1
|
152 |
which are violated at the optimal point $x^{\it LP}$, add them to $P$,
|
alpar@1
|
153 |
and GO TO 3.
|
alpar@1
|
154 |
|
alpar@1
|
155 |
\medskip
|
alpar@1
|
156 |
|
alpar@1
|
157 |
{\it 7. Branching}
|
alpar@1
|
158 |
|
alpar@1
|
159 |
Select {\it branching variable} $x_j$, i.e. a variable, which is
|
alpar@1
|
160 |
required to be integer, and whose value $x^{\it LP}_j\in x^{\it LP}$ is
|
alpar@1
|
161 |
fractional in the optimal solution to $P^{\it LP}$.
|
alpar@1
|
162 |
|
alpar@1
|
163 |
Create new subproblem $P^D$ (so called {\it down branch}), which is
|
alpar@1
|
164 |
identical to the current subproblem $P$ with exception that the upper
|
alpar@1
|
165 |
bound of $x_j$ is replaced by $\lfloor x^{\it LP}_j\rfloor$. (For
|
alpar@1
|
166 |
example, if $x^{\it LP}_j=3.14$, the new upper bound of $x_j$ in the
|
alpar@1
|
167 |
down branch will be $\lfloor 3.14\rfloor=3$.)
|
alpar@1
|
168 |
|
alpar@1
|
169 |
Create new subproblem $P^U$ (so called {\it up branch}), which is
|
alpar@1
|
170 |
identical to the current subproblem $P$ with exception that the lower
|
alpar@1
|
171 |
bound of $x_j$ is replaced by $\lceil x^{\it LP}_j\rceil$. (For example,
|
alpar@1
|
172 |
if $x^{\it LP}_j=3.14$, the new lower bound of $x_j$ in the up branch
|
alpar@1
|
173 |
will be $\lceil 3.14\rceil=4$.)
|
alpar@1
|
174 |
|
alpar@1
|
175 |
Set $L:=(L\backslash\{P\})\cup\{P^D,P^U\}$, i.e. remove the current
|
alpar@1
|
176 |
subproblem $P$ from the active list $L$ and add two new subproblems
|
alpar@1
|
177 |
$P^D$ and $P^U$ to it. Then GO TO 2.
|
alpar@1
|
178 |
|
alpar@1
|
179 |
\medskip
|
alpar@1
|
180 |
|
alpar@1
|
181 |
{\it 8. Pruning}
|
alpar@1
|
182 |
|
alpar@1
|
183 |
Remove from the active list $L$ all subproblems (including the current
|
alpar@1
|
184 |
one), whose local bound $\widetilde{z}$ is not better than the global
|
alpar@1
|
185 |
bound $z^{\it best}$, i.e. set $L:=L\backslash\{P\}$ for all $P$, where
|
alpar@1
|
186 |
$\widetilde{z}\geq z^{\it best}$ (in case of minimization) or
|
alpar@1
|
187 |
$\widetilde{z}\leq z^{\it best}$ (in case of maximization), and then
|
alpar@1
|
188 |
GO TO 2.
|
alpar@1
|
189 |
|
alpar@1
|
190 |
The local bound $\widetilde{z}$ for subproblem $P$ is an lower
|
alpar@1
|
191 |
(minimization) or upper (maximization) bound for integer optimal
|
alpar@1
|
192 |
solution to {\it this} subproblem (not to the original problem). This
|
alpar@1
|
193 |
bound is local in the sense that only subproblems in the subtree rooted
|
alpar@1
|
194 |
at node $P$ cannot have better integer feasible solutions. Note that
|
alpar@1
|
195 |
the local bound is not necessarily the optimal objective value to LP
|
alpar@1
|
196 |
relaxation $P^{\it LP}$.
|
alpar@1
|
197 |
|
alpar@1
|
198 |
\medskip
|
alpar@1
|
199 |
|
alpar@1
|
200 |
{\it 9. Termination}
|
alpar@1
|
201 |
|
alpar@1
|
202 |
If $z^{\it best}=+\infty$ (in case of minimization) or
|
alpar@1
|
203 |
$z^{\it best}=-\infty$ (in case of maximization), the original problem
|
alpar@1
|
204 |
$P_0$ has no integer feasible solution. Otherwise, the last integer
|
alpar@1
|
205 |
feasible solution stored on step 5 is the integer optimal solution to
|
alpar@1
|
206 |
the original problem $P_0$ with $z^{\it opt}=z^{\it best}$. STOP.
|
alpar@1
|
207 |
|
alpar@1
|
208 |
\subsection{The search tree}
|
alpar@1
|
209 |
|
alpar@1
|
210 |
On the branching step of the branch-and-cut algorithm the current
|
alpar@1
|
211 |
subproblem is divided into two\footnote{In more general cases the
|
alpar@1
|
212 |
current subproblem may be divided into more than two subproblems.
|
alpar@1
|
213 |
However, currently such feature is not used in GLPK.} new subproblems,
|
alpar@1
|
214 |
so the set of all subproblems can be represented in the form of a rooted
|
alpar@1
|
215 |
tree, which is called the {\it search} or {\it branch-and-bound} tree.
|
alpar@1
|
216 |
An example of the search tree is shown on Fig.~1. Each node of the
|
alpar@1
|
217 |
search tree corresponds to a subproblem, so the terms `node' and
|
alpar@1
|
218 |
`subproblem' may be used synonymously.
|
alpar@1
|
219 |
|
alpar@1
|
220 |
\newpage
|
alpar@1
|
221 |
|
alpar@1
|
222 |
\begin{figure}[t]
|
alpar@1
|
223 |
\noindent\hfil
|
alpar@1
|
224 |
\xymatrix @R=20pt @C=10pt
|
alpar@1
|
225 |
{&&&&&&*+<14pt>[o][F=]{A}\ar@{-}[dllll]\ar@{-}[dr]\ar@{-}[drrrr]&&&&\\
|
alpar@1
|
226 |
&&*+<14pt>[o][F=]{B}\ar@{-}[dl]\ar@{-}[dr]&&&&&*+<14pt>[o][F=]{C}
|
alpar@1
|
227 |
\ar@{-}[dll]\ar@{-}[dr]\ar@{-}[drrr]&&&*+<14pt>[o][F-]{\times}\\
|
alpar@1
|
228 |
&*+<14pt>[o][F-]{\times}\ar@{-}[dl]\ar@{-}[d]\ar@{-}[dr]&&
|
alpar@1
|
229 |
*+<14pt>[o][F-]{D}&&*+<14pt>[o][F=]{E}\ar@{-}[dl]\ar@{-}[dr]&&&
|
alpar@1
|
230 |
*+<14pt>[o][F=]{F}\ar@{-}[dl]\ar@{-}[dr]&&*+<14pt>[o][F-]{G}\\
|
alpar@1
|
231 |
*+<14pt>[o][F-]{\times}&*+<14pt>[o][F-]{\times}&*+<14pt>[o][F-]{\times}
|
alpar@1
|
232 |
&&*+<14pt>[][F-]{H}&&*+<14pt>[o][F-]{I}&*+<14pt>[o][F-]{\times}&&
|
alpar@1
|
233 |
*+<14pt>[o][F-]{J}&\\}
|
alpar@1
|
234 |
|
alpar@1
|
235 |
\bigskip
|
alpar@1
|
236 |
|
alpar@1
|
237 |
\noindent\hspace{.8in}
|
alpar@1
|
238 |
\xymatrix @R=11pt
|
alpar@1
|
239 |
{*+<20pt>[][F-]{}&*\txt{\makebox[1in][l]{Current}}&&
|
alpar@1
|
240 |
*+<20pt>[o][F-]{}&*\txt{\makebox[1in][l]{Active}}\\
|
alpar@1
|
241 |
*+<20pt>[o][F=]{}&*\txt{\makebox[1in][l]{Non-active}}&&
|
alpar@1
|
242 |
*+<14pt>[o][F-]{\times}&*\txt{\makebox[1in][l]{Fathomed}}\\
|
alpar@1
|
243 |
}
|
alpar@1
|
244 |
|
alpar@1
|
245 |
\begin{center}
|
alpar@1
|
246 |
Fig. 1. An example of the search tree.
|
alpar@1
|
247 |
\end{center}
|
alpar@1
|
248 |
\end{figure}
|
alpar@1
|
249 |
|
alpar@1
|
250 |
In GLPK each node may have one of the following four statuses:
|
alpar@1
|
251 |
|
alpar@1
|
252 |
$\bullet$ {\it current node} is the active node currently being
|
alpar@1
|
253 |
processed;
|
alpar@1
|
254 |
|
alpar@1
|
255 |
$\bullet$ {\it active node} is a leaf node, which still has to be
|
alpar@1
|
256 |
processed;
|
alpar@1
|
257 |
|
alpar@1
|
258 |
$\bullet$ {\it non-active node} is a node, which has been processed,
|
alpar@1
|
259 |
but not fathomed;
|
alpar@1
|
260 |
|
alpar@1
|
261 |
$\bullet$ {\it fathomed node} is a node, which has been processed and
|
alpar@1
|
262 |
fathomed.
|
alpar@1
|
263 |
|
alpar@1
|
264 |
In the data structure representing the search tree GLPK keeps only
|
alpar@1
|
265 |
current, active, and non-active nodes. Once a node has been fathomed,
|
alpar@1
|
266 |
it is removed from the tree data structure.
|
alpar@1
|
267 |
|
alpar@1
|
268 |
Being created each node of the search tree is assigned a distinct
|
alpar@1
|
269 |
positive integer called the {\it subproblem reference number}, which
|
alpar@1
|
270 |
may be used by the application program to specify a particular node of
|
alpar@1
|
271 |
the tree. The root node corresponding to the original problem to be
|
alpar@1
|
272 |
solved is always assigned the reference number 1.
|
alpar@1
|
273 |
|
alpar@1
|
274 |
\subsection{Current subproblem}
|
alpar@1
|
275 |
|
alpar@1
|
276 |
The current subproblem is a MIP problem corresponding to the current
|
alpar@1
|
277 |
node of the search tree. It is represented as the GLPK problem object
|
alpar@1
|
278 |
(\verb|glp_prob|) that allows the application program using API routines
|
alpar@1
|
279 |
to access its content in the standard way. If the MIP presolver is not
|
alpar@1
|
280 |
used, it is the original problem object passed to the routine
|
alpar@1
|
281 |
\verb|glp_intopt|; otherwise, it is an internal problem object built by
|
alpar@1
|
282 |
the MIP presolver.
|
alpar@1
|
283 |
|
alpar@1
|
284 |
Note that the problem object is used by the MIP solver itself during
|
alpar@1
|
285 |
the solution process for various purposes (to solve LP relaxations, to
|
alpar@1
|
286 |
perfom branching, etc.), and even if the MIP presolver is not used, the
|
alpar@1
|
287 |
current content of the problem object may differ from its original
|
alpar@1
|
288 |
content. For example, it may have additional rows, bounds of some rows
|
alpar@1
|
289 |
and columns may be changed, etc. In particular, LP segment of the
|
alpar@1
|
290 |
problem object corresponds to LP relaxation of the current subproblem.
|
alpar@1
|
291 |
However, on exit from the MIP solver the content of the problem object
|
alpar@1
|
292 |
is restored to its original state.
|
alpar@1
|
293 |
|
alpar@1
|
294 |
To obtain information from the problem object the application program
|
alpar@1
|
295 |
may use any API routines, which do not change the object. Using API
|
alpar@1
|
296 |
routines, which change the problem object, is restricted to stipulated
|
alpar@1
|
297 |
cases.
|
alpar@1
|
298 |
|
alpar@1
|
299 |
\subsection{The cut pool}
|
alpar@1
|
300 |
|
alpar@1
|
301 |
The {\it cut pool} is a set of cutting plane constraints maintained by
|
alpar@1
|
302 |
the MIP solver. It is used by the GLPK cut generation routines and may
|
alpar@1
|
303 |
be used by the application program in the same way, i.e. rather than
|
alpar@1
|
304 |
to add cutting plane constraints directly to the problem object the
|
alpar@1
|
305 |
application program may store them to the cut pool. In the latter case
|
alpar@1
|
306 |
the solver looks through the cut pool, selects efficient constraints,
|
alpar@1
|
307 |
and adds them to the problem object.
|
alpar@1
|
308 |
|
alpar@1
|
309 |
\subsection{Reasons for calling the callback routine}
|
alpar@1
|
310 |
|
alpar@1
|
311 |
The callback routine may be called by the MIP solver for the following
|
alpar@1
|
312 |
reasons.
|
alpar@1
|
313 |
|
alpar@1
|
314 |
\subsubsection*{Request for subproblem selection}
|
alpar@1
|
315 |
|
alpar@1
|
316 |
The callback routine is called with the reason code \verb|GLP_ISELECT|
|
alpar@1
|
317 |
if the current subproblem has been fathomed and therefore there is no
|
alpar@1
|
318 |
current subproblem.
|
alpar@1
|
319 |
|
alpar@1
|
320 |
In response the callback routine may select some subproblem from the
|
alpar@1
|
321 |
active list and pass its reference number to the solver using the
|
alpar@1
|
322 |
routine \verb|glp_ios_select_node|, in which case the solver continues
|
alpar@1
|
323 |
the search from the specified active subproblem. If no selection is made
|
alpar@1
|
324 |
by the callback routine, the solver uses a backtracking technique
|
alpar@1
|
325 |
specified by the control parameter \verb|bt_tech|.
|
alpar@1
|
326 |
|
alpar@1
|
327 |
To explore the active list (i.e. active nodes of the branch-and-bound
|
alpar@1
|
328 |
tree) the callback routine may use the routines \verb|glp_ios_next_node|
|
alpar@1
|
329 |
and \verb|glp_ios_prev_node|.
|
alpar@1
|
330 |
|
alpar@1
|
331 |
\subsubsection*{Request for preprocessing}
|
alpar@1
|
332 |
|
alpar@1
|
333 |
The callback routine is called with the reason code \verb|GLP_IPREPRO|
|
alpar@1
|
334 |
if the current subproblem has just been selected from the active list
|
alpar@1
|
335 |
and its LP relaxation is not solved yet.
|
alpar@1
|
336 |
|
alpar@1
|
337 |
In response the callback routine may perform some preprocessing of the
|
alpar@1
|
338 |
current subproblem like tightening bounds of some variables or removing
|
alpar@1
|
339 |
bounds of some redundant constraints.
|
alpar@1
|
340 |
|
alpar@1
|
341 |
\subsubsection*{Request for row generation}
|
alpar@1
|
342 |
|
alpar@1
|
343 |
The callback routine is called with the reason code \verb|GLP_IROWGEN|
|
alpar@1
|
344 |
if LP relaxation of the current subproblem has just been solved to
|
alpar@1
|
345 |
optimality and its objective value is better than the best known integer
|
alpar@1
|
346 |
feasible solution.
|
alpar@1
|
347 |
|
alpar@1
|
348 |
In response the callback routine may add one or more ``lazy''
|
alpar@1
|
349 |
constraints (rows), which are violated by the current optimal solution
|
alpar@1
|
350 |
of LP relaxation, using API routines \verb|glp_add_rows|,
|
alpar@1
|
351 |
\verb|glp_set_row_name|, \verb|glp_set_row_bnds|, and
|
alpar@1
|
352 |
\verb|glp_set_mat_row|, in which case the solver will perform
|
alpar@1
|
353 |
re-optimization of LP relaxation. If there are no violated constraints,
|
alpar@1
|
354 |
the callback routine should just return.
|
alpar@1
|
355 |
|
alpar@1
|
356 |
Optimal solution components for LP relaxation can be obtained with API
|
alpar@1
|
357 |
routines \verb|glp_get_obj_val|, \verb|glp_get_row_prim|,
|
alpar@1
|
358 |
\verb|glp_get_row_dual|, \verb|glp_get_col_prim|, and
|
alpar@1
|
359 |
\verb|glp_get_col_dual|.
|
alpar@1
|
360 |
|
alpar@1
|
361 |
\subsubsection*{Request for heuristic solution}
|
alpar@1
|
362 |
|
alpar@1
|
363 |
The callback routine is called with the reason code \verb|GLP_IHEUR|
|
alpar@1
|
364 |
if LP relaxation of the current subproblem being solved to optimality
|
alpar@1
|
365 |
is integer infeasible (i.e. values of some structural variables of
|
alpar@1
|
366 |
integer kind are fractional), though its objective value is better than
|
alpar@1
|
367 |
the best known integer feasible solution.
|
alpar@1
|
368 |
|
alpar@1
|
369 |
In response the callback routine may try applying a primal heuristic
|
alpar@1
|
370 |
to find an integer feasible solution,\footnote{Integer feasible to the
|
alpar@1
|
371 |
original MIP problem, not to the current subproblem.} which is better
|
alpar@1
|
372 |
than the best known one. In case of success the callback routine may
|
alpar@1
|
373 |
store such better solution in the problem object using the routine
|
alpar@1
|
374 |
\verb|glp_ios_heur_sol|.
|
alpar@1
|
375 |
|
alpar@1
|
376 |
\subsubsection*{Request for cut generation}
|
alpar@1
|
377 |
|
alpar@1
|
378 |
The callback routine is called with the reason code \verb|GLP_ICUTGEN|
|
alpar@1
|
379 |
if LP relaxation of the current subproblem being solved to optimality
|
alpar@1
|
380 |
is integer infeasible (i.e. values of some structural variables of
|
alpar@1
|
381 |
integer kind are fractional), though its objective value is better than
|
alpar@1
|
382 |
the best known integer feasible solution.
|
alpar@1
|
383 |
|
alpar@1
|
384 |
In response the callback routine may reformulate the {\it current}
|
alpar@1
|
385 |
subproblem (before it will be splitted up due to branching) by adding to
|
alpar@1
|
386 |
the problem object one or more {\it cutting plane constraints}, which
|
alpar@1
|
387 |
cut off the fractional optimal point from the MIP
|
alpar@1
|
388 |
polytope.\footnote{Since these constraints are added to the current
|
alpar@1
|
389 |
subproblem, they may be globally as well as locally valid.}
|
alpar@1
|
390 |
|
alpar@1
|
391 |
Adding cutting plane constraints may be performed in two ways.
|
alpar@1
|
392 |
One way is the same as for the reason code \verb|GLP_IROWGEN| (see
|
alpar@1
|
393 |
above), in which case the callback routine adds new rows corresponding
|
alpar@1
|
394 |
to cutting plane constraints directly to the current subproblem.
|
alpar@1
|
395 |
|
alpar@1
|
396 |
The other way is to add cutting plane constraints to the {\it cut pool},
|
alpar@1
|
397 |
a set of cutting plane constraints maintained by the solver, rather than
|
alpar@1
|
398 |
directly to the current subproblem. In this case after return from the
|
alpar@1
|
399 |
callback routine the solver looks through the cut pool, selects
|
alpar@1
|
400 |
efficient cutting plane constraints, adds them to the current
|
alpar@1
|
401 |
subproblem, drops other constraints, and then performs re-optimization.
|
alpar@1
|
402 |
|
alpar@1
|
403 |
\subsubsection*{Request for branching}
|
alpar@1
|
404 |
|
alpar@1
|
405 |
The callback routine is called with the reason code \verb|GLP_IBRANCH|
|
alpar@1
|
406 |
if LP relaxation of the current subproblem being solved to optimality
|
alpar@1
|
407 |
is integer infeasible (i.e. values of some structural variables of
|
alpar@1
|
408 |
integer kind are fractional), though its objective value is better than
|
alpar@1
|
409 |
the best known integer feasible solution.
|
alpar@1
|
410 |
|
alpar@1
|
411 |
In response the callback routine may choose some variable suitable for
|
alpar@1
|
412 |
branching (i.e. integer variable, whose value in optimal solution to
|
alpar@1
|
413 |
LP relaxation of the current subproblem is fractional) and pass its
|
alpar@1
|
414 |
ordinal number to the solver using the routine
|
alpar@1
|
415 |
\verb|glp_ios_branch_upon|, in which case the solver splits the current
|
alpar@1
|
416 |
subproblem in two new subproblems and continues the search. If no choice
|
alpar@1
|
417 |
is made by the callback routine, the solver uses a branching technique
|
alpar@1
|
418 |
specified by the control parameter \verb|br_tech|.
|
alpar@1
|
419 |
|
alpar@1
|
420 |
\subsubsection*{Better integer solution found}
|
alpar@1
|
421 |
|
alpar@1
|
422 |
The callback routine is called with the reason code \verb|GLP_IBINGO|
|
alpar@1
|
423 |
if LP relaxation of the current subproblem being solved to optimality
|
alpar@1
|
424 |
is integer feasible (i.e. values of all structural variables of integer
|
alpar@1
|
425 |
kind are integral within the working precision) and its objective value
|
alpar@1
|
426 |
is better than the best known integer feasible solution.
|
alpar@1
|
427 |
|
alpar@1
|
428 |
Optimal solution components for LP relaxation can be obtained in the
|
alpar@1
|
429 |
same way as for the reason code \verb|GLP_IROWGEN| (see above).
|
alpar@1
|
430 |
|
alpar@1
|
431 |
Components of the new MIP solution can be obtained with API routines
|
alpar@1
|
432 |
\verb|glp_mip_obj_val|, \verb|glp_mip_row_val|, and
|
alpar@1
|
433 |
\verb|glp_mip_col_val|. Note, however, that due to row/cut generation
|
alpar@1
|
434 |
there may be additional rows in the problem object.
|
alpar@1
|
435 |
|
alpar@1
|
436 |
The difference between optimal solution to LP relaxation and
|
alpar@1
|
437 |
corresponding MIP solution is that in the former case some structural
|
alpar@1
|
438 |
variables of integer kind (namely, basic variables) may have values,
|
alpar@1
|
439 |
which are close to nearest integers within the working precision, while
|
alpar@1
|
440 |
in the latter case all such variables have exact integral values.
|
alpar@1
|
441 |
|
alpar@1
|
442 |
The reason \verb|GLP_IBINGO| is intended only for informational
|
alpar@1
|
443 |
purposes, so the callback routine should not modify the problem object
|
alpar@1
|
444 |
in this case.
|
alpar@1
|
445 |
|
alpar@1
|
446 |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
alpar@1
|
447 |
|
alpar@1
|
448 |
\newpage
|
alpar@1
|
449 |
|
alpar@1
|
450 |
\section{Basic routines}
|
alpar@1
|
451 |
|
alpar@1
|
452 |
\subsection{glp\_ios\_reason---determine reason for calling the
|
alpar@1
|
453 |
callback routine}
|
alpar@1
|
454 |
|
alpar@1
|
455 |
\subsubsection*{Synopsis}
|
alpar@1
|
456 |
|
alpar@1
|
457 |
\begin{verbatim}
|
alpar@1
|
458 |
int glp_ios_reason(glp_tree *tree);
|
alpar@1
|
459 |
\end{verbatim}
|
alpar@1
|
460 |
|
alpar@1
|
461 |
\subsubsection*{Returns}
|
alpar@1
|
462 |
|
alpar@1
|
463 |
The routine \verb|glp_ios_reason| returns a code, which indicates why
|
alpar@1
|
464 |
the user-defined callback routine is being called:
|
alpar@1
|
465 |
|
alpar@1
|
466 |
\verb|GLP_ISELECT|---request for subproblem selection;
|
alpar@1
|
467 |
|
alpar@1
|
468 |
\verb|GLP_IPREPRO|---request for preprocessing;
|
alpar@1
|
469 |
|
alpar@1
|
470 |
\verb|GLP_IROWGEN|---request for row generation;
|
alpar@1
|
471 |
|
alpar@1
|
472 |
\verb|GLP_IHEUR |---request for heuristic solution;
|
alpar@1
|
473 |
|
alpar@1
|
474 |
\verb|GLP_ICUTGEN|---request for cut generation;
|
alpar@1
|
475 |
|
alpar@1
|
476 |
\verb|GLP_IBRANCH|---request for branching;
|
alpar@1
|
477 |
|
alpar@1
|
478 |
\verb|GLP_IBINGO |---better integer solution found.
|
alpar@1
|
479 |
|
alpar@1
|
480 |
\subsection{glp\_ios\_get\_prob---access the problem object}
|
alpar@1
|
481 |
|
alpar@1
|
482 |
\subsubsection*{Synopsis}
|
alpar@1
|
483 |
|
alpar@1
|
484 |
\begin{verbatim}
|
alpar@1
|
485 |
glp_prob *glp_ios_get_prob(glp_tree *tree);
|
alpar@1
|
486 |
\end{verbatim}
|
alpar@1
|
487 |
|
alpar@1
|
488 |
\subsubsection*{Description}
|
alpar@1
|
489 |
|
alpar@1
|
490 |
The routine \verb|glp_ios_get_prob| can be called from the user-defined
|
alpar@1
|
491 |
callback routine to access the problem object, which is used by the MIP
|
alpar@1
|
492 |
solver. It is the original problem object passed to the routine
|
alpar@1
|
493 |
\verb|glp_intopt| if the MIP presolver is not used; otherwise it is an
|
alpar@1
|
494 |
internal problem object built by the presolver.
|
alpar@1
|
495 |
|
alpar@1
|
496 |
\subsubsection*{Returns}
|
alpar@1
|
497 |
|
alpar@1
|
498 |
The routine \verb|glp_ios_get_prob| returns a pointer to the problem
|
alpar@1
|
499 |
object used by the MIP solver.
|
alpar@1
|
500 |
|
alpar@1
|
501 |
\subsubsection*{Comments}
|
alpar@1
|
502 |
|
alpar@1
|
503 |
To obtain various information about the problem instance the callback
|
alpar@1
|
504 |
routine can access the problem object (i.e. the object of type
|
alpar@1
|
505 |
\verb|glp_prob|) using the routine \verb|glp_ios_get_prob|. It is the
|
alpar@1
|
506 |
original problem object passed to the routine \verb|glp_intopt| if the
|
alpar@1
|
507 |
MIP presolver is not used; otherwise it is an internal problem object
|
alpar@1
|
508 |
built by the presolver.
|
alpar@1
|
509 |
|
alpar@1
|
510 |
\subsection{glp\_ios\_row\_attr---determine additional row attributes}
|
alpar@1
|
511 |
|
alpar@1
|
512 |
\subsubsection*{Synopsis}
|
alpar@1
|
513 |
|
alpar@1
|
514 |
\begin{verbatim}
|
alpar@1
|
515 |
void glp_ios_row_attr(glp_tree *tree, int i, glp_attr *attr);
|
alpar@1
|
516 |
\end{verbatim}
|
alpar@1
|
517 |
|
alpar@1
|
518 |
\subsubsection*{Description}
|
alpar@1
|
519 |
|
alpar@1
|
520 |
The routine \verb|glp_ios_row_attr| retrieves additional attributes of
|
alpar@1
|
521 |
$i$-th row of the current subproblem and stores them in the structure
|
alpar@1
|
522 |
\verb|glp_attr|, which the parameter \verb|attr| points to.
|
alpar@1
|
523 |
|
alpar@1
|
524 |
The structure \verb|glp_attr| has the following fields:
|
alpar@1
|
525 |
|
alpar@1
|
526 |
\medskip
|
alpar@1
|
527 |
|
alpar@1
|
528 |
\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
|
alpar@1
|
529 |
\multicolumn{2}{@{}l}{{\tt int level}}\\
|
alpar@1
|
530 |
&Subproblem level at which the row was created. (If \verb|level| = 0,
|
alpar@1
|
531 |
the row was added either to the original problem object passed to the
|
alpar@1
|
532 |
routine \verb|glp_intopt| or to the root subproblem on generating
|
alpar@1
|
533 |
``lazy'' or/and cutting plane constraints.)\\
|
alpar@1
|
534 |
\end{tabular}
|
alpar@1
|
535 |
|
alpar@1
|
536 |
\medskip
|
alpar@1
|
537 |
|
alpar@1
|
538 |
\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
|
alpar@1
|
539 |
\multicolumn{2}{@{}l}{{\tt int origin}}\\
|
alpar@1
|
540 |
&The row origin flag:\\
|
alpar@1
|
541 |
&\verb|GLP_RF_REG |---regular constraint;\\
|
alpar@1
|
542 |
&\verb|GLP_RF_LAZY|---``lazy'' constraint;\\
|
alpar@1
|
543 |
&\verb|GLP_RF_CUT |---cutting plane constraint.\\
|
alpar@1
|
544 |
\end{tabular}
|
alpar@1
|
545 |
|
alpar@1
|
546 |
\medskip
|
alpar@1
|
547 |
|
alpar@1
|
548 |
\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
|
alpar@1
|
549 |
\multicolumn{2}{@{}l}{{\tt int klass}}\\
|
alpar@1
|
550 |
&The row class descriptor, which is a number passed to the routine
|
alpar@1
|
551 |
\verb|glp_ios_add_row| as its third parameter. If the row is a cutting
|
alpar@1
|
552 |
plane constraint generated by the solver, its class may be the
|
alpar@1
|
553 |
following:\\
|
alpar@1
|
554 |
&\verb|GLP_RF_GMI |---Gomory's mixed integer cut;\\
|
alpar@1
|
555 |
&\verb|GLP_RF_MIR |---mixed integer rounding cut;\\
|
alpar@1
|
556 |
&\verb|GLP_RF_COV |---mixed cover cut;\\
|
alpar@1
|
557 |
&\verb|GLP_RF_CLQ |---clique cut.\\
|
alpar@1
|
558 |
\end{tabular}
|
alpar@1
|
559 |
|
alpar@1
|
560 |
\newpage
|
alpar@1
|
561 |
|
alpar@1
|
562 |
\subsection{glp\_ios\_mip\_gap---compute relative MIP gap}
|
alpar@1
|
563 |
|
alpar@1
|
564 |
\subsubsection*{Synopsis}
|
alpar@1
|
565 |
|
alpar@1
|
566 |
\begin{verbatim}
|
alpar@1
|
567 |
double glp_ios_mip_gap(glp_tree *tree);
|
alpar@1
|
568 |
\end{verbatim}
|
alpar@1
|
569 |
|
alpar@1
|
570 |
\subsubsection*{Description}
|
alpar@1
|
571 |
|
alpar@1
|
572 |
The routine \verb|glp_ios_mip_gap| computes the relative MIP gap (also
|
alpar@1
|
573 |
called {\it duality gap}) with the following formula:
|
alpar@1
|
574 |
$${\tt gap} = \frac{|{\tt best\_mip} - {\tt best\_bnd}|}
|
alpar@1
|
575 |
{|{\tt best\_mip}| + {\tt DBL\_EPSILON}}$$
|
alpar@1
|
576 |
where \verb|best_mip| is the best integer feasible solution found so
|
alpar@1
|
577 |
far, \verb|best_bnd| is the best (global) bound. If no integer feasible
|
alpar@1
|
578 |
solution has been found yet, \verb|gap| is set to \verb|DBL_MAX|.
|
alpar@1
|
579 |
|
alpar@1
|
580 |
\subsubsection*{Returns}
|
alpar@1
|
581 |
|
alpar@1
|
582 |
The routine \verb|glp_ios_mip_gap| returns the relative MIP gap.
|
alpar@1
|
583 |
|
alpar@1
|
584 |
\subsubsection*{Comments}
|
alpar@1
|
585 |
|
alpar@1
|
586 |
The relative MIP gap is used to measure the quality of the best integer
|
alpar@1
|
587 |
feasible solution found so far, because the optimal solution value
|
alpar@1
|
588 |
$z^*$ for the original MIP problem always lies in the range
|
alpar@1
|
589 |
$${\tt best\_bnd}\leq z^*\leq{\tt best\_mip}$$
|
alpar@1
|
590 |
in case of minimization, or in the range
|
alpar@1
|
591 |
$${\tt best\_mip}\leq z^*\leq{\tt best\_bnd}$$
|
alpar@1
|
592 |
in case of maximization.
|
alpar@1
|
593 |
|
alpar@1
|
594 |
To express the relative MIP gap in percents the value returned by the
|
alpar@1
|
595 |
routine \verb|glp_ios_mip_gap| should be multiplied by 100\%.
|
alpar@1
|
596 |
|
alpar@1
|
597 |
\newpage
|
alpar@1
|
598 |
|
alpar@1
|
599 |
\subsection{glp\_ios\_node\_data---access application-specific data}
|
alpar@1
|
600 |
|
alpar@1
|
601 |
\subsubsection*{Synopsis}
|
alpar@1
|
602 |
|
alpar@1
|
603 |
\begin{verbatim}
|
alpar@1
|
604 |
void *glp_ios_node_data(glp_tree *tree, int p);
|
alpar@1
|
605 |
\end{verbatim}
|
alpar@1
|
606 |
|
alpar@1
|
607 |
\subsubsection*{Description}
|
alpar@1
|
608 |
|
alpar@1
|
609 |
The routine \verb|glp_ios_node_data| allows the application accessing a
|
alpar@1
|
610 |
memory block allocated for the subproblem (which may be active or
|
alpar@1
|
611 |
inactive), whose reference number is $p$.
|
alpar@1
|
612 |
|
alpar@1
|
613 |
The size of the block is defined by the control parameter \verb|cb_size|
|
alpar@1
|
614 |
passed to the routine \verb|glp_intopt|. The block is initialized by
|
alpar@1
|
615 |
binary zeros on creating corresponding subproblem, and its contents is
|
alpar@1
|
616 |
kept until the subproblem will be removed from the tree.
|
alpar@1
|
617 |
|
alpar@1
|
618 |
The application may use these memory blocks to store specific data for
|
alpar@1
|
619 |
each subproblem.
|
alpar@1
|
620 |
|
alpar@1
|
621 |
\subsubsection*{Returns}
|
alpar@1
|
622 |
|
alpar@1
|
623 |
The routine \verb|glp_ios_node_data| returns a pointer to the memory
|
alpar@1
|
624 |
block for the specified subproblem. Note that if \verb|cb_size| = 0, the
|
alpar@1
|
625 |
routine returns a null pointer.
|
alpar@1
|
626 |
|
alpar@1
|
627 |
\subsection{glp\_ios\_select\_node---select subproblem to continue the
|
alpar@1
|
628 |
search}
|
alpar@1
|
629 |
|
alpar@1
|
630 |
\subsubsection*{Synopsis}
|
alpar@1
|
631 |
|
alpar@1
|
632 |
\begin{verbatim}
|
alpar@1
|
633 |
void glp_ios_select_node(glp_tree *tree, int p);
|
alpar@1
|
634 |
\end{verbatim}
|
alpar@1
|
635 |
|
alpar@1
|
636 |
\subsubsection*{Description}
|
alpar@1
|
637 |
|
alpar@1
|
638 |
The routine \verb|glp_ios_select_node| can be called from the
|
alpar@1
|
639 |
user-defined callback routine in response to the reason
|
alpar@1
|
640 |
\verb|GLP_ISELECT| to select an active subproblem, whose reference
|
alpar@1
|
641 |
number is $p$. The search will be continued from the subproblem
|
alpar@1
|
642 |
selected.
|
alpar@1
|
643 |
|
alpar@1
|
644 |
\newpage
|
alpar@1
|
645 |
|
alpar@1
|
646 |
\subsection{glp\_ios\_heur\_sol---provide solution found by heuristic}
|
alpar@1
|
647 |
|
alpar@1
|
648 |
\subsubsection*{Synopsis}
|
alpar@1
|
649 |
|
alpar@1
|
650 |
\begin{verbatim}
|
alpar@1
|
651 |
int glp_ios_heur_sol(glp_tree *tree, const double x[]);
|
alpar@1
|
652 |
\end{verbatim}
|
alpar@1
|
653 |
|
alpar@1
|
654 |
\subsubsection*{Description}
|
alpar@1
|
655 |
|
alpar@1
|
656 |
The routine \verb|glp_ios_heur_sol| can be called from the user-defined
|
alpar@1
|
657 |
callback routine in response to the reason \verb|GLP_IHEUR| to provide
|
alpar@1
|
658 |
an integer feasible solution found by a primal heuristic.
|
alpar@1
|
659 |
|
alpar@1
|
660 |
Primal values of {\it all} variables (columns) found by the heuristic
|
alpar@1
|
661 |
should be placed in locations $x[1]$, \dots, $x[n]$, where $n$ is the
|
alpar@1
|
662 |
number of columns in the original problem object. Note that the routine
|
alpar@1
|
663 |
\verb|glp_ios_heur_sol| does {\it not} check primal feasibility of the
|
alpar@1
|
664 |
solution provided.
|
alpar@1
|
665 |
|
alpar@1
|
666 |
Using the solution passed in the array $x$ the routine computes value
|
alpar@1
|
667 |
of the objective function. If the objective value is better than the
|
alpar@1
|
668 |
best known integer feasible solution, the routine computes values of
|
alpar@1
|
669 |
auxiliary variables (rows) and stores all solution components in the
|
alpar@1
|
670 |
problem object.
|
alpar@1
|
671 |
|
alpar@1
|
672 |
\subsubsection*{Returns}
|
alpar@1
|
673 |
|
alpar@1
|
674 |
If the provided solution is accepted, the routine
|
alpar@1
|
675 |
\verb|glp_ios_heur_sol| returns zero. Otherwise, if the provided
|
alpar@1
|
676 |
solution is rejected, the routine returns non-zero.
|
alpar@1
|
677 |
|
alpar@1
|
678 |
\subsection{glp\_ios\_can\_branch---check if can branch upon specified
|
alpar@1
|
679 |
variable}
|
alpar@1
|
680 |
|
alpar@1
|
681 |
\subsubsection*{Synopsis}
|
alpar@1
|
682 |
|
alpar@1
|
683 |
\begin{verbatim}
|
alpar@1
|
684 |
int glp_ios_can_branch(glp_tree *tree, int j);
|
alpar@1
|
685 |
\end{verbatim}
|
alpar@1
|
686 |
|
alpar@1
|
687 |
\subsubsection*{Returns}
|
alpar@1
|
688 |
|
alpar@1
|
689 |
If $j$-th variable (column) can be used to branch upon, the routine
|
alpar@1
|
690 |
returns non-zero, otherwise zero.
|
alpar@1
|
691 |
|
alpar@1
|
692 |
\newpage
|
alpar@1
|
693 |
|
alpar@1
|
694 |
\subsection{glp\_ios\_branch\_upon---choose variable to branch upon}
|
alpar@1
|
695 |
|
alpar@1
|
696 |
\subsubsection*{Synopsis}
|
alpar@1
|
697 |
|
alpar@1
|
698 |
\begin{verbatim}
|
alpar@1
|
699 |
void glp_ios_branch_upon(glp_tree *tree, int j, int sel);
|
alpar@1
|
700 |
\end{verbatim}
|
alpar@1
|
701 |
|
alpar@1
|
702 |
\subsubsection*{Description}
|
alpar@1
|
703 |
|
alpar@1
|
704 |
The routine \verb|glp_ios_branch_upon| can be called from the
|
alpar@1
|
705 |
user-defined callback routine in response to the reason
|
alpar@1
|
706 |
\verb|GLP_IBRANCH| to choose a branching variable, whose ordinal number
|
alpar@1
|
707 |
is $j$. Should note that only variables, for which the routine
|
alpar@1
|
708 |
\verb|glp_ios_can_branch| returns non-zero, can be used to branch upon.
|
alpar@1
|
709 |
|
alpar@1
|
710 |
The parameter \verb|sel| is a flag that indicates which branch
|
alpar@1
|
711 |
(subproblem) should be selected next to continue the search:
|
alpar@1
|
712 |
|
alpar@1
|
713 |
\verb|GLP_DN_BRNCH|---select down-branch;
|
alpar@1
|
714 |
|
alpar@1
|
715 |
\verb|GLP_UP_BRNCH|---select up-branch;
|
alpar@1
|
716 |
|
alpar@1
|
717 |
\verb|GLP_NO_BRNCH|---use general selection technique.
|
alpar@1
|
718 |
|
alpar@1
|
719 |
\subsubsection*{Comments}
|
alpar@1
|
720 |
|
alpar@1
|
721 |
On branching the solver removes the current active subproblem from the
|
alpar@1
|
722 |
active list and creates two new subproblems ({\it down-} and {\it
|
alpar@1
|
723 |
up-branches}), which are added to the end of the active list. Note that
|
alpar@1
|
724 |
the down-branch is created before the up-branch, so the last active
|
alpar@1
|
725 |
subproblem will be the up-branch.
|
alpar@1
|
726 |
|
alpar@1
|
727 |
The down- and up-branches are identical to the current subproblem with
|
alpar@1
|
728 |
exception that in the down-branch the upper bound of $x_j$, the variable
|
alpar@1
|
729 |
chosen to branch upon, is replaced by $\lfloor x_j^*\rfloor$, while in
|
alpar@1
|
730 |
the up-branch the lower bound of $x_j$ is replaced by
|
alpar@1
|
731 |
$\lceil x_j^*\rceil$, where $x_j^*$ is the value of $x_j$ in optimal
|
alpar@1
|
732 |
solution to LP relaxation of the current subproblem. For example, if
|
alpar@1
|
733 |
$x_j^*=3.14$, the new upper bound of $x_j$ in the down-branch is
|
alpar@1
|
734 |
$\lfloor 3.14\rfloor=3$, and the new lower bound in the up-branch is
|
alpar@1
|
735 |
$\lceil 3.14\rceil=4$.)
|
alpar@1
|
736 |
|
alpar@1
|
737 |
Additionally the callback routine may select either down- or up-branch,
|
alpar@1
|
738 |
from which the solver will continue the search. If none of the branches
|
alpar@1
|
739 |
is selected, a general selection technique will be used.
|
alpar@1
|
740 |
|
alpar@1
|
741 |
\newpage
|
alpar@1
|
742 |
|
alpar@1
|
743 |
\subsection{glp\_ios\_terminate---terminate the solution process}
|
alpar@1
|
744 |
|
alpar@1
|
745 |
\subsubsection*{Synopsis}
|
alpar@1
|
746 |
|
alpar@1
|
747 |
\begin{verbatim}
|
alpar@1
|
748 |
void glp_ios_terminate(glp_tree *tree);
|
alpar@1
|
749 |
\end{verbatim}
|
alpar@1
|
750 |
|
alpar@1
|
751 |
\subsubsection*{Description}
|
alpar@1
|
752 |
|
alpar@1
|
753 |
The routine \verb|glp_ios_terminate| sets a flag indicating that the
|
alpar@1
|
754 |
MIP solver should prematurely terminate the search.
|
alpar@1
|
755 |
|
alpar@1
|
756 |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
alpar@1
|
757 |
|
alpar@1
|
758 |
\newpage
|
alpar@1
|
759 |
|
alpar@1
|
760 |
\section{The search tree exploring routines}
|
alpar@1
|
761 |
|
alpar@1
|
762 |
\subsection{glp\_ios\_tree\_size---determine size of the search tree}
|
alpar@1
|
763 |
|
alpar@1
|
764 |
\subsubsection*{Synopsis}
|
alpar@1
|
765 |
|
alpar@1
|
766 |
\begin{verbatim}
|
alpar@1
|
767 |
void glp_ios_tree_size(glp_tree *tree, int *a_cnt, int *n_cnt,
|
alpar@1
|
768 |
int *t_cnt);
|
alpar@1
|
769 |
\end{verbatim}
|
alpar@1
|
770 |
|
alpar@1
|
771 |
\subsubsection*{Description}
|
alpar@1
|
772 |
|
alpar@1
|
773 |
The routine \verb|glp_ios_tree_size| stores the following three counts
|
alpar@1
|
774 |
which characterize the current size of the search tree:
|
alpar@1
|
775 |
|
alpar@1
|
776 |
\verb|a_cnt| is the current number of active nodes, i.e. the current
|
alpar@1
|
777 |
size of the active list;
|
alpar@1
|
778 |
|
alpar@1
|
779 |
\verb|n_cnt| is the current number of all (active and inactive) nodes;
|
alpar@1
|
780 |
|
alpar@1
|
781 |
\verb|t_cnt| is the total number of nodes including those which have
|
alpar@1
|
782 |
been already removed from the tree. This count is increased whenever
|
alpar@1
|
783 |
a new node appears in the tree and never decreased.
|
alpar@1
|
784 |
|
alpar@1
|
785 |
If some of the parameters \verb|a_cnt|, \verb|n_cnt|, \verb|t_cnt| is
|
alpar@1
|
786 |
a null pointer, the corresponding count is not stored.
|
alpar@1
|
787 |
|
alpar@1
|
788 |
\subsection{glp\_ios\_curr\_node---determine current active subprob-\\
|
alpar@1
|
789 |
lem}
|
alpar@1
|
790 |
|
alpar@1
|
791 |
\subsubsection*{Synopsis}
|
alpar@1
|
792 |
|
alpar@1
|
793 |
\begin{verbatim}
|
alpar@1
|
794 |
int glp_ios_curr_node(glp_tree *tree);
|
alpar@1
|
795 |
\end{verbatim}
|
alpar@1
|
796 |
|
alpar@1
|
797 |
\subsubsection*{Returns}
|
alpar@1
|
798 |
|
alpar@1
|
799 |
The routine \verb|glp_ios_curr_node| returns the reference number of the
|
alpar@1
|
800 |
current active subproblem. However, if the current subproblem does not
|
alpar@1
|
801 |
exist, the routine returns zero.
|
alpar@1
|
802 |
|
alpar@1
|
803 |
\newpage
|
alpar@1
|
804 |
|
alpar@1
|
805 |
\subsection{glp\_ios\_next\_node---determine next active subproblem}
|
alpar@1
|
806 |
|
alpar@1
|
807 |
\subsubsection*{Synopsis}
|
alpar@1
|
808 |
|
alpar@1
|
809 |
\begin{verbatim}
|
alpar@1
|
810 |
int glp_ios_next_node(glp_tree *tree, int p);
|
alpar@1
|
811 |
\end{verbatim}
|
alpar@1
|
812 |
|
alpar@1
|
813 |
\subsubsection*{Returns}
|
alpar@1
|
814 |
|
alpar@1
|
815 |
If the parameter $p$ is zero, the routine \verb|glp_ios_next_node|
|
alpar@1
|
816 |
returns the reference number of the first active subproblem. However,
|
alpar@1
|
817 |
if the tree is empty, zero is returned.
|
alpar@1
|
818 |
|
alpar@1
|
819 |
If the parameter $p$ is not zero, it must specify the reference number
|
alpar@1
|
820 |
of some active subproblem, in which case the routine returns the
|
alpar@1
|
821 |
reference number of the next active subproblem. However, if there is
|
alpar@1
|
822 |
no next active subproblem in the list, zero is returned.
|
alpar@1
|
823 |
|
alpar@1
|
824 |
All subproblems in the active list are ordered chronologically, i.e.
|
alpar@1
|
825 |
subproblem $A$ precedes subproblem $B$ if $A$ was created before $B$.
|
alpar@1
|
826 |
|
alpar@1
|
827 |
\subsection{glp\_ios\_prev\_node---determine previous active subproblem}
|
alpar@1
|
828 |
|
alpar@1
|
829 |
\subsubsection*{Synopsis}
|
alpar@1
|
830 |
|
alpar@1
|
831 |
\begin{verbatim}
|
alpar@1
|
832 |
int glp_ios_prev_node(glp_tree *tree, int p);
|
alpar@1
|
833 |
\end{verbatim}
|
alpar@1
|
834 |
|
alpar@1
|
835 |
\subsubsection*{Returns}
|
alpar@1
|
836 |
|
alpar@1
|
837 |
If the parameter $p$ is zero, the routine \verb|glp_ios_prev_node|
|
alpar@1
|
838 |
returns the reference number of the last active subproblem. However, if
|
alpar@1
|
839 |
the tree is empty, zero is returned.
|
alpar@1
|
840 |
|
alpar@1
|
841 |
If the parameter $p$ is not zero, it must specify the reference number
|
alpar@1
|
842 |
of some active subproblem, in which case the routine returns the
|
alpar@1
|
843 |
reference number of the previous active subproblem. However, if there
|
alpar@1
|
844 |
is no previous active subproblem in the list, zero is returned.
|
alpar@1
|
845 |
|
alpar@1
|
846 |
All subproblems in the active list are ordered chronologically, i.e.
|
alpar@1
|
847 |
subproblem $A$ precedes subproblem $B$ if $A$ was created before $B$.
|
alpar@1
|
848 |
|
alpar@1
|
849 |
\newpage
|
alpar@1
|
850 |
|
alpar@1
|
851 |
\subsection{glp\_ios\_up\_node---determine parent subproblem}
|
alpar@1
|
852 |
|
alpar@1
|
853 |
\subsubsection*{Synopsis}
|
alpar@1
|
854 |
|
alpar@1
|
855 |
\begin{verbatim}
|
alpar@1
|
856 |
int glp_ios_up_node(glp_tree *tree, int p);
|
alpar@1
|
857 |
\end{verbatim}
|
alpar@1
|
858 |
|
alpar@1
|
859 |
\subsubsection*{Returns}
|
alpar@1
|
860 |
|
alpar@1
|
861 |
The parameter $p$ must specify the reference number of some (active or
|
alpar@1
|
862 |
inactive) subproblem, in which case the routine \verb|iet_get_up_node|
|
alpar@1
|
863 |
returns the reference number of its parent subproblem. However, if the
|
alpar@1
|
864 |
specified subproblem is the root of the tree and, therefore, has
|
alpar@1
|
865 |
no parent, the routine returns zero.
|
alpar@1
|
866 |
|
alpar@1
|
867 |
\subsection{glp\_ios\_node\_level---determine subproblem level}
|
alpar@1
|
868 |
|
alpar@1
|
869 |
\subsubsection*{Synopsis}
|
alpar@1
|
870 |
|
alpar@1
|
871 |
\begin{verbatim}
|
alpar@1
|
872 |
int glp_ios_node_level(glp_tree *tree, int p);
|
alpar@1
|
873 |
\end{verbatim}
|
alpar@1
|
874 |
|
alpar@1
|
875 |
\subsubsection*{Returns}
|
alpar@1
|
876 |
|
alpar@1
|
877 |
The routine \verb|glp_ios_node_level| returns the level of the
|
alpar@1
|
878 |
subproblem,\linebreak whose reference number is $p$, in the
|
alpar@1
|
879 |
branch-and-bound tree. (The root subproblem has level 0, and the level
|
alpar@1
|
880 |
of any other subproblem is the level of its parent plus one.)
|
alpar@1
|
881 |
|
alpar@1
|
882 |
\subsection{glp\_ios\_node\_bound---determine subproblem local\\bound}
|
alpar@1
|
883 |
|
alpar@1
|
884 |
\subsubsection*{Synopsis}
|
alpar@1
|
885 |
|
alpar@1
|
886 |
\begin{verbatim}
|
alpar@1
|
887 |
double glp_ios_node_bound(glp_tree *tree, int p);
|
alpar@1
|
888 |
\end{verbatim}
|
alpar@1
|
889 |
|
alpar@1
|
890 |
\subsubsection*{Returns}
|
alpar@1
|
891 |
|
alpar@1
|
892 |
The routine \verb|glp_ios_node_bound| returns the local bound for
|
alpar@1
|
893 |
(active or inactive) subproblem, whose reference number is $p$.
|
alpar@1
|
894 |
|
alpar@1
|
895 |
\subsubsection*{Comments}
|
alpar@1
|
896 |
|
alpar@1
|
897 |
The local bound for subproblem $p$ is an lower (minimization) or upper
|
alpar@1
|
898 |
(maximization) bound for integer optimal solution to {\it this}
|
alpar@1
|
899 |
subproblem (not to the original problem). This bound is local in the
|
alpar@1
|
900 |
sense that only subproblems in the subtree rooted at node $p$ cannot
|
alpar@1
|
901 |
have better integer feasible solutions.
|
alpar@1
|
902 |
|
alpar@1
|
903 |
On creating a subproblem (due to the branching step) its local bound is
|
alpar@1
|
904 |
inherited from its parent and then may get only stronger (never weaker).
|
alpar@1
|
905 |
For the root subproblem its local bound is initially set to
|
alpar@1
|
906 |
\verb|-DBL_MAX| (minimization) or \verb|+DBL_MAX| (maximization) and
|
alpar@1
|
907 |
then improved as the root LP relaxation has been solved.
|
alpar@1
|
908 |
|
alpar@1
|
909 |
Note that the local bound is not necessarily the optimal objective value
|
alpar@1
|
910 |
to corresponding LP relaxation.
|
alpar@1
|
911 |
|
alpar@1
|
912 |
\subsection{glp\_ios\_best\_node---find active subproblem with best
|
alpar@1
|
913 |
local bound}
|
alpar@1
|
914 |
|
alpar@1
|
915 |
\subsubsection*{Synopsis}
|
alpar@1
|
916 |
|
alpar@1
|
917 |
\begin{verbatim}
|
alpar@1
|
918 |
int glp_ios_best_node(glp_tree *tree);
|
alpar@1
|
919 |
\end{verbatim}
|
alpar@1
|
920 |
|
alpar@1
|
921 |
\subsubsection*{Returns}
|
alpar@1
|
922 |
|
alpar@1
|
923 |
The routine \verb|glp_ios_best_node| returns the reference number of
|
alpar@1
|
924 |
the active subproblem, whose local bound is best (i.e. smallest in case
|
alpar@1
|
925 |
of minimization or largest in case of maximization). However, if the
|
alpar@1
|
926 |
tree is empty, the routine returns zero.
|
alpar@1
|
927 |
|
alpar@1
|
928 |
\subsubsection*{Comments}
|
alpar@1
|
929 |
|
alpar@1
|
930 |
The best local bound is an lower (minimization) or upper (maximization)
|
alpar@1
|
931 |
bound for integer optimal solution to the original MIP problem.
|
alpar@1
|
932 |
|
alpar@1
|
933 |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
alpar@1
|
934 |
|
alpar@1
|
935 |
\newpage
|
alpar@1
|
936 |
|
alpar@1
|
937 |
\section{The cut pool routines}
|
alpar@1
|
938 |
|
alpar@1
|
939 |
\subsection{glp\_ios\_pool\_size---determine current size of the cut\\
|
alpar@1
|
940 |
pool}
|
alpar@1
|
941 |
|
alpar@1
|
942 |
\subsubsection*{Synopsis}
|
alpar@1
|
943 |
|
alpar@1
|
944 |
\begin{verbatim}
|
alpar@1
|
945 |
int glp_ios_pool_size(glp_tree *tree);
|
alpar@1
|
946 |
\end{verbatim}
|
alpar@1
|
947 |
|
alpar@1
|
948 |
\subsubsection*{Returns}
|
alpar@1
|
949 |
|
alpar@1
|
950 |
The routine \verb|glp_ios_pool_size| returns the current size of the
|
alpar@1
|
951 |
cut pool, that is, the number of cutting plane constraints currently
|
alpar@1
|
952 |
added to it.
|
alpar@1
|
953 |
|
alpar@1
|
954 |
\subsection{glp\_ios\_add\_row---add constraint to the cut pool}
|
alpar@1
|
955 |
|
alpar@1
|
956 |
\subsubsection*{Synopsis}
|
alpar@1
|
957 |
|
alpar@1
|
958 |
\begin{verbatim}
|
alpar@1
|
959 |
int glp_ios_add_row(glp_tree *tree, const char *name,
|
alpar@1
|
960 |
int klass, int flags, int len, const int ind[],
|
alpar@1
|
961 |
const double val[], int type, double rhs);
|
alpar@1
|
962 |
\end{verbatim}
|
alpar@1
|
963 |
|
alpar@1
|
964 |
\subsubsection*{Description}
|
alpar@1
|
965 |
|
alpar@1
|
966 |
The routine \verb|glp_ios_add_row| adds specified row (cutting plane
|
alpar@1
|
967 |
constraint) to the cut pool.
|
alpar@1
|
968 |
|
alpar@1
|
969 |
The cutting plane constraint should have the following format:
|
alpar@1
|
970 |
$$\sum_{j\in J}a_jx_j\left\{\begin{array}{@{}c@{}}\geq\\\leq\\
|
alpar@1
|
971 |
\end{array}\right\}b,$$
|
alpar@1
|
972 |
where $J$ is a set of indices (ordinal numbers) of structural variables,
|
alpar@1
|
973 |
$a_j$ are constraint coefficients, $x_j$ are structural variables, $b$
|
alpar@1
|
974 |
is the right-hand side.
|
alpar@1
|
975 |
|
alpar@1
|
976 |
The parameter \verb|name| specifies a symbolic name assigned to the
|
alpar@1
|
977 |
constraint (1 up to 255 characters). If it is \verb|NULL| or an empty
|
alpar@1
|
978 |
string, no name is assigned.
|
alpar@1
|
979 |
|
alpar@1
|
980 |
The parameter \verb|klass| specifies the constraint class, which must
|
alpar@1
|
981 |
be either zero or a number in the range from 101 to 200. The application
|
alpar@1
|
982 |
may use this attribute to distinguish between cutting plane constraints
|
alpar@1
|
983 |
of different classes.\footnote{Constraint classes numbered from 1 to 100
|
alpar@1
|
984 |
are reserved for GLPK cutting plane generators.}
|
alpar@1
|
985 |
|
alpar@1
|
986 |
The parameter \verb|flags| currently is not used and must be zero.
|
alpar@1
|
987 |
|
alpar@1
|
988 |
Ordinal numbers of structural variables (i.e. column indices) $j\in J$
|
alpar@1
|
989 |
and numerical values of corresponding constraint coefficients $a_j$ must
|
alpar@1
|
990 |
be placed in locations \verb|ind[1]|, \dots, \verb|ind[len]| and
|
alpar@1
|
991 |
\verb|val[1]|, \dots, \verb|val[len]|, respectively, where
|
alpar@1
|
992 |
${\tt len}=|J|$ is the number of constraint coefficients,
|
alpar@1
|
993 |
$0\leq{\tt len}\leq n$, and $n$ is the number of columns in the problem
|
alpar@1
|
994 |
object. Coefficients with identical column indices are not allowed.
|
alpar@1
|
995 |
Zero coefficients are allowed, however, they are ignored.
|
alpar@1
|
996 |
|
alpar@1
|
997 |
The parameter \verb|type| specifies the constraint type as follows:
|
alpar@1
|
998 |
|
alpar@1
|
999 |
\verb|GLP_LO| means inequality constraint $\Sigma a_jx_j\geq b$;
|
alpar@1
|
1000 |
|
alpar@1
|
1001 |
\verb|GLP_UP| means inequality constraint $\Sigma a_jx_j\leq b$;
|
alpar@1
|
1002 |
|
alpar@1
|
1003 |
The parameter \verb|rhs| specifies the right-hand side $b$.
|
alpar@1
|
1004 |
|
alpar@1
|
1005 |
All cutting plane constraints in the cut pool are identified by their
|
alpar@1
|
1006 |
ordinal numbers 1, 2, \dots, $size$, where $size$ is the current size
|
alpar@1
|
1007 |
of the cut pool. New constraints are always added to the end of the cut
|
alpar@1
|
1008 |
pool, thus, ordinal numbers of previously added constraints are not
|
alpar@1
|
1009 |
changed.
|
alpar@1
|
1010 |
|
alpar@1
|
1011 |
\subsubsection*{Returns}
|
alpar@1
|
1012 |
|
alpar@1
|
1013 |
The routine \verb|glp_ios_add_row| returns the ordinal number of the
|
alpar@1
|
1014 |
cutting plane constraint added, which is the new size of the cut pool.
|
alpar@1
|
1015 |
|
alpar@1
|
1016 |
\subsubsection*{Example}
|
alpar@1
|
1017 |
|
alpar@1
|
1018 |
\begin{verbatim}
|
alpar@1
|
1019 |
/* generate triangle cutting plane:
|
alpar@1
|
1020 |
x[i] + x[j] + x[k] <= 1 */
|
alpar@1
|
1021 |
. . .
|
alpar@1
|
1022 |
/* add the constraint to the cut pool */
|
alpar@1
|
1023 |
ind[1] = i, val[1] = 1.0;
|
alpar@1
|
1024 |
ind[2] = j, val[2] = 1.0;
|
alpar@1
|
1025 |
ind[3] = k, val[3] = 1.0;
|
alpar@1
|
1026 |
glp_ios_add_row(tree, NULL, TRIANGLE_CUT, 0, 3, ind, val,
|
alpar@1
|
1027 |
GLP_UP, 1.0);
|
alpar@1
|
1028 |
\end{verbatim}
|
alpar@1
|
1029 |
|
alpar@1
|
1030 |
\subsubsection*{Comments}
|
alpar@1
|
1031 |
|
alpar@1
|
1032 |
Cutting plane constraints added to the cut pool are intended to be then
|
alpar@1
|
1033 |
added only to the {\it current} subproblem, so these constraints can be
|
alpar@1
|
1034 |
globally as well as locally valid. However, adding a constraint to the
|
alpar@1
|
1035 |
cut pool does not mean that it will be added to the current
|
alpar@1
|
1036 |
subproblem---it depends on the solver's decision: if the constraint
|
alpar@1
|
1037 |
seems to be efficient, it is moved from the pool to the current
|
alpar@1
|
1038 |
subproblem, otherwise it is simply dropped.\footnote{Globally valid
|
alpar@1
|
1039 |
constraints could be saved and then re-used for other subproblems, but
|
alpar@1
|
1040 |
currently such feature is not implemented.}
|
alpar@1
|
1041 |
|
alpar@1
|
1042 |
Normally, every time the callback routine is called for cut generation,
|
alpar@1
|
1043 |
the cut pool is empty. On the other hand, the solver itself can generate
|
alpar@1
|
1044 |
cutting plane constraints (like Gomory's or mixed integer rounding
|
alpar@1
|
1045 |
cuts), in which case the cut pool may be non-empty.
|
alpar@1
|
1046 |
|
alpar@1
|
1047 |
\subsection{glp\_ios\_del\_row---remove constraint from the cut pool}
|
alpar@1
|
1048 |
|
alpar@1
|
1049 |
\subsubsection*{Synopsis}
|
alpar@1
|
1050 |
|
alpar@1
|
1051 |
\begin{verbatim}
|
alpar@1
|
1052 |
void glp_ios_del_row(glp_tree *tree, int i);
|
alpar@1
|
1053 |
\end{verbatim}
|
alpar@1
|
1054 |
|
alpar@1
|
1055 |
\subsubsection*{Description}
|
alpar@1
|
1056 |
|
alpar@1
|
1057 |
The routine \verb|glp_ios_del_row| deletes $i$-th row (cutting plane
|
alpar@1
|
1058 |
constraint) from the cut pool, where $1\leq i\leq size$ is the ordinal
|
alpar@1
|
1059 |
number of the constraint in the pool, $size$ is the current size of the
|
alpar@1
|
1060 |
cut pool.
|
alpar@1
|
1061 |
|
alpar@1
|
1062 |
Note that deleting a constraint from the cut pool leads to changing
|
alpar@1
|
1063 |
ordinal numbers of other constraints remaining in the pool. New ordinal
|
alpar@1
|
1064 |
numbers of the remaining constraints are assigned under assumption that
|
alpar@1
|
1065 |
the original order of constraints is not changed. Let, for example,
|
alpar@1
|
1066 |
there be four constraints $a$, $b$, $c$ and $d$ in the cut pool, which
|
alpar@1
|
1067 |
have ordinal numbers 1, 2, 3 and 4, respectively, and let constraint
|
alpar@1
|
1068 |
$b$ have been deleted. Then after deletion the remaining constraint $a$,
|
alpar@1
|
1069 |
$c$ and $d$ are assigned new ordinal numbers 1, 2 and 3, respectively.
|
alpar@1
|
1070 |
|
alpar@1
|
1071 |
To find the constraint to be deleted the routine \verb|glp_ios_del_row|
|
alpar@1
|
1072 |
uses ``smart'' linear search, so it is recommended to remove constraints
|
alpar@1
|
1073 |
in a natural or reverse order and avoid removing them in a random order.
|
alpar@1
|
1074 |
|
alpar@1
|
1075 |
\subsubsection*{Example}
|
alpar@1
|
1076 |
|
alpar@1
|
1077 |
\begin{verbatim}
|
alpar@1
|
1078 |
/* keep first 10 constraints in the cut pool and remove other
|
alpar@1
|
1079 |
constraints */
|
alpar@1
|
1080 |
while (glp_ios_pool_size(tree) > 10)
|
alpar@1
|
1081 |
glp_ios_del_row(tree, glp_ios_pool_size(tree));
|
alpar@1
|
1082 |
\end{verbatim}
|
alpar@1
|
1083 |
|
alpar@1
|
1084 |
\newpage
|
alpar@1
|
1085 |
|
alpar@1
|
1086 |
\subsection{glp\_ios\_clear\_pool---remove all constraints from the cut
|
alpar@1
|
1087 |
pool}
|
alpar@1
|
1088 |
|
alpar@1
|
1089 |
\subsubsection*{Synopsis}
|
alpar@1
|
1090 |
|
alpar@1
|
1091 |
\begin{verbatim}
|
alpar@1
|
1092 |
void glp_ios_clear_pool(glp_tree *tree);
|
alpar@1
|
1093 |
\end{verbatim}
|
alpar@1
|
1094 |
|
alpar@1
|
1095 |
\subsubsection*{Description}
|
alpar@1
|
1096 |
|
alpar@1
|
1097 |
The routine \verb|glp_ios_clear_pool| makes the cut pool empty deleting
|
alpar@1
|
1098 |
all existing rows (cutting plane constraints) from it.
|
alpar@1
|
1099 |
|
alpar@1
|
1100 |
%* eof *%
|