1/* $Id: ClpPackedMatrix.hpp 1753 2011-06-19 16:27:26Z stefan $ */
2// Copyright (C) 2002, 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 ClpPackedMatrix_H
7#define ClpPackedMatrix_H
8
9#include "CoinPragma.hpp"
10
11#include "ClpMatrixBase.hpp"
12
13// Compilers can produce better code if they know about __restrict
14#ifndef COIN_RESTRICT
15#ifdef COIN_USE_RESTRICT
16#define COIN_RESTRICT __restrict
17#else
18#define COIN_RESTRICT
19#endif
20#endif
21
22/** This implements CoinPackedMatrix as derived from ClpMatrixBase.
23
24 It adds a few methods that know about model as well as matrix
25
26 For details see CoinPackedMatrix */
27
28class ClpPackedMatrix2;
29class ClpPackedMatrix3;
30class ClpPackedMatrix : public ClpMatrixBase {
31
32public:
33 /**@name Useful methods */
34 //@{
35 /// Return a complete CoinPackedMatrix
36 virtual CoinPackedMatrix * getPackedMatrix() const override {
37 return matrix_;
38 }
39 /** Whether the packed matrix is column major ordered or not. */
40 virtual bool isColOrdered() const override {
41 return matrix_->isColOrdered();
42 }
43 /** Number of entries in the packed matrix. */
44 virtual CoinBigIndex getNumElements() const override {
45 return matrix_->getNumElements();
46 }
47 /** Number of columns. */
48 virtual int getNumCols() const override {
49 return matrix_->getNumCols();
50 }
51 /** Number of rows. */
52 virtual int getNumRows() const override {
53 return matrix_->getNumRows();
54 }
55
56 /** A vector containing the elements in the packed matrix. Note that there
57 might be gaps in this list, entries that do not belong to any
58 major-dimension vector. To get the actual elements one should look at
59 this vector together with vectorStarts and vectorLengths. */
60 virtual const double * getElements() const override {
61 return matrix_->getElements();
62 }
63 /// Mutable elements
64 inline double * getMutableElements() const {
65 return matrix_->getMutableElements();
66 }
67 /** A vector containing the minor indices of the elements in the packed
68 matrix. Note that there might be gaps in this list, entries that do not
69 belong to any major-dimension vector. To get the actual elements one
70 should look at this vector together with vectorStarts and
71 vectorLengths. */
72 virtual const int * getIndices() const override {
73 return matrix_->getIndices();
74 }
75
76 virtual const CoinBigIndex * getVectorStarts() const override {
77 return matrix_->getVectorStarts();
78 }
79 /** The lengths of the major-dimension vectors. */
80 virtual const int * getVectorLengths() const override {
81 return matrix_->getVectorLengths();
82 }
83 /** The length of a single major-dimension vector. */
84 virtual int getVectorLength(int index) const override {
85 return matrix_->getVectorSize(index);
86 }
87
88 /** Delete the columns whose indices are listed in <code>indDel</code>. */
89 virtual void deleteCols(const int numDel, const int * indDel) override;
90 /** Delete the rows whose indices are listed in <code>indDel</code>. */
91 virtual void deleteRows(const int numDel, const int * indDel) override;
92#ifndef CLP_NO_VECTOR
93 /// Append Columns
94 virtual void appendCols(int number, const CoinPackedVectorBase * const * columns) override;
95 /// Append Rows
96 virtual void appendRows(int number, const CoinPackedVectorBase * const * rows) override;
97#endif
98 /** Append a set of rows/columns to the end of the matrix. Returns number of errors
99 i.e. if any of the new rows/columns contain an index that's larger than the
100 number of columns-1/rows-1 (if numberOther>0) or duplicates
101 If 0 then rows, 1 if columns */
102 virtual int appendMatrix(int number, int type,
103 const CoinBigIndex * starts, const int * index,
104 const double * element, int numberOther = -1) override;
105 /** Replace the elements of a vector. The indices remain the same.
106 This is only needed if scaling and a row copy is used.
107 At most the number specified will be replaced.
108 The index is between 0 and major dimension of matrix */
109 virtual void replaceVector(const int index,
110 const int numReplace, const double * newElements) {
111 matrix_->replaceVector(index, numReplace, newElements);
112 }
113 /** Modify one element of packed matrix. An element may be added.
114 This works for either ordering If the new element is zero it will be
115 deleted unless keepZero true */
116 virtual void modifyCoefficient(int row, int column, double newElement,
117 bool keepZero = false) override {
118 matrix_->modifyCoefficient(row, column, newElement, keepZero);
119 }
120 /** Returns a new matrix in reverse order without gaps */
121 virtual ClpMatrixBase * reverseOrderedCopy() const override;
122 /// Returns number of elements in column part of basis
123 virtual CoinBigIndex countBasis(const int * whichColumn,
124 int & numberColumnBasic) override;
125 /// Fills in column part of basis
126 virtual void fillBasis(ClpSimplex * model,
127 const int * whichColumn,
128 int & numberColumnBasic,
129 int * row, int * start,
130 int * rowCount, int * columnCount,
131 CoinFactorizationDouble * element) override;
132 /** Creates scales for column copy (rowCopy in model may be modified)
133 returns non-zero if no scaling done */
134 virtual int scale(ClpModel * model, const ClpSimplex * baseModel = nullptr) const override ;
135 /** Scales rowCopy if column copy scaled
136 Only called if scales already exist */
137 virtual void scaleRowCopy(ClpModel * model) const override ;
138 /// Creates scaled column copy if scales exist
139 void createScaledMatrix(ClpSimplex * model) const;
140 /** Realy really scales column copy
141 Only called if scales already exist.
142 Up to user ro delete */
143 virtual ClpMatrixBase * scaledColumnCopy(ClpModel * model) const override ;
144 /** Checks if all elements are in valid range. Can just
145 return true if you are not paranoid. For Clp I will
146 probably expect no zeros. Code can modify matrix to get rid of
147 small elements.
148 check bits (can be turned off to save time) :
149 1 - check if matrix has gaps
150 2 - check if zero elements
151 4 - check and compress duplicates
152 8 - report on large and small
153 */
154 virtual bool allElementsInRange(ClpModel * model,
155 double smallest, double largest,
156 int check = 15) override;
157 /** Returns largest and smallest elements of both signs.
158 Largest refers to largest absolute value.
159 */
160 virtual void rangeOfElements(double & smallestNegative, double & largestNegative,
161 double & smallestPositive, double & largestPositive) override;
162
163 /** Unpacks a column into an CoinIndexedvector
164 */
165 virtual void unpack(const ClpSimplex * model, CoinIndexedVector * rowArray,
166 int column) const override ;
167 /** Unpacks a column into an CoinIndexedvector
168 ** in packed foramt
169 Note that model is NOT const. Bounds and objective could
170 be modified if doing column generation (just for this variable) */
171 virtual void unpackPacked(ClpSimplex * model,
172 CoinIndexedVector * rowArray,
173 int column) const override;
174 /** Adds multiple of a column into an CoinIndexedvector
175 You can use quickAdd to add to vector */
176 virtual void add(const ClpSimplex * model, CoinIndexedVector * rowArray,
177 int column, double multiplier) const override ;
178 /** Adds multiple of a column into an array */
179 virtual void add(const ClpSimplex * model, double * array,
180 int column, double multiplier) const override;
181 /// Allow any parts of a created CoinPackedMatrix to be deleted
182 virtual void releasePackedMatrix() const override { }
183 /** Given positive integer weights for each row fills in sum of weights
184 for each column (and slack).
185 Returns weights vector
186 */
187 virtual CoinBigIndex * dubiousWeights(const ClpSimplex * model, int * inputWeights) const override;
188 /// Says whether it can do partial pricing
189 virtual bool canDoPartialPricing() const override;
190 /// Partial pricing
191 virtual void partialPricing(ClpSimplex * model, double start, double end,
192 int & bestSequence, int & numberWanted) override;
193 /// makes sure active columns correct
194 virtual int refresh(ClpSimplex * model) override;
195 // Really scale matrix
196 virtual void reallyScale(const double * rowScale, const double * columnScale) override;
197 /** Set the dimensions of the matrix. In effect, append new empty
198 columns/rows to the matrix. A negative number for either dimension
199 means that that dimension doesn't change. Otherwise the new dimensions
200 MUST be at least as large as the current ones otherwise an exception
201 is thrown. */
202 virtual void setDimensions(int numrows, int numcols) override;
203 //@}
204
205 /**@name Matrix times vector methods */
206 //@{
207 /** Return <code>y + A * scalar *x</code> in <code>y</code>.
208 @pre <code>x</code> must be of size <code>numColumns()</code>
209 @pre <code>y</code> must be of size <code>numRows()</code> */
210 virtual void times(double scalar,
211 const double * x, double * y) const override;
212 /// And for scaling
213 virtual void times(double scalar,
214 const double * x, double * y,
215 const double * rowScale,
216 const double * columnScale) const override;
217 /** Return <code>y + x * scalar * A</code> in <code>y</code>.
218 @pre <code>x</code> must be of size <code>numRows()</code>
219 @pre <code>y</code> must be of size <code>numColumns()</code> */
220 virtual void transposeTimes(double scalar,
221 const double * x, double * y) const override;
222 /// And for scaling
223 virtual void transposeTimes(double scalar,
224 const double * x, double * y,
225 const double * rowScale,
226 const double * columnScale,
227 double * spare = nullptr) const override;
228 /** Return <code>y - pi * A</code> in <code>y</code>.
229 @pre <code>pi</code> must be of size <code>numRows()</code>
230 @pre <code>y</code> must be of size <code>numColumns()</code>
231 This just does subset (but puts in correct place in y) */
232 void transposeTimesSubset( int number,
233 const int * which,
234 const double * pi, double * y,
235 const double * rowScale,
236 const double * columnScale,
237 double * spare = nullptr) const;
238 /** Return <code>x * scalar * A + y</code> in <code>z</code>.
239 Can use y as temporary array (will be empty at end)
240 Note - If x packed mode - then z packed mode
241 Squashes small elements and knows about ClpSimplex */
242 virtual void transposeTimes(const ClpSimplex * model, double scalar,
243 const CoinIndexedVector * x,
244 CoinIndexedVector * y,
245 CoinIndexedVector * z) const override;
246 /** Return <code>x * scalar * A + y</code> in <code>z</code>.
247 Note - If x packed mode - then z packed mode
248 This does by column and knows no gaps
249 Squashes small elements and knows about ClpSimplex */
250 void transposeTimesByColumn(const ClpSimplex * model, double scalar,
251 const CoinIndexedVector * x,
252 CoinIndexedVector * y,
253 CoinIndexedVector * z) const;
254 /** Return <code>x * scalar * A + y</code> in <code>z</code>.
255 Can use y as temporary array (will be empty at end)
256 Note - If x packed mode - then z packed mode
257 Squashes small elements and knows about ClpSimplex.
258 This version uses row copy*/
259 virtual void transposeTimesByRow(const ClpSimplex * model, double scalar,
260 const CoinIndexedVector * x,
261 CoinIndexedVector * y,
262 CoinIndexedVector * z) const;
263 /** Return <code>x *A</code> in <code>z</code> but
264 just for indices in y.
265 Note - z always packed mode */
266 virtual void subsetTransposeTimes(const ClpSimplex * model,
267 const CoinIndexedVector * x,
268 const CoinIndexedVector * y,
269 CoinIndexedVector * z) const override;
270 /** Returns true if can combine transposeTimes and subsetTransposeTimes
271 and if it would be faster */
272 virtual bool canCombine(const ClpSimplex * model,
273 const CoinIndexedVector * pi) const override;
274 /// Updates two arrays for steepest
275 virtual void transposeTimes2(const ClpSimplex * model,
276 const CoinIndexedVector * pi1, CoinIndexedVector * dj1,
277 const CoinIndexedVector * pi2,
278 CoinIndexedVector * spare,
279 double referenceIn, double devex,
280 // Array for exact devex to say what is in reference framework
281 unsigned int * reference,
282 double * weights, double scaleFactor) override;
283 /// Updates second array for steepest and does devex weights
284 virtual void subsetTimes2(const ClpSimplex * model,
285 CoinIndexedVector * dj1,
286 const CoinIndexedVector * pi2, CoinIndexedVector * dj2,
287 double referenceIn, double devex,
288 // Array for exact devex to say what is in reference framework
289 unsigned int * reference,
290 double * weights, double scaleFactor) override;
291 /// Sets up an effective RHS
292 void useEffectiveRhs(ClpSimplex * model);
293#if COIN_LONG_WORK
294 // For long double versions
295 virtual void times(CoinWorkDouble scalar,
296 const CoinWorkDouble * x, CoinWorkDouble * y) const ;
297 virtual void transposeTimes(CoinWorkDouble scalar,
298 const CoinWorkDouble * x, CoinWorkDouble * y) const ;
299#endif
300//@}
301
302 /**@name Other */
303 //@{
304 /// Returns CoinPackedMatrix (non const)
305 inline CoinPackedMatrix * matrix() const {
306 return matrix_;
307 }
308 /** Just sets matrix_ to NULL so it can be used elsewhere.
309 used in GUB
310 */
311 inline void setMatrixNull() {
312 matrix_ = nullptr;
313 }
314 /// Say we want special column copy
315 inline void makeSpecialColumnCopy() {
316 flags_ |= 16;
317 }
318 /// Say we don't want special column copy
319 void releaseSpecialColumnCopy();
320 /// Are there zeros?
321 inline bool zeros() const {
322 return ((flags_ & 1) != 0);
323 }
324 /// Do we want special column copy
325 inline bool wantsSpecialColumnCopy() const {
326 return ((flags_ & 16) != 0);
327 }
328 /// Flags
329 inline int flags() const {
330 return flags_;
331 }
332 /// Sets flags_ correctly
333 inline void checkGaps() {
334 flags_ = (matrix_->hasGaps()) ? (flags_ | 2) : (flags_ & (~2));
335 }
336 //@}
337
338
339 /**@name Constructors, destructor */
340 //@{
341 /** Default constructor. */
342 ClpPackedMatrix();
343 /** Destructor */
344 virtual ~ClpPackedMatrix();
345 //@}
346
347 /**@name Copy method */
348 //@{
349 /** The copy constructor. */
350 ClpPackedMatrix(const ClpPackedMatrix&);
351 /** The copy constructor from an CoinPackedMatrix. */
352 ClpPackedMatrix(const CoinPackedMatrix&);
353 /** Subset constructor (without gaps). Duplicates are allowed
354 and order is as given */
355 ClpPackedMatrix (const ClpPackedMatrix & wholeModel,
356 int numberRows, const int * whichRows,
357 int numberColumns, const int * whichColumns);
358 ClpPackedMatrix (const CoinPackedMatrix & wholeModel,
359 int numberRows, const int * whichRows,
360 int numberColumns, const int * whichColumns);
361
362 /** This takes over ownership (for space reasons) */
363 ClpPackedMatrix(CoinPackedMatrix * matrix);
364
365 ClpPackedMatrix& operator=(const ClpPackedMatrix&);
366 /// Clone
367 virtual ClpMatrixBase * clone() const override ;
368 /// Copy contents - resizing if necessary - otherwise re-use memory
369 virtual void copy(const ClpPackedMatrix * from);
370 /** Subset clone (without gaps). Duplicates are allowed
371 and order is as given */
372 virtual ClpMatrixBase * subsetClone (
373 int numberRows, const int * whichRows,
374 int numberColumns, const int * whichColumns) const override ;
375 /// make special row copy
376 void specialRowCopy(ClpSimplex * model, const ClpMatrixBase * rowCopy);
377 /// make special column copy
378 void specialColumnCopy(ClpSimplex * model);
379 /// Correct sequence in and out to give true value
380 virtual void correctSequence(const ClpSimplex * model, int & sequenceIn, int & sequenceOut) override ;
381 //@}
382private:
383 /// Meat of transposeTimes by column when not scaled
384 int gutsOfTransposeTimesUnscaled(const double * COIN_RESTRICT pi,
385 int * COIN_RESTRICT index,
386 double * COIN_RESTRICT array,
387 const double tolerance) const;
388 /// Meat of transposeTimes by column when scaled
389 int gutsOfTransposeTimesScaled(const double * COIN_RESTRICT pi,
390 const double * COIN_RESTRICT columnScale,
391 int * COIN_RESTRICT index,
392 double * COIN_RESTRICT array,
393 const double tolerance) const;
394 /// Meat of transposeTimes by column when not scaled and skipping
395 int gutsOfTransposeTimesUnscaled(const double * COIN_RESTRICT pi,
396 int * COIN_RESTRICT index,
397 double * COIN_RESTRICT array,
398 const unsigned char * status,
399 const double tolerance) const;
400 /** Meat of transposeTimes by column when not scaled and skipping
401 and doing part of dualColumn */
402 int gutsOfTransposeTimesUnscaled(const double * COIN_RESTRICT pi,
403 int * COIN_RESTRICT index,
404 double * COIN_RESTRICT array,
405 const unsigned char * status,
406 int * COIN_RESTRICT spareIndex,
407 double * COIN_RESTRICT spareArray,
408 const double * COIN_RESTRICT reducedCost,
409 double & upperTheta,
410 double & bestPossible,
411 double acceptablePivot,
412 double dualTolerance,
413 int & numberRemaining,
414 const double zeroTolerance) const;
415 /// Meat of transposeTimes by column when scaled and skipping
416 int gutsOfTransposeTimesScaled(const double * COIN_RESTRICT pi,
417 const double * COIN_RESTRICT columnScale,
418 int * COIN_RESTRICT index,
419 double * COIN_RESTRICT array,
420 const unsigned char * status,
421 const double tolerance) const;
422 /// Meat of transposeTimes by row n > K if packed - returns number nonzero
423 int gutsOfTransposeTimesByRowGEK(const CoinIndexedVector * COIN_RESTRICT piVector,
424 int * COIN_RESTRICT index,
425 double * COIN_RESTRICT output,
426 int numberColumns,
427 const double tolerance,
428 const double scalar) const;
429 /// Meat of transposeTimes by row n > 2 if packed - returns number nonzero
430 int gutsOfTransposeTimesByRowGE3(const CoinIndexedVector * COIN_RESTRICT piVector,
431 int * COIN_RESTRICT index,
432 double * COIN_RESTRICT output,
433 double * COIN_RESTRICT array2,
434 const double tolerance,
435 const double scalar) const;
436 /// Meat of transposeTimes by row n > 2 if packed - returns number nonzero
437 int gutsOfTransposeTimesByRowGE3a(const CoinIndexedVector * COIN_RESTRICT piVector,
438 int * COIN_RESTRICT index,
439 double * COIN_RESTRICT output,
440 int * COIN_RESTRICT lookup,
441 char * COIN_RESTRICT marked,
442 const double tolerance,
443 const double scalar) const;
444 /// Meat of transposeTimes by row n == 2 if packed
445 void gutsOfTransposeTimesByRowEQ2(const CoinIndexedVector * piVector, CoinIndexedVector * output,
446 CoinIndexedVector * spareVector, const double tolerance, const double scalar) const;
447 /// Meat of transposeTimes by row n == 1 if packed
448 void gutsOfTransposeTimesByRowEQ1(const CoinIndexedVector * piVector, CoinIndexedVector * output,
449 const double tolerance, const double scalar) const;
450 /// Gets rid of special copies
451 void clearCopies();
452
453
454protected:
455 /// Check validity
456 void checkFlags(int type) const;
457 /**@name Data members
458 The data members are protected to allow access for derived classes. */
459 //@{
460 /// Data
461 CoinPackedMatrix * matrix_;
462 /// number of active columns (normally same as number of columns)
463 int numberActiveColumns_;
464 /** Flags -
465 1 - has zero elements
466 2 - has gaps
467 4 - has special row copy
468 8 - has special column copy
469 16 - wants special column copy
470 */
471 int flags_;
472 /// Special row copy
473 ClpPackedMatrix2 * rowCopy_;
474 /// Special column copy
475 ClpPackedMatrix3 * columnCopy_;
476 //@}
477};
478#ifdef THREAD
479#include <pthread.h>
480typedef struct {
481 double acceptablePivot;
482 const ClpSimplex * model;
483 double * spare;
484 int * spareIndex;
485 double * arrayTemp;
486 int * indexTemp;
487 int * numberInPtr;
488 double * bestPossiblePtr;
489 double * upperThetaPtr;
490 int * posFreePtr;
491 double * freePivotPtr;
492 int * numberOutPtr;
493 const unsigned short * count;
494 const double * pi;
495 const CoinBigIndex * rowStart;
496 const double * element;
497 const unsigned short * column;
498 int offset;
499 int numberInRowArray;
500 int numberLook;
501} dualColumn0Struct;
502#endif
503class ClpPackedMatrix2 {
504
505public:
506 /**@name Useful methods */
507 //@{
508 /** Return <code>x * -1 * A in <code>z</code>.
509 Note - x packed and z will be packed mode
510 Squashes small elements and knows about ClpSimplex */
511 void transposeTimes(const ClpSimplex * model,
512 const CoinPackedMatrix * rowCopy,
513 const CoinIndexedVector * x,
514 CoinIndexedVector * spareArray,
515 CoinIndexedVector * z) const;
516 /// Returns true if copy has useful information
517 inline bool usefulInfo() const {
518 return rowStart_ != nullptr;
519 }
520 //@}
521
522
523 /**@name Constructors, destructor */
524 //@{
525 /** Default constructor. */
526 ClpPackedMatrix2();
527 /** Constructor from copy. */
528 ClpPackedMatrix2(ClpSimplex * model, const CoinPackedMatrix * rowCopy);
529 /** Destructor */
530 virtual ~ClpPackedMatrix2();
531 //@}
532
533 /**@name Copy method */
534 //@{
535 /** The copy constructor. */
536 ClpPackedMatrix2(const ClpPackedMatrix2&);
537 ClpPackedMatrix2& operator=(const ClpPackedMatrix2&);
538 //@}
539
540
541protected:
542 /**@name Data members
543 The data members are protected to allow access for derived classes. */
544 //@{
545 /// Number of blocks
546 int numberBlocks_;
547 /// Number of rows
548 int numberRows_;
549 /// Column offset for each block (plus one at end)
550 int * offset_;
551 /// Counts of elements in each part of row
552 mutable unsigned short * count_;
553 /// Row starts
554 mutable CoinBigIndex * rowStart_;
555 /// columns within block
556 unsigned short * column_;
557 /// work arrays
558 double * work_;
559#ifdef THREAD
560 pthread_t * threadId_;
561 dualColumn0Struct * info_;
562#endif
563 //@}
564};
565typedef struct {
566 CoinBigIndex startElements_; // point to data
567 int startIndices_; // point to column_
568 int numberInBlock_;
569 int numberPrice_; // at beginning
570 int numberElements_; // number elements per column
571} blockStruct;
572class ClpPackedMatrix3 {
573
574public:
575 /**@name Useful methods */
576 //@{
577 /** Return <code>x * -1 * A in <code>z</code>.
578 Note - x packed and z will be packed mode
579 Squashes small elements and knows about ClpSimplex */
580 void transposeTimes(const ClpSimplex * model,
581 const double * pi,
582 CoinIndexedVector * output) const;
583 /// Updates two arrays for steepest
584 void transposeTimes2(const ClpSimplex * model,
585 const double * pi, CoinIndexedVector * dj1,
586 const double * piWeight,
587 double referenceIn, double devex,
588 // Array for exact devex to say what is in reference framework
589 unsigned int * reference,
590 double * weights, double scaleFactor);
591 //@}
592
593
594 /**@name Constructors, destructor */
595 //@{
596 /** Default constructor. */
597 ClpPackedMatrix3();
598 /** Constructor from copy. */
599 ClpPackedMatrix3(ClpSimplex * model, const CoinPackedMatrix * columnCopy);
600 /** Destructor */
601 virtual ~ClpPackedMatrix3();
602 //@}
603
604 /**@name Copy method */
605 //@{
606 /** The copy constructor. */
607 ClpPackedMatrix3(const ClpPackedMatrix3&);
608 ClpPackedMatrix3& operator=(const ClpPackedMatrix3&);
609 //@}
610 /**@name Sort methods */
611 //@{
612 /** Sort blocks */
613 void sortBlocks(const ClpSimplex * model);
614 /// Swap one variable
615 void swapOne(const ClpSimplex * model, const ClpPackedMatrix * matrix,
616 int iColumn);
617 //@}
618
619
620protected:
621 /**@name Data members
622 The data members are protected to allow access for derived classes. */
623 //@{
624 /// Number of blocks
625 int numberBlocks_;
626 /// Number of columns
627 int numberColumns_;
628 /// Column indices and reverse lookup (within block)
629 int * column_;
630 /// Starts for odd/long vectors
631 CoinBigIndex * start_;
632 /// Rows
633 int * row_;
634 /// Elements
635 double * element_;
636 /// Blocks (ordinary start at 0 and go to first block)
637 blockStruct * block_;
638 //@}
639};
640
641#endif
642