1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2008-2009 Guillaume Saupin <guillaume.saupin@cea.fr>
5 //
6 // This Source Code Form is subject to the terms of the Mozilla
7 // Public License v. 2.0. If a copy of the MPL was not distributed
8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 
10 #ifndef EIGEN_SKYLINEMATRIX_H
11 #define EIGEN_SKYLINEMATRIX_H
12 
13 #include "SkylineStorage.h"
14 #include "SkylineMatrixBase.h"
15 
16 namespace Eigen {
17 
18 /** \ingroup Skyline_Module
19  *
20  * \class SkylineMatrix
21  *
22  * \brief The main skyline matrix class
23  *
24  * This class implements a skyline matrix using the very uncommon storage
25  * scheme.
26  *
27  * \param _Scalar the scalar type, i.e. the type of the coefficients
28  * \param _Options Union of bit flags controlling the storage scheme. Currently the only possibility
29  *                 is RowMajor. The default is 0 which means column-major.
30  *
31  *
32  */
33 namespace internal {
34 template<typename _Scalar, int _Options>
35 struct traits<SkylineMatrix<_Scalar, _Options> > {
36     typedef _Scalar Scalar;
37     typedef Sparse StorageKind;
38 
39     enum {
40         RowsAtCompileTime = Dynamic,
41         ColsAtCompileTime = Dynamic,
42         MaxRowsAtCompileTime = Dynamic,
43         MaxColsAtCompileTime = Dynamic,
44         Flags = SkylineBit | _Options,
45         CoeffReadCost = NumTraits<Scalar>::ReadCost,
46     };
47 };
48 }
49 
50 template<typename _Scalar, int _Options>
51 class SkylineMatrix
52 : public SkylineMatrixBase<SkylineMatrix<_Scalar, _Options> > {
53 public:
54     EIGEN_SKYLINE_GENERIC_PUBLIC_INTERFACE(SkylineMatrix)
55     EIGEN_SKYLINE_INHERIT_ASSIGNMENT_OPERATOR(SkylineMatrix, +=)
56     EIGEN_SKYLINE_INHERIT_ASSIGNMENT_OPERATOR(SkylineMatrix, -=)
57 
58     using Base::IsRowMajor;
59 
60 protected:
61 
62     typedef SkylineMatrix<Scalar, (Flags&~RowMajorBit) | (IsRowMajor ? RowMajorBit : 0) > TransposedSkylineMatrix;
63 
64     Index m_outerSize;
65     Index m_innerSize;
66 
67 public:
68     Index* m_colStartIndex;
69     Index* m_rowStartIndex;
70     SkylineStorage<Scalar> m_data;
71 
72 public:
73 
74     inline Index rows() const {
75         return IsRowMajor ? m_outerSize : m_innerSize;
76     }
77 
78     inline Index cols() const {
79         return IsRowMajor ? m_innerSize : m_outerSize;
80     }
81 
82     inline Index innerSize() const {
83         return m_innerSize;
84     }
85 
86     inline Index outerSize() const {
87         return m_outerSize;
88     }
89 
90     inline Index upperNonZeros() const {
91         return m_data.upperSize();
92     }
93 
94     inline Index lowerNonZeros() const {
95         return m_data.lowerSize();
96     }
97 
98     inline Index upperNonZeros(Index j) const {
99         return m_colStartIndex[j + 1] - m_colStartIndex[j];
100     }
101 
102     inline Index lowerNonZeros(Index j) const {
103         return m_rowStartIndex[j + 1] - m_rowStartIndex[j];
104     }
105 
106     inline const Scalar* _diagPtr() const {
107         return &m_data.diag(0);
108     }
109 
110     inline Scalar* _diagPtr() {
111         return &m_data.diag(0);
112     }
113 
114     inline const Scalar* _upperPtr() const {
115         return &m_data.upper(0);
116     }
117 
118     inline Scalar* _upperPtr() {
119         return &m_data.upper(0);
120     }
121 
122     inline const Scalar* _lowerPtr() const {
123         return &m_data.lower(0);
124     }
125 
126     inline Scalar* _lowerPtr() {
127         return &m_data.lower(0);
128     }
129 
130     inline const Index* _upperProfilePtr() const {
131         return &m_data.upperProfile(0);
132     }
133 
134     inline Index* _upperProfilePtr() {
135         return &m_data.upperProfile(0);
136     }
137 
138     inline const Index* _lowerProfilePtr() const {
139         return &m_data.lowerProfile(0);
140     }
141 
142     inline Index* _lowerProfilePtr() {
143         return &m_data.lowerProfile(0);
144     }
145 
146     inline Scalar coeff(Index row, Index col) const {
147         const Index outer = IsRowMajor ? row : col;
148         const Index inner = IsRowMajor ? col : row;
149 
150         eigen_assert(outer < outerSize());
151         eigen_assert(inner < innerSize());
152 
153         if (outer == inner)
154             return this->m_data.diag(outer);
155 
156         if (IsRowMajor) {
157             if (inner > outer) //upper matrix
158             {
159                 const Index minOuterIndex = inner - m_data.upperProfile(inner);
160                 if (outer >= minOuterIndex)
161                     return this->m_data.upper(m_colStartIndex[inner] + outer - (inner - m_data.upperProfile(inner)));
162                 else
163                     return Scalar(0);
164             }
165             if (inner < outer) //lower matrix
166             {
167                 const Index minInnerIndex = outer - m_data.lowerProfile(outer);
168                 if (inner >= minInnerIndex)
169                     return this->m_data.lower(m_rowStartIndex[outer] + inner - (outer - m_data.lowerProfile(outer)));
170                 else
171                     return Scalar(0);
172             }
173             return m_data.upper(m_colStartIndex[inner] + outer - inner);
174         } else {
175             if (outer > inner) //upper matrix
176             {
177                 const Index maxOuterIndex = inner + m_data.upperProfile(inner);
178                 if (outer <= maxOuterIndex)
179                     return this->m_data.upper(m_colStartIndex[inner] + (outer - inner));
180                 else
181                     return Scalar(0);
182             }
183             if (outer < inner) //lower matrix
184             {
185                 const Index maxInnerIndex = outer + m_data.lowerProfile(outer);
186 
187                 if (inner <= maxInnerIndex)
188                     return this->m_data.lower(m_rowStartIndex[outer] + (inner - outer));
189                 else
190                     return Scalar(0);
191             }
192         }
193     }
194 
195     inline Scalar& coeffRef(Index row, Index col) {
196         const Index outer = IsRowMajor ? row : col;
197         const Index inner = IsRowMajor ? col : row;
198 
199         eigen_assert(outer < outerSize());
200         eigen_assert(inner < innerSize());
201 
202         if (outer == inner)
203             return this->m_data.diag(outer);
204 
205         if (IsRowMajor) {
206             if (col > row) //upper matrix
207             {
208                 const Index minOuterIndex = inner - m_data.upperProfile(inner);
209                 eigen_assert(outer >= minOuterIndex && "you try to acces a coeff that do not exist in the storage");
210                 return this->m_data.upper(m_colStartIndex[inner] + outer - (inner - m_data.upperProfile(inner)));
211             }
212             if (col < row) //lower matrix
213             {
214                 const Index minInnerIndex = outer - m_data.lowerProfile(outer);
215                 eigen_assert(inner >= minInnerIndex && "you try to acces a coeff that do not exist in the storage");
216                 return this->m_data.lower(m_rowStartIndex[outer] + inner - (outer - m_data.lowerProfile(outer)));
217             }
218         } else {
219             if (outer > inner) //upper matrix
220             {
221                 const Index maxOuterIndex = inner + m_data.upperProfile(inner);
222                 eigen_assert(outer <= maxOuterIndex && "you try to acces a coeff that do not exist in the storage");
223                 return this->m_data.upper(m_colStartIndex[inner] + (outer - inner));
224             }
225             if (outer < inner) //lower matrix
226             {
227                 const Index maxInnerIndex = outer + m_data.lowerProfile(outer);
228                 eigen_assert(inner <= maxInnerIndex && "you try to acces a coeff that do not exist in the storage");
229                 return this->m_data.lower(m_rowStartIndex[outer] + (inner - outer));
230             }
231         }
232     }
233 
234     inline Scalar coeffDiag(Index idx) const {
235         eigen_assert(idx < outerSize());
236         eigen_assert(idx < innerSize());
237         return this->m_data.diag(idx);
238     }
239 
240     inline Scalar coeffLower(Index row, Index col) const {
241         const Index outer = IsRowMajor ? row : col;
242         const Index inner = IsRowMajor ? col : row;
243 
244         eigen_assert(outer < outerSize());
245         eigen_assert(inner < innerSize());
246         eigen_assert(inner != outer);
247 
248         if (IsRowMajor) {
249             const Index minInnerIndex = outer - m_data.lowerProfile(outer);
250             if (inner >= minInnerIndex)
251                 return this->m_data.lower(m_rowStartIndex[outer] + inner - (outer - m_data.lowerProfile(outer)));
252             else
253                 return Scalar(0);
254 
255         } else {
256             const Index maxInnerIndex = outer + m_data.lowerProfile(outer);
257             if (inner <= maxInnerIndex)
258                 return this->m_data.lower(m_rowStartIndex[outer] + (inner - outer));
259             else
260                 return Scalar(0);
261         }
262     }
263 
264     inline Scalar coeffUpper(Index row, Index col) const {
265         const Index outer = IsRowMajor ? row : col;
266         const Index inner = IsRowMajor ? col : row;
267 
268         eigen_assert(outer < outerSize());
269         eigen_assert(inner < innerSize());
270         eigen_assert(inner != outer);
271 
272         if (IsRowMajor) {
273             const Index minOuterIndex = inner - m_data.upperProfile(inner);
274             if (outer >= minOuterIndex)
275                 return this->m_data.upper(m_colStartIndex[inner] + outer - (inner - m_data.upperProfile(inner)));
276             else
277                 return Scalar(0);
278         } else {
279             const Index maxOuterIndex = inner + m_data.upperProfile(inner);
280             if (outer <= maxOuterIndex)
281                 return this->m_data.upper(m_colStartIndex[inner] + (outer - inner));
282             else
283                 return Scalar(0);
284         }
285     }
286 
287     inline Scalar& coeffRefDiag(Index idx) {
288         eigen_assert(idx < outerSize());
289         eigen_assert(idx < innerSize());
290         return this->m_data.diag(idx);
291     }
292 
293     inline Scalar& coeffRefLower(Index row, Index col) {
294         const Index outer = IsRowMajor ? row : col;
295         const Index inner = IsRowMajor ? col : row;
296 
297         eigen_assert(outer < outerSize());
298         eigen_assert(inner < innerSize());
299         eigen_assert(inner != outer);
300 
301         if (IsRowMajor) {
302             const Index minInnerIndex = outer - m_data.lowerProfile(outer);
303             eigen_assert(inner >= minInnerIndex && "you try to acces a coeff that do not exist in the storage");
304             return this->m_data.lower(m_rowStartIndex[outer] + inner - (outer - m_data.lowerProfile(outer)));
305         } else {
306             const Index maxInnerIndex = outer + m_data.lowerProfile(outer);
307             eigen_assert(inner <= maxInnerIndex && "you try to acces a coeff that do not exist in the storage");
308             return this->m_data.lower(m_rowStartIndex[outer] + (inner - outer));
309         }
310     }
311 
312     inline bool coeffExistLower(Index row, Index col) {
313         const Index outer = IsRowMajor ? row : col;
314         const Index inner = IsRowMajor ? col : row;
315 
316         eigen_assert(outer < outerSize());
317         eigen_assert(inner < innerSize());
318         eigen_assert(inner != outer);
319 
320         if (IsRowMajor) {
321             const Index minInnerIndex = outer - m_data.lowerProfile(outer);
322             return inner >= minInnerIndex;
323         } else {
324             const Index maxInnerIndex = outer + m_data.lowerProfile(outer);
325             return inner <= maxInnerIndex;
326         }
327     }
328 
329     inline Scalar& coeffRefUpper(Index row, Index col) {
330         const Index outer = IsRowMajor ? row : col;
331         const Index inner = IsRowMajor ? col : row;
332 
333         eigen_assert(outer < outerSize());
334         eigen_assert(inner < innerSize());
335         eigen_assert(inner != outer);
336 
337         if (IsRowMajor) {
338             const Index minOuterIndex = inner - m_data.upperProfile(inner);
339             eigen_assert(outer >= minOuterIndex && "you try to acces a coeff that do not exist in the storage");
340             return this->m_data.upper(m_colStartIndex[inner] + outer - (inner - m_data.upperProfile(inner)));
341         } else {
342             const Index maxOuterIndex = inner + m_data.upperProfile(inner);
343             eigen_assert(outer <= maxOuterIndex && "you try to acces a coeff that do not exist in the storage");
344             return this->m_data.upper(m_colStartIndex[inner] + (outer - inner));
345         }
346     }
347 
348     inline bool coeffExistUpper(Index row, Index col) {
349         const Index outer = IsRowMajor ? row : col;
350         const Index inner = IsRowMajor ? col : row;
351 
352         eigen_assert(outer < outerSize());
353         eigen_assert(inner < innerSize());
354         eigen_assert(inner != outer);
355 
356         if (IsRowMajor) {
357             const Index minOuterIndex = inner - m_data.upperProfile(inner);
358             return outer >= minOuterIndex;
359         } else {
360             const Index maxOuterIndex = inner + m_data.upperProfile(inner);
361             return outer <= maxOuterIndex;
362         }
363     }
364 
365 
366 protected:
367 
368 public:
369     class InnerUpperIterator;
370     class InnerLowerIterator;
371 
372     class OuterUpperIterator;
373     class OuterLowerIterator;
374 
375     /** Removes all non zeros */
376     inline void setZero() {
377         m_data.clear();
378         memset(m_colStartIndex, 0, (m_outerSize + 1) * sizeof (Index));
379         memset(m_rowStartIndex, 0, (m_outerSize + 1) * sizeof (Index));
380     }
381 
382     /** \returns the number of non zero coefficients */
383     inline Index nonZeros() const {
384         return m_data.diagSize() + m_data.upperSize() + m_data.lowerSize();
385     }
386 
387     /** Preallocates \a reserveSize non zeros */
388     inline void reserve(Index reserveSize, Index reserveUpperSize, Index reserveLowerSize) {
389         m_data.reserve(reserveSize, reserveUpperSize, reserveLowerSize);
390     }
391 
392     /** \returns a reference to a novel non zero coefficient with coordinates \a row x \a col.
393 
394      *
395      * \warning This function can be extremely slow if the non zero coefficients
396      * are not inserted in a coherent order.
397      *
398      * After an insertion session, you should call the finalize() function.
399      */
400     EIGEN_DONT_INLINE Scalar & insert(Index row, Index col) {
401         const Index outer = IsRowMajor ? row : col;
402         const Index inner = IsRowMajor ? col : row;
403 
404         eigen_assert(outer < outerSize());
405         eigen_assert(inner < innerSize());
406 
407         if (outer == inner)
408             return m_data.diag(col);
409 
410         if (IsRowMajor) {
411             if (outer < inner) //upper matrix
412             {
413                 Index minOuterIndex = 0;
414                 minOuterIndex = inner - m_data.upperProfile(inner);
415 
416                 if (outer < minOuterIndex) //The value does not yet exist
417                 {
418                     const Index previousProfile = m_data.upperProfile(inner);
419 
420                     m_data.upperProfile(inner) = inner - outer;
421 
422 
423                     const Index bandIncrement = m_data.upperProfile(inner) - previousProfile;
424                     //shift data stored after this new one
425                     const Index stop = m_colStartIndex[cols()];
426                     const Index start = m_colStartIndex[inner];
427 
428 
429                     for (Index innerIdx = stop; innerIdx >= start; innerIdx--) {
430                         m_data.upper(innerIdx + bandIncrement) = m_data.upper(innerIdx);
431                     }
432 
433                     for (Index innerIdx = cols(); innerIdx > inner; innerIdx--) {
434                         m_colStartIndex[innerIdx] += bandIncrement;
435                     }
436 
437                     //zeros new data
438                     memset(this->_upperPtr() + start, 0, (bandIncrement - 1) * sizeof (Scalar));
439 
440                     return m_data.upper(m_colStartIndex[inner]);
441                 } else {
442                     return m_data.upper(m_colStartIndex[inner] + outer - (inner - m_data.upperProfile(inner)));
443                 }
444             }
445 
446             if (outer > inner) //lower matrix
447             {
448                 const Index minInnerIndex = outer - m_data.lowerProfile(outer);
449                 if (inner < minInnerIndex) //The value does not yet exist
450                 {
451                     const Index previousProfile = m_data.lowerProfile(outer);
452                     m_data.lowerProfile(outer) = outer - inner;
453 
454                     const Index bandIncrement = m_data.lowerProfile(outer) - previousProfile;
455                     //shift data stored after this new one
456                     const Index stop = m_rowStartIndex[rows()];
457                     const Index start = m_rowStartIndex[outer];
458 
459 
460                     for (Index innerIdx = stop; innerIdx >= start; innerIdx--) {
461                         m_data.lower(innerIdx + bandIncrement) = m_data.lower(innerIdx);
462                     }
463 
464                     for (Index innerIdx = rows(); innerIdx > outer; innerIdx--) {
465                         m_rowStartIndex[innerIdx] += bandIncrement;
466                     }
467 
468                     //zeros new data
469                     memset(this->_lowerPtr() + start, 0, (bandIncrement - 1) * sizeof (Scalar));
470                     return m_data.lower(m_rowStartIndex[outer]);
471                 } else {
472                     return m_data.lower(m_rowStartIndex[outer] + inner - (outer - m_data.lowerProfile(outer)));
473                 }
474             }
475         } else {
476             if (outer > inner) //upper matrix
477             {
478                 const Index maxOuterIndex = inner + m_data.upperProfile(inner);
479                 if (outer > maxOuterIndex) //The value does not yet exist
480                 {
481                     const Index previousProfile = m_data.upperProfile(inner);
482                     m_data.upperProfile(inner) = outer - inner;
483 
484                     const Index bandIncrement = m_data.upperProfile(inner) - previousProfile;
485                     //shift data stored after this new one
486                     const Index stop = m_rowStartIndex[rows()];
487                     const Index start = m_rowStartIndex[inner + 1];
488 
489                     for (Index innerIdx = stop; innerIdx >= start; innerIdx--) {
490                         m_data.upper(innerIdx + bandIncrement) = m_data.upper(innerIdx);
491                     }
492 
493                     for (Index innerIdx = inner + 1; innerIdx < outerSize() + 1; innerIdx++) {
494                         m_rowStartIndex[innerIdx] += bandIncrement;
495                     }
496                     memset(this->_upperPtr() + m_rowStartIndex[inner] + previousProfile + 1, 0, (bandIncrement - 1) * sizeof (Scalar));
497                     return m_data.upper(m_rowStartIndex[inner] + m_data.upperProfile(inner));
498                 } else {
499                     return m_data.upper(m_rowStartIndex[inner] + (outer - inner));
500                 }
501             }
502 
503             if (outer < inner) //lower matrix
504             {
505                 const Index maxInnerIndex = outer + m_data.lowerProfile(outer);
506                 if (inner > maxInnerIndex) //The value does not yet exist
507                 {
508                     const Index previousProfile = m_data.lowerProfile(outer);
509                     m_data.lowerProfile(outer) = inner - outer;
510 
511                     const Index bandIncrement = m_data.lowerProfile(outer) - previousProfile;
512                     //shift data stored after this new one
513                     const Index stop = m_colStartIndex[cols()];
514                     const Index start = m_colStartIndex[outer + 1];
515 
516                     for (Index innerIdx = stop; innerIdx >= start; innerIdx--) {
517                         m_data.lower(innerIdx + bandIncrement) = m_data.lower(innerIdx);
518                     }
519 
520                     for (Index innerIdx = outer + 1; innerIdx < outerSize() + 1; innerIdx++) {
521                         m_colStartIndex[innerIdx] += bandIncrement;
522                     }
523                     memset(this->_lowerPtr() + m_colStartIndex[outer] + previousProfile + 1, 0, (bandIncrement - 1) * sizeof (Scalar));
524                     return m_data.lower(m_colStartIndex[outer] + m_data.lowerProfile(outer));
525                 } else {
526                     return m_data.lower(m_colStartIndex[outer] + (inner - outer));
527                 }
528             }
529         }
530     }
531 
532     /** Must be called after inserting a set of non zero entries.
533      */
534     inline void finalize() {
535         if (IsRowMajor) {
536             if (rows() > cols())
537                 m_data.resize(cols(), cols(), rows(), m_colStartIndex[cols()] + 1, m_rowStartIndex[rows()] + 1);
538             else
539                 m_data.resize(rows(), cols(), rows(), m_colStartIndex[cols()] + 1, m_rowStartIndex[rows()] + 1);
540 
541             //            eigen_assert(rows() == cols() && "memory reorganisatrion only works with suare matrix");
542             //
543             //            Scalar* newArray = new Scalar[m_colStartIndex[cols()] + 1 + m_rowStartIndex[rows()] + 1];
544             //            Index dataIdx = 0;
545             //            for (Index row = 0; row < rows(); row++) {
546             //
547             //                const Index nbLowerElts = m_rowStartIndex[row + 1] - m_rowStartIndex[row];
548             //                //                std::cout << "nbLowerElts" << nbLowerElts << std::endl;
549             //                memcpy(newArray + dataIdx, m_data.m_lower + m_rowStartIndex[row], nbLowerElts * sizeof (Scalar));
550             //                m_rowStartIndex[row] = dataIdx;
551             //                dataIdx += nbLowerElts;
552             //
553             //                const Index nbUpperElts = m_colStartIndex[row + 1] - m_colStartIndex[row];
554             //                memcpy(newArray + dataIdx, m_data.m_upper + m_colStartIndex[row], nbUpperElts * sizeof (Scalar));
555             //                m_colStartIndex[row] = dataIdx;
556             //                dataIdx += nbUpperElts;
557             //
558             //
559             //            }
560             //            //todo : don't access m_data profile directly : add an accessor from SkylineMatrix
561             //            m_rowStartIndex[rows()] = m_rowStartIndex[rows()-1] + m_data.lowerProfile(rows()-1);
562             //            m_colStartIndex[cols()] = m_colStartIndex[cols()-1] + m_data.upperProfile(cols()-1);
563             //
564             //            delete[] m_data.m_lower;
565             //            delete[] m_data.m_upper;
566             //
567             //            m_data.m_lower = newArray;
568             //            m_data.m_upper = newArray;
569         } else {
570             if (rows() > cols())
571                 m_data.resize(cols(), rows(), cols(), m_rowStartIndex[cols()] + 1, m_colStartIndex[cols()] + 1);
572             else
573                 m_data.resize(rows(), rows(), cols(), m_rowStartIndex[rows()] + 1, m_colStartIndex[rows()] + 1);
574         }
575     }
576 
577     inline void squeeze() {
578         finalize();
579         m_data.squeeze();
580     }
581 
582     void prune(Scalar reference, RealScalar epsilon = dummy_precision<RealScalar > ()) {
583         //TODO
584     }
585 
586     /** Resizes the matrix to a \a rows x \a cols matrix and initializes it to zero
587      * \sa resizeNonZeros(Index), reserve(), setZero()
588      */
589     void resize(size_t rows, size_t cols) {
590         const Index diagSize = rows > cols ? cols : rows;
591         m_innerSize = IsRowMajor ? cols : rows;
592 
593         eigen_assert(rows == cols && "Skyline matrix must be square matrix");
594 
595         if (diagSize % 2) { // diagSize is odd
596             const Index k = (diagSize - 1) / 2;
597 
598             m_data.resize(diagSize, IsRowMajor ? cols : rows, IsRowMajor ? rows : cols,
599                     2 * k * k + k + 1,
600                     2 * k * k + k + 1);
601 
602         } else // diagSize is even
603         {
604             const Index k = diagSize / 2;
605             m_data.resize(diagSize, IsRowMajor ? cols : rows, IsRowMajor ? rows : cols,
606                     2 * k * k - k + 1,
607                     2 * k * k - k + 1);
608         }
609 
610         if (m_colStartIndex && m_rowStartIndex) {
611             delete[] m_colStartIndex;
612             delete[] m_rowStartIndex;
613         }
614         m_colStartIndex = new Index [cols + 1];
615         m_rowStartIndex = new Index [rows + 1];
616         m_outerSize = diagSize;
617 
618         m_data.reset();
619         m_data.clear();
620 
621         m_outerSize = diagSize;
622         memset(m_colStartIndex, 0, (cols + 1) * sizeof (Index));
623         memset(m_rowStartIndex, 0, (rows + 1) * sizeof (Index));
624     }
625 
626     void resizeNonZeros(Index size) {
627         m_data.resize(size);
628     }
629 
630     inline SkylineMatrix()
631     : m_outerSize(-1), m_innerSize(0), m_colStartIndex(0), m_rowStartIndex(0) {
632         resize(0, 0);
633     }
634 
635     inline SkylineMatrix(size_t rows, size_t cols)
636     : m_outerSize(0), m_innerSize(0), m_colStartIndex(0), m_rowStartIndex(0) {
637         resize(rows, cols);
638     }
639 
640     template<typename OtherDerived>
641     inline SkylineMatrix(const SkylineMatrixBase<OtherDerived>& other)
642     : m_outerSize(0), m_innerSize(0), m_colStartIndex(0), m_rowStartIndex(0) {
643         *this = other.derived();
644     }
645 
646     inline SkylineMatrix(const SkylineMatrix & other)
647     : Base(), m_outerSize(0), m_innerSize(0), m_colStartIndex(0), m_rowStartIndex(0) {
648         *this = other.derived();
649     }
650 
651     inline void swap(SkylineMatrix & other) {
652         //EIGEN_DBG_SKYLINE(std::cout << "SkylineMatrix:: swap\n");
653         std::swap(m_colStartIndex, other.m_colStartIndex);
654         std::swap(m_rowStartIndex, other.m_rowStartIndex);
655         std::swap(m_innerSize, other.m_innerSize);
656         std::swap(m_outerSize, other.m_outerSize);
657         m_data.swap(other.m_data);
658     }
659 
660     inline SkylineMatrix & operator=(const SkylineMatrix & other) {
661         std::cout << "SkylineMatrix& operator=(const SkylineMatrix& other)\n";
662         if (other.isRValue()) {
663             swap(other.const_cast_derived());
664         } else {
665             resize(other.rows(), other.cols());
666             memcpy(m_colStartIndex, other.m_colStartIndex, (m_outerSize + 1) * sizeof (Index));
667             memcpy(m_rowStartIndex, other.m_rowStartIndex, (m_outerSize + 1) * sizeof (Index));
668             m_data = other.m_data;
669         }
670         return *this;
671     }
672 
673     template<typename OtherDerived>
674             inline SkylineMatrix & operator=(const SkylineMatrixBase<OtherDerived>& other) {
675         const bool needToTranspose = (Flags & RowMajorBit) != (OtherDerived::Flags & RowMajorBit);
676         if (needToTranspose) {
677             //         TODO
678             //            return *this;
679         } else {
680             // there is no special optimization
681             return SkylineMatrixBase<SkylineMatrix>::operator=(other.derived());
682         }
683     }
684 
685     friend std::ostream & operator <<(std::ostream & s, const SkylineMatrix & m) {
686 
687         EIGEN_DBG_SKYLINE(
688         std::cout << "upper elements : " << std::endl;
689         for (Index i = 0; i < m.m_data.upperSize(); i++)
690             std::cout << m.m_data.upper(i) << "\t";
691         std::cout << std::endl;
692         std::cout << "upper profile : " << std::endl;
693         for (Index i = 0; i < m.m_data.upperProfileSize(); i++)
694             std::cout << m.m_data.upperProfile(i) << "\t";
695         std::cout << std::endl;
696         std::cout << "lower startIdx : " << std::endl;
697         for (Index i = 0; i < m.m_data.upperProfileSize(); i++)
698             std::cout << (IsRowMajor ? m.m_colStartIndex[i] : m.m_rowStartIndex[i]) << "\t";
699         std::cout << std::endl;
700 
701 
702         std::cout << "lower elements : " << std::endl;
703         for (Index i = 0; i < m.m_data.lowerSize(); i++)
704             std::cout << m.m_data.lower(i) << "\t";
705         std::cout << std::endl;
706         std::cout << "lower profile : " << std::endl;
707         for (Index i = 0; i < m.m_data.lowerProfileSize(); i++)
708             std::cout << m.m_data.lowerProfile(i) << "\t";
709         std::cout << std::endl;
710         std::cout << "lower startIdx : " << std::endl;
711         for (Index i = 0; i < m.m_data.lowerProfileSize(); i++)
712             std::cout << (IsRowMajor ? m.m_rowStartIndex[i] : m.m_colStartIndex[i]) << "\t";
713         std::cout << std::endl;
714         );
715         for (Index rowIdx = 0; rowIdx < m.rows(); rowIdx++) {
716             for (Index colIdx = 0; colIdx < m.cols(); colIdx++) {
717                 s << m.coeff(rowIdx, colIdx) << "\t";
718             }
719             s << std::endl;
720         }
721         return s;
722     }
723 
724     /** Destructor */
725     inline ~SkylineMatrix() {
726         delete[] m_colStartIndex;
727         delete[] m_rowStartIndex;
728     }
729 
730     /** Overloaded for performance */
731     Scalar sum() const;
732 };
733 
734 template<typename Scalar, int _Options>
735 class SkylineMatrix<Scalar, _Options>::InnerUpperIterator {
736 public:
737 
738     InnerUpperIterator(const SkylineMatrix& mat, Index outer)
739     : m_matrix(mat), m_outer(outer),
740     m_id(_Options == RowMajor ? mat.m_colStartIndex[outer] : mat.m_rowStartIndex[outer] + 1),
741     m_start(m_id),
742     m_end(_Options == RowMajor ? mat.m_colStartIndex[outer + 1] : mat.m_rowStartIndex[outer + 1] + 1) {
743     }
744 
745     inline InnerUpperIterator & operator++() {
746         m_id++;
747         return *this;
748     }
749 
750     inline InnerUpperIterator & operator+=(Index shift) {
751         m_id += shift;
752         return *this;
753     }
754 
755     inline Scalar value() const {
756         return m_matrix.m_data.upper(m_id);
757     }
758 
759     inline Scalar* valuePtr() {
760         return const_cast<Scalar*> (&(m_matrix.m_data.upper(m_id)));
761     }
762 
763     inline Scalar& valueRef() {
764         return const_cast<Scalar&> (m_matrix.m_data.upper(m_id));
765     }
766 
767     inline Index index() const {
768         return IsRowMajor ? m_outer - m_matrix.m_data.upperProfile(m_outer) + (m_id - m_start) :
769                 m_outer + (m_id - m_start) + 1;
770     }
771 
772     inline Index row() const {
773         return IsRowMajor ? index() : m_outer;
774     }
775 
776     inline Index col() const {
777         return IsRowMajor ? m_outer : index();
778     }
779 
780     inline size_t size() const {
781         return m_matrix.m_data.upperProfile(m_outer);
782     }
783 
784     inline operator bool() const {
785         return (m_id < m_end) && (m_id >= m_start);
786     }
787 
788 protected:
789     const SkylineMatrix& m_matrix;
790     const Index m_outer;
791     Index m_id;
792     const Index m_start;
793     const Index m_end;
794 };
795 
796 template<typename Scalar, int _Options>
797 class SkylineMatrix<Scalar, _Options>::InnerLowerIterator {
798 public:
799 
800     InnerLowerIterator(const SkylineMatrix& mat, Index outer)
801     : m_matrix(mat),
802     m_outer(outer),
803     m_id(_Options == RowMajor ? mat.m_rowStartIndex[outer] : mat.m_colStartIndex[outer] + 1),
804     m_start(m_id),
805     m_end(_Options == RowMajor ? mat.m_rowStartIndex[outer + 1] : mat.m_colStartIndex[outer + 1] + 1) {
806     }
807 
808     inline InnerLowerIterator & operator++() {
809         m_id++;
810         return *this;
811     }
812 
813     inline InnerLowerIterator & operator+=(Index shift) {
814         m_id += shift;
815         return *this;
816     }
817 
818     inline Scalar value() const {
819         return m_matrix.m_data.lower(m_id);
820     }
821 
822     inline Scalar* valuePtr() {
823         return const_cast<Scalar*> (&(m_matrix.m_data.lower(m_id)));
824     }
825 
826     inline Scalar& valueRef() {
827         return const_cast<Scalar&> (m_matrix.m_data.lower(m_id));
828     }
829 
830     inline Index index() const {
831         return IsRowMajor ? m_outer - m_matrix.m_data.lowerProfile(m_outer) + (m_id - m_start) :
832                 m_outer + (m_id - m_start) + 1;
833         ;
834     }
835 
836     inline Index row() const {
837         return IsRowMajor ? m_outer : index();
838     }
839 
840     inline Index col() const {
841         return IsRowMajor ? index() : m_outer;
842     }
843 
844     inline size_t size() const {
845         return m_matrix.m_data.lowerProfile(m_outer);
846     }
847 
848     inline operator bool() const {
849         return (m_id < m_end) && (m_id >= m_start);
850     }
851 
852 protected:
853     const SkylineMatrix& m_matrix;
854     const Index m_outer;
855     Index m_id;
856     const Index m_start;
857     const Index m_end;
858 };
859 
860 } // end namespace Eigen
861 
862 #endif // EIGEN_SkylineMatrix_H
863