1 /* $Id: AbcMatrix.hpp 2385 2019-01-06 19:43:06Z unxusr $ */
2 // Copyright (C) 2002, International Business Machines
3 // Corporation and others, Copyright (C) 2012, FasterCoin.  All Rights Reserved.
4 // This code is licensed under the terms of the Eclipse Public License (EPL).
5 
6 #ifndef AbcMatrix_H
7 #define AbcMatrix_H
8 
9 #include "CoinPragma.hpp"
10 
11 #include "ClpMatrixBase.hpp"
12 #include "AbcSimplex.hpp"
13 #include "CoinAbcHelperFunctions.hpp"
14 /** This implements a scaled version of CoinPackedMatrix
15     It may have THREE! copies
16     1) scaled CoinPackedMatrix without gaps
17     2) row copy non-basic,basic, fixed
18     3) vector copy
19 */
20 class AbcMatrix2;
21 class AbcMatrix3;
22 class AbcMatrix {
23 
24 public:
25   /**@name Useful methods */
26   //@{
27   /// Return a complete CoinPackedMatrix
getPackedMatrix() const28   inline CoinPackedMatrix *getPackedMatrix() const
29   {
30     return matrix_;
31   }
32   /** Whether the packed matrix is column major ordered or not. */
isColOrdered() const33   inline bool isColOrdered() const
34   {
35     return true;
36   }
37   /** Number of entries in the packed matrix. */
getNumElements() const38   inline CoinBigIndex getNumElements() const
39   {
40     return matrix_->getNumElements();
41   }
42   /** Number of columns. */
getNumCols() const43   inline int getNumCols() const
44   {
45     assert(matrix_->getNumCols() == model_->numberColumns());
46     return matrix_->getNumCols();
47   }
48   /** Number of rows. */
getNumRows() const49   inline int getNumRows() const
50   {
51     assert(matrix_->getNumRows() == model_->numberRows());
52     return matrix_->getNumRows();
53   }
54   /// Sets model
55   void setModel(AbcSimplex *model);
56   /// A vector containing the elements in the packed matrix.
getElements() const57   inline const double *getElements() const
58   {
59     return matrix_->getElements();
60   }
61   /// Mutable elements
getMutableElements() const62   inline double *getMutableElements() const
63   {
64     return matrix_->getMutableElements();
65   }
66   /// A vector containing the minor indices of the elements in the packed matrix.
getIndices() const67   inline const int *getIndices() const
68   {
69     return matrix_->getIndices();
70   }
71   /// A vector containing the minor indices of the elements in the packed matrix.
getMutableIndices() const72   inline int *getMutableIndices() const
73   {
74     return matrix_->getMutableIndices();
75   }
76   /// Starts
getVectorStarts() const77   inline const CoinBigIndex *getVectorStarts() const
78   {
79     return matrix_->getVectorStarts();
80   }
getMutableVectorStarts() const81   inline CoinBigIndex *getMutableVectorStarts() const
82   {
83     return matrix_->getMutableVectorStarts();
84   }
85   /** The lengths of the major-dimension vectors. */
getVectorLengths() const86   inline const int *getVectorLengths() const
87   {
88     return matrix_->getVectorLengths();
89   }
90   /** The lengths of the major-dimension vectors. */
getMutableVectorLengths() const91   inline int *getMutableVectorLengths() const
92   {
93     return matrix_->getMutableVectorLengths();
94   }
95   /// Row starts
96   CoinBigIndex *rowStart() const;
97   /// Row ends
98   CoinBigIndex *rowEnd() const;
99   /// Row elements
100   double *rowElements() const;
101   /// Row columns
102   CoinSimplexInt *rowColumns() const;
103   /** Returns a new matrix in reverse order without gaps */
104   CoinPackedMatrix *reverseOrderedCopy() const;
105   /// Returns number of elements in column part of basis
106   CoinBigIndex countBasis(const int *whichColumn,
107     int &numberColumnBasic);
108   /// Fills in column part of basis
109   void fillBasis(const int *whichColumn,
110     int &numberColumnBasic,
111     int *row, int *start,
112     int *rowCount, int *columnCount,
113     CoinSimplexDouble *element);
114   /// Fills in column part of basis
115   void fillBasis(const int *whichColumn,
116     int &numberColumnBasic,
117     int *row, int *start,
118     int *rowCount, int *columnCount,
119     long double *element);
120   /** Scales and creates row copy
121   */
122   void scale(int numberRowsAlreadyScaled);
123   /// Creates row copy
124   void createRowCopy();
125   /// Take out of useful
126   void takeOutOfUseful(int sequence, CoinIndexedVector &spare);
127   /// Put into useful
128   void putIntofUseful(int sequence, CoinIndexedVector &spare);
129   /// Put in and out for useful
130   void inOutUseful(int sequenceIn, int sequenceOut);
131   /// Make all useful
132   void makeAllUseful(CoinIndexedVector &spare);
133   /// Sort into useful
134   void sortUseful(CoinIndexedVector &spare);
135   /// Move largest in column to beginning (not used as doesn't help factorization)
136   void moveLargestToStart();
137 
138   /** Unpacks a column into an CoinIndexedVector
139    */
140   void unpack(CoinIndexedVector &rowArray,
141     int column) const;
142   /** Adds multiple of a column (or slack) into an CoinIndexedvector
143       You can use quickAdd to add to vector */
144   void add(CoinIndexedVector &rowArray, int column, double multiplier) const;
145   //@}
146 
147   /**@name Matrix times vector methods */
148   //@{
149   /** Return <code>y + A * scalar *x</code> in <code>y</code>.
150       @pre <code>x</code> must be of size <code>numColumns()</code>
151       @pre <code>y</code> must be of size <code>numRows()</code> */
152   void timesModifyExcludingSlacks(double scalar,
153     const double *x, double *y) const;
154   /** Return <code>y + A * scalar(+-1) *x</code> in <code>y</code>.
155       @pre <code>x</code> must be of size <code>numColumns()+numRows()</code>
156       @pre <code>y</code> must be of size <code>numRows()</code> */
157   void timesModifyIncludingSlacks(double scalar,
158     const double *x, double *y) const;
159   /** Return <code>A * scalar(+-1) *x</code> in <code>y</code>.
160       @pre <code>x</code> must be of size <code>numColumns()+numRows()</code>
161       @pre <code>y</code> must be of size <code>numRows()</code> */
162   void timesIncludingSlacks(double scalar,
163     const double *x, double *y) const;
164   /** Return A * scalar(+-1) *x + y</code> in <code>y</code>.
165       @pre <code>x</code> must be of size <code>numRows()</code>
166       @pre <code>y</code> must be of size <code>numRows()+numColumns()</code> */
167   void transposeTimesNonBasic(double scalar,
168     const double *x, double *y) const;
169   /** Return y - A * x</code> in <code>y</code>.
170       @pre <code>x</code> must be of size <code>numRows()</code>
171       @pre <code>y</code> must be of size <code>numRows()+numColumns()</code> */
172   void transposeTimesAll(const double *x, double *y) const;
173   /** Return y + A * scalar(+-1) *x</code> in <code>y</code>.
174       @pre <code>x</code> must be of size <code>numRows()</code>
175       @pre <code>y</code> must be of size <code>numRows()</code> */
176   void transposeTimesBasic(double scalar,
177     const double *x, double *y) const;
178   /** Return <code>x * scalar * A/code> in <code>z</code>.
179       Note - x unpacked mode - z packed mode including slacks
180       All these return atLo/atUp first then free/superbasic
181       number of first set returned
182       pivotVariable is extended to have that order
183       reversePivotVariable used to update that list
184       free/superbasic only stored in normal format
185       can use spare array to get this effect
186       may put djs alongside atLo/atUp
187       Squashes small elements and knows about AbcSimplex */
188   int transposeTimesNonBasic(double scalar,
189     const CoinIndexedVector &x,
190     CoinIndexedVector &z) const;
191   /// gets sorted tableau row and a possible value of theta
192   double dualColumn1(const CoinIndexedVector &update,
193     CoinPartitionedVector &tableauRow,
194     CoinPartitionedVector &candidateList) const;
195   /// gets sorted tableau row and a possible value of theta
196   double dualColumn1Row(int iBlock, double upperThetaSlack, int &freeSequence,
197     const CoinIndexedVector &update,
198     CoinPartitionedVector &tableauRow,
199     CoinPartitionedVector &candidateList) const;
200   /// gets sorted tableau row and a possible value of theta
201   double dualColumn1RowFew(int iBlock, double upperThetaSlack, int &freeSequence,
202     const CoinIndexedVector &update,
203     CoinPartitionedVector &tableauRow,
204     CoinPartitionedVector &candidateList) const;
205   /// gets sorted tableau row and a possible value of theta
206   double dualColumn1Row2(double upperThetaSlack, int &freeSequence,
207     const CoinIndexedVector &update,
208     CoinPartitionedVector &tableauRow,
209     CoinPartitionedVector &candidateList) const;
210   /// gets sorted tableau row and a possible value of theta
211   double dualColumn1Row1(double upperThetaSlack, int &freeSequence,
212     const CoinIndexedVector &update,
213     CoinPartitionedVector &tableauRow,
214     CoinPartitionedVector &candidateList) const;
215   /** gets sorted tableau row and a possible value of theta
216       On input first,last give what to scan
217       On output is number in tableauRow and candidateList */
218   void dualColumn1Part(int iBlock, int &sequenceIn, double &upperTheta,
219     const CoinIndexedVector &update,
220     CoinPartitionedVector &tableauRow,
221     CoinPartitionedVector &candidateList) const;
222   /// rebalance for parallel
223   void rebalance() const;
224   /// Get sequenceIn when Dantzig
225   int pivotColumnDantzig(const CoinIndexedVector &updates,
226     CoinPartitionedVector &spare) const;
227   /// Get sequenceIn when Dantzig (One block)
228   int pivotColumnDantzig(int iBlock, bool doByRow, const CoinIndexedVector &updates,
229     CoinPartitionedVector &spare,
230     double &bestValue) const;
231   /// gets tableau row - returns number of slacks in block
232   int primalColumnRow(int iBlock, bool doByRow, const CoinIndexedVector &update,
233     CoinPartitionedVector &tableauRow) const;
234   /// gets tableau row and dj row - returns number of slacks in block
235   int primalColumnRowAndDjs(int iBlock, const CoinIndexedVector &updateTableau,
236     const CoinIndexedVector &updateDjs,
237     CoinPartitionedVector &tableauRow) const;
238   /** Chooses best weighted dj
239    */
240   int chooseBestDj(int iBlock, const CoinIndexedVector &infeasibilities,
241     const double *weights) const;
242   /** does steepest edge double or triple update
243       If scaleFactor!=0 then use with tableau row to update djs
244       otherwise use updateForDjs
245       Returns best sequence
246    */
247   int primalColumnDouble(int iBlock, CoinPartitionedVector &updateForTableauRow,
248     CoinPartitionedVector &updateForDjs,
249     const CoinIndexedVector &updateForWeights,
250     CoinPartitionedVector &spareColumn1,
251     double *infeasibilities,
252     double referenceIn, double devex,
253     // Array for exact devex to say what is in reference framework
254     unsigned int *reference,
255     double *weights, double scaleFactor) const;
256   /** does steepest edge double or triple update
257       If scaleFactor!=0 then use with tableau row to update djs
258       otherwise use updateForDjs
259       Returns best sequence
260    */
261   int primalColumnSparseDouble(int iBlock, CoinPartitionedVector &updateForTableauRow,
262     CoinPartitionedVector &updateForDjs,
263     const CoinIndexedVector &updateForWeights,
264     CoinPartitionedVector &spareColumn1,
265     double *infeasibilities,
266     double referenceIn, double devex,
267     // Array for exact devex to say what is in reference framework
268     unsigned int *reference,
269     double *weights, double scaleFactor) const;
270   /** does steepest edge double or triple update
271       If scaleFactor!=0 then use with tableau row to update djs
272       otherwise use updateForDjs
273       Returns best sequence
274    */
275   int primalColumnDouble(CoinPartitionedVector &updateForTableauRow,
276     CoinPartitionedVector &updateForDjs,
277     const CoinIndexedVector &updateForWeights,
278     CoinPartitionedVector &spareColumn1,
279     CoinIndexedVector &infeasible,
280     double referenceIn, double devex,
281     // Array for exact devex to say what is in reference framework
282     unsigned int *reference,
283     double *weights, double scaleFactor) const;
284   /// gets subset updates
285   void primalColumnSubset(int iBlock, const CoinIndexedVector &update,
286     const CoinPartitionedVector &tableauRow,
287     CoinPartitionedVector &weights) const;
288   /// Partial pricing
289   void partialPricing(double startFraction, double endFraction,
290     int &bestSequence, int &numberWanted);
291   /** Return <code>x *A</code> in <code>z</code> but
292       just for indices Already in z.
293       Note - z always packed mode */
294   void subsetTransposeTimes(const CoinIndexedVector &x,
295     CoinIndexedVector &z) const;
296   /// Return <code>-x *A</code> in <code>z</code>
297   void transposeTimes(const CoinIndexedVector &x,
298     CoinIndexedVector &z) const;
299   //@}
300 
301   /**@name Other */
302   //@{
303   /// Returns CoinPackedMatrix (non const)
matrix() const304   inline CoinPackedMatrix *matrix() const
305   {
306     return matrix_;
307   }
308   /** Partial pricing tuning parameter - minimum number of "objects" to scan.
309       e.g. number of Gub sets but could be number of variables */
minimumObjectsScan() const310   inline int minimumObjectsScan() const
311   {
312     return minimumObjectsScan_;
313   }
setMinimumObjectsScan(int value)314   inline void setMinimumObjectsScan(int value)
315   {
316     minimumObjectsScan_ = value;
317   }
318   /// Partial pricing tuning parameter - minimum number of negative reduced costs to get
minimumGoodReducedCosts() const319   inline int minimumGoodReducedCosts() const
320   {
321     return minimumGoodReducedCosts_;
322   }
setMinimumGoodReducedCosts(int value)323   inline void setMinimumGoodReducedCosts(int value)
324   {
325     minimumGoodReducedCosts_ = value;
326   }
327   /// Current start of search space in matrix (as fraction)
startFraction() const328   inline double startFraction() const
329   {
330     return startFraction_;
331   }
setStartFraction(double value)332   inline void setStartFraction(double value)
333   {
334     startFraction_ = value;
335   }
336   /// Current end of search space in matrix (as fraction)
endFraction() const337   inline double endFraction() const
338   {
339     return endFraction_;
340   }
setEndFraction(double value)341   inline void setEndFraction(double value)
342   {
343     endFraction_ = value;
344   }
345   /// Current best reduced cost
savedBestDj() const346   inline double savedBestDj() const
347   {
348     return savedBestDj_;
349   }
setSavedBestDj(double value)350   inline void setSavedBestDj(double value)
351   {
352     savedBestDj_ = value;
353   }
354   /// Initial number of negative reduced costs wanted
originalWanted() const355   inline int originalWanted() const
356   {
357     return originalWanted_;
358   }
setOriginalWanted(int value)359   inline void setOriginalWanted(int value)
360   {
361     originalWanted_ = value;
362   }
363   /// Current number of negative reduced costs which we still need
currentWanted() const364   inline int currentWanted() const
365   {
366     return currentWanted_;
367   }
setCurrentWanted(int value)368   inline void setCurrentWanted(int value)
369   {
370     currentWanted_ = value;
371   }
372   /// Current best sequence
savedBestSequence() const373   inline int savedBestSequence() const
374   {
375     return savedBestSequence_;
376   }
setSavedBestSequence(int value)377   inline void setSavedBestSequence(int value)
378   {
379     savedBestSequence_ = value;
380   }
381   /// Start of each column block
startColumnBlock() const382   inline int *startColumnBlock() const
383   {
384     return startColumnBlock_;
385   }
386   /// Start of each block (in stored)
blockStart() const387   inline const int *blockStart() const
388   {
389     return blockStart_;
390   }
gotRowCopy() const391   inline bool gotRowCopy() const
392   {
393     return rowStart_ != 0;
394   }
395   /// Start of each block (in stored)
blockStart(int block) const396   inline int blockStart(int block) const
397   {
398     return blockStart_[block];
399   }
400   /// Number of actual column blocks
numberColumnBlocks() const401   inline int numberColumnBlocks() const
402   {
403     return numberColumnBlocks_;
404   }
405   /// Number of actual row blocks
numberRowBlocks() const406   inline int numberRowBlocks() const
407   {
408     return numberRowBlocks_;
409   }
410   //@}
411 
412   /**@name Constructors, destructor */
413   //@{
414   /** Default constructor. */
415   AbcMatrix();
416   /** Destructor */
417   ~AbcMatrix();
418   //@}
419 
420   /**@name Copy method */
421   //@{
422   /** The copy constructor. */
423   AbcMatrix(const AbcMatrix &);
424   /** The copy constructor from an CoinPackedMatrix. */
425   AbcMatrix(const CoinPackedMatrix &);
426   /** Subset constructor (without gaps).  Duplicates are allowed
427       and order is as given */
428   AbcMatrix(const AbcMatrix &wholeModel,
429     int numberRows, const int *whichRows,
430     int numberColumns, const int *whichColumns);
431   AbcMatrix(const CoinPackedMatrix &wholeModel,
432     int numberRows, const int *whichRows,
433     int numberColumns, const int *whichColumns);
434 
435   AbcMatrix &operator=(const AbcMatrix &);
436   /// Copy contents - resizing if necessary - otherwise re-use memory
437   void copy(const AbcMatrix *from);
438   //@}
439 private:
440 protected:
441   /**@name Data members
442      The data members are protected to allow access for derived classes. */
443   //@{
444   /// Data
445   CoinPackedMatrix *matrix_;
446   /// Model
447   mutable AbcSimplex *model_;
448 #if ABC_PARALLEL == 0
449 #define NUMBER_ROW_BLOCKS 1
450 #define NUMBER_COLUMN_BLOCKS 1
451 #elif ABC_PARALLEL == 1
452 #define NUMBER_ROW_BLOCKS 4
453 #define NUMBER_COLUMN_BLOCKS 4
454 #else
455 #define NUMBER_ROW_BLOCKS 8
456 #define NUMBER_COLUMN_BLOCKS 8
457 #endif
458   /** Start of each row (per block) - last lot are useless
459       first all row starts for block 0, then for block2
460       so NUMBER_ROW_BLOCKS+2 times number rows */
461   CoinBigIndex *rowStart_;
462   /// Values by row
463   double *element_;
464   /// Columns
465   int *column_;
466   /// Start of each column block
467   mutable int startColumnBlock_[NUMBER_COLUMN_BLOCKS + 1];
468   /// Start of each block (in stored)
469   int blockStart_[NUMBER_ROW_BLOCKS + 1];
470   /// Number of actual column blocks
471   mutable int numberColumnBlocks_;
472   /// Number of actual row blocks
473   int numberRowBlocks_;
474   //#define COUNT_COPY
475 #ifdef COUNT_COPY
476 #define MAX_COUNT 13
477   /// Start in elements etc
478   CoinBigIndex countStart_[MAX_COUNT + 1];
479   /// First column
480   int countFirst_[MAX_COUNT + 1];
481   // later int countEndUseful_[MAX_COUNT+1];
482   int *countRealColumn_;
483   // later int * countInverseRealColumn_;
484   CoinBigIndex *countStartLarge_;
485   int *countRow_;
486   double *countElement_;
487   int smallestCount_;
488   int largestCount_;
489 #endif
490   /// Special row copy
491   //AbcMatrix2 * rowCopy_;
492   /// Special column copy
493   //AbcMatrix3 * columnCopy_;
494   /// Current start of search space in matrix (as fraction)
495   double startFraction_;
496   /// Current end of search space in matrix (as fraction)
497   double endFraction_;
498   /// Best reduced cost so far
499   double savedBestDj_;
500   /// Initial number of negative reduced costs wanted
501   int originalWanted_;
502   /// Current number of negative reduced costs which we still need
503   int currentWanted_;
504   /// Saved best sequence in pricing
505   int savedBestSequence_;
506   /// Partial pricing tuning parameter - minimum number of "objects" to scan
507   int minimumObjectsScan_;
508   /// Partial pricing tuning parameter - minimum number of negative reduced costs to get
509   int minimumGoodReducedCosts_;
510   //@}
511 };
512 #ifdef THREAD
513 #include <pthread.h>
514 typedef struct {
515   double acceptablePivot;
516   const AbcSimplex *model;
517   double *spare;
518   int *spareIndex;
519   double *arrayTemp;
520   int *indexTemp;
521   int *numberInPtr;
522   double *bestPossiblePtr;
523   double *upperThetaPtr;
524   int *posFreePtr;
525   double *freePivotPtr;
526   int *numberOutPtr;
527   const unsigned short *count;
528   const double *pi;
529   const CoinBigIndex *rowStart;
530   const double *element;
531   const unsigned short *column;
532   int offset;
533   int numberInRowArray;
534   int numberLook;
535 } dualColumn0Struct;
536 #endif
537 class AbcMatrix2 {
538 
539 public:
540   /**@name Useful methods */
541   //@{
542   /** Return <code>x * -1 * A in <code>z</code>.
543       Note - x packed and z will be packed mode
544       Squashes small elements and knows about AbcSimplex */
545   void transposeTimes(const AbcSimplex *model,
546     const CoinPackedMatrix *rowCopy,
547     const CoinIndexedVector &x,
548     CoinIndexedVector &spareArray,
549     CoinIndexedVector &z) const;
550   /// Returns true if copy has useful information
usefulInfo() const551   inline bool usefulInfo() const
552   {
553     return rowStart_ != NULL;
554   }
555   //@}
556 
557   /**@name Constructors, destructor */
558   //@{
559   /** Default constructor. */
560   AbcMatrix2();
561   /** Constructor from copy. */
562   AbcMatrix2(AbcSimplex *model, const CoinPackedMatrix *rowCopy);
563   /** Destructor */
564   ~AbcMatrix2();
565   //@}
566 
567   /**@name Copy method */
568   //@{
569   /** The copy constructor. */
570   AbcMatrix2(const AbcMatrix2 &);
571   AbcMatrix2 &operator=(const AbcMatrix2 &);
572   //@}
573 
574 protected:
575   /**@name Data members
576      The data members are protected to allow access for derived classes. */
577   //@{
578   /// Number of blocks
579   int numberBlocks_;
580   /// Number of rows
581   int numberRows_;
582   /// Column offset for each block (plus one at end)
583   int *offset_;
584   /// Counts of elements in each part of row
585   mutable unsigned short *count_;
586   /// Row starts
587   mutable CoinBigIndex *rowStart_;
588   /// columns within block
589   unsigned short *column_;
590   /// work arrays
591   double *work_;
592 #ifdef THREAD
593   pthread_t *threadId_;
594   dualColumn0Struct *info_;
595 #endif
596   //@}
597 };
598 typedef struct {
599   CoinBigIndex startElements_; // point to data
600   int startIndices_; // point to column_
601   int numberInBlock_;
602   int numberPrice_; // at beginning
603   int numberElements_; // number elements per column
604 } blockStruct3;
605 class AbcMatrix3 {
606 
607 public:
608   /**@name Useful methods */
609   //@{
610   /** Return <code>x * -1 * A in <code>z</code>.
611       Note - x packed and z will be packed mode
612       Squashes small elements and knows about AbcSimplex */
613   void transposeTimes(const AbcSimplex *model,
614     const double *pi,
615     CoinIndexedVector &output) const;
616   /// Updates two arrays for steepest
617   void transposeTimes2(const AbcSimplex *model,
618     const double *pi, CoinIndexedVector &dj1,
619     const double *piWeight,
620     double referenceIn, double devex,
621     // Array for exact devex to say what is in reference framework
622     unsigned int *reference,
623     double *weights, double scaleFactor);
624   //@}
625 
626   /**@name Constructors, destructor */
627   //@{
628   /** Default constructor. */
629   AbcMatrix3();
630   /** Constructor from copy. */
631   AbcMatrix3(AbcSimplex *model, const CoinPackedMatrix *columnCopy);
632   /** Destructor */
633   ~AbcMatrix3();
634   //@}
635 
636   /**@name Copy method */
637   //@{
638   /** The copy constructor. */
639   AbcMatrix3(const AbcMatrix3 &);
640   AbcMatrix3 &operator=(const AbcMatrix3 &);
641   //@}
642   /**@name Sort methods */
643   //@{
644   /** Sort blocks */
645   void sortBlocks(const AbcSimplex *model);
646   /// Swap one variable
647   void swapOne(const AbcSimplex *model, const AbcMatrix *matrix,
648     int iColumn);
649   //@}
650 
651 protected:
652   /**@name Data members
653      The data members are protected to allow access for derived classes. */
654   //@{
655   /// Number of blocks
656   int numberBlocks_;
657   /// Number of columns
658   int numberColumns_;
659   /// Column indices and reverse lookup (within block)
660   int *column_;
661   /// Starts for odd/long vectors
662   CoinBigIndex *start_;
663   /// Rows
664   int *row_;
665   /// Elements
666   double *element_;
667   /// Blocks (ordinary start at 0 and go to first block)
668   blockStruct *block_;
669   //@}
670 };
671 
672 #endif
673 
674 /* vi: softtabstop=2 shiftwidth=2 expandtab tabstop=2
675 */
676