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