1 // This file is part of Eigen, a lightweight C++ template library 2 // for linear algebra. 3 // 4 // Copyright (C) 2008-2014 Gael Guennebaud <gael.guennebaud@inria.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_SPARSEMATRIX_H 11 #define EIGEN_SPARSEMATRIX_H 12 13 namespace Eigen { 14 15 /** \ingroup SparseCore_Module 16 * 17 * \class SparseMatrix 18 * 19 * \brief A versatible sparse matrix representation 20 * 21 * This class implements a more versatile variants of the common \em compressed row/column storage format. 22 * Each colmun's (resp. row) non zeros are stored as a pair of value with associated row (resp. colmiun) index. 23 * All the non zeros are stored in a single large buffer. Unlike the \em compressed format, there might be extra 24 * space inbetween the nonzeros of two successive colmuns (resp. rows) such that insertion of new non-zero 25 * can be done with limited memory reallocation and copies. 26 * 27 * A call to the function makeCompressed() turns the matrix into the standard \em compressed format 28 * compatible with many library. 29 * 30 * More details on this storage sceheme are given in the \ref TutorialSparse "manual pages". 31 * 32 * \tparam _Scalar the scalar type, i.e. the type of the coefficients 33 * \tparam _Options Union of bit flags controlling the storage scheme. Currently the only possibility 34 * is ColMajor or RowMajor. The default is 0 which means column-major. 35 * \tparam _StorageIndex the type of the indices. It has to be a \b signed type (e.g., short, int, std::ptrdiff_t). Default is \c int. 36 * 37 * \warning In %Eigen 3.2, the undocumented type \c SparseMatrix::Index was improperly defined as the storage index type (e.g., int), 38 * whereas it is now (starting from %Eigen 3.3) deprecated and always defined as Eigen::Index. 39 * Codes making use of \c SparseMatrix::Index, might thus likely have to be changed to use \c SparseMatrix::StorageIndex instead. 40 * 41 * This class can be extended with the help of the plugin mechanism described on the page 42 * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_SPARSEMATRIX_PLUGIN. 43 */ 44 45 namespace internal { 46 template<typename _Scalar, int _Options, typename _StorageIndex> 47 struct traits<SparseMatrix<_Scalar, _Options, _StorageIndex> > 48 { 49 typedef _Scalar Scalar; 50 typedef _StorageIndex StorageIndex; 51 typedef Sparse StorageKind; 52 typedef MatrixXpr XprKind; 53 enum { 54 RowsAtCompileTime = Dynamic, 55 ColsAtCompileTime = Dynamic, 56 MaxRowsAtCompileTime = Dynamic, 57 MaxColsAtCompileTime = Dynamic, 58 Flags = _Options | NestByRefBit | LvalueBit | CompressedAccessBit, 59 SupportedAccessPatterns = InnerRandomAccessPattern 60 }; 61 }; 62 63 template<typename _Scalar, int _Options, typename _StorageIndex, int DiagIndex> 64 struct traits<Diagonal<SparseMatrix<_Scalar, _Options, _StorageIndex>, DiagIndex> > 65 { 66 typedef SparseMatrix<_Scalar, _Options, _StorageIndex> MatrixType; 67 typedef typename ref_selector<MatrixType>::type MatrixTypeNested; 68 typedef typename remove_reference<MatrixTypeNested>::type _MatrixTypeNested; 69 70 typedef _Scalar Scalar; 71 typedef Dense StorageKind; 72 typedef _StorageIndex StorageIndex; 73 typedef MatrixXpr XprKind; 74 75 enum { 76 RowsAtCompileTime = Dynamic, 77 ColsAtCompileTime = 1, 78 MaxRowsAtCompileTime = Dynamic, 79 MaxColsAtCompileTime = 1, 80 Flags = LvalueBit 81 }; 82 }; 83 84 template<typename _Scalar, int _Options, typename _StorageIndex, int DiagIndex> 85 struct traits<Diagonal<const SparseMatrix<_Scalar, _Options, _StorageIndex>, DiagIndex> > 86 : public traits<Diagonal<SparseMatrix<_Scalar, _Options, _StorageIndex>, DiagIndex> > 87 { 88 enum { 89 Flags = 0 90 }; 91 }; 92 93 } // end namespace internal 94 95 template<typename _Scalar, int _Options, typename _StorageIndex> 96 class SparseMatrix 97 : public SparseCompressedBase<SparseMatrix<_Scalar, _Options, _StorageIndex> > 98 { 99 typedef SparseCompressedBase<SparseMatrix> Base; 100 using Base::convert_index; 101 friend class SparseVector<_Scalar,0,_StorageIndex>; 102 public: 103 using Base::isCompressed; 104 using Base::nonZeros; 105 EIGEN_SPARSE_PUBLIC_INTERFACE(SparseMatrix) 106 using Base::operator+=; 107 using Base::operator-=; 108 109 typedef MappedSparseMatrix<Scalar,Flags> Map; 110 typedef Diagonal<SparseMatrix> DiagonalReturnType; 111 typedef Diagonal<const SparseMatrix> ConstDiagonalReturnType; 112 typedef typename Base::InnerIterator InnerIterator; 113 typedef typename Base::ReverseInnerIterator ReverseInnerIterator; 114 115 116 using Base::IsRowMajor; 117 typedef internal::CompressedStorage<Scalar,StorageIndex> Storage; 118 enum { 119 Options = _Options 120 }; 121 122 typedef typename Base::IndexVector IndexVector; 123 typedef typename Base::ScalarVector ScalarVector; 124 protected: 125 typedef SparseMatrix<Scalar,(Flags&~RowMajorBit)|(IsRowMajor?RowMajorBit:0)> TransposedSparseMatrix; 126 127 Index m_outerSize; 128 Index m_innerSize; 129 StorageIndex* m_outerIndex; 130 StorageIndex* m_innerNonZeros; // optional, if null then the data is compressed 131 Storage m_data; 132 133 public: 134 135 /** \returns the number of rows of the matrix */ 136 inline Index rows() const { return IsRowMajor ? m_outerSize : m_innerSize; } 137 /** \returns the number of columns of the matrix */ 138 inline Index cols() const { return IsRowMajor ? m_innerSize : m_outerSize; } 139 140 /** \returns the number of rows (resp. columns) of the matrix if the storage order column major (resp. row major) */ 141 inline Index innerSize() const { return m_innerSize; } 142 /** \returns the number of columns (resp. rows) of the matrix if the storage order column major (resp. row major) */ 143 inline Index outerSize() const { return m_outerSize; } 144 145 /** \returns a const pointer to the array of values. 146 * This function is aimed at interoperability with other libraries. 147 * \sa innerIndexPtr(), outerIndexPtr() */ 148 inline const Scalar* valuePtr() const { return m_data.valuePtr(); } 149 /** \returns a non-const pointer to the array of values. 150 * This function is aimed at interoperability with other libraries. 151 * \sa innerIndexPtr(), outerIndexPtr() */ 152 inline Scalar* valuePtr() { return m_data.valuePtr(); } 153 154 /** \returns a const pointer to the array of inner indices. 155 * This function is aimed at interoperability with other libraries. 156 * \sa valuePtr(), outerIndexPtr() */ 157 inline const StorageIndex* innerIndexPtr() const { return m_data.indexPtr(); } 158 /** \returns a non-const pointer to the array of inner indices. 159 * This function is aimed at interoperability with other libraries. 160 * \sa valuePtr(), outerIndexPtr() */ 161 inline StorageIndex* innerIndexPtr() { return m_data.indexPtr(); } 162 163 /** \returns a const pointer to the array of the starting positions of the inner vectors. 164 * This function is aimed at interoperability with other libraries. 165 * \sa valuePtr(), innerIndexPtr() */ 166 inline const StorageIndex* outerIndexPtr() const { return m_outerIndex; } 167 /** \returns a non-const pointer to the array of the starting positions of the inner vectors. 168 * This function is aimed at interoperability with other libraries. 169 * \sa valuePtr(), innerIndexPtr() */ 170 inline StorageIndex* outerIndexPtr() { return m_outerIndex; } 171 172 /** \returns a const pointer to the array of the number of non zeros of the inner vectors. 173 * This function is aimed at interoperability with other libraries. 174 * \warning it returns the null pointer 0 in compressed mode */ 175 inline const StorageIndex* innerNonZeroPtr() const { return m_innerNonZeros; } 176 /** \returns a non-const pointer to the array of the number of non zeros of the inner vectors. 177 * This function is aimed at interoperability with other libraries. 178 * \warning it returns the null pointer 0 in compressed mode */ 179 inline StorageIndex* innerNonZeroPtr() { return m_innerNonZeros; } 180 181 /** \internal */ 182 inline Storage& data() { return m_data; } 183 /** \internal */ 184 inline const Storage& data() const { return m_data; } 185 186 /** \returns the value of the matrix at position \a i, \a j 187 * This function returns Scalar(0) if the element is an explicit \em zero */ 188 inline Scalar coeff(Index row, Index col) const 189 { 190 eigen_assert(row>=0 && row<rows() && col>=0 && col<cols()); 191 192 const Index outer = IsRowMajor ? row : col; 193 const Index inner = IsRowMajor ? col : row; 194 Index end = m_innerNonZeros ? m_outerIndex[outer] + m_innerNonZeros[outer] : m_outerIndex[outer+1]; 195 return m_data.atInRange(m_outerIndex[outer], end, StorageIndex(inner)); 196 } 197 198 /** \returns a non-const reference to the value of the matrix at position \a i, \a j 199 * 200 * If the element does not exist then it is inserted via the insert(Index,Index) function 201 * which itself turns the matrix into a non compressed form if that was not the case. 202 * 203 * This is a O(log(nnz_j)) operation (binary search) plus the cost of insert(Index,Index) 204 * function if the element does not already exist. 205 */ 206 inline Scalar& coeffRef(Index row, Index col) 207 { 208 eigen_assert(row>=0 && row<rows() && col>=0 && col<cols()); 209 210 const Index outer = IsRowMajor ? row : col; 211 const Index inner = IsRowMajor ? col : row; 212 213 Index start = m_outerIndex[outer]; 214 Index end = m_innerNonZeros ? m_outerIndex[outer] + m_innerNonZeros[outer] : m_outerIndex[outer+1]; 215 eigen_assert(end>=start && "you probably called coeffRef on a non finalized matrix"); 216 if(end<=start) 217 return insert(row,col); 218 const Index p = m_data.searchLowerIndex(start,end-1,StorageIndex(inner)); 219 if((p<end) && (m_data.index(p)==inner)) 220 return m_data.value(p); 221 else 222 return insert(row,col); 223 } 224 225 /** \returns a reference to a novel non zero coefficient with coordinates \a row x \a col. 226 * The non zero coefficient must \b not already exist. 227 * 228 * If the matrix \c *this is in compressed mode, then \c *this is turned into uncompressed 229 * mode while reserving room for 2 x this->innerSize() non zeros if reserve(Index) has not been called earlier. 230 * In this case, the insertion procedure is optimized for a \e sequential insertion mode where elements are assumed to be 231 * inserted by increasing outer-indices. 232 * 233 * If that's not the case, then it is strongly recommended to either use a triplet-list to assemble the matrix, or to first 234 * call reserve(const SizesType &) to reserve the appropriate number of non-zero elements per inner vector. 235 * 236 * Assuming memory has been appropriately reserved, this function performs a sorted insertion in O(1) 237 * if the elements of each inner vector are inserted in increasing inner index order, and in O(nnz_j) for a random insertion. 238 * 239 */ 240 Scalar& insert(Index row, Index col); 241 242 public: 243 244 /** Removes all non zeros but keep allocated memory 245 * 246 * This function does not free the currently allocated memory. To release as much as memory as possible, 247 * call \code mat.data().squeeze(); \endcode after resizing it. 248 * 249 * \sa resize(Index,Index), data() 250 */ 251 inline void setZero() 252 { 253 m_data.clear(); 254 memset(m_outerIndex, 0, (m_outerSize+1)*sizeof(StorageIndex)); 255 if(m_innerNonZeros) 256 memset(m_innerNonZeros, 0, (m_outerSize)*sizeof(StorageIndex)); 257 } 258 259 /** Preallocates \a reserveSize non zeros. 260 * 261 * Precondition: the matrix must be in compressed mode. */ 262 inline void reserve(Index reserveSize) 263 { 264 eigen_assert(isCompressed() && "This function does not make sense in non compressed mode."); 265 m_data.reserve(reserveSize); 266 } 267 268 #ifdef EIGEN_PARSED_BY_DOXYGEN 269 /** Preallocates \a reserveSize[\c j] non zeros for each column (resp. row) \c j. 270 * 271 * This function turns the matrix in non-compressed mode. 272 * 273 * The type \c SizesType must expose the following interface: 274 \code 275 typedef value_type; 276 const value_type& operator[](i) const; 277 \endcode 278 * for \c i in the [0,this->outerSize()[ range. 279 * Typical choices include std::vector<int>, Eigen::VectorXi, Eigen::VectorXi::Constant, etc. 280 */ 281 template<class SizesType> 282 inline void reserve(const SizesType& reserveSizes); 283 #else 284 template<class SizesType> 285 inline void reserve(const SizesType& reserveSizes, const typename SizesType::value_type& enableif = 286 #if (!EIGEN_COMP_MSVC) || (EIGEN_COMP_MSVC>=1500) // MSVC 2005 fails to compile with this typename 287 typename 288 #endif 289 SizesType::value_type()) 290 { 291 EIGEN_UNUSED_VARIABLE(enableif); 292 reserveInnerVectors(reserveSizes); 293 } 294 #endif // EIGEN_PARSED_BY_DOXYGEN 295 protected: 296 template<class SizesType> 297 inline void reserveInnerVectors(const SizesType& reserveSizes) 298 { 299 if(isCompressed()) 300 { 301 Index totalReserveSize = 0; 302 // turn the matrix into non-compressed mode 303 m_innerNonZeros = static_cast<StorageIndex*>(std::malloc(m_outerSize * sizeof(StorageIndex))); 304 if (!m_innerNonZeros) internal::throw_std_bad_alloc(); 305 306 // temporarily use m_innerSizes to hold the new starting points. 307 StorageIndex* newOuterIndex = m_innerNonZeros; 308 309 StorageIndex count = 0; 310 for(Index j=0; j<m_outerSize; ++j) 311 { 312 newOuterIndex[j] = count; 313 count += reserveSizes[j] + (m_outerIndex[j+1]-m_outerIndex[j]); 314 totalReserveSize += reserveSizes[j]; 315 } 316 m_data.reserve(totalReserveSize); 317 StorageIndex previousOuterIndex = m_outerIndex[m_outerSize]; 318 for(Index j=m_outerSize-1; j>=0; --j) 319 { 320 StorageIndex innerNNZ = previousOuterIndex - m_outerIndex[j]; 321 for(Index i=innerNNZ-1; i>=0; --i) 322 { 323 m_data.index(newOuterIndex[j]+i) = m_data.index(m_outerIndex[j]+i); 324 m_data.value(newOuterIndex[j]+i) = m_data.value(m_outerIndex[j]+i); 325 } 326 previousOuterIndex = m_outerIndex[j]; 327 m_outerIndex[j] = newOuterIndex[j]; 328 m_innerNonZeros[j] = innerNNZ; 329 } 330 m_outerIndex[m_outerSize] = m_outerIndex[m_outerSize-1] + m_innerNonZeros[m_outerSize-1] + reserveSizes[m_outerSize-1]; 331 332 m_data.resize(m_outerIndex[m_outerSize]); 333 } 334 else 335 { 336 StorageIndex* newOuterIndex = static_cast<StorageIndex*>(std::malloc((m_outerSize+1)*sizeof(StorageIndex))); 337 if (!newOuterIndex) internal::throw_std_bad_alloc(); 338 339 StorageIndex count = 0; 340 for(Index j=0; j<m_outerSize; ++j) 341 { 342 newOuterIndex[j] = count; 343 StorageIndex alreadyReserved = (m_outerIndex[j+1]-m_outerIndex[j]) - m_innerNonZeros[j]; 344 StorageIndex toReserve = std::max<StorageIndex>(reserveSizes[j], alreadyReserved); 345 count += toReserve + m_innerNonZeros[j]; 346 } 347 newOuterIndex[m_outerSize] = count; 348 349 m_data.resize(count); 350 for(Index j=m_outerSize-1; j>=0; --j) 351 { 352 Index offset = newOuterIndex[j] - m_outerIndex[j]; 353 if(offset>0) 354 { 355 StorageIndex innerNNZ = m_innerNonZeros[j]; 356 for(Index i=innerNNZ-1; i>=0; --i) 357 { 358 m_data.index(newOuterIndex[j]+i) = m_data.index(m_outerIndex[j]+i); 359 m_data.value(newOuterIndex[j]+i) = m_data.value(m_outerIndex[j]+i); 360 } 361 } 362 } 363 364 std::swap(m_outerIndex, newOuterIndex); 365 std::free(newOuterIndex); 366 } 367 368 } 369 public: 370 371 //--- low level purely coherent filling --- 372 373 /** \internal 374 * \returns a reference to the non zero coefficient at position \a row, \a col assuming that: 375 * - the nonzero does not already exist 376 * - the new coefficient is the last one according to the storage order 377 * 378 * Before filling a given inner vector you must call the statVec(Index) function. 379 * 380 * After an insertion session, you should call the finalize() function. 381 * 382 * \sa insert, insertBackByOuterInner, startVec */ 383 inline Scalar& insertBack(Index row, Index col) 384 { 385 return insertBackByOuterInner(IsRowMajor?row:col, IsRowMajor?col:row); 386 } 387 388 /** \internal 389 * \sa insertBack, startVec */ 390 inline Scalar& insertBackByOuterInner(Index outer, Index inner) 391 { 392 eigen_assert(Index(m_outerIndex[outer+1]) == m_data.size() && "Invalid ordered insertion (invalid outer index)"); 393 eigen_assert( (m_outerIndex[outer+1]-m_outerIndex[outer]==0 || m_data.index(m_data.size()-1)<inner) && "Invalid ordered insertion (invalid inner index)"); 394 Index p = m_outerIndex[outer+1]; 395 ++m_outerIndex[outer+1]; 396 m_data.append(Scalar(0), inner); 397 return m_data.value(p); 398 } 399 400 /** \internal 401 * \warning use it only if you know what you are doing */ 402 inline Scalar& insertBackByOuterInnerUnordered(Index outer, Index inner) 403 { 404 Index p = m_outerIndex[outer+1]; 405 ++m_outerIndex[outer+1]; 406 m_data.append(Scalar(0), inner); 407 return m_data.value(p); 408 } 409 410 /** \internal 411 * \sa insertBack, insertBackByOuterInner */ 412 inline void startVec(Index outer) 413 { 414 eigen_assert(m_outerIndex[outer]==Index(m_data.size()) && "You must call startVec for each inner vector sequentially"); 415 eigen_assert(m_outerIndex[outer+1]==0 && "You must call startVec for each inner vector sequentially"); 416 m_outerIndex[outer+1] = m_outerIndex[outer]; 417 } 418 419 /** \internal 420 * Must be called after inserting a set of non zero entries using the low level compressed API. 421 */ 422 inline void finalize() 423 { 424 if(isCompressed()) 425 { 426 StorageIndex size = internal::convert_index<StorageIndex>(m_data.size()); 427 Index i = m_outerSize; 428 // find the last filled column 429 while (i>=0 && m_outerIndex[i]==0) 430 --i; 431 ++i; 432 while (i<=m_outerSize) 433 { 434 m_outerIndex[i] = size; 435 ++i; 436 } 437 } 438 } 439 440 //--- 441 442 template<typename InputIterators> 443 void setFromTriplets(const InputIterators& begin, const InputIterators& end); 444 445 template<typename InputIterators,typename DupFunctor> 446 void setFromTriplets(const InputIterators& begin, const InputIterators& end, DupFunctor dup_func); 447 448 void sumupDuplicates() { collapseDuplicates(internal::scalar_sum_op<Scalar,Scalar>()); } 449 450 template<typename DupFunctor> 451 void collapseDuplicates(DupFunctor dup_func = DupFunctor()); 452 453 //--- 454 455 /** \internal 456 * same as insert(Index,Index) except that the indices are given relative to the storage order */ 457 Scalar& insertByOuterInner(Index j, Index i) 458 { 459 return insert(IsRowMajor ? j : i, IsRowMajor ? i : j); 460 } 461 462 /** Turns the matrix into the \em compressed format. 463 */ 464 void makeCompressed() 465 { 466 if(isCompressed()) 467 return; 468 469 eigen_internal_assert(m_outerIndex!=0 && m_outerSize>0); 470 471 Index oldStart = m_outerIndex[1]; 472 m_outerIndex[1] = m_innerNonZeros[0]; 473 for(Index j=1; j<m_outerSize; ++j) 474 { 475 Index nextOldStart = m_outerIndex[j+1]; 476 Index offset = oldStart - m_outerIndex[j]; 477 if(offset>0) 478 { 479 for(Index k=0; k<m_innerNonZeros[j]; ++k) 480 { 481 m_data.index(m_outerIndex[j]+k) = m_data.index(oldStart+k); 482 m_data.value(m_outerIndex[j]+k) = m_data.value(oldStart+k); 483 } 484 } 485 m_outerIndex[j+1] = m_outerIndex[j] + m_innerNonZeros[j]; 486 oldStart = nextOldStart; 487 } 488 std::free(m_innerNonZeros); 489 m_innerNonZeros = 0; 490 m_data.resize(m_outerIndex[m_outerSize]); 491 m_data.squeeze(); 492 } 493 494 /** Turns the matrix into the uncompressed mode */ 495 void uncompress() 496 { 497 if(m_innerNonZeros != 0) 498 return; 499 m_innerNonZeros = static_cast<StorageIndex*>(std::malloc(m_outerSize * sizeof(StorageIndex))); 500 for (Index i = 0; i < m_outerSize; i++) 501 { 502 m_innerNonZeros[i] = m_outerIndex[i+1] - m_outerIndex[i]; 503 } 504 } 505 506 /** Suppresses all nonzeros which are \b much \b smaller \b than \a reference under the tolerence \a epsilon */ 507 void prune(const Scalar& reference, const RealScalar& epsilon = NumTraits<RealScalar>::dummy_precision()) 508 { 509 prune(default_prunning_func(reference,epsilon)); 510 } 511 512 /** Turns the matrix into compressed format, and suppresses all nonzeros which do not satisfy the predicate \a keep. 513 * The functor type \a KeepFunc must implement the following function: 514 * \code 515 * bool operator() (const Index& row, const Index& col, const Scalar& value) const; 516 * \endcode 517 * \sa prune(Scalar,RealScalar) 518 */ 519 template<typename KeepFunc> 520 void prune(const KeepFunc& keep = KeepFunc()) 521 { 522 // TODO optimize the uncompressed mode to avoid moving and allocating the data twice 523 makeCompressed(); 524 525 StorageIndex k = 0; 526 for(Index j=0; j<m_outerSize; ++j) 527 { 528 Index previousStart = m_outerIndex[j]; 529 m_outerIndex[j] = k; 530 Index end = m_outerIndex[j+1]; 531 for(Index i=previousStart; i<end; ++i) 532 { 533 if(keep(IsRowMajor?j:m_data.index(i), IsRowMajor?m_data.index(i):j, m_data.value(i))) 534 { 535 m_data.value(k) = m_data.value(i); 536 m_data.index(k) = m_data.index(i); 537 ++k; 538 } 539 } 540 } 541 m_outerIndex[m_outerSize] = k; 542 m_data.resize(k,0); 543 } 544 545 /** Resizes the matrix to a \a rows x \a cols matrix leaving old values untouched. 546 * 547 * If the sizes of the matrix are decreased, then the matrix is turned to \b uncompressed-mode 548 * and the storage of the out of bounds coefficients is kept and reserved. 549 * Call makeCompressed() to pack the entries and squeeze extra memory. 550 * 551 * \sa reserve(), setZero(), makeCompressed() 552 */ 553 void conservativeResize(Index rows, Index cols) 554 { 555 // No change 556 if (this->rows() == rows && this->cols() == cols) return; 557 558 // If one dimension is null, then there is nothing to be preserved 559 if(rows==0 || cols==0) return resize(rows,cols); 560 561 Index innerChange = IsRowMajor ? cols - this->cols() : rows - this->rows(); 562 Index outerChange = IsRowMajor ? rows - this->rows() : cols - this->cols(); 563 StorageIndex newInnerSize = convert_index(IsRowMajor ? cols : rows); 564 565 // Deals with inner non zeros 566 if (m_innerNonZeros) 567 { 568 // Resize m_innerNonZeros 569 StorageIndex *newInnerNonZeros = static_cast<StorageIndex*>(std::realloc(m_innerNonZeros, (m_outerSize + outerChange) * sizeof(StorageIndex))); 570 if (!newInnerNonZeros) internal::throw_std_bad_alloc(); 571 m_innerNonZeros = newInnerNonZeros; 572 573 for(Index i=m_outerSize; i<m_outerSize+outerChange; i++) 574 m_innerNonZeros[i] = 0; 575 } 576 else if (innerChange < 0) 577 { 578 // Inner size decreased: allocate a new m_innerNonZeros 579 m_innerNonZeros = static_cast<StorageIndex*>(std::malloc((m_outerSize+outerChange+1) * sizeof(StorageIndex))); 580 if (!m_innerNonZeros) internal::throw_std_bad_alloc(); 581 for(Index i = 0; i < m_outerSize; i++) 582 m_innerNonZeros[i] = m_outerIndex[i+1] - m_outerIndex[i]; 583 } 584 585 // Change the m_innerNonZeros in case of a decrease of inner size 586 if (m_innerNonZeros && innerChange < 0) 587 { 588 for(Index i = 0; i < m_outerSize + (std::min)(outerChange, Index(0)); i++) 589 { 590 StorageIndex &n = m_innerNonZeros[i]; 591 StorageIndex start = m_outerIndex[i]; 592 while (n > 0 && m_data.index(start+n-1) >= newInnerSize) --n; 593 } 594 } 595 596 m_innerSize = newInnerSize; 597 598 // Re-allocate outer index structure if necessary 599 if (outerChange == 0) 600 return; 601 602 StorageIndex *newOuterIndex = static_cast<StorageIndex*>(std::realloc(m_outerIndex, (m_outerSize + outerChange + 1) * sizeof(StorageIndex))); 603 if (!newOuterIndex) internal::throw_std_bad_alloc(); 604 m_outerIndex = newOuterIndex; 605 if (outerChange > 0) 606 { 607 StorageIndex last = m_outerSize == 0 ? 0 : m_outerIndex[m_outerSize]; 608 for(Index i=m_outerSize; i<m_outerSize+outerChange+1; i++) 609 m_outerIndex[i] = last; 610 } 611 m_outerSize += outerChange; 612 } 613 614 /** Resizes the matrix to a \a rows x \a cols matrix and initializes it to zero. 615 * 616 * This function does not free the currently allocated memory. To release as much as memory as possible, 617 * call \code mat.data().squeeze(); \endcode after resizing it. 618 * 619 * \sa reserve(), setZero() 620 */ 621 void resize(Index rows, Index cols) 622 { 623 const Index outerSize = IsRowMajor ? rows : cols; 624 m_innerSize = IsRowMajor ? cols : rows; 625 m_data.clear(); 626 if (m_outerSize != outerSize || m_outerSize==0) 627 { 628 std::free(m_outerIndex); 629 m_outerIndex = static_cast<StorageIndex*>(std::malloc((outerSize + 1) * sizeof(StorageIndex))); 630 if (!m_outerIndex) internal::throw_std_bad_alloc(); 631 632 m_outerSize = outerSize; 633 } 634 if(m_innerNonZeros) 635 { 636 std::free(m_innerNonZeros); 637 m_innerNonZeros = 0; 638 } 639 memset(m_outerIndex, 0, (m_outerSize+1)*sizeof(StorageIndex)); 640 } 641 642 /** \internal 643 * Resize the nonzero vector to \a size */ 644 void resizeNonZeros(Index size) 645 { 646 m_data.resize(size); 647 } 648 649 /** \returns a const expression of the diagonal coefficients. */ 650 const ConstDiagonalReturnType diagonal() const { return ConstDiagonalReturnType(*this); } 651 652 /** \returns a read-write expression of the diagonal coefficients. 653 * \warning If the diagonal entries are written, then all diagonal 654 * entries \b must already exist, otherwise an assertion will be raised. 655 */ 656 DiagonalReturnType diagonal() { return DiagonalReturnType(*this); } 657 658 /** Default constructor yielding an empty \c 0 \c x \c 0 matrix */ 659 inline SparseMatrix() 660 : m_outerSize(-1), m_innerSize(0), m_outerIndex(0), m_innerNonZeros(0) 661 { 662 check_template_parameters(); 663 resize(0, 0); 664 } 665 666 /** Constructs a \a rows \c x \a cols empty matrix */ 667 inline SparseMatrix(Index rows, Index cols) 668 : m_outerSize(0), m_innerSize(0), m_outerIndex(0), m_innerNonZeros(0) 669 { 670 check_template_parameters(); 671 resize(rows, cols); 672 } 673 674 /** Constructs a sparse matrix from the sparse expression \a other */ 675 template<typename OtherDerived> 676 inline SparseMatrix(const SparseMatrixBase<OtherDerived>& other) 677 : m_outerSize(0), m_innerSize(0), m_outerIndex(0), m_innerNonZeros(0) 678 { 679 EIGEN_STATIC_ASSERT((internal::is_same<Scalar, typename OtherDerived::Scalar>::value), 680 YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) 681 check_template_parameters(); 682 const bool needToTranspose = (Flags & RowMajorBit) != (internal::evaluator<OtherDerived>::Flags & RowMajorBit); 683 if (needToTranspose) 684 *this = other.derived(); 685 else 686 { 687 #ifdef EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN 688 EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN 689 #endif 690 internal::call_assignment_no_alias(*this, other.derived()); 691 } 692 } 693 694 /** Constructs a sparse matrix from the sparse selfadjoint view \a other */ 695 template<typename OtherDerived, unsigned int UpLo> 696 inline SparseMatrix(const SparseSelfAdjointView<OtherDerived, UpLo>& other) 697 : m_outerSize(0), m_innerSize(0), m_outerIndex(0), m_innerNonZeros(0) 698 { 699 check_template_parameters(); 700 Base::operator=(other); 701 } 702 703 /** Copy constructor (it performs a deep copy) */ 704 inline SparseMatrix(const SparseMatrix& other) 705 : Base(), m_outerSize(0), m_innerSize(0), m_outerIndex(0), m_innerNonZeros(0) 706 { 707 check_template_parameters(); 708 *this = other.derived(); 709 } 710 711 /** \brief Copy constructor with in-place evaluation */ 712 template<typename OtherDerived> 713 SparseMatrix(const ReturnByValue<OtherDerived>& other) 714 : Base(), m_outerSize(0), m_innerSize(0), m_outerIndex(0), m_innerNonZeros(0) 715 { 716 check_template_parameters(); 717 initAssignment(other); 718 other.evalTo(*this); 719 } 720 721 /** \brief Copy constructor with in-place evaluation */ 722 template<typename OtherDerived> 723 explicit SparseMatrix(const DiagonalBase<OtherDerived>& other) 724 : Base(), m_outerSize(0), m_innerSize(0), m_outerIndex(0), m_innerNonZeros(0) 725 { 726 check_template_parameters(); 727 *this = other.derived(); 728 } 729 730 /** Swaps the content of two sparse matrices of the same type. 731 * This is a fast operation that simply swaps the underlying pointers and parameters. */ 732 inline void swap(SparseMatrix& other) 733 { 734 //EIGEN_DBG_SPARSE(std::cout << "SparseMatrix:: swap\n"); 735 std::swap(m_outerIndex, other.m_outerIndex); 736 std::swap(m_innerSize, other.m_innerSize); 737 std::swap(m_outerSize, other.m_outerSize); 738 std::swap(m_innerNonZeros, other.m_innerNonZeros); 739 m_data.swap(other.m_data); 740 } 741 742 /** Sets *this to the identity matrix. 743 * This function also turns the matrix into compressed mode, and drop any reserved memory. */ 744 inline void setIdentity() 745 { 746 eigen_assert(rows() == cols() && "ONLY FOR SQUARED MATRICES"); 747 this->m_data.resize(rows()); 748 Eigen::Map<IndexVector>(this->m_data.indexPtr(), rows()).setLinSpaced(0, StorageIndex(rows()-1)); 749 Eigen::Map<ScalarVector>(this->m_data.valuePtr(), rows()).setOnes(); 750 Eigen::Map<IndexVector>(this->m_outerIndex, rows()+1).setLinSpaced(0, StorageIndex(rows())); 751 std::free(m_innerNonZeros); 752 m_innerNonZeros = 0; 753 } 754 inline SparseMatrix& operator=(const SparseMatrix& other) 755 { 756 if (other.isRValue()) 757 { 758 swap(other.const_cast_derived()); 759 } 760 else if(this!=&other) 761 { 762 #ifdef EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN 763 EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN 764 #endif 765 initAssignment(other); 766 if(other.isCompressed()) 767 { 768 internal::smart_copy(other.m_outerIndex, other.m_outerIndex + m_outerSize + 1, m_outerIndex); 769 m_data = other.m_data; 770 } 771 else 772 { 773 Base::operator=(other); 774 } 775 } 776 return *this; 777 } 778 779 #ifndef EIGEN_PARSED_BY_DOXYGEN 780 template<typename OtherDerived> 781 inline SparseMatrix& operator=(const EigenBase<OtherDerived>& other) 782 { return Base::operator=(other.derived()); } 783 #endif // EIGEN_PARSED_BY_DOXYGEN 784 785 template<typename OtherDerived> 786 EIGEN_DONT_INLINE SparseMatrix& operator=(const SparseMatrixBase<OtherDerived>& other); 787 788 friend std::ostream & operator << (std::ostream & s, const SparseMatrix& m) 789 { 790 EIGEN_DBG_SPARSE( 791 s << "Nonzero entries:\n"; 792 if(m.isCompressed()) 793 { 794 for (Index i=0; i<m.nonZeros(); ++i) 795 s << "(" << m.m_data.value(i) << "," << m.m_data.index(i) << ") "; 796 } 797 else 798 { 799 for (Index i=0; i<m.outerSize(); ++i) 800 { 801 Index p = m.m_outerIndex[i]; 802 Index pe = m.m_outerIndex[i]+m.m_innerNonZeros[i]; 803 Index k=p; 804 for (; k<pe; ++k) { 805 s << "(" << m.m_data.value(k) << "," << m.m_data.index(k) << ") "; 806 } 807 for (; k<m.m_outerIndex[i+1]; ++k) { 808 s << "(_,_) "; 809 } 810 } 811 } 812 s << std::endl; 813 s << std::endl; 814 s << "Outer pointers:\n"; 815 for (Index i=0; i<m.outerSize(); ++i) { 816 s << m.m_outerIndex[i] << " "; 817 } 818 s << " $" << std::endl; 819 if(!m.isCompressed()) 820 { 821 s << "Inner non zeros:\n"; 822 for (Index i=0; i<m.outerSize(); ++i) { 823 s << m.m_innerNonZeros[i] << " "; 824 } 825 s << " $" << std::endl; 826 } 827 s << std::endl; 828 ); 829 s << static_cast<const SparseMatrixBase<SparseMatrix>&>(m); 830 return s; 831 } 832 833 /** Destructor */ 834 inline ~SparseMatrix() 835 { 836 std::free(m_outerIndex); 837 std::free(m_innerNonZeros); 838 } 839 840 /** Overloaded for performance */ 841 Scalar sum() const; 842 843 # ifdef EIGEN_SPARSEMATRIX_PLUGIN 844 # include EIGEN_SPARSEMATRIX_PLUGIN 845 # endif 846 847 protected: 848 849 template<typename Other> 850 void initAssignment(const Other& other) 851 { 852 resize(other.rows(), other.cols()); 853 if(m_innerNonZeros) 854 { 855 std::free(m_innerNonZeros); 856 m_innerNonZeros = 0; 857 } 858 } 859 860 /** \internal 861 * \sa insert(Index,Index) */ 862 EIGEN_DONT_INLINE Scalar& insertCompressed(Index row, Index col); 863 864 /** \internal 865 * A vector object that is equal to 0 everywhere but v at the position i */ 866 class SingletonVector 867 { 868 StorageIndex m_index; 869 StorageIndex m_value; 870 public: 871 typedef StorageIndex value_type; 872 SingletonVector(Index i, Index v) 873 : m_index(convert_index(i)), m_value(convert_index(v)) 874 {} 875 876 StorageIndex operator[](Index i) const { return i==m_index ? m_value : 0; } 877 }; 878 879 /** \internal 880 * \sa insert(Index,Index) */ 881 EIGEN_DONT_INLINE Scalar& insertUncompressed(Index row, Index col); 882 883 public: 884 /** \internal 885 * \sa insert(Index,Index) */ 886 EIGEN_STRONG_INLINE Scalar& insertBackUncompressed(Index row, Index col) 887 { 888 const Index outer = IsRowMajor ? row : col; 889 const Index inner = IsRowMajor ? col : row; 890 891 eigen_assert(!isCompressed()); 892 eigen_assert(m_innerNonZeros[outer]<=(m_outerIndex[outer+1] - m_outerIndex[outer])); 893 894 Index p = m_outerIndex[outer] + m_innerNonZeros[outer]++; 895 m_data.index(p) = convert_index(inner); 896 return (m_data.value(p) = 0); 897 } 898 899 private: 900 static void check_template_parameters() 901 { 902 EIGEN_STATIC_ASSERT(NumTraits<StorageIndex>::IsSigned,THE_INDEX_TYPE_MUST_BE_A_SIGNED_TYPE); 903 EIGEN_STATIC_ASSERT((Options&(ColMajor|RowMajor))==Options,INVALID_MATRIX_TEMPLATE_PARAMETERS); 904 } 905 906 struct default_prunning_func { 907 default_prunning_func(const Scalar& ref, const RealScalar& eps) : reference(ref), epsilon(eps) {} 908 inline bool operator() (const Index&, const Index&, const Scalar& value) const 909 { 910 return !internal::isMuchSmallerThan(value, reference, epsilon); 911 } 912 Scalar reference; 913 RealScalar epsilon; 914 }; 915 }; 916 917 namespace internal { 918 919 template<typename InputIterator, typename SparseMatrixType, typename DupFunctor> 920 void set_from_triplets(const InputIterator& begin, const InputIterator& end, SparseMatrixType& mat, DupFunctor dup_func) 921 { 922 enum { IsRowMajor = SparseMatrixType::IsRowMajor }; 923 typedef typename SparseMatrixType::Scalar Scalar; 924 typedef typename SparseMatrixType::StorageIndex StorageIndex; 925 SparseMatrix<Scalar,IsRowMajor?ColMajor:RowMajor,StorageIndex> trMat(mat.rows(),mat.cols()); 926 927 if(begin!=end) 928 { 929 // pass 1: count the nnz per inner-vector 930 typename SparseMatrixType::IndexVector wi(trMat.outerSize()); 931 wi.setZero(); 932 for(InputIterator it(begin); it!=end; ++it) 933 { 934 eigen_assert(it->row()>=0 && it->row()<mat.rows() && it->col()>=0 && it->col()<mat.cols()); 935 wi(IsRowMajor ? it->col() : it->row())++; 936 } 937 938 // pass 2: insert all the elements into trMat 939 trMat.reserve(wi); 940 for(InputIterator it(begin); it!=end; ++it) 941 trMat.insertBackUncompressed(it->row(),it->col()) = it->value(); 942 943 // pass 3: 944 trMat.collapseDuplicates(dup_func); 945 } 946 947 // pass 4: transposed copy -> implicit sorting 948 mat = trMat; 949 } 950 951 } 952 953 954 /** Fill the matrix \c *this with the list of \em triplets defined by the iterator range \a begin - \a end. 955 * 956 * A \em triplet is a tuple (i,j,value) defining a non-zero element. 957 * The input list of triplets does not have to be sorted, and can contains duplicated elements. 958 * In any case, the result is a \b sorted and \b compressed sparse matrix where the duplicates have been summed up. 959 * This is a \em O(n) operation, with \em n the number of triplet elements. 960 * The initial contents of \c *this is destroyed. 961 * The matrix \c *this must be properly resized beforehand using the SparseMatrix(Index,Index) constructor, 962 * or the resize(Index,Index) method. The sizes are not extracted from the triplet list. 963 * 964 * The \a InputIterators value_type must provide the following interface: 965 * \code 966 * Scalar value() const; // the value 967 * Scalar row() const; // the row index i 968 * Scalar col() const; // the column index j 969 * \endcode 970 * See for instance the Eigen::Triplet template class. 971 * 972 * Here is a typical usage example: 973 * \code 974 typedef Triplet<double> T; 975 std::vector<T> tripletList; 976 triplets.reserve(estimation_of_entries); 977 for(...) 978 { 979 // ... 980 tripletList.push_back(T(i,j,v_ij)); 981 } 982 SparseMatrixType m(rows,cols); 983 m.setFromTriplets(tripletList.begin(), tripletList.end()); 984 // m is ready to go! 985 * \endcode 986 * 987 * \warning The list of triplets is read multiple times (at least twice). Therefore, it is not recommended to define 988 * an abstract iterator over a complex data-structure that would be expensive to evaluate. The triplets should rather 989 * be explicitely stored into a std::vector for instance. 990 */ 991 template<typename Scalar, int _Options, typename _StorageIndex> 992 template<typename InputIterators> 993 void SparseMatrix<Scalar,_Options,_StorageIndex>::setFromTriplets(const InputIterators& begin, const InputIterators& end) 994 { 995 internal::set_from_triplets<InputIterators, SparseMatrix<Scalar,_Options,_StorageIndex> >(begin, end, *this, internal::scalar_sum_op<Scalar,Scalar>()); 996 } 997 998 /** The same as setFromTriplets but when duplicates are met the functor \a dup_func is applied: 999 * \code 1000 * value = dup_func(OldValue, NewValue) 1001 * \endcode 1002 * Here is a C++11 example keeping the latest entry only: 1003 * \code 1004 * mat.setFromTriplets(triplets.begin(), triplets.end(), [] (const Scalar&,const Scalar &b) { return b; }); 1005 * \endcode 1006 */ 1007 template<typename Scalar, int _Options, typename _StorageIndex> 1008 template<typename InputIterators,typename DupFunctor> 1009 void SparseMatrix<Scalar,_Options,_StorageIndex>::setFromTriplets(const InputIterators& begin, const InputIterators& end, DupFunctor dup_func) 1010 { 1011 internal::set_from_triplets<InputIterators, SparseMatrix<Scalar,_Options,_StorageIndex>, DupFunctor>(begin, end, *this, dup_func); 1012 } 1013 1014 /** \internal */ 1015 template<typename Scalar, int _Options, typename _StorageIndex> 1016 template<typename DupFunctor> 1017 void SparseMatrix<Scalar,_Options,_StorageIndex>::collapseDuplicates(DupFunctor dup_func) 1018 { 1019 eigen_assert(!isCompressed()); 1020 // TODO, in practice we should be able to use m_innerNonZeros for that task 1021 IndexVector wi(innerSize()); 1022 wi.fill(-1); 1023 StorageIndex count = 0; 1024 // for each inner-vector, wi[inner_index] will hold the position of first element into the index/value buffers 1025 for(Index j=0; j<outerSize(); ++j) 1026 { 1027 StorageIndex start = count; 1028 Index oldEnd = m_outerIndex[j]+m_innerNonZeros[j]; 1029 for(Index k=m_outerIndex[j]; k<oldEnd; ++k) 1030 { 1031 Index i = m_data.index(k); 1032 if(wi(i)>=start) 1033 { 1034 // we already meet this entry => accumulate it 1035 m_data.value(wi(i)) = dup_func(m_data.value(wi(i)), m_data.value(k)); 1036 } 1037 else 1038 { 1039 m_data.value(count) = m_data.value(k); 1040 m_data.index(count) = m_data.index(k); 1041 wi(i) = count; 1042 ++count; 1043 } 1044 } 1045 m_outerIndex[j] = start; 1046 } 1047 m_outerIndex[m_outerSize] = count; 1048 1049 // turn the matrix into compressed form 1050 std::free(m_innerNonZeros); 1051 m_innerNonZeros = 0; 1052 m_data.resize(m_outerIndex[m_outerSize]); 1053 } 1054 1055 template<typename Scalar, int _Options, typename _StorageIndex> 1056 template<typename OtherDerived> 1057 EIGEN_DONT_INLINE SparseMatrix<Scalar,_Options,_StorageIndex>& SparseMatrix<Scalar,_Options,_StorageIndex>::operator=(const SparseMatrixBase<OtherDerived>& other) 1058 { 1059 EIGEN_STATIC_ASSERT((internal::is_same<Scalar, typename OtherDerived::Scalar>::value), 1060 YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) 1061 1062 #ifdef EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN 1063 EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN 1064 #endif 1065 1066 const bool needToTranspose = (Flags & RowMajorBit) != (internal::evaluator<OtherDerived>::Flags & RowMajorBit); 1067 if (needToTranspose) 1068 { 1069 #ifdef EIGEN_SPARSE_TRANSPOSED_COPY_PLUGIN 1070 EIGEN_SPARSE_TRANSPOSED_COPY_PLUGIN 1071 #endif 1072 // two passes algorithm: 1073 // 1 - compute the number of coeffs per dest inner vector 1074 // 2 - do the actual copy/eval 1075 // Since each coeff of the rhs has to be evaluated twice, let's evaluate it if needed 1076 typedef typename internal::nested_eval<OtherDerived,2,typename internal::plain_matrix_type<OtherDerived>::type >::type OtherCopy; 1077 typedef typename internal::remove_all<OtherCopy>::type _OtherCopy; 1078 typedef internal::evaluator<_OtherCopy> OtherCopyEval; 1079 OtherCopy otherCopy(other.derived()); 1080 OtherCopyEval otherCopyEval(otherCopy); 1081 1082 SparseMatrix dest(other.rows(),other.cols()); 1083 Eigen::Map<IndexVector> (dest.m_outerIndex,dest.outerSize()).setZero(); 1084 1085 // pass 1 1086 // FIXME the above copy could be merged with that pass 1087 for (Index j=0; j<otherCopy.outerSize(); ++j) 1088 for (typename OtherCopyEval::InnerIterator it(otherCopyEval, j); it; ++it) 1089 ++dest.m_outerIndex[it.index()]; 1090 1091 // prefix sum 1092 StorageIndex count = 0; 1093 IndexVector positions(dest.outerSize()); 1094 for (Index j=0; j<dest.outerSize(); ++j) 1095 { 1096 StorageIndex tmp = dest.m_outerIndex[j]; 1097 dest.m_outerIndex[j] = count; 1098 positions[j] = count; 1099 count += tmp; 1100 } 1101 dest.m_outerIndex[dest.outerSize()] = count; 1102 // alloc 1103 dest.m_data.resize(count); 1104 // pass 2 1105 for (StorageIndex j=0; j<otherCopy.outerSize(); ++j) 1106 { 1107 for (typename OtherCopyEval::InnerIterator it(otherCopyEval, j); it; ++it) 1108 { 1109 Index pos = positions[it.index()]++; 1110 dest.m_data.index(pos) = j; 1111 dest.m_data.value(pos) = it.value(); 1112 } 1113 } 1114 this->swap(dest); 1115 return *this; 1116 } 1117 else 1118 { 1119 if(other.isRValue()) 1120 { 1121 initAssignment(other.derived()); 1122 } 1123 // there is no special optimization 1124 return Base::operator=(other.derived()); 1125 } 1126 } 1127 1128 template<typename _Scalar, int _Options, typename _StorageIndex> 1129 typename SparseMatrix<_Scalar,_Options,_StorageIndex>::Scalar& SparseMatrix<_Scalar,_Options,_StorageIndex>::insert(Index row, Index col) 1130 { 1131 eigen_assert(row>=0 && row<rows() && col>=0 && col<cols()); 1132 1133 const Index outer = IsRowMajor ? row : col; 1134 const Index inner = IsRowMajor ? col : row; 1135 1136 if(isCompressed()) 1137 { 1138 if(nonZeros()==0) 1139 { 1140 // reserve space if not already done 1141 if(m_data.allocatedSize()==0) 1142 m_data.reserve(2*m_innerSize); 1143 1144 // turn the matrix into non-compressed mode 1145 m_innerNonZeros = static_cast<StorageIndex*>(std::malloc(m_outerSize * sizeof(StorageIndex))); 1146 if(!m_innerNonZeros) internal::throw_std_bad_alloc(); 1147 1148 memset(m_innerNonZeros, 0, (m_outerSize)*sizeof(StorageIndex)); 1149 1150 // pack all inner-vectors to the end of the pre-allocated space 1151 // and allocate the entire free-space to the first inner-vector 1152 StorageIndex end = convert_index(m_data.allocatedSize()); 1153 for(Index j=1; j<=m_outerSize; ++j) 1154 m_outerIndex[j] = end; 1155 } 1156 else 1157 { 1158 // turn the matrix into non-compressed mode 1159 m_innerNonZeros = static_cast<StorageIndex*>(std::malloc(m_outerSize * sizeof(StorageIndex))); 1160 if(!m_innerNonZeros) internal::throw_std_bad_alloc(); 1161 for(Index j=0; j<m_outerSize; ++j) 1162 m_innerNonZeros[j] = m_outerIndex[j+1]-m_outerIndex[j]; 1163 } 1164 } 1165 1166 // check whether we can do a fast "push back" insertion 1167 Index data_end = m_data.allocatedSize(); 1168 1169 // First case: we are filling a new inner vector which is packed at the end. 1170 // We assume that all remaining inner-vectors are also empty and packed to the end. 1171 if(m_outerIndex[outer]==data_end) 1172 { 1173 eigen_internal_assert(m_innerNonZeros[outer]==0); 1174 1175 // pack previous empty inner-vectors to end of the used-space 1176 // and allocate the entire free-space to the current inner-vector. 1177 StorageIndex p = convert_index(m_data.size()); 1178 Index j = outer; 1179 while(j>=0 && m_innerNonZeros[j]==0) 1180 m_outerIndex[j--] = p; 1181 1182 // push back the new element 1183 ++m_innerNonZeros[outer]; 1184 m_data.append(Scalar(0), inner); 1185 1186 // check for reallocation 1187 if(data_end != m_data.allocatedSize()) 1188 { 1189 // m_data has been reallocated 1190 // -> move remaining inner-vectors back to the end of the free-space 1191 // so that the entire free-space is allocated to the current inner-vector. 1192 eigen_internal_assert(data_end < m_data.allocatedSize()); 1193 StorageIndex new_end = convert_index(m_data.allocatedSize()); 1194 for(Index k=outer+1; k<=m_outerSize; ++k) 1195 if(m_outerIndex[k]==data_end) 1196 m_outerIndex[k] = new_end; 1197 } 1198 return m_data.value(p); 1199 } 1200 1201 // Second case: the next inner-vector is packed to the end 1202 // and the current inner-vector end match the used-space. 1203 if(m_outerIndex[outer+1]==data_end && m_outerIndex[outer]+m_innerNonZeros[outer]==m_data.size()) 1204 { 1205 eigen_internal_assert(outer+1==m_outerSize || m_innerNonZeros[outer+1]==0); 1206 1207 // add space for the new element 1208 ++m_innerNonZeros[outer]; 1209 m_data.resize(m_data.size()+1); 1210 1211 // check for reallocation 1212 if(data_end != m_data.allocatedSize()) 1213 { 1214 // m_data has been reallocated 1215 // -> move remaining inner-vectors back to the end of the free-space 1216 // so that the entire free-space is allocated to the current inner-vector. 1217 eigen_internal_assert(data_end < m_data.allocatedSize()); 1218 StorageIndex new_end = convert_index(m_data.allocatedSize()); 1219 for(Index k=outer+1; k<=m_outerSize; ++k) 1220 if(m_outerIndex[k]==data_end) 1221 m_outerIndex[k] = new_end; 1222 } 1223 1224 // and insert it at the right position (sorted insertion) 1225 Index startId = m_outerIndex[outer]; 1226 Index p = m_outerIndex[outer]+m_innerNonZeros[outer]-1; 1227 while ( (p > startId) && (m_data.index(p-1) > inner) ) 1228 { 1229 m_data.index(p) = m_data.index(p-1); 1230 m_data.value(p) = m_data.value(p-1); 1231 --p; 1232 } 1233 1234 m_data.index(p) = convert_index(inner); 1235 return (m_data.value(p) = 0); 1236 } 1237 1238 if(m_data.size() != m_data.allocatedSize()) 1239 { 1240 // make sure the matrix is compatible to random un-compressed insertion: 1241 m_data.resize(m_data.allocatedSize()); 1242 this->reserveInnerVectors(Array<StorageIndex,Dynamic,1>::Constant(m_outerSize, 2)); 1243 } 1244 1245 return insertUncompressed(row,col); 1246 } 1247 1248 template<typename _Scalar, int _Options, typename _StorageIndex> 1249 EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_StorageIndex>::Scalar& SparseMatrix<_Scalar,_Options,_StorageIndex>::insertUncompressed(Index row, Index col) 1250 { 1251 eigen_assert(!isCompressed()); 1252 1253 const Index outer = IsRowMajor ? row : col; 1254 const StorageIndex inner = convert_index(IsRowMajor ? col : row); 1255 1256 Index room = m_outerIndex[outer+1] - m_outerIndex[outer]; 1257 StorageIndex innerNNZ = m_innerNonZeros[outer]; 1258 if(innerNNZ>=room) 1259 { 1260 // this inner vector is full, we need to reallocate the whole buffer :( 1261 reserve(SingletonVector(outer,std::max<StorageIndex>(2,innerNNZ))); 1262 } 1263 1264 Index startId = m_outerIndex[outer]; 1265 Index p = startId + m_innerNonZeros[outer]; 1266 while ( (p > startId) && (m_data.index(p-1) > inner) ) 1267 { 1268 m_data.index(p) = m_data.index(p-1); 1269 m_data.value(p) = m_data.value(p-1); 1270 --p; 1271 } 1272 eigen_assert((p<=startId || m_data.index(p-1)!=inner) && "you cannot insert an element that already exists, you must call coeffRef to this end"); 1273 1274 m_innerNonZeros[outer]++; 1275 1276 m_data.index(p) = inner; 1277 return (m_data.value(p) = 0); 1278 } 1279 1280 template<typename _Scalar, int _Options, typename _StorageIndex> 1281 EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_StorageIndex>::Scalar& SparseMatrix<_Scalar,_Options,_StorageIndex>::insertCompressed(Index row, Index col) 1282 { 1283 eigen_assert(isCompressed()); 1284 1285 const Index outer = IsRowMajor ? row : col; 1286 const Index inner = IsRowMajor ? col : row; 1287 1288 Index previousOuter = outer; 1289 if (m_outerIndex[outer+1]==0) 1290 { 1291 // we start a new inner vector 1292 while (previousOuter>=0 && m_outerIndex[previousOuter]==0) 1293 { 1294 m_outerIndex[previousOuter] = convert_index(m_data.size()); 1295 --previousOuter; 1296 } 1297 m_outerIndex[outer+1] = m_outerIndex[outer]; 1298 } 1299 1300 // here we have to handle the tricky case where the outerIndex array 1301 // starts with: [ 0 0 0 0 0 1 ...] and we are inserted in, e.g., 1302 // the 2nd inner vector... 1303 bool isLastVec = (!(previousOuter==-1 && m_data.size()!=0)) 1304 && (std::size_t(m_outerIndex[outer+1]) == m_data.size()); 1305 1306 std::size_t startId = m_outerIndex[outer]; 1307 // FIXME let's make sure sizeof(long int) == sizeof(std::size_t) 1308 std::size_t p = m_outerIndex[outer+1]; 1309 ++m_outerIndex[outer+1]; 1310 1311 double reallocRatio = 1; 1312 if (m_data.allocatedSize()<=m_data.size()) 1313 { 1314 // if there is no preallocated memory, let's reserve a minimum of 32 elements 1315 if (m_data.size()==0) 1316 { 1317 m_data.reserve(32); 1318 } 1319 else 1320 { 1321 // we need to reallocate the data, to reduce multiple reallocations 1322 // we use a smart resize algorithm based on the current filling ratio 1323 // in addition, we use double to avoid integers overflows 1324 double nnzEstimate = double(m_outerIndex[outer])*double(m_outerSize)/double(outer+1); 1325 reallocRatio = (nnzEstimate-double(m_data.size()))/double(m_data.size()); 1326 // furthermore we bound the realloc ratio to: 1327 // 1) reduce multiple minor realloc when the matrix is almost filled 1328 // 2) avoid to allocate too much memory when the matrix is almost empty 1329 reallocRatio = (std::min)((std::max)(reallocRatio,1.5),8.); 1330 } 1331 } 1332 m_data.resize(m_data.size()+1,reallocRatio); 1333 1334 if (!isLastVec) 1335 { 1336 if (previousOuter==-1) 1337 { 1338 // oops wrong guess. 1339 // let's correct the outer offsets 1340 for (Index k=0; k<=(outer+1); ++k) 1341 m_outerIndex[k] = 0; 1342 Index k=outer+1; 1343 while(m_outerIndex[k]==0) 1344 m_outerIndex[k++] = 1; 1345 while (k<=m_outerSize && m_outerIndex[k]!=0) 1346 m_outerIndex[k++]++; 1347 p = 0; 1348 --k; 1349 k = m_outerIndex[k]-1; 1350 while (k>0) 1351 { 1352 m_data.index(k) = m_data.index(k-1); 1353 m_data.value(k) = m_data.value(k-1); 1354 k--; 1355 } 1356 } 1357 else 1358 { 1359 // we are not inserting into the last inner vec 1360 // update outer indices: 1361 Index j = outer+2; 1362 while (j<=m_outerSize && m_outerIndex[j]!=0) 1363 m_outerIndex[j++]++; 1364 --j; 1365 // shift data of last vecs: 1366 Index k = m_outerIndex[j]-1; 1367 while (k>=Index(p)) 1368 { 1369 m_data.index(k) = m_data.index(k-1); 1370 m_data.value(k) = m_data.value(k-1); 1371 k--; 1372 } 1373 } 1374 } 1375 1376 while ( (p > startId) && (m_data.index(p-1) > inner) ) 1377 { 1378 m_data.index(p) = m_data.index(p-1); 1379 m_data.value(p) = m_data.value(p-1); 1380 --p; 1381 } 1382 1383 m_data.index(p) = inner; 1384 return (m_data.value(p) = 0); 1385 } 1386 1387 namespace internal { 1388 1389 template<typename _Scalar, int _Options, typename _StorageIndex> 1390 struct evaluator<SparseMatrix<_Scalar,_Options,_StorageIndex> > 1391 : evaluator<SparseCompressedBase<SparseMatrix<_Scalar,_Options,_StorageIndex> > > 1392 { 1393 typedef evaluator<SparseCompressedBase<SparseMatrix<_Scalar,_Options,_StorageIndex> > > Base; 1394 typedef SparseMatrix<_Scalar,_Options,_StorageIndex> SparseMatrixType; 1395 evaluator() : Base() {} 1396 explicit evaluator(const SparseMatrixType &mat) : Base(mat) {} 1397 }; 1398 1399 } 1400 1401 } // end namespace Eigen 1402 1403 #endif // EIGEN_SPARSEMATRIX_H 1404