1 | /* $Id: CoinPackedMatrix.hpp 1505 2011-11-20 16:00:54Z forrest $ */ |
2 | // Copyright (C) 2000, International Business Machines |
3 | // Corporation and others. All Rights Reserved. |
4 | // This code is licensed under the terms of the Eclipse Public License (EPL). |
5 | |
6 | #ifndef CoinPackedMatrix_H |
7 | #define CoinPackedMatrix_H |
8 | |
9 | #include "CoinError.hpp" |
10 | #include "CoinTypes.hpp" |
11 | #ifndef CLP_NO_VECTOR |
12 | #include "CoinPackedVectorBase.hpp" |
13 | #include "CoinShallowPackedVector.hpp" |
14 | #else |
15 | class CoinRelFltEq; |
16 | #endif |
17 | |
18 | /** Sparse Matrix Base Class |
19 | |
20 | This class is intended to represent sparse matrices using row-major |
21 | or column-major ordering. The representation is very efficient for |
22 | adding, deleting, or retrieving major-dimension vectors. Adding |
23 | a minor-dimension vector is less efficient, but can be helped by |
24 | providing "extra" space as described in the next paragraph. Deleting |
25 | a minor-dimension vector requires inspecting all coefficients in the |
26 | matrix. Retrieving a minor-dimension vector would incur the same cost |
27 | and is not supported (except in the sense that you can write a loop to |
28 | retrieve all coefficients one at a time). Consider physically transposing |
29 | the matrix, or keeping a second copy with the other major-vector ordering. |
30 | |
31 | The sparse represention can be completely compact or it can have "extra" |
32 | space available at the end of each major vector. Incorporating extra |
33 | space into the sparse matrix representation can improve performance in |
34 | cases where new data needs to be inserted into the packed matrix against |
35 | the major-vector orientation (e.g, inserting a row into a matrix stored |
36 | in column-major order). |
37 | |
38 | For example if the matrix: |
39 | @verbatim |
40 | 3 1 0 -2 -1 0 0 -1 |
41 | 0 2 1.1 0 0 0 0 0 |
42 | 0 0 1 0 0 1 0 0 |
43 | 0 0 0 2.8 0 0 -1.2 0 |
44 | 5.6 0 0 0 1 0 0 1.9 |
45 | |
46 | was stored by rows (with no extra space) in |
47 | CoinPackedMatrix r then: |
48 | r.getElements() returns a vector containing: |
49 | 3 1 -2 -1 -1 2 1.1 1 1 2.8 -1.2 5.6 1 1.9 |
50 | r.getIndices() returns a vector containing: |
51 | 0 1 3 4 7 1 2 2 5 3 6 0 4 7 |
52 | r.getVectorStarts() returns a vector containing: |
53 | 0 5 7 9 11 14 |
54 | r.getNumElements() returns 14. |
55 | r.getMajorDim() returns 5. |
56 | r.getVectorSize(0) returns 5. |
57 | r.getVectorSize(1) returns 2. |
58 | r.getVectorSize(2) returns 2. |
59 | r.getVectorSize(3) returns 2. |
60 | r.getVectorSize(4) returns 3. |
61 | |
62 | If stored by columns (with no extra space) then: |
63 | c.getElements() returns a vector containing: |
64 | 3 5.6 1 2 1.1 1 -2 2.8 -1 1 1 -1.2 -1 1.9 |
65 | c.getIndices() returns a vector containing: |
66 | 0 4 0 1 1 2 0 3 0 4 2 3 0 4 |
67 | c.getVectorStarts() returns a vector containing: |
68 | 0 2 4 6 8 10 11 12 14 |
69 | c.getNumElements() returns 14. |
70 | c.getMajorDim() returns 8. |
71 | @endverbatim |
72 | |
73 | Compiling this class with CLP_NO_VECTOR defined will excise all methods |
74 | which use CoinPackedVectorBase, CoinPackedVector, or CoinShallowPackedVector |
75 | as parameters or return types. |
76 | |
77 | Compiling this class with COIN_FAST_CODE defined removes index range checks. |
78 | */ |
79 | class CoinPackedMatrix { |
80 | friend void CoinPackedMatrixUnitTest(); |
81 | |
82 | public: |
83 | |
84 | |
85 | //--------------------------------------------------------------------------- |
86 | /**@name Query members */ |
87 | //@{ |
88 | /** Return the current setting of the extra gap. */ |
89 | inline double () const { return extraGap_; } |
90 | /** Return the current setting of the extra major. */ |
91 | inline double () const { return extraMajor_; } |
92 | |
93 | /** Reserve sufficient space for appending major-ordered vectors. |
94 | If create is true, empty columns are created (for column generation) */ |
95 | void reserve(const int newMaxMajorDim, const CoinBigIndex newMaxSize, |
96 | bool create=false); |
97 | /** Clear the data, but do not free any arrays */ |
98 | void clear(); |
99 | |
100 | /** Whether the packed matrix is column major ordered or not. */ |
101 | inline bool isColOrdered() const { return colOrdered_; } |
102 | |
103 | /** Whether the packed matrix has gaps or not. */ |
104 | inline bool hasGaps() const { return (size_<start_[majorDim_]) ; } |
105 | |
106 | /** Number of entries in the packed matrix. */ |
107 | inline CoinBigIndex getNumElements() const { return size_; } |
108 | |
109 | /** Number of columns. */ |
110 | inline int getNumCols() const |
111 | { return colOrdered_ ? majorDim_ : minorDim_; } |
112 | |
113 | /** Number of rows. */ |
114 | inline int getNumRows() const |
115 | { return colOrdered_ ? minorDim_ : majorDim_; } |
116 | |
117 | /*! \brief A vector containing the elements in the packed matrix. |
118 | |
119 | Returns #elements_. Note that there might be gaps in this vector, |
120 | entries that do not belong to any major-dimension vector. To get |
121 | the actual elements one should look at this vector together with |
122 | vectorStarts (#start_) and vectorLengths (#length_). |
123 | */ |
124 | inline const double * getElements() const { return element_; } |
125 | |
126 | /*! \brief A vector containing the minor indices of the elements in |
127 | the packed matrix. |
128 | |
129 | Returns #index_. Note that there might be gaps in this list, |
130 | entries that do not belong to any major-dimension vector. To get |
131 | the actual elements one should look at this vector together with |
132 | vectorStarts (#start_) and vectorLengths (#length_). |
133 | */ |
134 | inline const int * getIndices() const { return index_; } |
135 | |
136 | /*! \brief The size of the <code>vectorStarts</code> array |
137 | |
138 | See #start_. |
139 | */ |
140 | inline int getSizeVectorStarts() const |
141 | { return ((majorDim_ > 0)?(majorDim_+1):(0)) ; } |
142 | |
143 | /*! \brief The size of the <code>vectorLengths</code> array |
144 | |
145 | See #length_. |
146 | */ |
147 | inline int getSizeVectorLengths() const { return majorDim_; } |
148 | |
149 | /*! \brief The positions where the major-dimension vectors start in |
150 | elements and indices. |
151 | |
152 | See #start_. |
153 | */ |
154 | inline const CoinBigIndex * getVectorStarts() const { return start_; } |
155 | |
156 | /*! \brief The lengths of the major-dimension vectors. |
157 | |
158 | See #length_. |
159 | */ |
160 | inline const int * getVectorLengths() const { return length_; } |
161 | |
162 | /** The position of the first element in the i'th major-dimension vector. |
163 | */ |
164 | CoinBigIndex getVectorFirst(const int i) const { |
165 | #ifndef COIN_FAST_CODE |
166 | if (i < 0 || i >= majorDim_) |
167 | throw CoinError("bad index" , "vectorFirst" , "CoinPackedMatrix" ); |
168 | #endif |
169 | return start_[i]; |
170 | } |
171 | /** The position of the last element (well, one entry <em>past</em> the |
172 | last) in the i'th major-dimension vector. */ |
173 | CoinBigIndex getVectorLast(const int i) const { |
174 | #ifndef COIN_FAST_CODE |
175 | if (i < 0 || i >= majorDim_) |
176 | throw CoinError("bad index" , "vectorLast" , "CoinPackedMatrix" ); |
177 | #endif |
178 | return start_[i] + length_[i]; |
179 | } |
180 | /** The length of i'th vector. */ |
181 | inline int getVectorSize(const int i) const { |
182 | #ifndef COIN_FAST_CODE |
183 | if (i < 0 || i >= majorDim_) |
184 | throw CoinError("bad index" , "vectorSize" , "CoinPackedMatrix" ); |
185 | #endif |
186 | return length_[i]; |
187 | } |
188 | #ifndef CLP_NO_VECTOR |
189 | /** Return the i'th vector in matrix. */ |
190 | const CoinShallowPackedVector getVector(int i) const { |
191 | #ifndef COIN_FAST_CODE |
192 | if (i < 0 || i >= majorDim_) |
193 | throw CoinError("bad index" , "vector" , "CoinPackedMatrix" ); |
194 | #endif |
195 | return CoinShallowPackedVector(length_[i], |
196 | index_ + start_[i], |
197 | element_ + start_[i], |
198 | false); |
199 | } |
200 | #endif |
201 | /** Returns an array containing major indices. The array is |
202 | getNumElements long and if getVectorStarts() is 0,2,5 then |
203 | the array would start 0,0,1,1,1,2... |
204 | This method is provided to go back from a packed format |
205 | to a triple format. It returns NULL if there are gaps in |
206 | matrix so user should use removeGaps() if there are any gaps. |
207 | It does this as this array has to match getElements() and |
208 | getIndices() and because it makes no sense otherwise. |
209 | The returned array is allocated with <code>new int[]</code>, |
210 | free it with <code>delete[]</code>. */ |
211 | int * getMajorIndices() const; |
212 | //@} |
213 | |
214 | //--------------------------------------------------------------------------- |
215 | /**@name Modifying members */ |
216 | //@{ |
217 | /*! \brief Set the dimensions of the matrix. |
218 | |
219 | The method name is deceptive; the effect is to append empty columns |
220 | and/or rows to the matrix to reach the specified dimensions. |
221 | A negative number for either dimension means that that dimension |
222 | doesn't change. An exception will be thrown if the specified dimensions |
223 | are smaller than the current dimensions. |
224 | */ |
225 | void setDimensions(int numrows, int numcols); |
226 | |
227 | /** Set the extra gap to be allocated to the specified value. */ |
228 | void (const double newGap); |
229 | /** Set the extra major to be allocated to the specified value. */ |
230 | void (const double newMajor); |
231 | #ifndef CLP_NO_VECTOR |
232 | /*! Append a column to the end of the matrix. |
233 | |
234 | When compiled with COIN_DEBUG defined this method throws an exception |
235 | if the column vector specifies a nonexistent row index. Otherwise the |
236 | method assumes that every index fits into the matrix. |
237 | */ |
238 | void appendCol(const CoinPackedVectorBase& vec); |
239 | #endif |
240 | /*! Append a column to the end of the matrix. |
241 | |
242 | When compiled with COIN_DEBUG defined this method throws an exception |
243 | if the column vector specifies a nonexistent row index. Otherwise the |
244 | method assumes that every index fits into the matrix. |
245 | */ |
246 | void appendCol(const int vecsize, |
247 | const int *vecind, const double *vecelem); |
248 | #ifndef CLP_NO_VECTOR |
249 | /*! Append a set of columns to the end of the matrix. |
250 | |
251 | When compiled with COIN_DEBUG defined this method throws an exception |
252 | if any of the column vectors specify a nonexistent row index. Otherwise |
253 | the method assumes that every index fits into the matrix. |
254 | */ |
255 | void appendCols(const int numcols, |
256 | const CoinPackedVectorBase * const * cols); |
257 | #endif |
258 | /*! Append a set of columns to the end of the matrix. |
259 | |
260 | Returns the number of errors (nonexistent or duplicate row index). |
261 | No error checking is performed if \p numberRows < 0. |
262 | */ |
263 | int appendCols(const int numcols, |
264 | const CoinBigIndex * columnStarts, const int * row, |
265 | const double * element, int numberRows=-1); |
266 | #ifndef CLP_NO_VECTOR |
267 | /*! Append a row to the end of the matrix. |
268 | |
269 | When compiled with COIN_DEBUG defined this method throws an exception |
270 | if the row vector specifies a nonexistent column index. Otherwise the |
271 | method assumes that every index fits into the matrix. |
272 | */ |
273 | void appendRow(const CoinPackedVectorBase& vec); |
274 | #endif |
275 | /*! Append a row to the end of the matrix. |
276 | |
277 | When compiled with COIN_DEBUG defined this method throws an exception |
278 | if the row vector specifies a nonexistent column index. Otherwise the |
279 | method assumes that every index fits into the matrix. |
280 | */ |
281 | void appendRow(const int vecsize, |
282 | const int *vecind, const double *vecelem); |
283 | #ifndef CLP_NO_VECTOR |
284 | /*! Append a set of rows to the end of the matrix. |
285 | |
286 | When compiled with COIN_DEBUG defined this method throws an exception |
287 | if any of the row vectors specify a nonexistent column index. Otherwise |
288 | the method assumes that every index fits into the matrix. |
289 | */ |
290 | void appendRows(const int numrows, |
291 | const CoinPackedVectorBase * const * rows); |
292 | #endif |
293 | /*! Append a set of rows to the end of the matrix. |
294 | |
295 | Returns the number of errors (nonexistent or duplicate column index). |
296 | No error checking is performed if \p numberColumns < 0. |
297 | */ |
298 | int appendRows(const int numrows, |
299 | const CoinBigIndex * rowStarts, const int * column, |
300 | const double * element, int numberColumns=-1); |
301 | |
302 | /** Append the argument to the "right" of the current matrix. Imagine this |
303 | as adding new columns (don't worry about how the matrices are ordered, |
304 | that is taken care of). An exception is thrown if the number of rows |
305 | is different in the matrices. */ |
306 | void rightAppendPackedMatrix(const CoinPackedMatrix& matrix); |
307 | /** Append the argument to the "bottom" of the current matrix. Imagine this |
308 | as adding new rows (don't worry about how the matrices are ordered, |
309 | that is taken care of). An exception is thrown if the number of columns |
310 | is different in the matrices. */ |
311 | void bottomAppendPackedMatrix(const CoinPackedMatrix& matrix); |
312 | |
313 | /** Delete the columns whose indices are listed in <code>indDel</code>. */ |
314 | void deleteCols(const int numDel, const int * indDel); |
315 | /** Delete the rows whose indices are listed in <code>indDel</code>. */ |
316 | void deleteRows(const int numDel, const int * indDel); |
317 | |
318 | /** Replace the elements of a vector. The indices remain the same. |
319 | At most the number specified will be replaced. |
320 | The index is between 0 and major dimension of matrix */ |
321 | void replaceVector(const int index, |
322 | const int numReplace, const double * newElements); |
323 | /** Modify one element of packed matrix. An element may be added. |
324 | This works for either ordering |
325 | If the new element is zero it will be deleted unless |
326 | keepZero true */ |
327 | void modifyCoefficient(int row, int column, double newElement, |
328 | bool keepZero=false); |
329 | /** Return one element of packed matrix. |
330 | This works for either ordering |
331 | If it is not present will return 0.0 */ |
332 | double getCoefficient(int row, int column) const; |
333 | |
334 | /** Eliminate all elements in matrix whose |
335 | absolute value is less than threshold. |
336 | The column starts are not affected. Returns number of elements |
337 | eliminated. Elements eliminated are at end of each vector |
338 | */ |
339 | int compress(double threshold); |
340 | /** Eliminate all duplicate AND small elements in matrix |
341 | The column starts are not affected. Returns number of elements |
342 | eliminated. |
343 | */ |
344 | int eliminateDuplicates(double threshold); |
345 | /** Sort all columns so indices are increasing.in each column */ |
346 | void orderMatrix(); |
347 | /** Really clean up matrix. |
348 | a) eliminate all duplicate AND small elements in matrix |
349 | b) remove all gaps and set extraGap_ and extraMajor_ to 0.0 |
350 | c) reallocate arrays and make max lengths equal to lengths |
351 | d) orders elements |
352 | returns number of elements eliminated |
353 | */ |
354 | int cleanMatrix(double threshold=1.0e-20); |
355 | //@} |
356 | |
357 | //--------------------------------------------------------------------------- |
358 | /**@name Methods that reorganize the whole matrix */ |
359 | //@{ |
360 | /** Remove the gaps from the matrix if there were any |
361 | Can also remove small elements fabs() <= removeValue*/ |
362 | void removeGaps(double removeValue=-1.0); |
363 | |
364 | /** Extract a submatrix from matrix. Those major-dimension vectors of |
365 | the matrix comprise the submatrix whose indices are given in the |
366 | arguments. Does not allow duplicates. */ |
367 | void submatrixOf(const CoinPackedMatrix& matrix, |
368 | const int numMajor, const int * indMajor); |
369 | /** Extract a submatrix from matrix. Those major-dimension vectors of |
370 | the matrix comprise the submatrix whose indices are given in the |
371 | arguments. Allows duplicates and keeps order. */ |
372 | void submatrixOfWithDuplicates(const CoinPackedMatrix& matrix, |
373 | const int numMajor, const int * indMajor); |
374 | #if 0 |
375 | /** Extract a submatrix from matrix. Those major/minor-dimension vectors of |
376 | the matrix comprise the submatrix whose indices are given in the |
377 | arguments. */ |
378 | void submatrixOf(const CoinPackedMatrix& matrix, |
379 | const int numMajor, const int * indMajor, |
380 | const int numMinor, const int * indMinor); |
381 | #endif |
382 | |
383 | /** Copy method. This method makes an exact replica of the argument, |
384 | including the extra space parameters. */ |
385 | void copyOf(const CoinPackedMatrix& rhs); |
386 | /** Copy the arguments to the matrix. If <code>len</code> is a NULL pointer |
387 | then the matrix is assumed to have no gaps in it and <code>len</code> |
388 | will be created accordingly. */ |
389 | void copyOf(const bool colordered, |
390 | const int minor, const int major, const CoinBigIndex numels, |
391 | const double * elem, const int * ind, |
392 | const CoinBigIndex * start, const int * len, |
393 | const double =0.0, const double =0.0); |
394 | /** Copy method. This method makes an exact replica of the argument, |
395 | including the extra space parameters. |
396 | If there is room it will re-use arrays */ |
397 | void copyReuseArrays(const CoinPackedMatrix& rhs); |
398 | |
399 | /*! \brief Make a reverse-ordered copy. |
400 | |
401 | This method makes an exact replica of the argument with the major |
402 | vector orientation changed from row (column) to column (row). |
403 | The extra space parameters are also copied and reversed. |
404 | (Cf. #reverseOrdering, which does the same thing in place.) |
405 | */ |
406 | void reverseOrderedCopyOf(const CoinPackedMatrix& rhs); |
407 | |
408 | /** Assign the arguments to the matrix. If <code>len</code> is a NULL |
409 | pointer then the matrix is assumed to have no gaps in it and |
410 | <code>len</code> will be created accordingly. <br> |
411 | <strong>NOTE 1</strong>: After this method returns the pointers |
412 | passed to the method will be NULL pointers! <br> |
413 | <strong>NOTE 2</strong>: When the matrix is eventually destructed the |
414 | arrays will be deleted by <code>delete[]</code>. Hence one should use |
415 | this method ONLY if all array swere allocated by <code>new[]</code>! */ |
416 | void assignMatrix(const bool colordered, |
417 | const int minor, const int major, |
418 | const CoinBigIndex numels, |
419 | double *& elem, int *& ind, |
420 | CoinBigIndex *& start, int *& len, |
421 | const int maxmajor = -1, const CoinBigIndex maxsize = -1); |
422 | |
423 | |
424 | |
425 | /** Assignment operator. This copies out the data, but uses the current |
426 | matrix's extra space parameters. */ |
427 | CoinPackedMatrix & operator=(const CoinPackedMatrix& rhs); |
428 | |
429 | /*! \brief Reverse the ordering of the packed matrix. |
430 | |
431 | Change the major vector orientation of the matrix data structures from |
432 | row (column) to column (row). (Cf. #reverseOrderedCopyOf, which does |
433 | the same thing but produces a new matrix.) |
434 | */ |
435 | void reverseOrdering(); |
436 | |
437 | /*! \brief Transpose the matrix. |
438 | |
439 | \note |
440 | If you start with a column-ordered matrix and invoke transpose, you |
441 | will have a row-ordered transposed matrix. To change the major vector |
442 | orientation (e.g., to transform a column-ordered matrix to a |
443 | column-ordered transposed matrix), invoke transpose() followed by |
444 | #reverseOrdering(). |
445 | */ |
446 | void transpose(); |
447 | |
448 | /*! \brief Swap the content of two packed matrices. */ |
449 | void swap(CoinPackedMatrix& matrix); |
450 | |
451 | //@} |
452 | |
453 | //--------------------------------------------------------------------------- |
454 | /**@name Matrix times vector methods */ |
455 | //@{ |
456 | /** Return <code>A * x</code> in <code>y</code>. |
457 | @pre <code>x</code> must be of size <code>numColumns()</code> |
458 | @pre <code>y</code> must be of size <code>numRows()</code> */ |
459 | void times(const double * x, double * y) const; |
460 | #ifndef CLP_NO_VECTOR |
461 | /** Return <code>A * x</code> in <code>y</code>. Same as the previous |
462 | method, just <code>x</code> is given in the form of a packed vector. */ |
463 | void times(const CoinPackedVectorBase& x, double * y) const; |
464 | #endif |
465 | /** Return <code>x * A</code> in <code>y</code>. |
466 | @pre <code>x</code> must be of size <code>numRows()</code> |
467 | @pre <code>y</code> must be of size <code>numColumns()</code> */ |
468 | void transposeTimes(const double * x, double * y) const; |
469 | #ifndef CLP_NO_VECTOR |
470 | /** Return <code>x * A</code> in <code>y</code>. Same as the previous |
471 | method, just <code>x</code> is given in the form of a packed vector. */ |
472 | void transposeTimes(const CoinPackedVectorBase& x, double * y) const; |
473 | #endif |
474 | //@} |
475 | |
476 | //--------------------------------------------------------------------------- |
477 | /**@name Helper functions used internally, but maybe useful externally. |
478 | |
479 | These methods do not worry about testing whether the packed matrix is |
480 | row or column major ordered; they operate under the assumption that the |
481 | correct version is invoked. In fact, a number of other methods simply |
482 | just call one of these after testing the ordering of the matrix. */ |
483 | //@{ |
484 | |
485 | //------------------------------------------------------------------------- |
486 | /**@name Queries */ |
487 | //@{ |
488 | /** Count the number of entries in every minor-dimension vector and |
489 | return an array containing these lengths. The returned array is |
490 | allocated with <code>new int[]</code>, free it with |
491 | <code>delete[]</code>. */ |
492 | int * countOrthoLength() const; |
493 | /** Count the number of entries in every minor-dimension vector and |
494 | fill in an array containing these lengths. */ |
495 | void countOrthoLength(int * counts) const; |
496 | /** Major dimension. For row ordered matrix this would be the number of |
497 | rows. */ |
498 | inline int getMajorDim() const { return majorDim_; } |
499 | /** Set major dimension. For row ordered matrix this would be the number of |
500 | rows. Use with great care.*/ |
501 | inline void setMajorDim(int value) { majorDim_ = value; } |
502 | /** Minor dimension. For row ordered matrix this would be the number of |
503 | columns. */ |
504 | inline int getMinorDim() const { return minorDim_; } |
505 | /** Set minor dimension. For row ordered matrix this would be the number of |
506 | columns. Use with great care.*/ |
507 | inline void setMinorDim(int value) { minorDim_ = value; } |
508 | /** Current maximum for major dimension. For row ordered matrix this many |
509 | rows can be added without reallocating the vector related to the |
510 | major dimension (<code>start_</code> and <code>length_</code>). */ |
511 | inline int getMaxMajorDim() const { return maxMajorDim_; } |
512 | |
513 | /** Dump the matrix on stdout. When in dire straits this method can |
514 | help. */ |
515 | void dumpMatrix(const char* fname = nullptr) const; |
516 | |
517 | /// Print a single matrix element. |
518 | void printMatrixElement(const int row_val, const int col_val) const; |
519 | //@} |
520 | |
521 | //------------------------------------------------------------------------- |
522 | /*! @name Append vectors |
523 | |
524 | \details |
525 | When compiled with COIN_DEBUG defined these methods throw an exception |
526 | if the major (minor) vector contains an index that's invalid for the |
527 | minor (major) dimension. Otherwise the methods assume that every index |
528 | fits into the matrix. |
529 | */ |
530 | //@{ |
531 | #ifndef CLP_NO_VECTOR |
532 | /** Append a major-dimension vector to the end of the matrix. */ |
533 | void appendMajorVector(const CoinPackedVectorBase& vec); |
534 | #endif |
535 | /** Append a major-dimension vector to the end of the matrix. */ |
536 | void appendMajorVector(const int vecsize, const int *vecind, |
537 | const double *vecelem); |
538 | #ifndef CLP_NO_VECTOR |
539 | /** Append several major-dimensonvectors to the end of the matrix */ |
540 | void appendMajorVectors(const int numvecs, |
541 | const CoinPackedVectorBase * const * vecs); |
542 | |
543 | /** Append a minor-dimension vector to the end of the matrix. */ |
544 | void appendMinorVector(const CoinPackedVectorBase& vec); |
545 | #endif |
546 | /** Append a minor-dimension vector to the end of the matrix. */ |
547 | void appendMinorVector(const int vecsize, const int *vecind, |
548 | const double *vecelem); |
549 | #ifndef CLP_NO_VECTOR |
550 | /** Append several minor-dimension vectors to the end of the matrix */ |
551 | void appendMinorVectors(const int numvecs, |
552 | const CoinPackedVectorBase * const * vecs); |
553 | #endif |
554 | /*! \brief Append a set of rows (columns) to the end of a column (row) |
555 | ordered matrix. |
556 | |
557 | This case is when we know there are no gaps and majorDim_ will not |
558 | change. |
559 | |
560 | \todo |
561 | This method really belongs in the group of protected methods with |
562 | #appendMinor; there are no safeties here even with COIN_DEBUG. |
563 | Apparently this method was needed in ClpPackedMatrix and giving it |
564 | proper visibility was too much trouble. Should be moved. |
565 | */ |
566 | void appendMinorFast(const int number, |
567 | const CoinBigIndex * starts, const int * index, |
568 | const double * element); |
569 | //@} |
570 | |
571 | //------------------------------------------------------------------------- |
572 | /*! \name Append matrices |
573 | |
574 | \details |
575 | We'll document these methods assuming that the current matrix is |
576 | column major ordered (Hence in the <code>...SameOrdered()</code> |
577 | methods the argument is column ordered, in the |
578 | <code>OrthoOrdered()</code> methods the argument is row ordered.) |
579 | */ |
580 | //@{ |
581 | /** Append the columns of the argument to the right end of this matrix. |
582 | @pre <code>minorDim_ == matrix.minorDim_</code> <br> |
583 | This method throws an exception if the minor dimensions are not the |
584 | same. */ |
585 | void majorAppendSameOrdered(const CoinPackedMatrix& matrix); |
586 | /** Append the columns of the argument to the bottom end of this matrix. |
587 | @pre <code>majorDim_ == matrix.majorDim_</code> <br> |
588 | This method throws an exception if the major dimensions are not the |
589 | same. */ |
590 | void minorAppendSameOrdered(const CoinPackedMatrix& matrix); |
591 | /** Append the rows of the argument to the right end of this matrix. |
592 | @pre <code>minorDim_ == matrix.majorDim_</code> <br> |
593 | This method throws an exception if the minor dimension of the |
594 | current matrix is not the same as the major dimension of the |
595 | argument matrix. */ |
596 | void majorAppendOrthoOrdered(const CoinPackedMatrix& matrix); |
597 | /** Append the rows of the argument to the bottom end of this matrix. |
598 | @pre <code>majorDim_ == matrix.minorDim_</code> <br> |
599 | This method throws an exception if the major dimension of the |
600 | current matrix is not the same as the minor dimension of the |
601 | argument matrix. */ |
602 | void minorAppendOrthoOrdered(const CoinPackedMatrix& matrix); |
603 | //@} |
604 | |
605 | //----------------------------------------------------------------------- |
606 | /**@name Delete vectors */ |
607 | //@{ |
608 | /** Delete the major-dimension vectors whose indices are listed in |
609 | <code>indDel</code>. */ |
610 | void deleteMajorVectors(const int numDel, const int * indDel); |
611 | /** Delete the minor-dimension vectors whose indices are listed in |
612 | <code>indDel</code>. */ |
613 | void deleteMinorVectors(const int numDel, const int * indDel); |
614 | //@} |
615 | |
616 | //----------------------------------------------------------------------- |
617 | /**@name Various dot products. */ |
618 | //@{ |
619 | /** Return <code>A * x</code> (multiplied from the "right" direction) in |
620 | <code>y</code>. |
621 | @pre <code>x</code> must be of size <code>majorDim()</code> |
622 | @pre <code>y</code> must be of size <code>minorDim()</code> */ |
623 | void timesMajor(const double * x, double * y) const; |
624 | #ifndef CLP_NO_VECTOR |
625 | /** Return <code>A * x</code> (multiplied from the "right" direction) in |
626 | <code>y</code>. Same as the previous method, just <code>x</code> is |
627 | given in the form of a packed vector. */ |
628 | void timesMajor(const CoinPackedVectorBase& x, double * y) const; |
629 | #endif |
630 | /** Return <code>A * x</code> (multiplied from the "right" direction) in |
631 | <code>y</code>. |
632 | @pre <code>x</code> must be of size <code>minorDim()</code> |
633 | @pre <code>y</code> must be of size <code>majorDim()</code> */ |
634 | void timesMinor(const double * x, double * y) const; |
635 | #ifndef CLP_NO_VECTOR |
636 | /** Return <code>A * x</code> (multiplied from the "right" direction) in |
637 | <code>y</code>. Same as the previous method, just <code>x</code> is |
638 | given in the form of a packed vector. */ |
639 | void timesMinor(const CoinPackedVectorBase& x, double * y) const; |
640 | #endif |
641 | //@} |
642 | //@} |
643 | |
644 | //-------------------------------------------------------------------------- |
645 | /**@name Logical Operations. */ |
646 | //@{ |
647 | #ifndef CLP_NO_VECTOR |
648 | /*! \brief Test for equivalence. |
649 | |
650 | Two matrices are equivalent if they are both row- or column-ordered, |
651 | they have the same dimensions, and each (major) vector is equivalent. |
652 | The operator used to test for equality can be specified using the |
653 | \p FloatEqual template parameter. |
654 | */ |
655 | template <class FloatEqual> bool |
656 | isEquivalent(const CoinPackedMatrix& rhs, const FloatEqual& eq) const |
657 | { |
658 | // Both must be column order or both row ordered and must be of same size |
659 | if ((isColOrdered() ^ rhs.isColOrdered()) || |
660 | (getNumCols() != rhs.getNumCols()) || |
661 | (getNumRows() != rhs.getNumRows()) || |
662 | (getNumElements() != rhs.getNumElements())) |
663 | return false; |
664 | |
665 | for (int i=getMajorDim()-1; i >= 0; --i) { |
666 | CoinShallowPackedVector pv = getVector(i); |
667 | CoinShallowPackedVector rhsPv = rhs.getVector(i); |
668 | if ( !pv.isEquivalent(rhsPv,eq) ) |
669 | return false; |
670 | } |
671 | return true; |
672 | } |
673 | |
674 | /*! \brief Test for equivalence and report differences |
675 | |
676 | Equivalence is defined as for #isEquivalent. In addition, this method will |
677 | print differences to std::cerr. Intended for use in unit tests and |
678 | for debugging. |
679 | */ |
680 | bool isEquivalent2(const CoinPackedMatrix& rhs) const; |
681 | #else |
682 | /*! \brief Test for equivalence. |
683 | |
684 | Two matrices are equivalent if they are both row- or column-ordered, |
685 | they have the same dimensions, and each (major) vector is equivalent. |
686 | This method is optimised for speed. CoinPackedVector#isEquivalent is |
687 | replaced with more efficient code for repeated comparison of |
688 | equal-length vectors. The CoinRelFltEq operator is used. |
689 | */ |
690 | bool isEquivalent(const CoinPackedMatrix& rhs, const CoinRelFltEq & eq) const; |
691 | #endif |
692 | /*! \brief Test for equivalence. |
693 | |
694 | The test for element equality is the default CoinRelFltEq operator. |
695 | */ |
696 | bool isEquivalent(const CoinPackedMatrix& rhs) const; |
697 | //@} |
698 | |
699 | //-------------------------------------------------------------------------- |
700 | /*! \name Non-const methods |
701 | |
702 | These are to be used with great care when doing column generation, etc. |
703 | */ |
704 | //@{ |
705 | /** A vector containing the elements in the packed matrix. Note that there |
706 | might be gaps in this list, entries that do not belong to any |
707 | major-dimension vector. To get the actual elements one should look at |
708 | this vector together with #start_ and #length_. */ |
709 | inline double * getMutableElements() const { return element_; } |
710 | /** A vector containing the minor indices of the elements in the packed |
711 | matrix. Note that there might be gaps in this list, entries that do not |
712 | belong to any major-dimension vector. To get the actual elements one |
713 | should look at this vector together with #start_ and |
714 | #length_. */ |
715 | inline int * getMutableIndices() const { return index_; } |
716 | |
717 | /** The positions where the major-dimension vectors start in #element_ and |
718 | #index_. */ |
719 | inline CoinBigIndex * getMutableVectorStarts() const { return start_; } |
720 | /** The lengths of the major-dimension vectors. */ |
721 | inline int * getMutableVectorLengths() const { return length_; } |
722 | /// Change the size of the bulk store after modifying - be careful |
723 | inline void setNumElements(CoinBigIndex value) |
724 | { size_ = value;} |
725 | /*! NULLify element array |
726 | |
727 | Used when space is very tight. Does not free the space! |
728 | */ |
729 | inline void nullElementArray() {element_=nullptr;} |
730 | |
731 | /*! NULLify start array |
732 | |
733 | Used when space is very tight. Does not free the space! |
734 | */ |
735 | inline void nullStartArray() {start_=nullptr;} |
736 | |
737 | /*! NULLify length array |
738 | |
739 | Used when space is very tight. Does not free the space! |
740 | */ |
741 | inline void nullLengthArray() {length_=nullptr;} |
742 | |
743 | /*! NULLify index array |
744 | |
745 | Used when space is very tight. Does not free the space! |
746 | */ |
747 | inline void nullIndexArray() {index_=nullptr;} |
748 | //@} |
749 | |
750 | //-------------------------------------------------------------------------- |
751 | /*! \name Constructors and destructors */ |
752 | //@{ |
753 | /// Default Constructor creates an empty column ordered packed matrix |
754 | CoinPackedMatrix(); |
755 | |
756 | /// A constructor where the ordering and the gaps are specified |
757 | CoinPackedMatrix(const bool colordered, |
758 | const double , const double ); |
759 | |
760 | CoinPackedMatrix(const bool colordered, |
761 | const int minor, const int major, const CoinBigIndex numels, |
762 | const double * elem, const int * ind, |
763 | const CoinBigIndex * start, const int * len, |
764 | const double , const double ); |
765 | |
766 | CoinPackedMatrix(const bool colordered, |
767 | const int minor, const int major, const CoinBigIndex numels, |
768 | const double * elem, const int * ind, |
769 | const CoinBigIndex * start, const int * len); |
770 | |
771 | /** Create packed matrix from triples. |
772 | If colordered is true then the created matrix will be column ordered. |
773 | Duplicate matrix elements are allowed. The created matrix will have |
774 | the sum of the duplicates. <br> |
775 | For example if: <br> |
776 | rowIndices[0]=2; colIndices[0]=5; elements[0]=2.0 <br> |
777 | rowIndices[1]=2; colIndices[1]=5; elements[1]=0.5 <br> |
778 | then the created matrix will contain a value of 2.5 in row 2 and column 5.<br> |
779 | The matrix is created without gaps. |
780 | */ |
781 | CoinPackedMatrix(const bool colordered, |
782 | const int * rowIndices, |
783 | const int * colIndices, |
784 | const double * elements, |
785 | CoinBigIndex numels ); |
786 | |
787 | /// Copy constructor |
788 | CoinPackedMatrix(const CoinPackedMatrix& m); |
789 | |
790 | /** Copy constructor - fine tuning - allowing extra space and/or reverse ordering. |
791 | extraForMajor is exact extra after any possible reverse ordering. |
792 | extraMajor_ and extraGap_ set to zero. |
793 | */ |
794 | CoinPackedMatrix(const CoinPackedMatrix& m, int , int , bool reverseOrdering=false); |
795 | |
796 | /** Subset constructor (without gaps). Duplicates are allowed |
797 | and order is as given */ |
798 | CoinPackedMatrix (const CoinPackedMatrix & wholeModel, |
799 | int numberRows, const int * whichRows, |
800 | int numberColumns, const int * whichColumns); |
801 | |
802 | /// Destructor |
803 | virtual ~CoinPackedMatrix(); |
804 | //@} |
805 | |
806 | /*! \name Debug Utilities */ |
807 | //@{ |
808 | /*! \brief Scan the matrix for anomalies. |
809 | |
810 | Returns the number of anomalies. Scans the structure for gaps, |
811 | obviously bogus indices and coefficients, and inconsistencies. Gaps |
812 | are not an error unless #hasGaps() says the matrix should be |
813 | gap-free. Zeroes are not an error unless \p zeroesAreError is set to |
814 | true. |
815 | |
816 | Values for verbosity are: |
817 | - 0: No messages, just the return value |
818 | - 1: Messages about errors |
819 | - 2: If there are no errors, a message indicating the matrix was |
820 | checked is printed (positive confirmation). |
821 | - 3: Adds a bit more information about the matrix. |
822 | - 4: Prints warnings about zeroes even if they're not considered |
823 | errors. |
824 | |
825 | Obviously bogus coefficients are coefficients that are NaN or have |
826 | absolute value greater than 1e50. Zeros have absolute value less |
827 | than 1e-50. |
828 | */ |
829 | int verifyMtx(int verbosity = 1, bool zeroesAreError = false) const ; |
830 | //@} |
831 | |
832 | //-------------------------------------------------------------------------- |
833 | protected: |
834 | void gutsOfDestructor(); |
835 | void gutsOfCopyOf(const bool colordered, |
836 | const int minor, const int major, const CoinBigIndex numels, |
837 | const double * elem, const int * ind, |
838 | const CoinBigIndex * start, const int * len, |
839 | const double =0.0, const double =0.0); |
840 | /// When no gaps we can do faster |
841 | void gutsOfCopyOfNoGaps(const bool colordered, |
842 | const int minor, const int major, |
843 | const double * elem, const int * ind, |
844 | const CoinBigIndex * start); |
845 | void gutsOfOpEqual(const bool colordered, |
846 | const int minor, const int major, const CoinBigIndex numels, |
847 | const double * elem, const int * ind, |
848 | const CoinBigIndex * start, const int * len); |
849 | void resizeForAddingMajorVectors(const int numVec, const int * lengthVec); |
850 | void resizeForAddingMinorVectors(const int * addedEntries); |
851 | |
852 | /*! \brief Append a set of rows (columns) to the end of a row (colum) |
853 | ordered matrix. |
854 | |
855 | If \p numberOther > 0 the method will check if any of the new rows |
856 | (columns) contain duplicate indices or invalid indices and return the |
857 | number of errors. A valid minor index must satisfy |
858 | \code 0 <= k < numberOther \endcode |
859 | If \p numberOther < 0 no checking is performed. |
860 | */ |
861 | int appendMajor(const int number, |
862 | const CoinBigIndex * starts, const int * index, |
863 | const double * element, int numberOther=-1); |
864 | /*! \brief Append a set of rows (columns) to the end of a column (row) |
865 | ordered matrix. |
866 | |
867 | If \p numberOther > 0 the method will check if any of the new rows |
868 | (columns) contain duplicate indices or indices outside the current |
869 | range for the major dimension and return the number of violations. |
870 | If \p numberOther <= 0 the major dimension will be expanded as |
871 | necessary and there are no checks for duplicate indices. |
872 | */ |
873 | int appendMinor(const int number, |
874 | const CoinBigIndex * starts, const int * index, |
875 | const double * element, int numberOther=-1); |
876 | |
877 | private: |
878 | inline CoinBigIndex getLastStart() const { |
879 | return majorDim_ == 0 ? 0 : start_[majorDim_]; |
880 | } |
881 | |
882 | //-------------------------------------------------------------------------- |
883 | protected: |
884 | /**@name Data members |
885 | The data members are protected to allow access for derived classes. */ |
886 | //@{ |
887 | /** A flag indicating whether the matrix is column or row major ordered. */ |
888 | bool colOrdered_; |
889 | /** This much times more space should be allocated for each major-dimension |
890 | vector (with respect to the number of entries in the vector) when the |
891 | matrix is resized. The purpose of these gaps is to allow fast insertion |
892 | of new minor-dimension vectors. */ |
893 | double ; |
894 | /** his much times more space should be allocated for major-dimension |
895 | vectors when the matrix is resized. The purpose of these gaps is to |
896 | allow fast addition of new major-dimension vectors. */ |
897 | double ; |
898 | |
899 | /** List of nonzero element values. The entries in the gaps between |
900 | major-dimension vectors are undefined. */ |
901 | double *element_; |
902 | /** List of nonzero element minor-dimension indices. The entries in the gaps |
903 | between major-dimension vectors are undefined. */ |
904 | int *index_; |
905 | /** Starting positions of major-dimension vectors. */ |
906 | CoinBigIndex *start_; |
907 | /** Lengths of major-dimension vectors. */ |
908 | int *length_; |
909 | |
910 | /// number of vectors in matrix |
911 | int majorDim_; |
912 | /// size of other dimension |
913 | int minorDim_; |
914 | /// the number of nonzero entries |
915 | CoinBigIndex size_; |
916 | |
917 | /// max space allocated for major-dimension |
918 | int maxMajorDim_; |
919 | /// max space allocated for entries |
920 | CoinBigIndex maxSize_; |
921 | //@} |
922 | }; |
923 | |
924 | //############################################################################# |
925 | /*! \brief Test the methods in the CoinPackedMatrix class. |
926 | |
927 | The only reason for it not to be a member method is that this way |
928 | it doesn't have to be compiled into the library. And that's a gain, |
929 | because the library should be compiled with optimization on, but this |
930 | method should be compiled with debugging. |
931 | */ |
932 | void |
933 | CoinPackedMatrixUnitTest(); |
934 | |
935 | #endif |
936 | |