source: stable/2.6/Cbc/doc/otherclasses.xml @ 2464

Last change on this file since 2464 was 120, checked in by rlh, 14 years ago

Rennovated Cbc user guide for INFORMS Tutorial book chapter

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.2 KB
Line 
1<?xml version="1.0" encoding="ISO-8859-1"?>
2  <chapter id="otherclasses">
3  <title>
4  Selecting the Next Node in the Search Tree
5  </title>
6  <section id="comparison">
7  <title>CbcCompare - Comparison Methods</title>
8  <para>
9  The order in which the nodes of the search tree are explored can strongly influence the performance of branch-and-cut algorithms. CBC give users complete control over the search order. The search order is controlled via the <classname>CbcCompare...</classname> class. CBC provides an abstract base class, <classname>CbcCompareBase</classname>,  and several commonly used instances which are described in <xref linkend="compareTable"/>.
10  </para>
11    <table frame="none" id="compareTable">
12  <title>Compare Classes Provided</title>
13    <tgroup cols="2">
14    <thead>
15    <row>
16    <entry>
17    Class name
18    </entry>
19    <entry>
20    Description
21    </entry>
22    </row>
23    </thead>
24    <tbody>
25    <row>
26      <entry align="left" valign="top">
27      <classname>CbcCompareDepth</classname>
28      </entry>
29      <entry align="left" valign="top">
30      This will always choose the node deepest in tree.  It gives minimum
31      tree size but may take a long time to find the best solution.
32      </entry>
33    </row>
34    <row>
35      <entry align="left" valign="top">
36      <classname>CbcCompareObjective</classname>
37      </entry>
38      <entry align="left" valign="top">
39      This will always choose the node with the best objective value.  This may
40      give a very large tree.  It is likely that the first solution found
41      will be the best and the search should finish soon after the first solution
42      is found.
43      </entry>
44    </row>
45    <row>
46      <entry align="left" valign="top">
47      <classname>CbcCompareDefault</classname>
48      </entry>
49      <entry align="left" valign="top">
50      This is designed to do a mostly depth-first search until a solution has
51      been found. It then use estimates that are designed to give a slightly better solution.
52      If a reasonable number of nodes have been explored (or a reasonable number of
53      solutions found), then this class will adopt a breadth-first search (i.e., making a comparison based strictly on objective function values) unless the tree is very large when it will revert to depth-first search. A better description of <classname>CbcCompareUser</classname> is given below.
54      </entry>
55    </row>
56    <row>
57      <entry align="left" valign="top">
58      <classname>CbcCompareEstimate</classname>
59      </entry>
60      <entry align="left" valign="top">
61      When pseudo costs are invoked, they can be used to guess a solution.  This class uses the guessed solution.
62      </entry>
63    </row>
64    </tbody>
65  </tgroup>
66  </table>
67  <para>
68  It is relatively simple for an experienced user to create new compare class instances. The code in <xref linkend="test"/> describes how to build a new comparison class and the reasoning behind it. The complete source can be found in <filename>CbcCompareUser.hpp</filename> and <filename>CbcCompareUser.cpp</filename>, located in the CBC Samples directory. See <xref linkend="moreexamples"/>. The key method in <classname>CbcCompare</classname> is <function>bool test(CbcNode* x, CbcNode* y))</function> which returns <parameter>true</parameter> if node <parameter>y</parameter> is preferred over node <parameter>x</parameter>. In the <function>test()</function> method, information from <classname>CbcNode</classname> can easily be used. <xref linkend="nodeTable"/> list some commonly used methods to access information at a node.
69  <table frame="none" id="nodeTable">
70  <title>Information Available from <classname>CbcNode</classname></title>
71    <tgroup cols="2">
72    <tbody>
73    <row>
74      <entry align="left" valign="top">
75      <function>double objectiveValue() const</function>
76      </entry>
77      <entry align="left" valign="top">
78      Value of objective at the node.
79      </entry>
80    </row>
81    <row>
82      <entry align="left" valign="top">
83      <function>int numberUnsatisfied() const</function>
84      </entry>
85      <entry align="left" valign="top">
86      Number of unsatisfied integers (assuming branching
87      object is an integer - otherwise it might be number of unsatisfied sets).
88      </entry>
89    </row>
90    <row>
91      <entry align="left" valign="top">
92      <function>int depth() const</function>
93      </entry>
94      <entry align="left" valign="top">
95       Depth of the node in the search tree.
96      </entry>
97    </row>
98    <row>
99      <entry align="left" valign="top">
100      <function>double guessedObjectiveValue() const</function>
101      </entry>
102     <entry align="left" valign="top"> 
103     If user was setting this (e.g., if using pseudo costs).
104      </entry>
105    </row>
106    <row>
107      <entry align="left" valign="top">
108      <function>int way() const</function>
109      </entry>
110      <entry align="left" valign="top">
111       The way which branching would next occur from this node
112       (for more advanced use).
113      </entry>
114    </row>
115    <row>
116      <entry align="left" valign="top">
117      <function>int variable() const</function>
118      </entry>
119      <entry align="left" valign="top">
120       The branching "variable" (associated with the <classname>CbcBranchingObject</classname> -- for more advanced use).
121      </entry>
122    </row>
123    </tbody>
124  </tgroup>
125  </table>
126</para>
127
128<para>
129The node desired in the tree is often a function of the how the search is progressing. In the design of CBC, there is no information on the state of the tree. The CBC is designed so that the method
130  <function>newSolution()</function> is called whenever a solution is found and the method <function>every1000Nodes()</function> is called every 1000 nodes.  When these methods are called, the user has the opportunity to modify the
131  behavior of <function>test()</function> by adjusting their common variables (e.g., <varname>weight_</varname>). Because <classname>CbcNode</classname> has a pointer to the model, the user can also influence the search through actions such as changing the maximum time CBC is allowed, once a solution has been found (e.g., <function>CbcModel::setMaximumSeconds(double value)</function>). In <filename>CbcCompareUser.cpp</filename> of the <filename>COIN/Cbc/Samples</filename> directory,  four items of data are used.
132</para>
133<itemizedlist>
134  <listitem>
135  <para>
1361) The number of solutions found so far
137  </para>
138  </listitem>
139  <listitem>
140  <para>
1412) The size of the tree (defined to be the number of active nodes)
142  </para>
143  </listitem>
144  <listitem>
145  <para>
1463) A weight, <varname>weight_</varname>, which is initialized to -1.0
147  </para>
148  </listitem>
149  <listitem>
150  <para>
1514) A saved value of weight, <varname>saveWeight_</varname> (for when weight is set back to -1.0 for special reason)
152  </para>
153  </listitem>
154</itemizedlist>
155<para>
156The full code for the <function>CbcCompareUser::test()</function> method is given in <xref linkend="test"/>.
157</para>
158  <example id="test">
159  <title><function>CbcCompareUser::test()</function></title>
160  <programlisting>
161  <![CDATA[ 
162// Returns true if y better than x
163bool
164CbcCompareUser::test (CbcNode * x, CbcNode * y)
165{
166  if (weight_==-1.0) {
167    // before solution
168    if (x->numberUnsatisfied() > y->numberUnsatisfied())
169      return true;
170    else if (x->numberUnsatisfied() < y->numberUnsatisfied())
171      return false;
172    else
173      return x->depth() < y->depth();
174  } else {
175    // after solution.
176    // note: if weight_=0, comparison is based
177    //       solely on objective value
178    double weight = CoinMax(weight_,0.0);
179    return x->objectiveValue()+ weight*x->numberUnsatisfied() >
180      y->objectiveValue() + weight*y->numberUnsatisfied();
181  }
182}
183  ]]>   
184  </programlisting>
185  </example>
186<para>
187Initially, <varname>weight</varname>_ is -1.0 and the search is biased towards depth first.  In
188fact, <function>test()</function> prefers <parameter>y</parameter> if <parameter>y</parameter> has fewer unsatisfied variables. In the case of a tie, <function>test()</function> prefers the node with the greater depth in tree. Once a solution is found, <function>newSolution()</function> is called. The method <function>newSolution()</function> interacts with <function>test()</function> by means of the variable <varname>weight_</varname>. If the solution was achieved by branching, <!-- how do can you determine that? --> a calculation is made to determine the cost per unsatisfied integer variable to go from the continuous solution to an integer solution.  The variable <varname>weight_</varname> is then set to aim at a slightly better solution.  From then on, <function>test()</function> returns <parameter>true</parameter> if it seems that <parameter>y</parameter> will lead to a better solution than <parameter>x</parameter>. This source for <function>newSolution()</function> in given in <xref linkend="newSolution"/>.
189</para>
190  <example id="newSolution">
191  <title><function>CbcCompareUser::newSolution()</function></title>
192  <programlisting>
193  <![CDATA[ 
194// This allows the test() method to change behavior by resetting weight_.
195// It is called after each new solution is found.
196void
197CbcCompareUser::newSolution(CbcModel * model,
198                               double objectiveAtContinuous,
199                               int numberInfeasibilitiesAtContinuous)
200{
201  if (model->getSolutionCount()==model->getNumberHeuristicSolutions())
202    return; // solution was found by rounding so ignore it.
203
204  // set weight_ to get close to this solution
205  double costPerInteger =
206    (model->getObjValue()-objectiveAtContinuous)/
207    ((double) numberInfeasibilitiesAtContinuous);
208  weight_ = 0.98*costPerInteger;
209  saveWeight_=weight_;
210  numberSolutions_++;
211  if (numberSolutions_>5)
212    weight_ =0.0; // comparison in test() will be
213                  // based strictly on objective value.
214}
215  ]]>   
216  </programlisting>
217  </example>
218<para>
219
220As the search progresses, the comparison can be <!-- what? is "this"? -->modified. If many nodes (or many solutions) have been genereated, then <varname>weight_</varname> is set to 0.0 leading to a breadth-first search.  Breadth-first search can lead to an enormous tree. If the tree size is exceeds 10000, it may be desirable to return to a search biased towards depth first. Changing the behavior in this manner is done by the method <function>every1000Nodes</function> shown in <xref linkend="everyK"/>.
221  </para>
222  <example id="everyK">
223  <title><function>CbcCompareUser::every1000Nodes()</function></title>
224  <programlisting>
225  <![CDATA[ 
226// This allows the test() method to change behavior every so often
227bool
228CbcCompareUser::every1000Nodes(CbcModel * model, int numberNodes)
229{
230  if (numberNodes>10000)
231    weight_ =0.0; // compare nodes based on objective value
232  else if (numberNodes==1000&&weight_==-2.0)
233    weight_=-1.0; // Go to depth first
234  // get size of tree
235  treeSize_ = model->tree()->size();
236  if (treeSize_>10000) {
237    // set weight to reduce size most of time
238    if (treeSize_>20000)
239      weight_=-1.0;
240    else if ((numberNodes%4000)!=0)
241      weight_=-1.0;
242    else
243      weight_=saveWeight_;
244  }
245  return numberNodes==11000; // resort if first time
246}
247  ]]>   
248  </programlisting>
249  </example>
250  </section>
251</chapter>
252<chapter id="hueristicChap">
253  <title>
254  Getting Good Bounds in CBC
255  </title>
256  <section id="heuristics">
257  <title>CbcHeuristic - Heuristic Methods</title>
258  <para>
259  In practice, it is very useful to get a good solution reasonably fast. Any MIP-feasible solution produces an upper bound, and a good bound will greatly reduce the run time. Good solutions can satisfy the user
260  on very large problems where a complete search is impossible.  Obviously, heuristics are
261  problem dependent, although some do have more general use.
262  At present there is only one heuristic in CBC itself, <classname>CbcRounding</classname>. Hopefully, the number will grow. Other heuristics are in the <filename>COIN/Cbc/Samples</filename>
263  directory.  A heuristic tries to obtain a solution to the original
264  problem so it only needs to consider the original rows and does not have to use the
265  current bounds. CBC provides an abstract base class <classname>CbcHeuristic</classname> and a rounding heuristic in CBC. <!-- rlh: we need an example of using an existing heuristic -->
266  </para>
267  <para>
268  This chapter describes how to build a greedy heuristic for a set covering problem, e.g., the miplib problem fast0507. A more general (and efficient) version of the heuristic is in <filename>CbcHeuristicGreedy.hpp</filename> and <filename>CbcHeuristicGreedy.cpp</filename> located in the <filename>COIN/Cbc/Samples</filename> directory, see <xref linkend="moreexamples"/>.
269</para>
270<para>
271  The greedy heuristic will leave all variables taking value one at this node of the
272  tree at value one, and will initially set all other variable to value zero. 
273  All variables are then sorted in order of their cost
274  divided by the number of entries in rows which are not yet covered. (We may randomize that
275  value a bit so that ties will be broken in different ways on different runs of the heuristic.)
276  The best one is choosen, and set to one. The process is repeated. Because this is
277  a set covering problem (i.e., all constraints are &ge;), the heuristic is guaranteed to find a solution (but not necessarily an improved solution). The speed of the heuristic could be improved by just redoing those affected, but for illustrative purposes we will keep it simple.(The speed could also be improved if all elements are 1.0).
278</para>
279<para>
280  The key <classname>CbcHeuristic</classname> method is <function>int&nbsp;solution(double &amp; solutionValue,
281                                              double&nbsp;*&nbsp;betterSolution)</function>.
282  The <function>solution()</function> method returns 0 if no solution found, and returns 1 if a solution is found, in which case it fills in the objective value and primal solution.  The code in <filename>CbcHeuristicGreedy.cpp</filename> is a little more complicated than this following example. For instance, the code here assumes all variables are integer.  The important bit of data is a copy of the matrix (stored by column) before any cuts have been made.  The data used are bounds, objective and the matrix plus two work arrays.
283  </para>
284  <example>
285  <title>Data</title>
286  <programlisting>
287  <![CDATA[ 
288  OsiSolverInterface * solver = model_->solver(); // Get solver from CbcModel
289  const double * columnLower = solver->getColLower(); // Column Bounds
290  const double * columnUpper = solver->getColUpper();
291  const double * rowLower = solver->getRowLower(); // We know we only need lower bounds
292  const double * solution = solver->getColSolution();
293  const double * objective = solver->getObjCoefficients(); // In code we also use min/max
294  double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance);
295  double primalTolerance;
296  solver->getDblParam(OsiPrimalTolerance,primalTolerance);
297  int numberRows = originalNumberRows_; // This is number of rows when matrix was passed in
298  // Column copy of matrix (before cuts)
299  const double * element = matrix_.getElements();
300  const int * row = matrix_.getIndices();
301  const CoinBigIndex * columnStart = matrix_.getVectorStarts();
302  const int * columnLength = matrix_.getVectorLengths();
303
304  // Get solution array for heuristic solution
305  int numberColumns = solver->getNumCols();
306  double * newSolution = new double [numberColumns];
307  // And to sum row activities
308  double * rowActivity = new double[numberRows];
309  ]]>   
310  </programlisting>
311  </example>
312<para>
313The <varname>newSolution</varname> is then initialized to the rounded down solution.
314</para>
315  <example>
316  <title>Initialize <varname>newSolution</varname></title>
317  <programlisting>
318  <![CDATA[ 
319  for (iColumn=0;iColumn<numberColumns;iColumn++) {
320    CoinBigIndex j;
321    double value = solution[iColumn];
322    // Round down integer
323    if (fabs(floor(value+0.5)-value)<integerTolerance)
324      value=floor(CoinMax(value+1.0e-3,columnLower[iColumn]));
325    // make sure clean
326    value = CoinMin(value,columnUpper[iColumn]);
327    value = CoinMax(value,columnLower[iColumn]);
328    newSolution[iColumn]=value;
329    if (value) {
330      double cost = direction * objective[iColumn];
331      newSolutionValue += value*cost;
332      for (j=columnStart[iColumn];
333           j<columnStart[iColumn]+columnLength[iColumn];j++) {
334        int iRow=row[j];
335        rowActivity[iRow] += value*element[j];
336      }
337    }
338  }
339  ]]>   
340  </programlisting>
341  </example>
342<para>
343<!-- rlh: where is "direction" from? -->
344
345At this point some row activities may be below their lower bound. To correct this infeasibility, the variable which is cheapest in reducing the sum of infeasibilities is found and updated, and the process repeats.  This is a finite process. (Theimplementation could be faster, but is kept simple for illustrative purposes.)
346  </para>
347  <example>
348  <title>Create Feasible <varname>newSolution</varname> from Initial <varname>newSolution</varname></title>
349  <programlisting>
350  <![CDATA[ 
351  while (true) {
352    // Get column with best ratio
353    int bestColumn=-1;
354    double bestRatio=COIN_DBL_MAX;
355    for (int iColumn=0;iColumn<numberColumns;iColumn++) {
356      CoinBigIndex j;
357      double value = newSolution[iColumn];
358      double cost = direction * objective[iColumn];
359      // we could use original upper rather than current
360      if (value+0.99<columnUpper[iColumn]) {
361        double sum=0.0; // Compute how much we will reduce infeasibility by
362        for (j=columnStart[iColumn];
363             j<columnStart[iColumn]+columnLength[iColumn];j++) {
364          int iRow=row[j];
365          double gap = rowLower[iRow]-rowActivity[iRow];
366          if (gap>1.0e-7) {
367            sum += CoinMin(element[j],gap);
368          if (element[j]+rowActivity[iRow]<rowLower[iRow]+1.0e-7) {
369            sum += element[j];
370          }
371        }
372        if (sum>0.0) {
373          double ratio = (cost/sum)*(1.0+0.1*CoinDrand48());
374          if (ratio<bestRatio) {
375            bestRatio=ratio;
376            bestColumn=iColumn;
377          }
378        }
379      }
380    }
381    if (bestColumn<0)
382      break; // we have finished
383    // Increase chosen column
384    newSolution[bestColumn] += 1.0;
385    double cost = direction * objective[bestColumn];
386    newSolutionValue += cost;
387    for (CoinBigIndex j=columnStart[bestColumn];
388         j<columnStart[bestColumn]+columnLength[bestColumn];j++) {
389      int iRow = row[j];
390      rowActivity[iRow] += element[j];
391    }
392  }
393  ]]>   
394  </programlisting>
395  </example>
396<para>
397A solution value of <varname>newSolution</varname> is compared to the best solution value. If <varname>newSolution</varname> is an improvement, its feasibility is validated.
398  </para>
399  <example>
400  <title>Check Solution Quality of <varname>newSolution</varname></title>
401  <programlisting>
402  <![CDATA[ 
403  returnCode=0; // 0 means no good solution
404  if (newSolutionValue<solutionValue) { // minimization
405    // check feasible
406    memset(rowActivity,0,numberRows*sizeof(double));
407    for (iColumn=0;iColumn<numberColumns;iColumn++) {
408      CoinBigIndex j;
409      double value = newSolution[iColumn];
410      if (value) {
411        for (j=columnStart[iColumn];
412             j<columnStart[iColumn]+columnLength[iColumn];j++) {
413          int iRow=row[j];
414          rowActivity[iRow] += value*element[j];
415        }
416      }
417    }
418    // check was approximately feasible
419    bool feasible=true;
420    for (iRow=0;iRow<numberRows;iRow++) {
421      if(rowActivity[iRow]<rowLower[iRow]) {
422        if (rowActivity[iRow]<rowLower[iRow]-10.0*primalTolerance)
423          feasible = false;
424      }
425    }
426    if (feasible) {
427      // new solution
428      memcpy(betterSolution,newSolution,numberColumns*sizeof(double));
429      solutionValue = newSolutionValue;
430      // We have good solution
431      returnCode=1;
432    }
433  }
434  ]]>   
435  </programlisting>
436  </example>
437  </section>
438</chapter>
439
440<chapter id="branchChapter">
441  <title>
442  Branching
443 </title>
444  <section id="branching">
445  <title>Pseudo Cost Branching</title>
446  <para>
447<!-- rlh: need a description of "objects" -->
448If the user declares variables as integer but does no more, then CBC will treat them
449as simple integer variables.  In many cases the user would like to do some more fine tuning. This section shows how to create integer variables with pseudo costs.  When pseudo costs are given then
450it is assumed that if a variable is at 1.3 then the cost of branching that variable down will be 0.3 times the down pseudo cost and the cost of branching up would be 0.7 times the up pseudo cost.  Pseudo costs can be used both for branching and for choosing a node.
451   The full code is in <filename>longthin.cpp</filename> located in the CBC Samples directory, see
452  <xref linkend="moreexamples"/>.
453</para>
454<para> 
455  The idea is simple for set covering problems.
456  Branching up gets us much closer to an integer solution so we will encourage that direction by branch up if variable value > 0.333333.
457  The expected cost of going up obviously depends on the cost of the
458  variable. The pseudo costs are choosen to reflect that fact.
459<!-- rlh: what's the difference between simple var objects and pseudo cost objects? explain. -->
460  </para>
461  <example id="pseudo">
462  <title><classname>CbcSimpleIntegerPseudoCosts</classname></title>
463  <programlisting>
464  <![CDATA[ 
465  int iColumn;
466  int numberColumns = solver3->getNumCols();
467  // do pseudo costs
468  CbcObject ** objects = new CbcObject * [numberColumns];
469  // Point to objective
470  const double * objective = model.getObjCoefficients();
471  int numberIntegers=0;
472  for (iColumn=0;iColumn<numberColumns;iColumn++) {
473    if (solver3->isInteger(iColumn)) {
474      double cost = objective[iColumn];
475      CbcSimpleIntegerPseudoCost * newObject =
476        new CbcSimpleIntegerPseudoCost(&model,numberIntegers,iColumn,
477                                       2.0*cost,cost);
478      newObject->setMethod(3);
479      objects[numberIntegers++]= newObject;
480    }
481  }
482  // Now add in objects (they will replace simple integers)
483  model.addObjects(numberIntegers,objects);
484  for (iColumn=0;iColumn<numberIntegers;iColumn++)
485    delete objects[iColumn];
486  delete [] objects;
487  ]]>   
488  </programlisting>
489  </example>
490<para>
491The code in <xref linkend="pseudo"/> also tries to give more importance to variables with more
492coefficients.  Whether this sort of thing is worthwhile should be the subject of experimentation.
493<!-- needs more explaination, e.g., why do you have to delete objects? -->
494<!-- what does a pseudo cost object do for you? and how does it do it? -->
495</para>
496</section>
497  <section id="followOn">
498  <title>Follow-On Branching</title>
499  <para>
500In crew scheduling, the problems are long and thin. A problem may have a few rows but many thousands of variables.  Branching a variable to 1 is very powerful as it fixes many other variables to zero, but branching to zero is very weak as thousands of variables can increase from zero.  In crew scheduling problems, each constraint is a flight leg, e.g., JFK airport to DFW airport.
501From DFW there may be several flights the crew could take next - suppose one flight is
502the 9:30 flight from DFW to LAX airport.  A binary branch is that the crew arriving
503at DFW either take the 9:30 flight to LAX or they don't.  This "follow-on" branching does not
504fix individual variables. Instead this branching divides all the variables with entries in the JFK-DFW
505constraint into two groups - those with entries in the DFW-LAX constraint and those without
506entries.
507</para>
508<para>
509   The full sample code for follow-on brancing is in <filename>crew.cpp</filename>
510  located in the CBC Samples directory, see
511  <xref linkend="moreexamples"/>).  In this case, the simple integer
512variables are left which may be necessary if other sorts of constraints exist. Follow-on branching rules are to be considered first, so the priorities are set to indicated the follow-on rules take precedence. Priority 1 is the highest priority.
513<!-- rlh:need to explain how *priorities* work, and where they are used -->
514</para>
515  <example>
516  <title><classname>CbcFollowOn</classname></title>
517  <programlisting>
518  <![CDATA[ 
519  int iColumn;
520  int numberColumns = solver3->getNumCols();
521  /* We are going to add a single follow-on object but we
522     want to give low priority to existing integers
523     As the default priority is 1000 we don't actually need to give
524     integer priorities but it is here to show how.
525  */
526  // Normal integer priorities
527  int * priority = new int [numberColumns];
528  int numberIntegers=0;
529  for (iColumn=0;iColumn<numberColumns;iColumn++) {
530    if (solver3->isInteger(iColumn)) {
531      priority[numberIntegers++]= 100; // low priority
532    }
533  }
534  /* Second parameter is set to true for objects,
535     and false for integers. This indicates integers */
536  model.passInPriorities(priority,false);
537  delete [] priority;
538  /* Add in objects before we can give them a priority.
539     In this case just one object
540     - but it shows the general method
541  */
542  CbcObject ** objects = new CbcObject * [1];
543  objects[0]=new CbcFollowOn(&model);
544  model.addObjects(1,objects);
545  delete objects[0];
546  delete [] objects;
547  // High priority
548  int followPriority=1;
549  model.passInPriorities(&followPriority,true);
550  ]]>   
551  </programlisting>
552  </example>
553<!-- rlh: need to explain the CbcFollowOn object -->
554  </section>
555</chapter>
556<chapter id="SolverChap">
557<title>
558  Advance Solver Uses
559</title>
560  <section id="solver">
561  <title>Creating a Solver via Inheritance</title>
562  <para>
563  CBC uses a generic <classname>OsiSolverInterface</classname> and its <function>resolve</function> capability.
564  This does not give much flexibility so advanced users can inherit from their interface
565  of choice.  This section illustrates how to implement such a solver for a long thin problem, e.g., fast0507 again.  As with the other examples in the Guide, the sample code is not guaranteed to be the fastest way to solve the problem. The main purpose of the example is to illustrate techniques. The full source is in <filename>CbcSolver2.hpp</filename> and <filename>CbcSolver2.cpp</filename> located in the CBC Samples directory, see
566  <xref linkend="moreexamples"/>.
567</para>
568<para>
569The method <function>initialSolve</function> is called a few times in CBC, and provides a convenient starting point. The <varname>modelPtr_</varname> derives from <classname>OsiClpSolverInterface</classname>.
570  </para>
571  <example id="initialSolve">
572  <title><function>initialSolve()</function></title>
573  <programlisting>
574  <![CDATA[ 
575  // modelPtr_ is of type ClpSimplex *
576  modelPtr_->setLogLevel(1); // switch on a bit of printout
577  modelPtr_->scaling(0); // We don't want scaling for fast0507
578  setBasis(basis_,modelPtr_); // Put basis into ClpSimplex
579  // Do long thin by sprint
580  ClpSolve options;
581  options.setSolveType(ClpSolve::usePrimalorSprint);
582  options.setPresolveType(ClpSolve::presolveOff);
583  options.setSpecialOption(1,3,15); // Do 15 sprint iterations
584  modelPtr_->initialSolve(options); // solve problem
585  basis_ = getBasis(modelPtr_); // save basis
586  modelPtr_->setLogLevel(0); // switch off printout
587  ]]>   
588  </programlisting>
589  </example>
590<!-- rlh: need a verbal description to go with the intialSolve() code -->
591<para>
592The <function>resolve()</function> method is more complicated than <function>initialSolve()</function>.  The main pieces of data are a counter <varname>count_</varname> which is incremented each solve and an integer array <varname>node_</varname> which stores the last time
593a variable was active in a solution.  For the first few times, the normal Dual Simplex is called and
594<varname>node_</varname> array is updated.
595</para>
596  <example>
597  <title>First Few Solves</title>
598  <programlisting>
599  <![CDATA[ 
600  if (count_<10) {
601    OsiClpSolverInterface::resolve(); // Normal resolve
602    if (modelPtr_->status()==0) {
603      count_++; // feasible - save any nonzero or basic
604      const double * solution = modelPtr_->primalColumnSolution();
605      for (int i=0;i<numberColumns;i++) {
606        if (solution[i]>1.0e-6||modelPtr_->getStatus(i)==ClpSimplex::basic) {
607          node_[i]=CoinMax(count_,node_[i]);
608          howMany_[i]++;
609        }
610      }
611    } else {
612      printf("infeasible early on\n");
613    }
614  }
615  ]]>   
616  </programlisting>
617  </example>
618<!-- rlh: need more explanation of what's being illustrated in the code -->
619<para>
620After the first few solves, only those variables which took part in a solution in the last so many
621solves are used.  As fast0507 is a set covering problem, any rows which are already covered can be taken out.
622  </para>
623  <example>
624  <title>Create Small Problem</title>
625  <programlisting>
626  <![CDATA[ 
627    int * whichRow = new int[numberRows]; // Array to say which rows used
628    int * whichColumn = new int [numberColumns]; // Array to say which columns used
629    int i;
630    const double * lower = modelPtr_->columnLower();
631    const double * upper = modelPtr_->columnUpper();
632    setBasis(basis_,modelPtr_); // Set basis
633    int nNewCol=0; // Number of columns in small model
634    // Column copy of matrix
635    const double * element = modelPtr_->matrix()->getElements();
636    const int * row = modelPtr_->matrix()->getIndices();
637    const CoinBigIndex * columnStart = modelPtr_->matrix()->getVectorStarts();
638    const int * columnLength = modelPtr_->matrix()->getVectorLengths();
639   
640    int * rowActivity = new int[numberRows]; // Number of columns with entries in each row
641    memset(rowActivity,0,numberRows*sizeof(int));
642    int * rowActivity2 = new int[numberRows]; // Lower bound on row activity for each row
643    memset(rowActivity2,0,numberRows*sizeof(int));
644    char * mark = (char *) modelPtr_->dualColumnSolution(); // Get some space to mark columns
645    memset(mark,0,numberColumns);
646    for (i=0;i<numberColumns;i++) {
647      bool choose = (node_[i]>count_-memory_&&node_[i]>0); // Choose if used recently
648      // Take if used recently or active in some sense
649      if ((choose&&upper[i])
650          ||(modelPtr_->getStatus(i)!=ClpSimplex::atLowerBound&&
651             modelPtr_->getStatus(i)!=ClpSimplex::isFixed)
652          ||lower[i]>0.0) {
653        mark[i]=1; // mark as used
654        whichColumn[nNewCol++]=i; // add to list
655        CoinBigIndex j;
656        double value = upper[i];
657        if (value) {
658          for (j=columnStart[i];
659               j<columnStart[i]+columnLength[i];j++) {
660            int iRow=row[j];
661            assert (element[j]==1.0);
662            rowActivity[iRow] ++; // This variable can cover this row
663          }
664          if (lower[i]>0.0) {
665            for (j=columnStart[i];
666                 j<columnStart[i]+columnLength[i];j++) {
667              int iRow=row[j];
668              rowActivity2[iRow] ++; // This row redundant
669            }
670          }
671        }
672      }
673    }
674    int nOK=0; // Use to count rows which can be covered
675    int nNewRow=0; // Use to make list of rows needed
676    for (i=0;i<numberRows;i++) {
677      if (rowActivity[i])
678        nOK++;
679      if (!rowActivity2[i])
680        whichRow[nNewRow++]=i; // not satisfied
681      else
682        modelPtr_->setRowStatus(i,ClpSimplex::basic); // make slack basic
683    }
684    if (nOK<numberRows) {
685      // The variables we have do not cover rows - see if we can find any that do
686      for (i=0;i<numberColumns;i++) {
687        if (!mark[i]&&upper[i]) {
688          CoinBigIndex j;
689          int good=0;
690          for (j=columnStart[i];
691               j<columnStart[i]+columnLength[i];j++) {
692            int iRow=row[j];
693            if (!rowActivity[iRow]) {
694              rowActivity[iRow] ++;
695              good++;
696            }
697          }
698          if (good) {
699            nOK+=good; // This covers - put in list
700            whichColumn[nNewCol++]=i;
701          }
702        }
703      }
704    }
705    delete [] rowActivity;
706    delete [] rowActivity2;
707    if (nOK<numberRows) {
708      // By inspection the problem is infeasible - no need to solve
709      modelPtr_->setProblemStatus(1);
710      delete [] whichRow;
711      delete [] whichColumn;
712      printf("infeasible by inspection\n");
713      return;
714    }
715    // Now make up a small model with the right rows and columns
716    ClpSimplex *  temp = new ClpSimplex(modelPtr_,nNewRow,whichRow,nNewCol,whichColumn);
717  ]]>   
718  </programlisting>
719  </example>
720<para>
721If the variables cover the rows, then the problem is feasible (no cuts are being used). If the rows
722were equality constraints, then this might not be the case. More work would be needed.  After the solution, the reduct costs are checked. If any reduced costs are negative, the code goes back to the full problem and cleans up with Primal Simplex.
723  </para>
724  <example>
725  <title>Check Optimal Solution</title>
726  <programlisting>
727  <![CDATA[ 
728    temp->setDualObjectiveLimit(1.0e50); // Switch off dual cutoff as problem is restricted
729    temp->dual(); // solve
730    double * solution = modelPtr_->primalColumnSolution(); // put back solution
731    const double * solution2 = temp->primalColumnSolution();
732    memset(solution,0,numberColumns*sizeof(double));
733    for (i=0;i<nNewCol;i++) {
734      int iColumn = whichColumn[i];
735      solution[iColumn]=solution2[i];
736      modelPtr_->setStatus(iColumn,temp->getStatus(i));
737    }
738    double * rowSolution = modelPtr_->primalRowSolution();
739    const double * rowSolution2 = temp->primalRowSolution();
740    double * dual = modelPtr_->dualRowSolution();
741    const double * dual2 = temp->dualRowSolution();
742    memset(dual,0,numberRows*sizeof(double));
743    for (i=0;i<nNewRow;i++) {
744      int iRow=whichRow[i];
745      modelPtr_->setRowStatus(iRow,temp->getRowStatus(i));
746      rowSolution[iRow]=rowSolution2[i];
747      dual[iRow]=dual2[i];
748    }
749    // See if optimal
750    double * dj = modelPtr_->dualColumnSolution();
751    // get reduced cost for large problem
752    // this assumes minimization
753    memcpy(dj,modelPtr_->objective(),numberColumns*sizeof(double));
754    modelPtr_->transposeTimes(-1.0,dual,dj);
755    modelPtr_->setObjectiveValue(temp->objectiveValue());
756    modelPtr_->setProblemStatus(0);
757    int nBad=0;
758     
759    for (i=0;i<numberColumns;i++) {
760      if (modelPtr_->getStatus(i)==ClpSimplex::atLowerBound
761          &&upper[i]>lower[i]&&dj[i]<-1.0e-5)
762        nBad++;
763    }
764    // If necessary clean up with primal (and save some statistics)
765    if (nBad) {
766      timesBad_++;
767      modelPtr_->primal(1);
768      iterationsBad_ += modelPtr_->numberIterations();
769    }
770  ]]>   
771  </programlisting>
772  </example>
773<para>
774The array <varname>node_</varname> is updated, as for the first few solves.  To give some idea of the effect of this tactic, the problem fast0507 has 63,009 variables but the small problem never has more than 4,000 variables. In only about ten percent of solves was it necessary to resolve, and then the average number of iterations
775on full problem was less than 20.
776</para>
777</section>
778 <section id="quadratic">
779  <title>Quadratic MIP</title>
780<para>
781To give another example - again only for illustrative purposes -- it is possible to do quadratic
782MIP with CBC.  In this case, we make <function>resolve</function> the same as
783<function>initialSolve</function>.
784   The full code is in <filename>ClpQuadInterface.hpp</filename> and
785   <filename>ClpQuadInterface.cpp</filename> located in the CBC Samples directory, see
786  <xref linkend="moreexamples"/>).
787  </para>
788  <example>
789  <title>Solving a Quadratic MIP</title>
790  <programlisting>
791  <![CDATA[ 
792  // save cutoff
793  double cutoff = modelPtr_->dualObjectiveLimit();
794  modelPtr_->setDualObjectiveLimit(1.0e50);
795  modelPtr_->scaling(0);
796  modelPtr_->setLogLevel(0);
797  // solve with no objective to get feasible solution
798  setBasis(basis_,modelPtr_);
799  modelPtr_->dual();
800  basis_ = getBasis(modelPtr_);
801  modelPtr_->setDualObjectiveLimit(cutoff);
802  if (modelPtr_->problemStatus())
803    return; // problem was infeasible
804  // Now pass in quadratic objective
805  ClpObjective * saveObjective  = modelPtr_->objectiveAsObject();
806  modelPtr_->setObjectivePointer(quadraticObjective_);
807  modelPtr_->primal();
808  modelPtr_->setDualObjectiveLimit(cutoff);
809  if (modelPtr_->objectiveValue()>cutoff)
810    modelPtr_->setProblemStatus(1);
811  modelPtr_->setObjectivePointer(saveObjective);
812  ]]>   
813  </programlisting>
814  </example>
815  </section>
816  </chapter>
Note: See TracBrowser for help on using the repository browser.