1 | <?xml version="1.0" encoding="ISO-8859-1"?> |
---|
2 | <chapter id="notsobasic"> |
---|
3 | <title> |
---|
4 | Not-Quite-So-Basic Model Classes |
---|
5 | </title> |
---|
6 | <section id="pivotchoices"> |
---|
7 | <title>Pivot Choices</title> |
---|
8 | <para> |
---|
9 | In the dual algorithm, any infeasible basic variable may be chosen to leave the |
---|
10 | basis. Similarly in the primal algorithm, any non-basic variable with a |
---|
11 | "bad" reduced cost may be chosen to enter the basis. This choice is |
---|
12 | probably the most important factor in determining the number of iterations it |
---|
13 | will take to solve a problem. Clp provides a abstract base class for each case |
---|
14 | and then instances of each. It is relatively simple for an advanced user to |
---|
15 | create new instances. |
---|
16 | </para> |
---|
17 | <para> |
---|
18 | For the dual method the base class is <function>ClpDualRowPivot</function>. |
---|
19 | The two existing instances are <function>ClpDualRowDantzig</function> and |
---|
20 | <function>ClpDualRowSteepest</function>. The Dantzig version implements the |
---|
21 | "standard" pivot rule: choose the most violated basic variable. It |
---|
22 | is easily dominated by the Steepest instance which should normally be used. The |
---|
23 | default is to use un-initialized weights where the initial weight for each basic |
---|
24 | variable is 1.0. If an all-slack basis is being used then these are the correct |
---|
25 | weights. To use a version which calculates the weights, create an instance and |
---|
26 | pass it to ClpSimplex model as in the following code fragment: |
---|
27 | </para> |
---|
28 | <programlisting> |
---|
29 | ClpDualRowSteepest steep(1); // 0 uninitialized, 1 compute weights |
---|
30 | model.setDualRowPivotAlgorithm(steep); |
---|
31 | </programlisting> |
---|
32 | <para>Similarly for the primal method the base class is |
---|
33 | <function>ClpPrimalColumnPivot</function>. The two existing instances are |
---|
34 | <function>ClpPrimalColumnDantzig</function> and |
---|
35 | <function>ClpPrimalColumnSteepest</function>. The Dantzig version implements |
---|
36 | "standard" pivot rule: choose the most "violated" non-basic |
---|
37 | variable. It is dominated by the Steepest instance which should normally be |
---|
38 | used. The default is to use exact Devex where the initial weight for each |
---|
39 | non-basic variable is 1.0. Unlike for the dual, this is never the same as |
---|
40 | normal steepest edge. To use a version which does steepest edge create an |
---|
41 | instance and pass it to ClpSimplex model as in the following code fragment: |
---|
42 | </para> |
---|
43 | <programlisting> |
---|
44 | ClpPrimalColumnSteepest steep(1); // 0 devex, 1 steepest |
---|
45 | model.setPrimalColumnPivotAlgorithm(steep); |
---|
46 | </programlisting> |
---|
47 | <para> |
---|
48 | The partial pricing scheme (for long, thin problems) currently does not |
---|
49 | exist. This could be implemented by anyone who is interested. |
---|
50 | </para> |
---|
51 | </section> |
---|
52 | <section id="matrixclasses"> |
---|
53 | <title>Matrix Classes</title> |
---|
54 | <para> |
---|
55 | The next abstract class of interest is <function>ClpMatrixBase</function>. |
---|
56 | CLP encapsulates its knowledge of how a matrix is stored in this class. The |
---|
57 | default instance of this is the <function>ClpPackedMatrix</function> class. |
---|
58 | This is identical in format to <function>CoinPackedMatrix</function>. Below |
---|
59 | is a diagram summarizing the hierarchy of the most important matrix classes: |
---|
60 | </para> |
---|
61 | <mediaobject> |
---|
62 | <!-- Caption doesn't line-up nicely in HTML, leave out for now |
---|
63 | <caption align="top"> |
---|
64 | <para> |
---|
65 | CLP Matrix Classes |
---|
66 | </para> |
---|
67 | </caption> |
---|
68 | --> |
---|
69 | <imageobject> |
---|
70 | <imagedata fileref="figures/clpbasicmatrixhier.gif" format="GIF"/> |
---|
71 | </imageobject> |
---|
72 | </mediaobject> |
---|
73 | <para> |
---|
74 | The important new methods implemented are for filling a basis, checking validity |
---|
75 | of elements and faster "times" and "transposeTimes" when |
---|
76 | the input array is sparse and/or we have a row copy of the matrix. Advanced |
---|
77 | users should note that not all methods have to be implemented. In particular, |
---|
78 | <function>scaling</function> need not be implemented and |
---|
79 | <function>reverseOrderedCopy</function> can return <parameter>NULL</parameter> |
---|
80 | if a row copy does not make sense. |
---|
81 | </para> |
---|
82 | <para> |
---|
83 | In addition to the default class, there are two others at present: |
---|
84 | <function>ClpPlusMinusOneMatrix</function> and |
---|
85 | <function>ClpNetworkMatrix</function>. As the name implies, the first one is |
---|
86 | useful when all elements are ±1. In this case multiplies are not needed |
---|
87 | and more importantly less memory is used and there are fewer cache misses. A |
---|
88 | class for a matrix where all elements are +1 would be trivial to create. If |
---|
89 | there were fewer than 64000 rows one could even store row indices as shorts |
---|
90 | etc. |
---|
91 | </para> |
---|
92 | <para> |
---|
93 | The use of <function>ClpPlusMinusOneMatrix</function> involves some work as one |
---|
94 | cannot simply read-in an MPS file. The key is to use |
---|
95 | <function>loadProblem</function> to pass in a matrix. So if |
---|
96 | <varname>matrix</varname> was a <function>CoinPackedMatrix</function> one |
---|
97 | could do the following: |
---|
98 | </para> |
---|
99 | <programlisting> |
---|
100 | ClpPlusMinusOneMatrix plusMinus(matrix); |
---|
101 | assert (plusMinus.getIndices()); // would be zero if not +- one |
---|
102 | model.loadProblem(plusMinus, |
---|
103 | lowerColumn,upperColumn,objective, |
---|
104 | lower,upper); |
---|
105 | </programlisting> |
---|
106 | <para> |
---|
107 | <function>ClpNetworkMatrix</function> is similar, but represents a network, |
---|
108 | thus may only have one element per column. Fortunately, using is is very |
---|
109 | easy. Given <varname>head</varname> and <varname>tail</varname>, one could |
---|
110 | do the following: |
---|
111 | </para> |
---|
112 | <programlisting> |
---|
113 | ClpNetworkMatrix network(numberColumns,head,tail); |
---|
114 | model.loadProblem(network, |
---|
115 | lowerColumn,upperColumn,objective, |
---|
116 | lower,upper); |
---|
117 | </programlisting> |
---|
118 | <para> |
---|
119 | Actual code is in <filename>COIN/Clp/Test/unitTest.cpp</filename>. A quick |
---|
120 | glance at the output of this program shows that use of |
---|
121 | <function>ClpNetworkMatrix</function> gives much faster run times. This is |
---|
122 | not because of storage issues, but because CLP recognizes the network and uses |
---|
123 | a network basis factorization which is much faster. However, in this mode CLP |
---|
124 | is not a genuine network code as it does not take full advantage of the |
---|
125 | structure by combining operations but it does have the advantage of |
---|
126 | flexibility. |
---|
127 | </para> |
---|
128 | <para> |
---|
129 | Other instances are possible. In particular, it should be possible to use the |
---|
130 | abstract class for column generation or for dynamic matrices which change over |
---|
131 | time. Minor modifications may be needed but it should work quite smoothly |
---|
132 | (there is already a dummy "refresh" method which would be used). |
---|
133 | </para> |
---|
134 | </section> |
---|
135 | <section id="messagehandling"> |
---|
136 | <title>Message Handling</title> |
---|
137 | <para> |
---|
138 | Strictly speaking, message handling is a general COIN topic, but it won't hurt |
---|
139 | to repeat a few important things here. |
---|
140 | </para> |
---|
141 | <para> |
---|
142 | A simple user you may wish to turn off some output. This is done with |
---|
143 | <function>model.setLogLevel(int value)</function> |
---|
144 | where 0 gives nothing and each increase in value switches on more |
---|
145 | messages. See <filename>ClpMessage.cpp</filename>, |
---|
146 | <filename>CoinMessage.cpp</filename> and <xref linkend="messages"/> to see |
---|
147 | which messages are at which level. A more sophisticated user may wish to |
---|
148 | handle messages in a different way. This is done using |
---|
149 | <function>passInMessageHandler</function> with a pointer to a handler of the |
---|
150 | user's own design. The simplest case would be to use the default handler but |
---|
151 | use a constructor which writes to file. The code would be: |
---|
152 | </para> |
---|
153 | <programlisting> |
---|
154 | FILE * fp; // assumed open |
---|
155 | CoinMessageHandler handler(fp); |
---|
156 | model.passInMessageHandler(&handler); |
---|
157 | </programlisting> |
---|
158 | <para> |
---|
159 | A still more sophisticated use would be to write a class derived from |
---|
160 | <function>CoinMessageHandler</function> and then override the |
---|
161 | <function>print</function> method. Below follows an example which would |
---|
162 | print only a message for optimality (or infeasibility): |
---|
163 | </para> |
---|
164 | <example> |
---|
165 | <title>Sophisticated message handling</title> |
---|
166 | <programlisting> |
---|
167 | class DerivedHandler : |
---|
168 | public CoinMessageHandler { |
---|
169 | public: |
---|
170 | virtual int print() ; |
---|
171 | }; |
---|
172 | |
---|
173 | |
---|
174 | int DerivedHandler::print() |
---|
175 | { |
---|
176 | if (currentSource()=="Clp") { |
---|
177 | if (currentMessage().externalNumber()>=0 |
---|
178 | && currentMessage().externalNumber()<4) { |
---|
179 | // finished |
---|
180 | return CoinMessageHandler::print(); // print |
---|
181 | } |
---|
182 | } |
---|
183 | return 0; |
---|
184 | } |
---|
185 | </programlisting> |
---|
186 | </example> |
---|
187 | </section> |
---|
188 | </chapter> |
---|