1% BEGIN LICENSE BLOCK
2% Version: CMPL 1.1
3%
4% The contents of this file are subject to the Cisco-style Mozilla Public
5% License Version 1.1 (the "License"); you may not use this file except
6% in compliance with the License.  You may obtain a copy of the License
7% at www.eclipse-clp.org/license.
8% 
9% Software distributed under the License is distributed on an "AS IS"
10% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
11% the License for the specific language governing rights and limitations
12% under the License. 
13% 
14% The Original Code is  The ECLiPSe Constraint Logic Programming System. 
15% The Initial Developer of the Original Code is  Cisco Systems, Inc. 
16% Portions created by the Initial Developer are
17% Copyright (C) 2006 Cisco Systems, Inc.  All Rights Reserved.
18% 
19% Contributor(s): Andrew Eremin, IC-Parc
20% 
21% END LICENSE BLOCK
22
23:- comment(desc, html("\
24<P>
25   This library lets you use customisable branch-and-bound search. It
26   is primarily intended for use with the colgen library in implementing
27   branch-and-price algorithms, but can be used with arbitrary
28   user-defined node solution, separation and selection goals.
29   When application specific methods are not required for node
30   separation and/or selection the use of built-in depth-first
31   and best-first node selection, and branching on most fractional
32   variable or generalised upper bound constraint may be specified.
33   When the relaxed problem to be solved at a node involves an eplex
34   instance branching may additionally be specified by built-in
35   objective coefficient, estimate- or lower-bounding based methods,
36   and best-estimate node selection may be used.
37</P>
38")).
39
40:- comment(statistics/0, [
41template: "BfsInstance:statistics",
42summary: "Display search tree statistics for bfs instance BfsInstance.",
43see_also:[solver_setup/2, solver_setup/3, solve/1
44         ],
45desc: html("\
46<P>
47  Display statistics for the search tree associated with the bfs
48  instance BfsInstance: total number of nodes created, total search
49  time, number of nodes solved, node solution time, number of nodes
50  separated, node separation time, total number of global feasible
51  solutions found, first and optimal global solution solution time.
52</P>
53")
54]).
55
56:- comment(solver_setup/2, [
57template: "BfsInstance:solver_setup(+OptSense, +Solver)",
58args:    ["OptSense":     "Optimisation direction: min or max",
59          "Solver":       "Node relaxation solver"],
60summary: "Setup a bfs solver tree for bfs instance BfsInstance.",
61see_also:[integers/1, bfs_branch/1, node_info/5,
62          solver_setup/3, solve/1,
63          get/2, var_get/3, bfs:statistics/0
64         ],
65desc: html("\
66<P>
67  Setup a new solver tree for the bfs instance BfsInstance. The tree
68  will be associated with BfsInstance; BfsInstance must not already
69  have a solver tree associated with it. Once the solver tree is setup,
70  it can be optimised via solve/1.
71</P><P>
72  This is a simplified version of solver_setup/3, it is equivalent to
73  calling solver_setup/3 with the following default options:
74<PRE>
75       solver_setup(OptSense, Solver, [])
76</PRE>
77")
78]).
79
80:- comment(solver_setup/3, [
81template: "BfsInstance:solver_setup(+OptSense, +Solver, ++ListOfOptions)",    
82args:      ["OptSense":     "Optimisation direction: min or max",
83            "Solver":       "Node relaxation solver",
84            "ListOfOptions": "List of solver options"
85           ],
86summary: "Setup a bfs solver tree for bfs instance BfsInstance.",
87see_also:[integers/1, bfs_branch/1, node_info/5,
88          solver_setup/2, solve/1,
89          get/2, var_get/3, bfs:statistics/0
90         ],
91desc: html("\
92<P>
93  Setup a new solver tree for the bfs instance BfsInstance. The tree
94  will be associated with BfsInstance; BfsInstance must not already
95  have a solver tree associated with it. Once the solver tree is setup,
96  it can be optimised via solve/1. This predicate allow various
97  options to be specified when setting up the  solver state via
98  <TT>ListOfOptions</TT>.
99</P><P>
100  <TT>OptSense</TT> is the optimisation direction. <B>Note</B> that this
101  is assumed to be the same as the sense of optimisation used in
102  <TT>Solver</TT>. It is the user's responsibility to ensure 
103  that this is in fact the case. <TT>OptSense</TT> is used internally
104  for bound updates and pruning, and for node ordering with the built-in
105  best-first and best-estimate node selection methods.
106</P><P>
107  <TT>Solver</TT> is the node relaxed problem solver. It is either a
108  user-defined predicate or an eplex instance or handle, for which a
109  built-in node relaxation solver is available.
110
111</P><P>
112ListOfOptions are:
113
114<DL>
115
116<P>
117<DT><STRONG><TT>separation(+Separation)</TT></STRONG>
118    <DD>Use the specified method to separate the current node.
119    <TT>Separation</TT> is either a user-defined predicate, or one of
120    the atoms <TT>fracvar, enhanced, strong, deg_est</TT>
121    corresponding to the built-in separation methods. Note that the
122    methods <TT>enhanced, strong, deg_est</TT> are only available when
123    the node relaxation solver involves an eplex instance.
124    <TT>Separation</TT> defaults to fracvar.
125
126<P>
127<DT><STRONG><TT>node_select(+Select)</TT></STRONG>
128    <DD>Use the specified method (<TT>depth_first, best_first,
129    best_estimate</TT>) to select the next open node for solution and
130    separation. <TT>Select</TT> defaults to best_first.
131
132<P>
133<DT><STRONG><TT>alpha(?AlphaMin, ?AlphaMax)</TT></STRONG>
134    <DD>When using estimate- or lower-bounding based dichotomic node
135    separation methods the overall value assigned to branching on a
136    particular variable or constraint is calculated as a weighted sum
137    of the estimates obtained for the two branches it would produce.
138    AlphaMin is the weighting given to the minimum of the two estimates
139    and AlphaMax to the maximum. <TT>AlphaMin</TT> and <TT>AlphaMax</TT>
140    are numbers and default to 2 and 1 respectively.
141
142<P>
143<DT><STRONG><TT>beta(?BetaConst, ?BetaPC, ?BetaLB)</TT></STRONG>
144    <DD>When using estimate- or lower-bounding based node separation
145    methods with a problem involving an eplex instance the estimate
146    assigned to each branch produced by branching on a particular
147    variable or constraint is calculated as a weighted sum  of the
148    pseudo-cost estimate and the lower bound. BetaPC is the weighting
149    given to the pseudo-cost estimate and BetaLB to the lower bound.
150    BetaConst is a constant offset only used when linear regression is
151    employed to update these values during search. <TT>BetaConst</TT>,
152    <TT>BetaPC</TT>, <TT>BetaLB</TT> are numbers and default to 0, 1,
153    1 respectively.
154
155<P>
156<DT><STRONG><TT>pseudo_cost(?PCInit, ?PCUpdate, ?PCRatio)</TT></STRONG>
157    <DD>
158    <P>When using estimate-based dichotomic node separation methods
159    with a problem involving an eplex instance up and down pseudo-costs
160    are assigned to each variable and generalised upper bound constraint 
161    branch-point representing the estimated degradation in objective
162    cost per unit change in variable or constraint value incurred on
163    that branch.
164    </P><P><TT>PCInit</TT> specifies the method used to initialise these
165    values when a variable or constraint branch-point is first considered
166    for branching:
167    <DL>
168    <DD><TT>average</TT> : the pseudocosts are initialised to the average
169    of the observed changes in cost of all up or down branches in the
170    search tree.
171    <DD><TT>cost</TT> : variable pseudocosts are initialised to the
172    objective cost coefficient of the variable, constraint branch-point
173    pseudocosts to the average of the cost coefficients of variables
174    involved.
175    <DD><TT>calculated</TT> : the pseudocosts are initialised to a
176    value calculated by performing a number of external solver iterations
177    equal to <TT>(PCRatio * #iterations in root node)/(2* #fractional
178    vars in root node)</TT>.
179    </DL>
180    The default is <TT>calculated</TT>.
181    </P><P><TT>PCUpdate</TT> is an atom specifying the method used to
182    update these values throughout the search tree once the variable
183    or constraint has been branched on:
184    <DL>
185    <DD><TT>average</TT> : the pseudocosts are updated to the average
186    of the observed changes in cost of all up or down branches in the
187    search tree for that variable or constraint. 
188    <DD><TT>first</TT> : the pseudocosts are fixed to the observed
189    change in cost at the first up or down branch in the search tree for
190    that variable or constraint.
191    <DD><TT>last</TT> : the pseudocosts are fixed to the observed
192    change in cost at the last up or down branch in the search tree for
193    that variable or constraint.
194    </DL>
195    The default is <TT>average</TT>.
196    </P><P><TT>PCRatio</TT> is a float between 0 and 1 and is used in
197    calculating the number of external solver iterations to perform
198    when explicitly calculating initial pseudo-cost estimates; the
199    default value is 0.05. Setting small ratios will result in faster
200    node separation, but the initial estimates for variables and
201    constraints on which the branching decisions are taken will be less
202    accurate. Setting larger values will result in more work being performed
203    in node separation and better estimates for the branching
204    decisions. The optimum value will be problem specific, although in 
205    general the overhead of performing a total number of iterations
206    more than a small ratio of the root node iterations will outweigh the
207    benefit obtained.
208
209<P>
210<DT><STRONG><TT>lower_bound(+Limit)</TT></STRONG>
211    <DD>When using lower-bounding based node separation methods with a
212    problem involving an eplex instance, specify how many external solver
213    iterations should be performed to calculate the lower bound.
214    <TT>Limit</TT> is an integer and defaults to 1. Setting small
215    values of iterations will result in faster node separation, but the
216    lower bounds on which the branching decisions are taken will be less
217    tight. Setting larger values will result in more work being performed
218    in node separation and tighter lower bounds for the branching
219    decisions. The optimum value will be problem specific, although in
220    general the overhead of performing more than a few iterations will
221    outweigh the benefit obtained.
222
223<P>
224<DT><STRONG><TT>int_tolerance(+IntTol)</TT></STRONG>
225    <DD>Specify how far from integrality an integer variable's node
226    solution can fall before it is considered for separation by the
227    built-in separation methods. <TT>IntTol</TT> is a float and
228    defaults to 0.00001.  
229<P>
230<DT><STRONG><TT>info_messages(+OnOff)</TT></STRONG>
231    <DD>Specify whether information messages should be output at
232    various points during solution. This option is most useful for
233    debugging purposes. OnOff is one of the atoms <TT>on</TT> or
234    <TT>off</TT>, the default is <TT>off</TT>.
235
236</DL>
237</P>")
238]).
239
240:- comment(bfs_branch/1, [
241template:  "BfsInstance:bfs_branch(+Branch)",
242args:      ["Branch":   "Prolog term"
243           ],
244summary:   "Post a branching constraint to the bfs instance BfsInstance.",
245see_also:  [solver_setup/2, solver_setup/3, get/2],
246desc:      html("\
247<P>
248   Post a new branching constraint <TT>Branch</TT> to the bfs instance
249   BfsInstance. The constraint will be used to create a new child node
250   of the current open node in the search tree for BfsInstance.
251   <TT>Branch</TT> may be any prolog term, but clearly should be an
252   appropriate constraint for the node relaxation solver associated with
253   BfsInstance. 
254</P>")
255]).
256
257
258:- comment(solve/1, [
259template:  "BfsInstance:solve(-Cost)",
260args:      ["Cost":   "The optimal solution cost of the problem"
261                      " associated with BfsInstance"
262           ],
263summary:   "Optimise the problem associated with BfsInstance.",
264fail_if:   "No solution exists satisfying the global feasibility conditions.",
265see_also:  [solver_setup/2, solver_setup/3, get/2, var_get/3, bfs:statistics/0],
266desc:      html("\
267<P>
268   A solver setup with solver_setup/2 or solver_setup/3 is triggered
269   using this predicate.
270</P><P>
271   The node relaxation and separation solvers are applied to the next
272   selected node of the problem represented by Handle repeatedly until
273   no more open nodes remain. The criteria for node selection order
274   depends on the options given to solver_setup/2,3.  solve/1 fails if
275   there is no solution or succeeds if an optimal solution is found,
276   returning the solution's cost in Cost.  After a success, various
277   solution information and statistics can be retrieved using get/2,
278   var_get/3 and statistics/0.
279</P>")
280]).
281
282:- comment(node_cost/1, [
283template:  "BfsInstance:node_cost(+Val)",
284args:      ["Val":  "Solution cost for problem (number)"
285           ],
286summary:   "Set solution cost for the problem at a node.",
287desc:      html("\
288<P>
289   Set the solution cost for the problem at the current open node of
290   the search tree associated with the bfs instance BfsInstance.
291</P>")
292]).
293
294:- comment(node_info/5, [
295template:  "BfsInstance:node_info(+Var, ?Lo, ?Hi, ?Val, ?RC)",
296args:      ["Var":   "A solver problem variable for solver the associated with BfsInstance",
297            "Lo":  "Lower bound for Var (number)",
298            "Hi":  "Upper bound for Var (number)",
299            "Val":  "Solution value for Var (number)",
300            "RC":  "Reduced cost for Var (number)"
301           ],
302summary:   "Get or set node bounds and solution information for an individual"
303           " solver problem variable Var.",
304desc:      html("\
305<P>
306   Retrieve or update bounds and solution information for an
307   individual solver problem variable Var for the current open node of
308   the search tree associated with the bfs instance BfsInstance. If Var
309   was not already a problem variable for BfsInstance it will now be
310   considered one. If reduced costs are available in problems
311   involving eplex instances supplying these to the bfs solver can lead
312   to improved pruning.
313</P>")
314]).
315
316:- comment(var_get/3, [
317template:  "BfsInstance:var_get(+Var, ++What, -Value)",
318args:      ["Var":   "A solver problem variable for the solver associated with BfsInstance",
319            "What":  "Specification for information wanted (atom)",
320	    "Value": "Returned value of What"
321           ],
322summary:   "Obtain information for an individual solver problem variable Var.",
323exceptions: [6: "What is not a valid value."],
324desc:      html("\
325<P>
326   Retrieve information about solver results related to a particular
327   variable, for the bfs instance BfsInstance. Fails if Var is not a
328   problem variable for BfsInstance. What can take one of the following
329   values: 
330
331<DL>
332    <DT><TT>optimal_val</TT>
333    <DD>Returns the floating-point solution for variable Var.
334<P>
335
336    <DT><TT>node_val</TT>
337    <DD>Returns the floating-point solution for variable Var for the
338    current node in the search tree of this instance.
339<P>
340
341    <DT><TT>type</TT>
342    <DD>Returns the type real or integer of Var in this instance.
343</DL>")
344]).
345
346:- comment(get/2, [
347template:  "BfsInstance:get(++What, -Value)",
348args:      ["What":  "Specification for information wanted (atom)",
349	    "Value": "Returned value of What"
350           ],
351summary:   "Obtain information for the problem associated with BfsInstance.",
352exceptions: [6: "What is not a valid value."],
353desc:      html("\
354<P>
355   Retrieve information about the problem associated with the bfs
356   instance BfsInstance. What can take one of the following values:
357
358<DL>
359    <DT><TT>frac_vars</TT>
360    <DD>Returns the list of variables declared as integer for
361    BfsInstance which have fractional solution values in the current node
362    of the search tree.
363<P>
364
365    <DT><TT>branches</TT>
366    <DD>Returns the branching decisions taken from the root to the
367    current node of the search tree.
368<P>
369
370    <DT><TT>data</TT>
371    <DD>Returns the user-defined data associated with the instance.
372<P>
373
374    <DT><TT>node_count</TT>
375    <DD>Returns the total number of nodes in the search tree.
376</DL>")
377]).
378
379:- comment(integers/1, [
380template:  "BfsInstance:integers(+Ints)",
381args:      ["Ints":   "A variable or list of variables"
382           ],
383summary:   "Declare Ints as integers in BfsInstance.",
384desc:      html("\
385<P>
386   The variable or list of variables Ints will be considered integers
387   when solving the problem associated with BfsInstance. Note that
388   this does not mean that they will be treated as integers by the
389   specified node relaxation solver, rather that they will be considered
390   as candidates for branching decisions in nodes where their solution
391   value is not integral (to within a tolerance parameter set in the
392   options list of BfsInstance:solver_setup/3). The predefined
393   node separation schemes will branch on these variables. User-defined
394   node separation predicates may access the fractional variables
395   at the current node via a call to BfsInstance:get/2"),
396see_also:   [solver_setup/3, get/2]
397]).
398
399:- comment(bfs_instance/1, [
400amode:bfs_instance(++),
401args:  ["BfsInstance": "Bfs instance name (atom)"
402       ],
403summary: "Initialises the bfs instance BfsInstance.",
404desc: html("\
405  <P>
406  Initialises the bfs instance BfsInstance. A bfs instance is an
407  instance of the best first search solver, with which node
408  relaxation and separation solvers can be associated and used to
409  optimise the problem constraints posted to the relaxed node solver
410  with respect to its objective using a specified node ordering scheme.
411  In particular best-first and best-estimate search schemes are
412  supported and application-specific schemes may be easily defined by
413  the user.
414  </P><P>
415  If BfsInstance is not an already existing bfs instance, a new bfs
416  instance will be created and initialised. If it is an existing bfs
417  instance, and it is not currently being used (having no associated
418  solvers), it is effectively reinitialised. Otherwise, the predicate
419  aborts with an error. Note that a bfs instance is a module, and each
420  bfs instance can be associated with at most one relaxation and one
421  separation solver at any time and vice versa.
422  </P>
423  "),
424see_also:   [integers/1, bfs_branch/1, node_info/5,
425             solver_setup/2, solver_setup/3, solve/1,
426             get/2, var_get/3, bfs:statistics/0]
427]).
428
429
430
431
432