ruby-eigen 0.0.9 → 0.0.10.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (293) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +22 -0
  3. data/README.md +21 -0
  4. data/ext/eigen/eigen3/COPYING.BSD +26 -0
  5. data/ext/eigen/eigen3/COPYING.MPL2 +373 -0
  6. data/ext/eigen/eigen3/COPYING.README +18 -0
  7. data/ext/eigen/eigen3/Eigen/Array +11 -0
  8. data/ext/eigen/eigen3/Eigen/Cholesky +32 -0
  9. data/ext/eigen/eigen3/Eigen/CholmodSupport +45 -0
  10. data/ext/eigen/eigen3/Eigen/Core +376 -0
  11. data/ext/eigen/eigen3/Eigen/Dense +7 -0
  12. data/ext/eigen/eigen3/Eigen/Eigen +2 -0
  13. data/ext/eigen/eigen3/Eigen/Eigen2Support +95 -0
  14. data/ext/eigen/eigen3/Eigen/Eigenvalues +48 -0
  15. data/ext/eigen/eigen3/Eigen/Geometry +63 -0
  16. data/ext/eigen/eigen3/Eigen/Householder +23 -0
  17. data/ext/eigen/eigen3/Eigen/IterativeLinearSolvers +40 -0
  18. data/ext/eigen/eigen3/Eigen/Jacobi +26 -0
  19. data/ext/eigen/eigen3/Eigen/LU +41 -0
  20. data/ext/eigen/eigen3/Eigen/LeastSquares +32 -0
  21. data/ext/eigen/eigen3/Eigen/MetisSupport +28 -0
  22. data/ext/eigen/eigen3/Eigen/PaStiXSupport +46 -0
  23. data/ext/eigen/eigen3/Eigen/PardisoSupport +30 -0
  24. data/ext/eigen/eigen3/Eigen/QR +45 -0
  25. data/ext/eigen/eigen3/Eigen/QtAlignedMalloc +34 -0
  26. data/ext/eigen/eigen3/Eigen/SPQRSupport +29 -0
  27. data/ext/eigen/eigen3/Eigen/SVD +37 -0
  28. data/ext/eigen/eigen3/Eigen/Sparse +27 -0
  29. data/ext/eigen/eigen3/Eigen/SparseCore +64 -0
  30. data/ext/eigen/eigen3/Eigen/SparseLU +49 -0
  31. data/ext/eigen/eigen3/Eigen/SparseQR +33 -0
  32. data/ext/eigen/eigen3/Eigen/StdDeque +27 -0
  33. data/ext/eigen/eigen3/Eigen/StdList +26 -0
  34. data/ext/eigen/eigen3/Eigen/StdVector +27 -0
  35. data/ext/eigen/eigen3/Eigen/SuperLUSupport +59 -0
  36. data/ext/eigen/eigen3/Eigen/UmfPackSupport +36 -0
  37. data/ext/eigen/eigen3/Eigen/src/Cholesky/LDLT.h +611 -0
  38. data/ext/eigen/eigen3/Eigen/src/Cholesky/LLT.h +498 -0
  39. data/ext/eigen/eigen3/Eigen/src/Cholesky/LLT_MKL.h +102 -0
  40. data/ext/eigen/eigen3/Eigen/src/CholmodSupport/CholmodSupport.h +607 -0
  41. data/ext/eigen/eigen3/Eigen/src/Core/Array.h +323 -0
  42. data/ext/eigen/eigen3/Eigen/src/Core/ArrayBase.h +226 -0
  43. data/ext/eigen/eigen3/Eigen/src/Core/ArrayWrapper.h +264 -0
  44. data/ext/eigen/eigen3/Eigen/src/Core/Assign.h +590 -0
  45. data/ext/eigen/eigen3/Eigen/src/Core/Assign_MKL.h +224 -0
  46. data/ext/eigen/eigen3/Eigen/src/Core/BandMatrix.h +334 -0
  47. data/ext/eigen/eigen3/Eigen/src/Core/Block.h +406 -0
  48. data/ext/eigen/eigen3/Eigen/src/Core/BooleanRedux.h +154 -0
  49. data/ext/eigen/eigen3/Eigen/src/Core/CommaInitializer.h +154 -0
  50. data/ext/eigen/eigen3/Eigen/src/Core/CoreIterators.h +61 -0
  51. data/ext/eigen/eigen3/Eigen/src/Core/CwiseBinaryOp.h +230 -0
  52. data/ext/eigen/eigen3/Eigen/src/Core/CwiseNullaryOp.h +864 -0
  53. data/ext/eigen/eigen3/Eigen/src/Core/CwiseUnaryOp.h +126 -0
  54. data/ext/eigen/eigen3/Eigen/src/Core/CwiseUnaryView.h +139 -0
  55. data/ext/eigen/eigen3/Eigen/src/Core/DenseBase.h +521 -0
  56. data/ext/eigen/eigen3/Eigen/src/Core/DenseCoeffsBase.h +754 -0
  57. data/ext/eigen/eigen3/Eigen/src/Core/DenseStorage.h +434 -0
  58. data/ext/eigen/eigen3/Eigen/src/Core/Diagonal.h +237 -0
  59. data/ext/eigen/eigen3/Eigen/src/Core/DiagonalMatrix.h +313 -0
  60. data/ext/eigen/eigen3/Eigen/src/Core/DiagonalProduct.h +131 -0
  61. data/ext/eigen/eigen3/Eigen/src/Core/Dot.h +263 -0
  62. data/ext/eigen/eigen3/Eigen/src/Core/EigenBase.h +131 -0
  63. data/ext/eigen/eigen3/Eigen/src/Core/Flagged.h +140 -0
  64. data/ext/eigen/eigen3/Eigen/src/Core/ForceAlignedAccess.h +146 -0
  65. data/ext/eigen/eigen3/Eigen/src/Core/Functors.h +1026 -0
  66. data/ext/eigen/eigen3/Eigen/src/Core/Fuzzy.h +150 -0
  67. data/ext/eigen/eigen3/Eigen/src/Core/GeneralProduct.h +635 -0
  68. data/ext/eigen/eigen3/Eigen/src/Core/GenericPacketMath.h +350 -0
  69. data/ext/eigen/eigen3/Eigen/src/Core/GlobalFunctions.h +92 -0
  70. data/ext/eigen/eigen3/Eigen/src/Core/IO.h +250 -0
  71. data/ext/eigen/eigen3/Eigen/src/Core/Map.h +192 -0
  72. data/ext/eigen/eigen3/Eigen/src/Core/MapBase.h +247 -0
  73. data/ext/eigen/eigen3/Eigen/src/Core/MathFunctions.h +768 -0
  74. data/ext/eigen/eigen3/Eigen/src/Core/Matrix.h +420 -0
  75. data/ext/eigen/eigen3/Eigen/src/Core/MatrixBase.h +563 -0
  76. data/ext/eigen/eigen3/Eigen/src/Core/NestByValue.h +111 -0
  77. data/ext/eigen/eigen3/Eigen/src/Core/NoAlias.h +134 -0
  78. data/ext/eigen/eigen3/Eigen/src/Core/NumTraits.h +150 -0
  79. data/ext/eigen/eigen3/Eigen/src/Core/PermutationMatrix.h +721 -0
  80. data/ext/eigen/eigen3/Eigen/src/Core/PlainObjectBase.h +822 -0
  81. data/ext/eigen/eigen3/Eigen/src/Core/ProductBase.h +290 -0
  82. data/ext/eigen/eigen3/Eigen/src/Core/Random.h +152 -0
  83. data/ext/eigen/eigen3/Eigen/src/Core/Redux.h +409 -0
  84. data/ext/eigen/eigen3/Eigen/src/Core/Ref.h +278 -0
  85. data/ext/eigen/eigen3/Eigen/src/Core/Replicate.h +177 -0
  86. data/ext/eigen/eigen3/Eigen/src/Core/ReturnByValue.h +99 -0
  87. data/ext/eigen/eigen3/Eigen/src/Core/Reverse.h +224 -0
  88. data/ext/eigen/eigen3/Eigen/src/Core/Select.h +162 -0
  89. data/ext/eigen/eigen3/Eigen/src/Core/SelfAdjointView.h +314 -0
  90. data/ext/eigen/eigen3/Eigen/src/Core/SelfCwiseBinaryOp.h +191 -0
  91. data/ext/eigen/eigen3/Eigen/src/Core/SolveTriangular.h +260 -0
  92. data/ext/eigen/eigen3/Eigen/src/Core/StableNorm.h +203 -0
  93. data/ext/eigen/eigen3/Eigen/src/Core/Stride.h +108 -0
  94. data/ext/eigen/eigen3/Eigen/src/Core/Swap.h +126 -0
  95. data/ext/eigen/eigen3/Eigen/src/Core/Transpose.h +419 -0
  96. data/ext/eigen/eigen3/Eigen/src/Core/Transpositions.h +436 -0
  97. data/ext/eigen/eigen3/Eigen/src/Core/TriangularMatrix.h +839 -0
  98. data/ext/eigen/eigen3/Eigen/src/Core/VectorBlock.h +95 -0
  99. data/ext/eigen/eigen3/Eigen/src/Core/VectorwiseOp.h +642 -0
  100. data/ext/eigen/eigen3/Eigen/src/Core/Visitor.h +237 -0
  101. data/ext/eigen/eigen3/Eigen/src/Core/arch/AltiVec/Complex.h +217 -0
  102. data/ext/eigen/eigen3/Eigen/src/Core/arch/AltiVec/PacketMath.h +501 -0
  103. data/ext/eigen/eigen3/Eigen/src/Core/arch/Default/Settings.h +49 -0
  104. data/ext/eigen/eigen3/Eigen/src/Core/arch/NEON/Complex.h +253 -0
  105. data/ext/eigen/eigen3/Eigen/src/Core/arch/NEON/PacketMath.h +420 -0
  106. data/ext/eigen/eigen3/Eigen/src/Core/arch/SSE/Complex.h +442 -0
  107. data/ext/eigen/eigen3/Eigen/src/Core/arch/SSE/MathFunctions.h +475 -0
  108. data/ext/eigen/eigen3/Eigen/src/Core/arch/SSE/PacketMath.h +649 -0
  109. data/ext/eigen/eigen3/Eigen/src/Core/products/CoeffBasedProduct.h +476 -0
  110. data/ext/eigen/eigen3/Eigen/src/Core/products/GeneralBlockPanelKernel.h +1341 -0
  111. data/ext/eigen/eigen3/Eigen/src/Core/products/GeneralMatrixMatrix.h +427 -0
  112. data/ext/eigen/eigen3/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h +278 -0
  113. data/ext/eigen/eigen3/Eigen/src/Core/products/GeneralMatrixMatrixTriangular_MKL.h +146 -0
  114. data/ext/eigen/eigen3/Eigen/src/Core/products/GeneralMatrixMatrix_MKL.h +118 -0
  115. data/ext/eigen/eigen3/Eigen/src/Core/products/GeneralMatrixVector.h +566 -0
  116. data/ext/eigen/eigen3/Eigen/src/Core/products/GeneralMatrixVector_MKL.h +131 -0
  117. data/ext/eigen/eigen3/Eigen/src/Core/products/Parallelizer.h +162 -0
  118. data/ext/eigen/eigen3/Eigen/src/Core/products/SelfadjointMatrixMatrix.h +436 -0
  119. data/ext/eigen/eigen3/Eigen/src/Core/products/SelfadjointMatrixMatrix_MKL.h +295 -0
  120. data/ext/eigen/eigen3/Eigen/src/Core/products/SelfadjointMatrixVector.h +281 -0
  121. data/ext/eigen/eigen3/Eigen/src/Core/products/SelfadjointMatrixVector_MKL.h +114 -0
  122. data/ext/eigen/eigen3/Eigen/src/Core/products/SelfadjointProduct.h +123 -0
  123. data/ext/eigen/eigen3/Eigen/src/Core/products/SelfadjointRank2Update.h +93 -0
  124. data/ext/eigen/eigen3/Eigen/src/Core/products/TriangularMatrixMatrix.h +427 -0
  125. data/ext/eigen/eigen3/Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h +309 -0
  126. data/ext/eigen/eigen3/Eigen/src/Core/products/TriangularMatrixVector.h +348 -0
  127. data/ext/eigen/eigen3/Eigen/src/Core/products/TriangularMatrixVector_MKL.h +247 -0
  128. data/ext/eigen/eigen3/Eigen/src/Core/products/TriangularSolverMatrix.h +332 -0
  129. data/ext/eigen/eigen3/Eigen/src/Core/products/TriangularSolverMatrix_MKL.h +155 -0
  130. data/ext/eigen/eigen3/Eigen/src/Core/products/TriangularSolverVector.h +139 -0
  131. data/ext/eigen/eigen3/Eigen/src/Core/util/BlasUtil.h +264 -0
  132. data/ext/eigen/eigen3/Eigen/src/Core/util/Constants.h +451 -0
  133. data/ext/eigen/eigen3/Eigen/src/Core/util/DisableStupidWarnings.h +40 -0
  134. data/ext/eigen/eigen3/Eigen/src/Core/util/ForwardDeclarations.h +302 -0
  135. data/ext/eigen/eigen3/Eigen/src/Core/util/MKL_support.h +158 -0
  136. data/ext/eigen/eigen3/Eigen/src/Core/util/Macros.h +451 -0
  137. data/ext/eigen/eigen3/Eigen/src/Core/util/Memory.h +977 -0
  138. data/ext/eigen/eigen3/Eigen/src/Core/util/Meta.h +243 -0
  139. data/ext/eigen/eigen3/Eigen/src/Core/util/NonMPL2.h +3 -0
  140. data/ext/eigen/eigen3/Eigen/src/Core/util/ReenableStupidWarnings.h +14 -0
  141. data/ext/eigen/eigen3/Eigen/src/Core/util/StaticAssert.h +208 -0
  142. data/ext/eigen/eigen3/Eigen/src/Core/util/XprHelper.h +469 -0
  143. data/ext/eigen/eigen3/Eigen/src/Eigen2Support/Block.h +126 -0
  144. data/ext/eigen/eigen3/Eigen/src/Eigen2Support/Cwise.h +192 -0
  145. data/ext/eigen/eigen3/Eigen/src/Eigen2Support/CwiseOperators.h +298 -0
  146. data/ext/eigen/eigen3/Eigen/src/Eigen2Support/Geometry/AlignedBox.h +159 -0
  147. data/ext/eigen/eigen3/Eigen/src/Eigen2Support/Geometry/All.h +115 -0
  148. data/ext/eigen/eigen3/Eigen/src/Eigen2Support/Geometry/AngleAxis.h +214 -0
  149. data/ext/eigen/eigen3/Eigen/src/Eigen2Support/Geometry/Hyperplane.h +254 -0
  150. data/ext/eigen/eigen3/Eigen/src/Eigen2Support/Geometry/ParametrizedLine.h +141 -0
  151. data/ext/eigen/eigen3/Eigen/src/Eigen2Support/Geometry/Quaternion.h +495 -0
  152. data/ext/eigen/eigen3/Eigen/src/Eigen2Support/Geometry/Rotation2D.h +145 -0
  153. data/ext/eigen/eigen3/Eigen/src/Eigen2Support/Geometry/RotationBase.h +123 -0
  154. data/ext/eigen/eigen3/Eigen/src/Eigen2Support/Geometry/Scaling.h +167 -0
  155. data/ext/eigen/eigen3/Eigen/src/Eigen2Support/Geometry/Transform.h +786 -0
  156. data/ext/eigen/eigen3/Eigen/src/Eigen2Support/Geometry/Translation.h +184 -0
  157. data/ext/eigen/eigen3/Eigen/src/Eigen2Support/LU.h +120 -0
  158. data/ext/eigen/eigen3/Eigen/src/Eigen2Support/Lazy.h +71 -0
  159. data/ext/eigen/eigen3/Eigen/src/Eigen2Support/LeastSquares.h +169 -0
  160. data/ext/eigen/eigen3/Eigen/src/Eigen2Support/Macros.h +20 -0
  161. data/ext/eigen/eigen3/Eigen/src/Eigen2Support/MathFunctions.h +57 -0
  162. data/ext/eigen/eigen3/Eigen/src/Eigen2Support/Memory.h +45 -0
  163. data/ext/eigen/eigen3/Eigen/src/Eigen2Support/Meta.h +75 -0
  164. data/ext/eigen/eigen3/Eigen/src/Eigen2Support/Minor.h +117 -0
  165. data/ext/eigen/eigen3/Eigen/src/Eigen2Support/QR.h +67 -0
  166. data/ext/eigen/eigen3/Eigen/src/Eigen2Support/SVD.h +637 -0
  167. data/ext/eigen/eigen3/Eigen/src/Eigen2Support/TriangularSolver.h +42 -0
  168. data/ext/eigen/eigen3/Eigen/src/Eigen2Support/VectorBlock.h +94 -0
  169. data/ext/eigen/eigen3/Eigen/src/Eigenvalues/ComplexEigenSolver.h +341 -0
  170. data/ext/eigen/eigen3/Eigen/src/Eigenvalues/ComplexSchur.h +456 -0
  171. data/ext/eigen/eigen3/Eigen/src/Eigenvalues/ComplexSchur_MKL.h +94 -0
  172. data/ext/eigen/eigen3/Eigen/src/Eigenvalues/EigenSolver.h +607 -0
  173. data/ext/eigen/eigen3/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h +350 -0
  174. data/ext/eigen/eigen3/Eigen/src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h +227 -0
  175. data/ext/eigen/eigen3/Eigen/src/Eigenvalues/HessenbergDecomposition.h +373 -0
  176. data/ext/eigen/eigen3/Eigen/src/Eigenvalues/MatrixBaseEigenvalues.h +160 -0
  177. data/ext/eigen/eigen3/Eigen/src/Eigenvalues/RealQZ.h +624 -0
  178. data/ext/eigen/eigen3/Eigen/src/Eigenvalues/RealSchur.h +525 -0
  179. data/ext/eigen/eigen3/Eigen/src/Eigenvalues/RealSchur_MKL.h +83 -0
  180. data/ext/eigen/eigen3/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h +801 -0
  181. data/ext/eigen/eigen3/Eigen/src/Eigenvalues/SelfAdjointEigenSolver_MKL.h +92 -0
  182. data/ext/eigen/eigen3/Eigen/src/Eigenvalues/Tridiagonalization.h +557 -0
  183. data/ext/eigen/eigen3/Eigen/src/Geometry/AlignedBox.h +392 -0
  184. data/ext/eigen/eigen3/Eigen/src/Geometry/AngleAxis.h +233 -0
  185. data/ext/eigen/eigen3/Eigen/src/Geometry/EulerAngles.h +104 -0
  186. data/ext/eigen/eigen3/Eigen/src/Geometry/Homogeneous.h +307 -0
  187. data/ext/eigen/eigen3/Eigen/src/Geometry/Hyperplane.h +280 -0
  188. data/ext/eigen/eigen3/Eigen/src/Geometry/OrthoMethods.h +218 -0
  189. data/ext/eigen/eigen3/Eigen/src/Geometry/ParametrizedLine.h +195 -0
  190. data/ext/eigen/eigen3/Eigen/src/Geometry/Quaternion.h +776 -0
  191. data/ext/eigen/eigen3/Eigen/src/Geometry/Rotation2D.h +160 -0
  192. data/ext/eigen/eigen3/Eigen/src/Geometry/RotationBase.h +206 -0
  193. data/ext/eigen/eigen3/Eigen/src/Geometry/Scaling.h +166 -0
  194. data/ext/eigen/eigen3/Eigen/src/Geometry/Transform.h +1455 -0
  195. data/ext/eigen/eigen3/Eigen/src/Geometry/Translation.h +206 -0
  196. data/ext/eigen/eigen3/Eigen/src/Geometry/Umeyama.h +177 -0
  197. data/ext/eigen/eigen3/Eigen/src/Geometry/arch/Geometry_SSE.h +115 -0
  198. data/ext/eigen/eigen3/Eigen/src/Householder/BlockHouseholder.h +68 -0
  199. data/ext/eigen/eigen3/Eigen/src/Householder/Householder.h +171 -0
  200. data/ext/eigen/eigen3/Eigen/src/Householder/HouseholderSequence.h +441 -0
  201. data/ext/eigen/eigen3/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h +149 -0
  202. data/ext/eigen/eigen3/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h +263 -0
  203. data/ext/eigen/eigen3/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h +256 -0
  204. data/ext/eigen/eigen3/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h +282 -0
  205. data/ext/eigen/eigen3/Eigen/src/Jacobi/Jacobi.h +433 -0
  206. data/ext/eigen/eigen3/Eigen/src/LU/Determinant.h +101 -0
  207. data/ext/eigen/eigen3/Eigen/src/LU/FullPivLU.h +751 -0
  208. data/ext/eigen/eigen3/Eigen/src/LU/Inverse.h +400 -0
  209. data/ext/eigen/eigen3/Eigen/src/LU/PartialPivLU.h +509 -0
  210. data/ext/eigen/eigen3/Eigen/src/LU/PartialPivLU_MKL.h +85 -0
  211. data/ext/eigen/eigen3/Eigen/src/LU/arch/Inverse_SSE.h +329 -0
  212. data/ext/eigen/eigen3/Eigen/src/MetisSupport/MetisSupport.h +137 -0
  213. data/ext/eigen/eigen3/Eigen/src/OrderingMethods/Amd.h +444 -0
  214. data/ext/eigen/eigen3/Eigen/src/OrderingMethods/Eigen_Colamd.h +1850 -0
  215. data/ext/eigen/eigen3/Eigen/src/PaStiXSupport/PaStiXSupport.h +721 -0
  216. data/ext/eigen/eigen3/Eigen/src/PardisoSupport/PardisoSupport.h +592 -0
  217. data/ext/eigen/eigen3/Eigen/src/QR/ColPivHouseholderQR.h +580 -0
  218. data/ext/eigen/eigen3/Eigen/src/QR/ColPivHouseholderQR_MKL.h +99 -0
  219. data/ext/eigen/eigen3/Eigen/src/QR/FullPivHouseholderQR.h +622 -0
  220. data/ext/eigen/eigen3/Eigen/src/QR/HouseholderQR.h +388 -0
  221. data/ext/eigen/eigen3/Eigen/src/QR/HouseholderQR_MKL.h +71 -0
  222. data/ext/eigen/eigen3/Eigen/src/SPQRSupport/SuiteSparseQRSupport.h +338 -0
  223. data/ext/eigen/eigen3/Eigen/src/SVD/JacobiSVD.h +976 -0
  224. data/ext/eigen/eigen3/Eigen/src/SVD/JacobiSVD_MKL.h +92 -0
  225. data/ext/eigen/eigen3/Eigen/src/SVD/UpperBidiagonalization.h +148 -0
  226. data/ext/eigen/eigen3/Eigen/src/SparseCholesky/SimplicialCholesky.h +671 -0
  227. data/ext/eigen/eigen3/Eigen/src/SparseCholesky/SimplicialCholesky_impl.h +199 -0
  228. data/ext/eigen/eigen3/Eigen/src/SparseCore/AmbiVector.h +373 -0
  229. data/ext/eigen/eigen3/Eigen/src/SparseCore/CompressedStorage.h +233 -0
  230. data/ext/eigen/eigen3/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h +245 -0
  231. data/ext/eigen/eigen3/Eigen/src/SparseCore/MappedSparseMatrix.h +181 -0
  232. data/ext/eigen/eigen3/Eigen/src/SparseCore/SparseBlock.h +537 -0
  233. data/ext/eigen/eigen3/Eigen/src/SparseCore/SparseColEtree.h +206 -0
  234. data/ext/eigen/eigen3/Eigen/src/SparseCore/SparseCwiseBinaryOp.h +325 -0
  235. data/ext/eigen/eigen3/Eigen/src/SparseCore/SparseCwiseUnaryOp.h +163 -0
  236. data/ext/eigen/eigen3/Eigen/src/SparseCore/SparseDenseProduct.h +311 -0
  237. data/ext/eigen/eigen3/Eigen/src/SparseCore/SparseDiagonalProduct.h +196 -0
  238. data/ext/eigen/eigen3/Eigen/src/SparseCore/SparseDot.h +101 -0
  239. data/ext/eigen/eigen3/Eigen/src/SparseCore/SparseFuzzy.h +26 -0
  240. data/ext/eigen/eigen3/Eigen/src/SparseCore/SparseMatrix.h +1262 -0
  241. data/ext/eigen/eigen3/Eigen/src/SparseCore/SparseMatrixBase.h +461 -0
  242. data/ext/eigen/eigen3/Eigen/src/SparseCore/SparsePermutation.h +148 -0
  243. data/ext/eigen/eigen3/Eigen/src/SparseCore/SparseProduct.h +188 -0
  244. data/ext/eigen/eigen3/Eigen/src/SparseCore/SparseRedux.h +45 -0
  245. data/ext/eigen/eigen3/Eigen/src/SparseCore/SparseSelfAdjointView.h +507 -0
  246. data/ext/eigen/eigen3/Eigen/src/SparseCore/SparseSparseProductWithPruning.h +150 -0
  247. data/ext/eigen/eigen3/Eigen/src/SparseCore/SparseTranspose.h +63 -0
  248. data/ext/eigen/eigen3/Eigen/src/SparseCore/SparseTriangularView.h +179 -0
  249. data/ext/eigen/eigen3/Eigen/src/SparseCore/SparseUtil.h +172 -0
  250. data/ext/eigen/eigen3/Eigen/src/SparseCore/SparseVector.h +448 -0
  251. data/ext/eigen/eigen3/Eigen/src/SparseCore/SparseView.h +99 -0
  252. data/ext/eigen/eigen3/Eigen/src/SparseCore/TriangularSolver.h +334 -0
  253. data/ext/eigen/eigen3/Eigen/src/SparseLU/SparseLU.h +806 -0
  254. data/ext/eigen/eigen3/Eigen/src/SparseLU/SparseLUImpl.h +66 -0
  255. data/ext/eigen/eigen3/Eigen/src/SparseLU/SparseLU_Memory.h +227 -0
  256. data/ext/eigen/eigen3/Eigen/src/SparseLU/SparseLU_Structs.h +111 -0
  257. data/ext/eigen/eigen3/Eigen/src/SparseLU/SparseLU_SupernodalMatrix.h +298 -0
  258. data/ext/eigen/eigen3/Eigen/src/SparseLU/SparseLU_Utils.h +80 -0
  259. data/ext/eigen/eigen3/Eigen/src/SparseLU/SparseLU_column_bmod.h +180 -0
  260. data/ext/eigen/eigen3/Eigen/src/SparseLU/SparseLU_column_dfs.h +177 -0
  261. data/ext/eigen/eigen3/Eigen/src/SparseLU/SparseLU_copy_to_ucol.h +106 -0
  262. data/ext/eigen/eigen3/Eigen/src/SparseLU/SparseLU_gemm_kernel.h +279 -0
  263. data/ext/eigen/eigen3/Eigen/src/SparseLU/SparseLU_heap_relax_snode.h +127 -0
  264. data/ext/eigen/eigen3/Eigen/src/SparseLU/SparseLU_kernel_bmod.h +130 -0
  265. data/ext/eigen/eigen3/Eigen/src/SparseLU/SparseLU_panel_bmod.h +223 -0
  266. data/ext/eigen/eigen3/Eigen/src/SparseLU/SparseLU_panel_dfs.h +258 -0
  267. data/ext/eigen/eigen3/Eigen/src/SparseLU/SparseLU_pivotL.h +137 -0
  268. data/ext/eigen/eigen3/Eigen/src/SparseLU/SparseLU_pruneL.h +135 -0
  269. data/ext/eigen/eigen3/Eigen/src/SparseLU/SparseLU_relax_snode.h +83 -0
  270. data/ext/eigen/eigen3/Eigen/src/SparseQR/SparseQR.h +714 -0
  271. data/ext/eigen/eigen3/Eigen/src/StlSupport/StdDeque.h +134 -0
  272. data/ext/eigen/eigen3/Eigen/src/StlSupport/StdList.h +114 -0
  273. data/ext/eigen/eigen3/Eigen/src/StlSupport/StdVector.h +126 -0
  274. data/ext/eigen/eigen3/Eigen/src/StlSupport/details.h +84 -0
  275. data/ext/eigen/eigen3/Eigen/src/SuperLUSupport/SuperLUSupport.h +1026 -0
  276. data/ext/eigen/eigen3/Eigen/src/UmfPackSupport/UmfPackSupport.h +474 -0
  277. data/ext/eigen/eigen3/Eigen/src/misc/Image.h +84 -0
  278. data/ext/eigen/eigen3/Eigen/src/misc/Kernel.h +81 -0
  279. data/ext/eigen/eigen3/Eigen/src/misc/Solve.h +76 -0
  280. data/ext/eigen/eigen3/Eigen/src/misc/SparseSolve.h +128 -0
  281. data/ext/eigen/eigen3/Eigen/src/misc/blas.h +658 -0
  282. data/ext/eigen/eigen3/Eigen/src/plugins/ArrayCwiseBinaryOps.h +253 -0
  283. data/ext/eigen/eigen3/Eigen/src/plugins/ArrayCwiseUnaryOps.h +187 -0
  284. data/ext/eigen/eigen3/Eigen/src/plugins/BlockMethods.h +935 -0
  285. data/ext/eigen/eigen3/Eigen/src/plugins/CommonCwiseBinaryOps.h +46 -0
  286. data/ext/eigen/eigen3/Eigen/src/plugins/CommonCwiseUnaryOps.h +172 -0
  287. data/ext/eigen/eigen3/Eigen/src/plugins/MatrixCwiseBinaryOps.h +143 -0
  288. data/ext/eigen/eigen3/Eigen/src/plugins/MatrixCwiseUnaryOps.h +52 -0
  289. data/ext/eigen/eigen3/signature_of_eigen3_matrix_library +1 -0
  290. data/ext/eigen/eigen_wrap.cxx +19420 -10396
  291. data/ext/eigen/extconf.rb +37 -2
  292. data/lib/eigen.rb +146 -3
  293. metadata +294 -7
@@ -0,0 +1,444 @@
1
+ // This file is part of Eigen, a lightweight C++ template library
2
+ // for linear algebra.
3
+ //
4
+ // Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@inria.fr>
5
+
6
+ /*
7
+
8
+ NOTE: this routine has been adapted from the CSparse library:
9
+
10
+ Copyright (c) 2006, Timothy A. Davis.
11
+ http://www.cise.ufl.edu/research/sparse/CSparse
12
+
13
+ CSparse is free software; you can redistribute it and/or
14
+ modify it under the terms of the GNU Lesser General Public
15
+ License as published by the Free Software Foundation; either
16
+ version 2.1 of the License, or (at your option) any later version.
17
+
18
+ CSparse is distributed in the hope that it will be useful,
19
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
20
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21
+ Lesser General Public License for more details.
22
+
23
+ You should have received a copy of the GNU Lesser General Public
24
+ License along with this Module; if not, write to the Free Software
25
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26
+
27
+ */
28
+
29
+ #include "../Core/util/NonMPL2.h"
30
+
31
+ #ifndef EIGEN_SPARSE_AMD_H
32
+ #define EIGEN_SPARSE_AMD_H
33
+
34
+ namespace Eigen {
35
+
36
+ namespace internal {
37
+
38
+ template<typename T> inline T amd_flip(const T& i) { return -i-2; }
39
+ template<typename T> inline T amd_unflip(const T& i) { return i<0 ? amd_flip(i) : i; }
40
+ template<typename T0, typename T1> inline bool amd_marked(const T0* w, const T1& j) { return w[j]<0; }
41
+ template<typename T0, typename T1> inline void amd_mark(const T0* w, const T1& j) { return w[j] = amd_flip(w[j]); }
42
+
43
+ /* clear w */
44
+ template<typename Index>
45
+ static int cs_wclear (Index mark, Index lemax, Index *w, Index n)
46
+ {
47
+ Index k;
48
+ if(mark < 2 || (mark + lemax < 0))
49
+ {
50
+ for(k = 0; k < n; k++)
51
+ if(w[k] != 0)
52
+ w[k] = 1;
53
+ mark = 2;
54
+ }
55
+ return (mark); /* at this point, w[0..n-1] < mark holds */
56
+ }
57
+
58
+ /* depth-first search and postorder of a tree rooted at node j */
59
+ template<typename Index>
60
+ Index cs_tdfs(Index j, Index k, Index *head, const Index *next, Index *post, Index *stack)
61
+ {
62
+ int i, p, top = 0;
63
+ if(!head || !next || !post || !stack) return (-1); /* check inputs */
64
+ stack[0] = j; /* place j on the stack */
65
+ while (top >= 0) /* while (stack is not empty) */
66
+ {
67
+ p = stack[top]; /* p = top of stack */
68
+ i = head[p]; /* i = youngest child of p */
69
+ if(i == -1)
70
+ {
71
+ top--; /* p has no unordered children left */
72
+ post[k++] = p; /* node p is the kth postordered node */
73
+ }
74
+ else
75
+ {
76
+ head[p] = next[i]; /* remove i from children of p */
77
+ stack[++top] = i; /* start dfs on child node i */
78
+ }
79
+ }
80
+ return k;
81
+ }
82
+
83
+
84
+ /** \internal
85
+ * \ingroup OrderingMethods_Module
86
+ * Approximate minimum degree ordering algorithm.
87
+ * \returns the permutation P reducing the fill-in of the input matrix \a C
88
+ * The input matrix \a C must be a selfadjoint compressed column major SparseMatrix object. Both the upper and lower parts have to be stored, but the diagonal entries are optional.
89
+ * On exit the values of C are destroyed */
90
+ template<typename Scalar, typename Index>
91
+ void minimum_degree_ordering(SparseMatrix<Scalar,ColMajor,Index>& C, PermutationMatrix<Dynamic,Dynamic,Index>& perm)
92
+ {
93
+ using std::sqrt;
94
+
95
+ int d, dk, dext, lemax = 0, e, elenk, eln, i, j, k, k1,
96
+ k2, k3, jlast, ln, dense, nzmax, mindeg = 0, nvi, nvj, nvk, mark, wnvi,
97
+ ok, nel = 0, p, p1, p2, p3, p4, pj, pk, pk1, pk2, pn, q, t;
98
+ unsigned int h;
99
+
100
+ Index n = C.cols();
101
+ dense = std::max<Index> (16, Index(10 * sqrt(double(n)))); /* find dense threshold */
102
+ dense = std::min<Index> (n-2, dense);
103
+
104
+ Index cnz = C.nonZeros();
105
+ perm.resize(n+1);
106
+ t = cnz + cnz/5 + 2*n; /* add elbow room to C */
107
+ C.resizeNonZeros(t);
108
+
109
+ Index* W = new Index[8*(n+1)]; /* get workspace */
110
+ Index* len = W;
111
+ Index* nv = W + (n+1);
112
+ Index* next = W + 2*(n+1);
113
+ Index* head = W + 3*(n+1);
114
+ Index* elen = W + 4*(n+1);
115
+ Index* degree = W + 5*(n+1);
116
+ Index* w = W + 6*(n+1);
117
+ Index* hhead = W + 7*(n+1);
118
+ Index* last = perm.indices().data(); /* use P as workspace for last */
119
+
120
+ /* --- Initialize quotient graph ---------------------------------------- */
121
+ Index* Cp = C.outerIndexPtr();
122
+ Index* Ci = C.innerIndexPtr();
123
+ for(k = 0; k < n; k++)
124
+ len[k] = Cp[k+1] - Cp[k];
125
+ len[n] = 0;
126
+ nzmax = t;
127
+
128
+ for(i = 0; i <= n; i++)
129
+ {
130
+ head[i] = -1; // degree list i is empty
131
+ last[i] = -1;
132
+ next[i] = -1;
133
+ hhead[i] = -1; // hash list i is empty
134
+ nv[i] = 1; // node i is just one node
135
+ w[i] = 1; // node i is alive
136
+ elen[i] = 0; // Ek of node i is empty
137
+ degree[i] = len[i]; // degree of node i
138
+ }
139
+ mark = internal::cs_wclear<Index>(0, 0, w, n); /* clear w */
140
+
141
+ /* --- Initialize degree lists ------------------------------------------ */
142
+ for(i = 0; i < n; i++)
143
+ {
144
+ bool has_diag = false;
145
+ for(p = Cp[i]; p<Cp[i+1]; ++p)
146
+ if(Ci[p]==i)
147
+ {
148
+ has_diag = true;
149
+ break;
150
+ }
151
+
152
+ d = degree[i];
153
+ if(d == 1 && has_diag) /* node i is empty */
154
+ {
155
+ elen[i] = -2; /* element i is dead */
156
+ nel++;
157
+ Cp[i] = -1; /* i is a root of assembly tree */
158
+ w[i] = 0;
159
+ }
160
+ else if(d > dense || !has_diag) /* node i is dense or has no structural diagonal element */
161
+ {
162
+ nv[i] = 0; /* absorb i into element n */
163
+ elen[i] = -1; /* node i is dead */
164
+ nel++;
165
+ Cp[i] = amd_flip (n);
166
+ nv[n]++;
167
+ }
168
+ else
169
+ {
170
+ if(head[d] != -1) last[head[d]] = i;
171
+ next[i] = head[d]; /* put node i in degree list d */
172
+ head[d] = i;
173
+ }
174
+ }
175
+
176
+ elen[n] = -2; /* n is a dead element */
177
+ Cp[n] = -1; /* n is a root of assembly tree */
178
+ w[n] = 0; /* n is a dead element */
179
+
180
+ while (nel < n) /* while (selecting pivots) do */
181
+ {
182
+ /* --- Select node of minimum approximate degree -------------------- */
183
+ for(k = -1; mindeg < n && (k = head[mindeg]) == -1; mindeg++) {}
184
+ if(next[k] != -1) last[next[k]] = -1;
185
+ head[mindeg] = next[k]; /* remove k from degree list */
186
+ elenk = elen[k]; /* elenk = |Ek| */
187
+ nvk = nv[k]; /* # of nodes k represents */
188
+ nel += nvk; /* nv[k] nodes of A eliminated */
189
+
190
+ /* --- Garbage collection ------------------------------------------- */
191
+ if(elenk > 0 && cnz + mindeg >= nzmax)
192
+ {
193
+ for(j = 0; j < n; j++)
194
+ {
195
+ if((p = Cp[j]) >= 0) /* j is a live node or element */
196
+ {
197
+ Cp[j] = Ci[p]; /* save first entry of object */
198
+ Ci[p] = amd_flip (j); /* first entry is now amd_flip(j) */
199
+ }
200
+ }
201
+ for(q = 0, p = 0; p < cnz; ) /* scan all of memory */
202
+ {
203
+ if((j = amd_flip (Ci[p++])) >= 0) /* found object j */
204
+ {
205
+ Ci[q] = Cp[j]; /* restore first entry of object */
206
+ Cp[j] = q++; /* new pointer to object j */
207
+ for(k3 = 0; k3 < len[j]-1; k3++) Ci[q++] = Ci[p++];
208
+ }
209
+ }
210
+ cnz = q; /* Ci[cnz...nzmax-1] now free */
211
+ }
212
+
213
+ /* --- Construct new element ---------------------------------------- */
214
+ dk = 0;
215
+ nv[k] = -nvk; /* flag k as in Lk */
216
+ p = Cp[k];
217
+ pk1 = (elenk == 0) ? p : cnz; /* do in place if elen[k] == 0 */
218
+ pk2 = pk1;
219
+ for(k1 = 1; k1 <= elenk + 1; k1++)
220
+ {
221
+ if(k1 > elenk)
222
+ {
223
+ e = k; /* search the nodes in k */
224
+ pj = p; /* list of nodes starts at Ci[pj]*/
225
+ ln = len[k] - elenk; /* length of list of nodes in k */
226
+ }
227
+ else
228
+ {
229
+ e = Ci[p++]; /* search the nodes in e */
230
+ pj = Cp[e];
231
+ ln = len[e]; /* length of list of nodes in e */
232
+ }
233
+ for(k2 = 1; k2 <= ln; k2++)
234
+ {
235
+ i = Ci[pj++];
236
+ if((nvi = nv[i]) <= 0) continue; /* node i dead, or seen */
237
+ dk += nvi; /* degree[Lk] += size of node i */
238
+ nv[i] = -nvi; /* negate nv[i] to denote i in Lk*/
239
+ Ci[pk2++] = i; /* place i in Lk */
240
+ if(next[i] != -1) last[next[i]] = last[i];
241
+ if(last[i] != -1) /* remove i from degree list */
242
+ {
243
+ next[last[i]] = next[i];
244
+ }
245
+ else
246
+ {
247
+ head[degree[i]] = next[i];
248
+ }
249
+ }
250
+ if(e != k)
251
+ {
252
+ Cp[e] = amd_flip (k); /* absorb e into k */
253
+ w[e] = 0; /* e is now a dead element */
254
+ }
255
+ }
256
+ if(elenk != 0) cnz = pk2; /* Ci[cnz...nzmax] is free */
257
+ degree[k] = dk; /* external degree of k - |Lk\i| */
258
+ Cp[k] = pk1; /* element k is in Ci[pk1..pk2-1] */
259
+ len[k] = pk2 - pk1;
260
+ elen[k] = -2; /* k is now an element */
261
+
262
+ /* --- Find set differences ----------------------------------------- */
263
+ mark = internal::cs_wclear<Index>(mark, lemax, w, n); /* clear w if necessary */
264
+ for(pk = pk1; pk < pk2; pk++) /* scan 1: find |Le\Lk| */
265
+ {
266
+ i = Ci[pk];
267
+ if((eln = elen[i]) <= 0) continue;/* skip if elen[i] empty */
268
+ nvi = -nv[i]; /* nv[i] was negated */
269
+ wnvi = mark - nvi;
270
+ for(p = Cp[i]; p <= Cp[i] + eln - 1; p++) /* scan Ei */
271
+ {
272
+ e = Ci[p];
273
+ if(w[e] >= mark)
274
+ {
275
+ w[e] -= nvi; /* decrement |Le\Lk| */
276
+ }
277
+ else if(w[e] != 0) /* ensure e is a live element */
278
+ {
279
+ w[e] = degree[e] + wnvi; /* 1st time e seen in scan 1 */
280
+ }
281
+ }
282
+ }
283
+
284
+ /* --- Degree update ------------------------------------------------ */
285
+ for(pk = pk1; pk < pk2; pk++) /* scan2: degree update */
286
+ {
287
+ i = Ci[pk]; /* consider node i in Lk */
288
+ p1 = Cp[i];
289
+ p2 = p1 + elen[i] - 1;
290
+ pn = p1;
291
+ for(h = 0, d = 0, p = p1; p <= p2; p++) /* scan Ei */
292
+ {
293
+ e = Ci[p];
294
+ if(w[e] != 0) /* e is an unabsorbed element */
295
+ {
296
+ dext = w[e] - mark; /* dext = |Le\Lk| */
297
+ if(dext > 0)
298
+ {
299
+ d += dext; /* sum up the set differences */
300
+ Ci[pn++] = e; /* keep e in Ei */
301
+ h += e; /* compute the hash of node i */
302
+ }
303
+ else
304
+ {
305
+ Cp[e] = amd_flip (k); /* aggressive absorb. e->k */
306
+ w[e] = 0; /* e is a dead element */
307
+ }
308
+ }
309
+ }
310
+ elen[i] = pn - p1 + 1; /* elen[i] = |Ei| */
311
+ p3 = pn;
312
+ p4 = p1 + len[i];
313
+ for(p = p2 + 1; p < p4; p++) /* prune edges in Ai */
314
+ {
315
+ j = Ci[p];
316
+ if((nvj = nv[j]) <= 0) continue; /* node j dead or in Lk */
317
+ d += nvj; /* degree(i) += |j| */
318
+ Ci[pn++] = j; /* place j in node list of i */
319
+ h += j; /* compute hash for node i */
320
+ }
321
+ if(d == 0) /* check for mass elimination */
322
+ {
323
+ Cp[i] = amd_flip (k); /* absorb i into k */
324
+ nvi = -nv[i];
325
+ dk -= nvi; /* |Lk| -= |i| */
326
+ nvk += nvi; /* |k| += nv[i] */
327
+ nel += nvi;
328
+ nv[i] = 0;
329
+ elen[i] = -1; /* node i is dead */
330
+ }
331
+ else
332
+ {
333
+ degree[i] = std::min<Index> (degree[i], d); /* update degree(i) */
334
+ Ci[pn] = Ci[p3]; /* move first node to end */
335
+ Ci[p3] = Ci[p1]; /* move 1st el. to end of Ei */
336
+ Ci[p1] = k; /* add k as 1st element in of Ei */
337
+ len[i] = pn - p1 + 1; /* new len of adj. list of node i */
338
+ h %= n; /* finalize hash of i */
339
+ next[i] = hhead[h]; /* place i in hash bucket */
340
+ hhead[h] = i;
341
+ last[i] = h; /* save hash of i in last[i] */
342
+ }
343
+ } /* scan2 is done */
344
+ degree[k] = dk; /* finalize |Lk| */
345
+ lemax = std::max<Index>(lemax, dk);
346
+ mark = internal::cs_wclear<Index>(mark+lemax, lemax, w, n); /* clear w */
347
+
348
+ /* --- Supernode detection ------------------------------------------ */
349
+ for(pk = pk1; pk < pk2; pk++)
350
+ {
351
+ i = Ci[pk];
352
+ if(nv[i] >= 0) continue; /* skip if i is dead */
353
+ h = last[i]; /* scan hash bucket of node i */
354
+ i = hhead[h];
355
+ hhead[h] = -1; /* hash bucket will be empty */
356
+ for(; i != -1 && next[i] != -1; i = next[i], mark++)
357
+ {
358
+ ln = len[i];
359
+ eln = elen[i];
360
+ for(p = Cp[i]+1; p <= Cp[i] + ln-1; p++) w[Ci[p]] = mark;
361
+ jlast = i;
362
+ for(j = next[i]; j != -1; ) /* compare i with all j */
363
+ {
364
+ ok = (len[j] == ln) && (elen[j] == eln);
365
+ for(p = Cp[j] + 1; ok && p <= Cp[j] + ln - 1; p++)
366
+ {
367
+ if(w[Ci[p]] != mark) ok = 0; /* compare i and j*/
368
+ }
369
+ if(ok) /* i and j are identical */
370
+ {
371
+ Cp[j] = amd_flip (i); /* absorb j into i */
372
+ nv[i] += nv[j];
373
+ nv[j] = 0;
374
+ elen[j] = -1; /* node j is dead */
375
+ j = next[j]; /* delete j from hash bucket */
376
+ next[jlast] = j;
377
+ }
378
+ else
379
+ {
380
+ jlast = j; /* j and i are different */
381
+ j = next[j];
382
+ }
383
+ }
384
+ }
385
+ }
386
+
387
+ /* --- Finalize new element------------------------------------------ */
388
+ for(p = pk1, pk = pk1; pk < pk2; pk++) /* finalize Lk */
389
+ {
390
+ i = Ci[pk];
391
+ if((nvi = -nv[i]) <= 0) continue;/* skip if i is dead */
392
+ nv[i] = nvi; /* restore nv[i] */
393
+ d = degree[i] + dk - nvi; /* compute external degree(i) */
394
+ d = std::min<Index> (d, n - nel - nvi);
395
+ if(head[d] != -1) last[head[d]] = i;
396
+ next[i] = head[d]; /* put i back in degree list */
397
+ last[i] = -1;
398
+ head[d] = i;
399
+ mindeg = std::min<Index> (mindeg, d); /* find new minimum degree */
400
+ degree[i] = d;
401
+ Ci[p++] = i; /* place i in Lk */
402
+ }
403
+ nv[k] = nvk; /* # nodes absorbed into k */
404
+ if((len[k] = p-pk1) == 0) /* length of adj list of element k*/
405
+ {
406
+ Cp[k] = -1; /* k is a root of the tree */
407
+ w[k] = 0; /* k is now a dead element */
408
+ }
409
+ if(elenk != 0) cnz = p; /* free unused space in Lk */
410
+ }
411
+
412
+ /* --- Postordering ----------------------------------------------------- */
413
+ for(i = 0; i < n; i++) Cp[i] = amd_flip (Cp[i]);/* fix assembly tree */
414
+ for(j = 0; j <= n; j++) head[j] = -1;
415
+ for(j = n; j >= 0; j--) /* place unordered nodes in lists */
416
+ {
417
+ if(nv[j] > 0) continue; /* skip if j is an element */
418
+ next[j] = head[Cp[j]]; /* place j in list of its parent */
419
+ head[Cp[j]] = j;
420
+ }
421
+ for(e = n; e >= 0; e--) /* place elements in lists */
422
+ {
423
+ if(nv[e] <= 0) continue; /* skip unless e is an element */
424
+ if(Cp[e] != -1)
425
+ {
426
+ next[e] = head[Cp[e]]; /* place e in list of its parent */
427
+ head[Cp[e]] = e;
428
+ }
429
+ }
430
+ for(k = 0, i = 0; i <= n; i++) /* postorder the assembly tree */
431
+ {
432
+ if(Cp[i] == -1) k = internal::cs_tdfs<Index>(i, k, head, next, perm.indices().data(), w);
433
+ }
434
+
435
+ perm.indices().conservativeResize(n);
436
+
437
+ delete[] W;
438
+ }
439
+
440
+ } // namespace internal
441
+
442
+ } // end namespace Eigen
443
+
444
+ #endif // EIGEN_SPARSE_AMD_H
@@ -0,0 +1,1850 @@
1
+ // // This file is part of Eigen, a lightweight C++ template library
2
+ // for linear algebra.
3
+ //
4
+ // Copyright (C) 2012 Desire Nuentsa Wakam <desire.nuentsa_wakam@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
+ // This file is modified from the colamd/symamd library. The copyright is below
11
+
12
+ // The authors of the code itself are Stefan I. Larimore and Timothy A.
13
+ // Davis (davis@cise.ufl.edu), University of Florida. The algorithm was
14
+ // developed in collaboration with John Gilbert, Xerox PARC, and Esmond
15
+ // Ng, Oak Ridge National Laboratory.
16
+ //
17
+ // Date:
18
+ //
19
+ // September 8, 2003. Version 2.3.
20
+ //
21
+ // Acknowledgements:
22
+ //
23
+ // This work was supported by the National Science Foundation, under
24
+ // grants DMS-9504974 and DMS-9803599.
25
+ //
26
+ // Notice:
27
+ //
28
+ // Copyright (c) 1998-2003 by the University of Florida.
29
+ // All Rights Reserved.
30
+ //
31
+ // THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
32
+ // EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
33
+ //
34
+ // Permission is hereby granted to use, copy, modify, and/or distribute
35
+ // this program, provided that the Copyright, this License, and the
36
+ // Availability of the original version is retained on all copies and made
37
+ // accessible to the end-user of any code or package that includes COLAMD
38
+ // or any modified version of COLAMD.
39
+ //
40
+ // Availability:
41
+ //
42
+ // The colamd/symamd library is available at
43
+ //
44
+ // http://www.cise.ufl.edu/research/sparse/colamd/
45
+
46
+ // This is the http://www.cise.ufl.edu/research/sparse/colamd/colamd.h
47
+ // file. It is required by the colamd.c, colamdmex.c, and symamdmex.c
48
+ // files, and by any C code that calls the routines whose prototypes are
49
+ // listed below, or that uses the colamd/symamd definitions listed below.
50
+
51
+ #ifndef EIGEN_COLAMD_H
52
+ #define EIGEN_COLAMD_H
53
+
54
+ namespace internal {
55
+ /* Ensure that debugging is turned off: */
56
+ #ifndef COLAMD_NDEBUG
57
+ #define COLAMD_NDEBUG
58
+ #endif /* NDEBUG */
59
+ /* ========================================================================== */
60
+ /* === Knob and statistics definitions ====================================== */
61
+ /* ========================================================================== */
62
+
63
+ /* size of the knobs [ ] array. Only knobs [0..1] are currently used. */
64
+ #define COLAMD_KNOBS 20
65
+
66
+ /* number of output statistics. Only stats [0..6] are currently used. */
67
+ #define COLAMD_STATS 20
68
+
69
+ /* knobs [0] and stats [0]: dense row knob and output statistic. */
70
+ #define COLAMD_DENSE_ROW 0
71
+
72
+ /* knobs [1] and stats [1]: dense column knob and output statistic. */
73
+ #define COLAMD_DENSE_COL 1
74
+
75
+ /* stats [2]: memory defragmentation count output statistic */
76
+ #define COLAMD_DEFRAG_COUNT 2
77
+
78
+ /* stats [3]: colamd status: zero OK, > 0 warning or notice, < 0 error */
79
+ #define COLAMD_STATUS 3
80
+
81
+ /* stats [4..6]: error info, or info on jumbled columns */
82
+ #define COLAMD_INFO1 4
83
+ #define COLAMD_INFO2 5
84
+ #define COLAMD_INFO3 6
85
+
86
+ /* error codes returned in stats [3]: */
87
+ #define COLAMD_OK (0)
88
+ #define COLAMD_OK_BUT_JUMBLED (1)
89
+ #define COLAMD_ERROR_A_not_present (-1)
90
+ #define COLAMD_ERROR_p_not_present (-2)
91
+ #define COLAMD_ERROR_nrow_negative (-3)
92
+ #define COLAMD_ERROR_ncol_negative (-4)
93
+ #define COLAMD_ERROR_nnz_negative (-5)
94
+ #define COLAMD_ERROR_p0_nonzero (-6)
95
+ #define COLAMD_ERROR_A_too_small (-7)
96
+ #define COLAMD_ERROR_col_length_negative (-8)
97
+ #define COLAMD_ERROR_row_index_out_of_bounds (-9)
98
+ #define COLAMD_ERROR_out_of_memory (-10)
99
+ #define COLAMD_ERROR_internal_error (-999)
100
+
101
+ /* ========================================================================== */
102
+ /* === Definitions ========================================================== */
103
+ /* ========================================================================== */
104
+
105
+ #define COLAMD_MAX(a,b) (((a) > (b)) ? (a) : (b))
106
+ #define COLAMD_MIN(a,b) (((a) < (b)) ? (a) : (b))
107
+
108
+ #define ONES_COMPLEMENT(r) (-(r)-1)
109
+
110
+ /* -------------------------------------------------------------------------- */
111
+
112
+ #define COLAMD_EMPTY (-1)
113
+
114
+ /* Row and column status */
115
+ #define ALIVE (0)
116
+ #define DEAD (-1)
117
+
118
+ /* Column status */
119
+ #define DEAD_PRINCIPAL (-1)
120
+ #define DEAD_NON_PRINCIPAL (-2)
121
+
122
+ /* Macros for row and column status update and checking. */
123
+ #define ROW_IS_DEAD(r) ROW_IS_MARKED_DEAD (Row[r].shared2.mark)
124
+ #define ROW_IS_MARKED_DEAD(row_mark) (row_mark < ALIVE)
125
+ #define ROW_IS_ALIVE(r) (Row [r].shared2.mark >= ALIVE)
126
+ #define COL_IS_DEAD(c) (Col [c].start < ALIVE)
127
+ #define COL_IS_ALIVE(c) (Col [c].start >= ALIVE)
128
+ #define COL_IS_DEAD_PRINCIPAL(c) (Col [c].start == DEAD_PRINCIPAL)
129
+ #define KILL_ROW(r) { Row [r].shared2.mark = DEAD ; }
130
+ #define KILL_PRINCIPAL_COL(c) { Col [c].start = DEAD_PRINCIPAL ; }
131
+ #define KILL_NON_PRINCIPAL_COL(c) { Col [c].start = DEAD_NON_PRINCIPAL ; }
132
+
133
+ /* ========================================================================== */
134
+ /* === Colamd reporting mechanism =========================================== */
135
+ /* ========================================================================== */
136
+
137
+ // == Row and Column structures ==
138
+ template <typename Index>
139
+ struct colamd_col
140
+ {
141
+ Index start ; /* index for A of first row in this column, or DEAD */
142
+ /* if column is dead */
143
+ Index length ; /* number of rows in this column */
144
+ union
145
+ {
146
+ Index thickness ; /* number of original columns represented by this */
147
+ /* col, if the column is alive */
148
+ Index parent ; /* parent in parent tree super-column structure, if */
149
+ /* the column is dead */
150
+ } shared1 ;
151
+ union
152
+ {
153
+ Index score ; /* the score used to maintain heap, if col is alive */
154
+ Index order ; /* pivot ordering of this column, if col is dead */
155
+ } shared2 ;
156
+ union
157
+ {
158
+ Index headhash ; /* head of a hash bucket, if col is at the head of */
159
+ /* a degree list */
160
+ Index hash ; /* hash value, if col is not in a degree list */
161
+ Index prev ; /* previous column in degree list, if col is in a */
162
+ /* degree list (but not at the head of a degree list) */
163
+ } shared3 ;
164
+ union
165
+ {
166
+ Index degree_next ; /* next column, if col is in a degree list */
167
+ Index hash_next ; /* next column, if col is in a hash list */
168
+ } shared4 ;
169
+
170
+ };
171
+
172
+ template <typename Index>
173
+ struct Colamd_Row
174
+ {
175
+ Index start ; /* index for A of first col in this row */
176
+ Index length ; /* number of principal columns in this row */
177
+ union
178
+ {
179
+ Index degree ; /* number of principal & non-principal columns in row */
180
+ Index p ; /* used as a row pointer in init_rows_cols () */
181
+ } shared1 ;
182
+ union
183
+ {
184
+ Index mark ; /* for computing set differences and marking dead rows*/
185
+ Index first_column ;/* first column in row (used in garbage collection) */
186
+ } shared2 ;
187
+
188
+ };
189
+
190
+ /* ========================================================================== */
191
+ /* === Colamd recommended memory size ======================================= */
192
+ /* ========================================================================== */
193
+
194
+ /*
195
+ The recommended length Alen of the array A passed to colamd is given by
196
+ the COLAMD_RECOMMENDED (nnz, n_row, n_col) macro. It returns -1 if any
197
+ argument is negative. 2*nnz space is required for the row and column
198
+ indices of the matrix. colamd_c (n_col) + colamd_r (n_row) space is
199
+ required for the Col and Row arrays, respectively, which are internal to
200
+ colamd. An additional n_col space is the minimal amount of "elbow room",
201
+ and nnz/5 more space is recommended for run time efficiency.
202
+
203
+ This macro is not needed when using symamd.
204
+
205
+ Explicit typecast to Index added Sept. 23, 2002, COLAMD version 2.2, to avoid
206
+ gcc -pedantic warning messages.
207
+ */
208
+ template <typename Index>
209
+ inline Index colamd_c(Index n_col)
210
+ { return Index( ((n_col) + 1) * sizeof (colamd_col<Index>) / sizeof (Index) ) ; }
211
+
212
+ template <typename Index>
213
+ inline Index colamd_r(Index n_row)
214
+ { return Index(((n_row) + 1) * sizeof (Colamd_Row<Index>) / sizeof (Index)); }
215
+
216
+ // Prototypes of non-user callable routines
217
+ template <typename Index>
218
+ static Index init_rows_cols (Index n_row, Index n_col, Colamd_Row<Index> Row [], colamd_col<Index> col [], Index A [], Index p [], Index stats[COLAMD_STATS] );
219
+
220
+ template <typename Index>
221
+ static void init_scoring (Index n_row, Index n_col, Colamd_Row<Index> Row [], colamd_col<Index> Col [], Index A [], Index head [], double knobs[COLAMD_KNOBS], Index *p_n_row2, Index *p_n_col2, Index *p_max_deg);
222
+
223
+ template <typename Index>
224
+ static Index find_ordering (Index n_row, Index n_col, Index Alen, Colamd_Row<Index> Row [], colamd_col<Index> Col [], Index A [], Index head [], Index n_col2, Index max_deg, Index pfree);
225
+
226
+ template <typename Index>
227
+ static void order_children (Index n_col, colamd_col<Index> Col [], Index p []);
228
+
229
+ template <typename Index>
230
+ static void detect_super_cols (colamd_col<Index> Col [], Index A [], Index head [], Index row_start, Index row_length ) ;
231
+
232
+ template <typename Index>
233
+ static Index garbage_collection (Index n_row, Index n_col, Colamd_Row<Index> Row [], colamd_col<Index> Col [], Index A [], Index *pfree) ;
234
+
235
+ template <typename Index>
236
+ static inline Index clear_mark (Index n_row, Colamd_Row<Index> Row [] ) ;
237
+
238
+ /* === No debugging ========================================================= */
239
+
240
+ #define COLAMD_DEBUG0(params) ;
241
+ #define COLAMD_DEBUG1(params) ;
242
+ #define COLAMD_DEBUG2(params) ;
243
+ #define COLAMD_DEBUG3(params) ;
244
+ #define COLAMD_DEBUG4(params) ;
245
+
246
+ #define COLAMD_ASSERT(expression) ((void) 0)
247
+
248
+
249
+ /**
250
+ * \brief Returns the recommended value of Alen
251
+ *
252
+ * Returns recommended value of Alen for use by colamd.
253
+ * Returns -1 if any input argument is negative.
254
+ * The use of this routine or macro is optional.
255
+ * Note that the macro uses its arguments more than once,
256
+ * so be careful for side effects, if you pass expressions as arguments to COLAMD_RECOMMENDED.
257
+ *
258
+ * \param nnz nonzeros in A
259
+ * \param n_row number of rows in A
260
+ * \param n_col number of columns in A
261
+ * \return recommended value of Alen for use by colamd
262
+ */
263
+ template <typename Index>
264
+ inline Index colamd_recommended ( Index nnz, Index n_row, Index n_col)
265
+ {
266
+ if ((nnz) < 0 || (n_row) < 0 || (n_col) < 0)
267
+ return (-1);
268
+ else
269
+ return (2 * (nnz) + colamd_c (n_col) + colamd_r (n_row) + (n_col) + ((nnz) / 5));
270
+ }
271
+
272
+ /**
273
+ * \brief set default parameters The use of this routine is optional.
274
+ *
275
+ * Colamd: rows with more than (knobs [COLAMD_DENSE_ROW] * n_col)
276
+ * entries are removed prior to ordering. Columns with more than
277
+ * (knobs [COLAMD_DENSE_COL] * n_row) entries are removed prior to
278
+ * ordering, and placed last in the output column ordering.
279
+ *
280
+ * COLAMD_DENSE_ROW and COLAMD_DENSE_COL are defined as 0 and 1,
281
+ * respectively, in colamd.h. Default values of these two knobs
282
+ * are both 0.5. Currently, only knobs [0] and knobs [1] are
283
+ * used, but future versions may use more knobs. If so, they will
284
+ * be properly set to their defaults by the future version of
285
+ * colamd_set_defaults, so that the code that calls colamd will
286
+ * not need to change, assuming that you either use
287
+ * colamd_set_defaults, or pass a (double *) NULL pointer as the
288
+ * knobs array to colamd or symamd.
289
+ *
290
+ * \param knobs parameter settings for colamd
291
+ */
292
+
293
+ static inline void colamd_set_defaults(double knobs[COLAMD_KNOBS])
294
+ {
295
+ /* === Local variables ================================================== */
296
+
297
+ int i ;
298
+
299
+ if (!knobs)
300
+ {
301
+ return ; /* no knobs to initialize */
302
+ }
303
+ for (i = 0 ; i < COLAMD_KNOBS ; i++)
304
+ {
305
+ knobs [i] = 0 ;
306
+ }
307
+ knobs [COLAMD_DENSE_ROW] = 0.5 ; /* ignore rows over 50% dense */
308
+ knobs [COLAMD_DENSE_COL] = 0.5 ; /* ignore columns over 50% dense */
309
+ }
310
+
311
+ /**
312
+ * \brief Computes a column ordering using the column approximate minimum degree ordering
313
+ *
314
+ * Computes a column ordering (Q) of A such that P(AQ)=LU or
315
+ * (AQ)'AQ=LL' have less fill-in and require fewer floating point
316
+ * operations than factorizing the unpermuted matrix A or A'A,
317
+ * respectively.
318
+ *
319
+ *
320
+ * \param n_row number of rows in A
321
+ * \param n_col number of columns in A
322
+ * \param Alen, size of the array A
323
+ * \param A row indices of the matrix, of size ALen
324
+ * \param p column pointers of A, of size n_col+1
325
+ * \param knobs parameter settings for colamd
326
+ * \param stats colamd output statistics and error codes
327
+ */
328
+ template <typename Index>
329
+ static bool colamd(Index n_row, Index n_col, Index Alen, Index *A, Index *p, double knobs[COLAMD_KNOBS], Index stats[COLAMD_STATS])
330
+ {
331
+ /* === Local variables ================================================== */
332
+
333
+ Index i ; /* loop index */
334
+ Index nnz ; /* nonzeros in A */
335
+ Index Row_size ; /* size of Row [], in integers */
336
+ Index Col_size ; /* size of Col [], in integers */
337
+ Index need ; /* minimum required length of A */
338
+ Colamd_Row<Index> *Row ; /* pointer into A of Row [0..n_row] array */
339
+ colamd_col<Index> *Col ; /* pointer into A of Col [0..n_col] array */
340
+ Index n_col2 ; /* number of non-dense, non-empty columns */
341
+ Index n_row2 ; /* number of non-dense, non-empty rows */
342
+ Index ngarbage ; /* number of garbage collections performed */
343
+ Index max_deg ; /* maximum row degree */
344
+ double default_knobs [COLAMD_KNOBS] ; /* default knobs array */
345
+
346
+
347
+ /* === Check the input arguments ======================================== */
348
+
349
+ if (!stats)
350
+ {
351
+ COLAMD_DEBUG0 (("colamd: stats not present\n")) ;
352
+ return (false) ;
353
+ }
354
+ for (i = 0 ; i < COLAMD_STATS ; i++)
355
+ {
356
+ stats [i] = 0 ;
357
+ }
358
+ stats [COLAMD_STATUS] = COLAMD_OK ;
359
+ stats [COLAMD_INFO1] = -1 ;
360
+ stats [COLAMD_INFO2] = -1 ;
361
+
362
+ if (!A) /* A is not present */
363
+ {
364
+ stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ;
365
+ COLAMD_DEBUG0 (("colamd: A not present\n")) ;
366
+ return (false) ;
367
+ }
368
+
369
+ if (!p) /* p is not present */
370
+ {
371
+ stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ;
372
+ COLAMD_DEBUG0 (("colamd: p not present\n")) ;
373
+ return (false) ;
374
+ }
375
+
376
+ if (n_row < 0) /* n_row must be >= 0 */
377
+ {
378
+ stats [COLAMD_STATUS] = COLAMD_ERROR_nrow_negative ;
379
+ stats [COLAMD_INFO1] = n_row ;
380
+ COLAMD_DEBUG0 (("colamd: nrow negative %d\n", n_row)) ;
381
+ return (false) ;
382
+ }
383
+
384
+ if (n_col < 0) /* n_col must be >= 0 */
385
+ {
386
+ stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ;
387
+ stats [COLAMD_INFO1] = n_col ;
388
+ COLAMD_DEBUG0 (("colamd: ncol negative %d\n", n_col)) ;
389
+ return (false) ;
390
+ }
391
+
392
+ nnz = p [n_col] ;
393
+ if (nnz < 0) /* nnz must be >= 0 */
394
+ {
395
+ stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ;
396
+ stats [COLAMD_INFO1] = nnz ;
397
+ COLAMD_DEBUG0 (("colamd: number of entries negative %d\n", nnz)) ;
398
+ return (false) ;
399
+ }
400
+
401
+ if (p [0] != 0)
402
+ {
403
+ stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ;
404
+ stats [COLAMD_INFO1] = p [0] ;
405
+ COLAMD_DEBUG0 (("colamd: p[0] not zero %d\n", p [0])) ;
406
+ return (false) ;
407
+ }
408
+
409
+ /* === If no knobs, set default knobs =================================== */
410
+
411
+ if (!knobs)
412
+ {
413
+ colamd_set_defaults (default_knobs) ;
414
+ knobs = default_knobs ;
415
+ }
416
+
417
+ /* === Allocate the Row and Col arrays from array A ===================== */
418
+
419
+ Col_size = colamd_c (n_col) ;
420
+ Row_size = colamd_r (n_row) ;
421
+ need = 2*nnz + n_col + Col_size + Row_size ;
422
+
423
+ if (need > Alen)
424
+ {
425
+ /* not enough space in array A to perform the ordering */
426
+ stats [COLAMD_STATUS] = COLAMD_ERROR_A_too_small ;
427
+ stats [COLAMD_INFO1] = need ;
428
+ stats [COLAMD_INFO2] = Alen ;
429
+ COLAMD_DEBUG0 (("colamd: Need Alen >= %d, given only Alen = %d\n", need,Alen));
430
+ return (false) ;
431
+ }
432
+
433
+ Alen -= Col_size + Row_size ;
434
+ Col = (colamd_col<Index> *) &A [Alen] ;
435
+ Row = (Colamd_Row<Index> *) &A [Alen + Col_size] ;
436
+
437
+ /* === Construct the row and column data structures ===================== */
438
+
439
+ if (!Eigen::internal::init_rows_cols (n_row, n_col, Row, Col, A, p, stats))
440
+ {
441
+ /* input matrix is invalid */
442
+ COLAMD_DEBUG0 (("colamd: Matrix invalid\n")) ;
443
+ return (false) ;
444
+ }
445
+
446
+ /* === Initialize scores, kill dense rows/columns ======================= */
447
+
448
+ Eigen::internal::init_scoring (n_row, n_col, Row, Col, A, p, knobs,
449
+ &n_row2, &n_col2, &max_deg) ;
450
+
451
+ /* === Order the supercolumns =========================================== */
452
+
453
+ ngarbage = Eigen::internal::find_ordering (n_row, n_col, Alen, Row, Col, A, p,
454
+ n_col2, max_deg, 2*nnz) ;
455
+
456
+ /* === Order the non-principal columns ================================== */
457
+
458
+ Eigen::internal::order_children (n_col, Col, p) ;
459
+
460
+ /* === Return statistics in stats ======================================= */
461
+
462
+ stats [COLAMD_DENSE_ROW] = n_row - n_row2 ;
463
+ stats [COLAMD_DENSE_COL] = n_col - n_col2 ;
464
+ stats [COLAMD_DEFRAG_COUNT] = ngarbage ;
465
+ COLAMD_DEBUG0 (("colamd: done.\n")) ;
466
+ return (true) ;
467
+ }
468
+
469
+ /* ========================================================================== */
470
+ /* === NON-USER-CALLABLE ROUTINES: ========================================== */
471
+ /* ========================================================================== */
472
+
473
+ /* There are no user-callable routines beyond this point in the file */
474
+
475
+
476
+ /* ========================================================================== */
477
+ /* === init_rows_cols ======================================================= */
478
+ /* ========================================================================== */
479
+
480
+ /*
481
+ Takes the column form of the matrix in A and creates the row form of the
482
+ matrix. Also, row and column attributes are stored in the Col and Row
483
+ structs. If the columns are un-sorted or contain duplicate row indices,
484
+ this routine will also sort and remove duplicate row indices from the
485
+ column form of the matrix. Returns false if the matrix is invalid,
486
+ true otherwise. Not user-callable.
487
+ */
488
+ template <typename Index>
489
+ static Index init_rows_cols /* returns true if OK, or false otherwise */
490
+ (
491
+ /* === Parameters ======================================================= */
492
+
493
+ Index n_row, /* number of rows of A */
494
+ Index n_col, /* number of columns of A */
495
+ Colamd_Row<Index> Row [], /* of size n_row+1 */
496
+ colamd_col<Index> Col [], /* of size n_col+1 */
497
+ Index A [], /* row indices of A, of size Alen */
498
+ Index p [], /* pointers to columns in A, of size n_col+1 */
499
+ Index stats [COLAMD_STATS] /* colamd statistics */
500
+ )
501
+ {
502
+ /* === Local variables ================================================== */
503
+
504
+ Index col ; /* a column index */
505
+ Index row ; /* a row index */
506
+ Index *cp ; /* a column pointer */
507
+ Index *cp_end ; /* a pointer to the end of a column */
508
+ Index *rp ; /* a row pointer */
509
+ Index *rp_end ; /* a pointer to the end of a row */
510
+ Index last_row ; /* previous row */
511
+
512
+ /* === Initialize columns, and check column pointers ==================== */
513
+
514
+ for (col = 0 ; col < n_col ; col++)
515
+ {
516
+ Col [col].start = p [col] ;
517
+ Col [col].length = p [col+1] - p [col] ;
518
+
519
+ if (Col [col].length < 0)
520
+ {
521
+ /* column pointers must be non-decreasing */
522
+ stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ;
523
+ stats [COLAMD_INFO1] = col ;
524
+ stats [COLAMD_INFO2] = Col [col].length ;
525
+ COLAMD_DEBUG0 (("colamd: col %d length %d < 0\n", col, Col [col].length)) ;
526
+ return (false) ;
527
+ }
528
+
529
+ Col [col].shared1.thickness = 1 ;
530
+ Col [col].shared2.score = 0 ;
531
+ Col [col].shared3.prev = COLAMD_EMPTY ;
532
+ Col [col].shared4.degree_next = COLAMD_EMPTY ;
533
+ }
534
+
535
+ /* p [0..n_col] no longer needed, used as "head" in subsequent routines */
536
+
537
+ /* === Scan columns, compute row degrees, and check row indices ========= */
538
+
539
+ stats [COLAMD_INFO3] = 0 ; /* number of duplicate or unsorted row indices*/
540
+
541
+ for (row = 0 ; row < n_row ; row++)
542
+ {
543
+ Row [row].length = 0 ;
544
+ Row [row].shared2.mark = -1 ;
545
+ }
546
+
547
+ for (col = 0 ; col < n_col ; col++)
548
+ {
549
+ last_row = -1 ;
550
+
551
+ cp = &A [p [col]] ;
552
+ cp_end = &A [p [col+1]] ;
553
+
554
+ while (cp < cp_end)
555
+ {
556
+ row = *cp++ ;
557
+
558
+ /* make sure row indices within range */
559
+ if (row < 0 || row >= n_row)
560
+ {
561
+ stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ;
562
+ stats [COLAMD_INFO1] = col ;
563
+ stats [COLAMD_INFO2] = row ;
564
+ stats [COLAMD_INFO3] = n_row ;
565
+ COLAMD_DEBUG0 (("colamd: row %d col %d out of bounds\n", row, col)) ;
566
+ return (false) ;
567
+ }
568
+
569
+ if (row <= last_row || Row [row].shared2.mark == col)
570
+ {
571
+ /* row index are unsorted or repeated (or both), thus col */
572
+ /* is jumbled. This is a notice, not an error condition. */
573
+ stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ;
574
+ stats [COLAMD_INFO1] = col ;
575
+ stats [COLAMD_INFO2] = row ;
576
+ (stats [COLAMD_INFO3]) ++ ;
577
+ COLAMD_DEBUG1 (("colamd: row %d col %d unsorted/duplicate\n",row,col));
578
+ }
579
+
580
+ if (Row [row].shared2.mark != col)
581
+ {
582
+ Row [row].length++ ;
583
+ }
584
+ else
585
+ {
586
+ /* this is a repeated entry in the column, */
587
+ /* it will be removed */
588
+ Col [col].length-- ;
589
+ }
590
+
591
+ /* mark the row as having been seen in this column */
592
+ Row [row].shared2.mark = col ;
593
+
594
+ last_row = row ;
595
+ }
596
+ }
597
+
598
+ /* === Compute row pointers ============================================= */
599
+
600
+ /* row form of the matrix starts directly after the column */
601
+ /* form of matrix in A */
602
+ Row [0].start = p [n_col] ;
603
+ Row [0].shared1.p = Row [0].start ;
604
+ Row [0].shared2.mark = -1 ;
605
+ for (row = 1 ; row < n_row ; row++)
606
+ {
607
+ Row [row].start = Row [row-1].start + Row [row-1].length ;
608
+ Row [row].shared1.p = Row [row].start ;
609
+ Row [row].shared2.mark = -1 ;
610
+ }
611
+
612
+ /* === Create row form ================================================== */
613
+
614
+ if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED)
615
+ {
616
+ /* if cols jumbled, watch for repeated row indices */
617
+ for (col = 0 ; col < n_col ; col++)
618
+ {
619
+ cp = &A [p [col]] ;
620
+ cp_end = &A [p [col+1]] ;
621
+ while (cp < cp_end)
622
+ {
623
+ row = *cp++ ;
624
+ if (Row [row].shared2.mark != col)
625
+ {
626
+ A [(Row [row].shared1.p)++] = col ;
627
+ Row [row].shared2.mark = col ;
628
+ }
629
+ }
630
+ }
631
+ }
632
+ else
633
+ {
634
+ /* if cols not jumbled, we don't need the mark (this is faster) */
635
+ for (col = 0 ; col < n_col ; col++)
636
+ {
637
+ cp = &A [p [col]] ;
638
+ cp_end = &A [p [col+1]] ;
639
+ while (cp < cp_end)
640
+ {
641
+ A [(Row [*cp++].shared1.p)++] = col ;
642
+ }
643
+ }
644
+ }
645
+
646
+ /* === Clear the row marks and set row degrees ========================== */
647
+
648
+ for (row = 0 ; row < n_row ; row++)
649
+ {
650
+ Row [row].shared2.mark = 0 ;
651
+ Row [row].shared1.degree = Row [row].length ;
652
+ }
653
+
654
+ /* === See if we need to re-create columns ============================== */
655
+
656
+ if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED)
657
+ {
658
+ COLAMD_DEBUG0 (("colamd: reconstructing column form, matrix jumbled\n")) ;
659
+
660
+
661
+ /* === Compute col pointers ========================================= */
662
+
663
+ /* col form of the matrix starts at A [0]. */
664
+ /* Note, we may have a gap between the col form and the row */
665
+ /* form if there were duplicate entries, if so, it will be */
666
+ /* removed upon the first garbage collection */
667
+ Col [0].start = 0 ;
668
+ p [0] = Col [0].start ;
669
+ for (col = 1 ; col < n_col ; col++)
670
+ {
671
+ /* note that the lengths here are for pruned columns, i.e. */
672
+ /* no duplicate row indices will exist for these columns */
673
+ Col [col].start = Col [col-1].start + Col [col-1].length ;
674
+ p [col] = Col [col].start ;
675
+ }
676
+
677
+ /* === Re-create col form =========================================== */
678
+
679
+ for (row = 0 ; row < n_row ; row++)
680
+ {
681
+ rp = &A [Row [row].start] ;
682
+ rp_end = rp + Row [row].length ;
683
+ while (rp < rp_end)
684
+ {
685
+ A [(p [*rp++])++] = row ;
686
+ }
687
+ }
688
+ }
689
+
690
+ /* === Done. Matrix is not (or no longer) jumbled ====================== */
691
+
692
+ return (true) ;
693
+ }
694
+
695
+
696
+ /* ========================================================================== */
697
+ /* === init_scoring ========================================================= */
698
+ /* ========================================================================== */
699
+
700
+ /*
701
+ Kills dense or empty columns and rows, calculates an initial score for
702
+ each column, and places all columns in the degree lists. Not user-callable.
703
+ */
704
+ template <typename Index>
705
+ static void init_scoring
706
+ (
707
+ /* === Parameters ======================================================= */
708
+
709
+ Index n_row, /* number of rows of A */
710
+ Index n_col, /* number of columns of A */
711
+ Colamd_Row<Index> Row [], /* of size n_row+1 */
712
+ colamd_col<Index> Col [], /* of size n_col+1 */
713
+ Index A [], /* column form and row form of A */
714
+ Index head [], /* of size n_col+1 */
715
+ double knobs [COLAMD_KNOBS],/* parameters */
716
+ Index *p_n_row2, /* number of non-dense, non-empty rows */
717
+ Index *p_n_col2, /* number of non-dense, non-empty columns */
718
+ Index *p_max_deg /* maximum row degree */
719
+ )
720
+ {
721
+ /* === Local variables ================================================== */
722
+
723
+ Index c ; /* a column index */
724
+ Index r, row ; /* a row index */
725
+ Index *cp ; /* a column pointer */
726
+ Index deg ; /* degree of a row or column */
727
+ Index *cp_end ; /* a pointer to the end of a column */
728
+ Index *new_cp ; /* new column pointer */
729
+ Index col_length ; /* length of pruned column */
730
+ Index score ; /* current column score */
731
+ Index n_col2 ; /* number of non-dense, non-empty columns */
732
+ Index n_row2 ; /* number of non-dense, non-empty rows */
733
+ Index dense_row_count ; /* remove rows with more entries than this */
734
+ Index dense_col_count ; /* remove cols with more entries than this */
735
+ Index min_score ; /* smallest column score */
736
+ Index max_deg ; /* maximum row degree */
737
+ Index next_col ; /* Used to add to degree list.*/
738
+
739
+
740
+ /* === Extract knobs ==================================================== */
741
+
742
+ dense_row_count = COLAMD_MAX (0, COLAMD_MIN (knobs [COLAMD_DENSE_ROW] * n_col, n_col)) ;
743
+ dense_col_count = COLAMD_MAX (0, COLAMD_MIN (knobs [COLAMD_DENSE_COL] * n_row, n_row)) ;
744
+ COLAMD_DEBUG1 (("colamd: densecount: %d %d\n", dense_row_count, dense_col_count)) ;
745
+ max_deg = 0 ;
746
+ n_col2 = n_col ;
747
+ n_row2 = n_row ;
748
+
749
+ /* === Kill empty columns =============================================== */
750
+
751
+ /* Put the empty columns at the end in their natural order, so that LU */
752
+ /* factorization can proceed as far as possible. */
753
+ for (c = n_col-1 ; c >= 0 ; c--)
754
+ {
755
+ deg = Col [c].length ;
756
+ if (deg == 0)
757
+ {
758
+ /* this is a empty column, kill and order it last */
759
+ Col [c].shared2.order = --n_col2 ;
760
+ KILL_PRINCIPAL_COL (c) ;
761
+ }
762
+ }
763
+ COLAMD_DEBUG1 (("colamd: null columns killed: %d\n", n_col - n_col2)) ;
764
+
765
+ /* === Kill dense columns =============================================== */
766
+
767
+ /* Put the dense columns at the end, in their natural order */
768
+ for (c = n_col-1 ; c >= 0 ; c--)
769
+ {
770
+ /* skip any dead columns */
771
+ if (COL_IS_DEAD (c))
772
+ {
773
+ continue ;
774
+ }
775
+ deg = Col [c].length ;
776
+ if (deg > dense_col_count)
777
+ {
778
+ /* this is a dense column, kill and order it last */
779
+ Col [c].shared2.order = --n_col2 ;
780
+ /* decrement the row degrees */
781
+ cp = &A [Col [c].start] ;
782
+ cp_end = cp + Col [c].length ;
783
+ while (cp < cp_end)
784
+ {
785
+ Row [*cp++].shared1.degree-- ;
786
+ }
787
+ KILL_PRINCIPAL_COL (c) ;
788
+ }
789
+ }
790
+ COLAMD_DEBUG1 (("colamd: Dense and null columns killed: %d\n", n_col - n_col2)) ;
791
+
792
+ /* === Kill dense and empty rows ======================================== */
793
+
794
+ for (r = 0 ; r < n_row ; r++)
795
+ {
796
+ deg = Row [r].shared1.degree ;
797
+ COLAMD_ASSERT (deg >= 0 && deg <= n_col) ;
798
+ if (deg > dense_row_count || deg == 0)
799
+ {
800
+ /* kill a dense or empty row */
801
+ KILL_ROW (r) ;
802
+ --n_row2 ;
803
+ }
804
+ else
805
+ {
806
+ /* keep track of max degree of remaining rows */
807
+ max_deg = COLAMD_MAX (max_deg, deg) ;
808
+ }
809
+ }
810
+ COLAMD_DEBUG1 (("colamd: Dense and null rows killed: %d\n", n_row - n_row2)) ;
811
+
812
+ /* === Compute initial column scores ==================================== */
813
+
814
+ /* At this point the row degrees are accurate. They reflect the number */
815
+ /* of "live" (non-dense) columns in each row. No empty rows exist. */
816
+ /* Some "live" columns may contain only dead rows, however. These are */
817
+ /* pruned in the code below. */
818
+
819
+ /* now find the initial matlab score for each column */
820
+ for (c = n_col-1 ; c >= 0 ; c--)
821
+ {
822
+ /* skip dead column */
823
+ if (COL_IS_DEAD (c))
824
+ {
825
+ continue ;
826
+ }
827
+ score = 0 ;
828
+ cp = &A [Col [c].start] ;
829
+ new_cp = cp ;
830
+ cp_end = cp + Col [c].length ;
831
+ while (cp < cp_end)
832
+ {
833
+ /* get a row */
834
+ row = *cp++ ;
835
+ /* skip if dead */
836
+ if (ROW_IS_DEAD (row))
837
+ {
838
+ continue ;
839
+ }
840
+ /* compact the column */
841
+ *new_cp++ = row ;
842
+ /* add row's external degree */
843
+ score += Row [row].shared1.degree - 1 ;
844
+ /* guard against integer overflow */
845
+ score = COLAMD_MIN (score, n_col) ;
846
+ }
847
+ /* determine pruned column length */
848
+ col_length = (Index) (new_cp - &A [Col [c].start]) ;
849
+ if (col_length == 0)
850
+ {
851
+ /* a newly-made null column (all rows in this col are "dense" */
852
+ /* and have already been killed) */
853
+ COLAMD_DEBUG2 (("Newly null killed: %d\n", c)) ;
854
+ Col [c].shared2.order = --n_col2 ;
855
+ KILL_PRINCIPAL_COL (c) ;
856
+ }
857
+ else
858
+ {
859
+ /* set column length and set score */
860
+ COLAMD_ASSERT (score >= 0) ;
861
+ COLAMD_ASSERT (score <= n_col) ;
862
+ Col [c].length = col_length ;
863
+ Col [c].shared2.score = score ;
864
+ }
865
+ }
866
+ COLAMD_DEBUG1 (("colamd: Dense, null, and newly-null columns killed: %d\n",
867
+ n_col-n_col2)) ;
868
+
869
+ /* At this point, all empty rows and columns are dead. All live columns */
870
+ /* are "clean" (containing no dead rows) and simplicial (no supercolumns */
871
+ /* yet). Rows may contain dead columns, but all live rows contain at */
872
+ /* least one live column. */
873
+
874
+ /* === Initialize degree lists ========================================== */
875
+
876
+
877
+ /* clear the hash buckets */
878
+ for (c = 0 ; c <= n_col ; c++)
879
+ {
880
+ head [c] = COLAMD_EMPTY ;
881
+ }
882
+ min_score = n_col ;
883
+ /* place in reverse order, so low column indices are at the front */
884
+ /* of the lists. This is to encourage natural tie-breaking */
885
+ for (c = n_col-1 ; c >= 0 ; c--)
886
+ {
887
+ /* only add principal columns to degree lists */
888
+ if (COL_IS_ALIVE (c))
889
+ {
890
+ COLAMD_DEBUG4 (("place %d score %d minscore %d ncol %d\n",
891
+ c, Col [c].shared2.score, min_score, n_col)) ;
892
+
893
+ /* === Add columns score to DList =============================== */
894
+
895
+ score = Col [c].shared2.score ;
896
+
897
+ COLAMD_ASSERT (min_score >= 0) ;
898
+ COLAMD_ASSERT (min_score <= n_col) ;
899
+ COLAMD_ASSERT (score >= 0) ;
900
+ COLAMD_ASSERT (score <= n_col) ;
901
+ COLAMD_ASSERT (head [score] >= COLAMD_EMPTY) ;
902
+
903
+ /* now add this column to dList at proper score location */
904
+ next_col = head [score] ;
905
+ Col [c].shared3.prev = COLAMD_EMPTY ;
906
+ Col [c].shared4.degree_next = next_col ;
907
+
908
+ /* if there already was a column with the same score, set its */
909
+ /* previous pointer to this new column */
910
+ if (next_col != COLAMD_EMPTY)
911
+ {
912
+ Col [next_col].shared3.prev = c ;
913
+ }
914
+ head [score] = c ;
915
+
916
+ /* see if this score is less than current min */
917
+ min_score = COLAMD_MIN (min_score, score) ;
918
+
919
+
920
+ }
921
+ }
922
+
923
+
924
+ /* === Return number of remaining columns, and max row degree =========== */
925
+
926
+ *p_n_col2 = n_col2 ;
927
+ *p_n_row2 = n_row2 ;
928
+ *p_max_deg = max_deg ;
929
+ }
930
+
931
+
932
+ /* ========================================================================== */
933
+ /* === find_ordering ======================================================== */
934
+ /* ========================================================================== */
935
+
936
+ /*
937
+ Order the principal columns of the supercolumn form of the matrix
938
+ (no supercolumns on input). Uses a minimum approximate column minimum
939
+ degree ordering method. Not user-callable.
940
+ */
941
+ template <typename Index>
942
+ static Index find_ordering /* return the number of garbage collections */
943
+ (
944
+ /* === Parameters ======================================================= */
945
+
946
+ Index n_row, /* number of rows of A */
947
+ Index n_col, /* number of columns of A */
948
+ Index Alen, /* size of A, 2*nnz + n_col or larger */
949
+ Colamd_Row<Index> Row [], /* of size n_row+1 */
950
+ colamd_col<Index> Col [], /* of size n_col+1 */
951
+ Index A [], /* column form and row form of A */
952
+ Index head [], /* of size n_col+1 */
953
+ Index n_col2, /* Remaining columns to order */
954
+ Index max_deg, /* Maximum row degree */
955
+ Index pfree /* index of first free slot (2*nnz on entry) */
956
+ )
957
+ {
958
+ /* === Local variables ================================================== */
959
+
960
+ Index k ; /* current pivot ordering step */
961
+ Index pivot_col ; /* current pivot column */
962
+ Index *cp ; /* a column pointer */
963
+ Index *rp ; /* a row pointer */
964
+ Index pivot_row ; /* current pivot row */
965
+ Index *new_cp ; /* modified column pointer */
966
+ Index *new_rp ; /* modified row pointer */
967
+ Index pivot_row_start ; /* pointer to start of pivot row */
968
+ Index pivot_row_degree ; /* number of columns in pivot row */
969
+ Index pivot_row_length ; /* number of supercolumns in pivot row */
970
+ Index pivot_col_score ; /* score of pivot column */
971
+ Index needed_memory ; /* free space needed for pivot row */
972
+ Index *cp_end ; /* pointer to the end of a column */
973
+ Index *rp_end ; /* pointer to the end of a row */
974
+ Index row ; /* a row index */
975
+ Index col ; /* a column index */
976
+ Index max_score ; /* maximum possible score */
977
+ Index cur_score ; /* score of current column */
978
+ unsigned int hash ; /* hash value for supernode detection */
979
+ Index head_column ; /* head of hash bucket */
980
+ Index first_col ; /* first column in hash bucket */
981
+ Index tag_mark ; /* marker value for mark array */
982
+ Index row_mark ; /* Row [row].shared2.mark */
983
+ Index set_difference ; /* set difference size of row with pivot row */
984
+ Index min_score ; /* smallest column score */
985
+ Index col_thickness ; /* "thickness" (no. of columns in a supercol) */
986
+ Index max_mark ; /* maximum value of tag_mark */
987
+ Index pivot_col_thickness ; /* number of columns represented by pivot col */
988
+ Index prev_col ; /* Used by Dlist operations. */
989
+ Index next_col ; /* Used by Dlist operations. */
990
+ Index ngarbage ; /* number of garbage collections performed */
991
+
992
+
993
+ /* === Initialization and clear mark ==================================== */
994
+
995
+ max_mark = INT_MAX - n_col ; /* INT_MAX defined in <limits.h> */
996
+ tag_mark = Eigen::internal::clear_mark (n_row, Row) ;
997
+ min_score = 0 ;
998
+ ngarbage = 0 ;
999
+ COLAMD_DEBUG1 (("colamd: Ordering, n_col2=%d\n", n_col2)) ;
1000
+
1001
+ /* === Order the columns ================================================ */
1002
+
1003
+ for (k = 0 ; k < n_col2 ; /* 'k' is incremented below */)
1004
+ {
1005
+
1006
+ /* === Select pivot column, and order it ============================ */
1007
+
1008
+ /* make sure degree list isn't empty */
1009
+ COLAMD_ASSERT (min_score >= 0) ;
1010
+ COLAMD_ASSERT (min_score <= n_col) ;
1011
+ COLAMD_ASSERT (head [min_score] >= COLAMD_EMPTY) ;
1012
+
1013
+ /* get pivot column from head of minimum degree list */
1014
+ while (head [min_score] == COLAMD_EMPTY && min_score < n_col)
1015
+ {
1016
+ min_score++ ;
1017
+ }
1018
+ pivot_col = head [min_score] ;
1019
+ COLAMD_ASSERT (pivot_col >= 0 && pivot_col <= n_col) ;
1020
+ next_col = Col [pivot_col].shared4.degree_next ;
1021
+ head [min_score] = next_col ;
1022
+ if (next_col != COLAMD_EMPTY)
1023
+ {
1024
+ Col [next_col].shared3.prev = COLAMD_EMPTY ;
1025
+ }
1026
+
1027
+ COLAMD_ASSERT (COL_IS_ALIVE (pivot_col)) ;
1028
+ COLAMD_DEBUG3 (("Pivot col: %d\n", pivot_col)) ;
1029
+
1030
+ /* remember score for defrag check */
1031
+ pivot_col_score = Col [pivot_col].shared2.score ;
1032
+
1033
+ /* the pivot column is the kth column in the pivot order */
1034
+ Col [pivot_col].shared2.order = k ;
1035
+
1036
+ /* increment order count by column thickness */
1037
+ pivot_col_thickness = Col [pivot_col].shared1.thickness ;
1038
+ k += pivot_col_thickness ;
1039
+ COLAMD_ASSERT (pivot_col_thickness > 0) ;
1040
+
1041
+ /* === Garbage_collection, if necessary ============================= */
1042
+
1043
+ needed_memory = COLAMD_MIN (pivot_col_score, n_col - k) ;
1044
+ if (pfree + needed_memory >= Alen)
1045
+ {
1046
+ pfree = Eigen::internal::garbage_collection (n_row, n_col, Row, Col, A, &A [pfree]) ;
1047
+ ngarbage++ ;
1048
+ /* after garbage collection we will have enough */
1049
+ COLAMD_ASSERT (pfree + needed_memory < Alen) ;
1050
+ /* garbage collection has wiped out the Row[].shared2.mark array */
1051
+ tag_mark = Eigen::internal::clear_mark (n_row, Row) ;
1052
+
1053
+ }
1054
+
1055
+ /* === Compute pivot row pattern ==================================== */
1056
+
1057
+ /* get starting location for this new merged row */
1058
+ pivot_row_start = pfree ;
1059
+
1060
+ /* initialize new row counts to zero */
1061
+ pivot_row_degree = 0 ;
1062
+
1063
+ /* tag pivot column as having been visited so it isn't included */
1064
+ /* in merged pivot row */
1065
+ Col [pivot_col].shared1.thickness = -pivot_col_thickness ;
1066
+
1067
+ /* pivot row is the union of all rows in the pivot column pattern */
1068
+ cp = &A [Col [pivot_col].start] ;
1069
+ cp_end = cp + Col [pivot_col].length ;
1070
+ while (cp < cp_end)
1071
+ {
1072
+ /* get a row */
1073
+ row = *cp++ ;
1074
+ COLAMD_DEBUG4 (("Pivot col pattern %d %d\n", ROW_IS_ALIVE (row), row)) ;
1075
+ /* skip if row is dead */
1076
+ if (ROW_IS_DEAD (row))
1077
+ {
1078
+ continue ;
1079
+ }
1080
+ rp = &A [Row [row].start] ;
1081
+ rp_end = rp + Row [row].length ;
1082
+ while (rp < rp_end)
1083
+ {
1084
+ /* get a column */
1085
+ col = *rp++ ;
1086
+ /* add the column, if alive and untagged */
1087
+ col_thickness = Col [col].shared1.thickness ;
1088
+ if (col_thickness > 0 && COL_IS_ALIVE (col))
1089
+ {
1090
+ /* tag column in pivot row */
1091
+ Col [col].shared1.thickness = -col_thickness ;
1092
+ COLAMD_ASSERT (pfree < Alen) ;
1093
+ /* place column in pivot row */
1094
+ A [pfree++] = col ;
1095
+ pivot_row_degree += col_thickness ;
1096
+ }
1097
+ }
1098
+ }
1099
+
1100
+ /* clear tag on pivot column */
1101
+ Col [pivot_col].shared1.thickness = pivot_col_thickness ;
1102
+ max_deg = COLAMD_MAX (max_deg, pivot_row_degree) ;
1103
+
1104
+
1105
+ /* === Kill all rows used to construct pivot row ==================== */
1106
+
1107
+ /* also kill pivot row, temporarily */
1108
+ cp = &A [Col [pivot_col].start] ;
1109
+ cp_end = cp + Col [pivot_col].length ;
1110
+ while (cp < cp_end)
1111
+ {
1112
+ /* may be killing an already dead row */
1113
+ row = *cp++ ;
1114
+ COLAMD_DEBUG3 (("Kill row in pivot col: %d\n", row)) ;
1115
+ KILL_ROW (row) ;
1116
+ }
1117
+
1118
+ /* === Select a row index to use as the new pivot row =============== */
1119
+
1120
+ pivot_row_length = pfree - pivot_row_start ;
1121
+ if (pivot_row_length > 0)
1122
+ {
1123
+ /* pick the "pivot" row arbitrarily (first row in col) */
1124
+ pivot_row = A [Col [pivot_col].start] ;
1125
+ COLAMD_DEBUG3 (("Pivotal row is %d\n", pivot_row)) ;
1126
+ }
1127
+ else
1128
+ {
1129
+ /* there is no pivot row, since it is of zero length */
1130
+ pivot_row = COLAMD_EMPTY ;
1131
+ COLAMD_ASSERT (pivot_row_length == 0) ;
1132
+ }
1133
+ COLAMD_ASSERT (Col [pivot_col].length > 0 || pivot_row_length == 0) ;
1134
+
1135
+ /* === Approximate degree computation =============================== */
1136
+
1137
+ /* Here begins the computation of the approximate degree. The column */
1138
+ /* score is the sum of the pivot row "length", plus the size of the */
1139
+ /* set differences of each row in the column minus the pattern of the */
1140
+ /* pivot row itself. The column ("thickness") itself is also */
1141
+ /* excluded from the column score (we thus use an approximate */
1142
+ /* external degree). */
1143
+
1144
+ /* The time taken by the following code (compute set differences, and */
1145
+ /* add them up) is proportional to the size of the data structure */
1146
+ /* being scanned - that is, the sum of the sizes of each column in */
1147
+ /* the pivot row. Thus, the amortized time to compute a column score */
1148
+ /* is proportional to the size of that column (where size, in this */
1149
+ /* context, is the column "length", or the number of row indices */
1150
+ /* in that column). The number of row indices in a column is */
1151
+ /* monotonically non-decreasing, from the length of the original */
1152
+ /* column on input to colamd. */
1153
+
1154
+ /* === Compute set differences ====================================== */
1155
+
1156
+ COLAMD_DEBUG3 (("** Computing set differences phase. **\n")) ;
1157
+
1158
+ /* pivot row is currently dead - it will be revived later. */
1159
+
1160
+ COLAMD_DEBUG3 (("Pivot row: ")) ;
1161
+ /* for each column in pivot row */
1162
+ rp = &A [pivot_row_start] ;
1163
+ rp_end = rp + pivot_row_length ;
1164
+ while (rp < rp_end)
1165
+ {
1166
+ col = *rp++ ;
1167
+ COLAMD_ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ;
1168
+ COLAMD_DEBUG3 (("Col: %d\n", col)) ;
1169
+
1170
+ /* clear tags used to construct pivot row pattern */
1171
+ col_thickness = -Col [col].shared1.thickness ;
1172
+ COLAMD_ASSERT (col_thickness > 0) ;
1173
+ Col [col].shared1.thickness = col_thickness ;
1174
+
1175
+ /* === Remove column from degree list =========================== */
1176
+
1177
+ cur_score = Col [col].shared2.score ;
1178
+ prev_col = Col [col].shared3.prev ;
1179
+ next_col = Col [col].shared4.degree_next ;
1180
+ COLAMD_ASSERT (cur_score >= 0) ;
1181
+ COLAMD_ASSERT (cur_score <= n_col) ;
1182
+ COLAMD_ASSERT (cur_score >= COLAMD_EMPTY) ;
1183
+ if (prev_col == COLAMD_EMPTY)
1184
+ {
1185
+ head [cur_score] = next_col ;
1186
+ }
1187
+ else
1188
+ {
1189
+ Col [prev_col].shared4.degree_next = next_col ;
1190
+ }
1191
+ if (next_col != COLAMD_EMPTY)
1192
+ {
1193
+ Col [next_col].shared3.prev = prev_col ;
1194
+ }
1195
+
1196
+ /* === Scan the column ========================================== */
1197
+
1198
+ cp = &A [Col [col].start] ;
1199
+ cp_end = cp + Col [col].length ;
1200
+ while (cp < cp_end)
1201
+ {
1202
+ /* get a row */
1203
+ row = *cp++ ;
1204
+ row_mark = Row [row].shared2.mark ;
1205
+ /* skip if dead */
1206
+ if (ROW_IS_MARKED_DEAD (row_mark))
1207
+ {
1208
+ continue ;
1209
+ }
1210
+ COLAMD_ASSERT (row != pivot_row) ;
1211
+ set_difference = row_mark - tag_mark ;
1212
+ /* check if the row has been seen yet */
1213
+ if (set_difference < 0)
1214
+ {
1215
+ COLAMD_ASSERT (Row [row].shared1.degree <= max_deg) ;
1216
+ set_difference = Row [row].shared1.degree ;
1217
+ }
1218
+ /* subtract column thickness from this row's set difference */
1219
+ set_difference -= col_thickness ;
1220
+ COLAMD_ASSERT (set_difference >= 0) ;
1221
+ /* absorb this row if the set difference becomes zero */
1222
+ if (set_difference == 0)
1223
+ {
1224
+ COLAMD_DEBUG3 (("aggressive absorption. Row: %d\n", row)) ;
1225
+ KILL_ROW (row) ;
1226
+ }
1227
+ else
1228
+ {
1229
+ /* save the new mark */
1230
+ Row [row].shared2.mark = set_difference + tag_mark ;
1231
+ }
1232
+ }
1233
+ }
1234
+
1235
+
1236
+ /* === Add up set differences for each column ======================= */
1237
+
1238
+ COLAMD_DEBUG3 (("** Adding set differences phase. **\n")) ;
1239
+
1240
+ /* for each column in pivot row */
1241
+ rp = &A [pivot_row_start] ;
1242
+ rp_end = rp + pivot_row_length ;
1243
+ while (rp < rp_end)
1244
+ {
1245
+ /* get a column */
1246
+ col = *rp++ ;
1247
+ COLAMD_ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ;
1248
+ hash = 0 ;
1249
+ cur_score = 0 ;
1250
+ cp = &A [Col [col].start] ;
1251
+ /* compact the column */
1252
+ new_cp = cp ;
1253
+ cp_end = cp + Col [col].length ;
1254
+
1255
+ COLAMD_DEBUG4 (("Adding set diffs for Col: %d.\n", col)) ;
1256
+
1257
+ while (cp < cp_end)
1258
+ {
1259
+ /* get a row */
1260
+ row = *cp++ ;
1261
+ COLAMD_ASSERT(row >= 0 && row < n_row) ;
1262
+ row_mark = Row [row].shared2.mark ;
1263
+ /* skip if dead */
1264
+ if (ROW_IS_MARKED_DEAD (row_mark))
1265
+ {
1266
+ continue ;
1267
+ }
1268
+ COLAMD_ASSERT (row_mark > tag_mark) ;
1269
+ /* compact the column */
1270
+ *new_cp++ = row ;
1271
+ /* compute hash function */
1272
+ hash += row ;
1273
+ /* add set difference */
1274
+ cur_score += row_mark - tag_mark ;
1275
+ /* integer overflow... */
1276
+ cur_score = COLAMD_MIN (cur_score, n_col) ;
1277
+ }
1278
+
1279
+ /* recompute the column's length */
1280
+ Col [col].length = (Index) (new_cp - &A [Col [col].start]) ;
1281
+
1282
+ /* === Further mass elimination ================================= */
1283
+
1284
+ if (Col [col].length == 0)
1285
+ {
1286
+ COLAMD_DEBUG4 (("further mass elimination. Col: %d\n", col)) ;
1287
+ /* nothing left but the pivot row in this column */
1288
+ KILL_PRINCIPAL_COL (col) ;
1289
+ pivot_row_degree -= Col [col].shared1.thickness ;
1290
+ COLAMD_ASSERT (pivot_row_degree >= 0) ;
1291
+ /* order it */
1292
+ Col [col].shared2.order = k ;
1293
+ /* increment order count by column thickness */
1294
+ k += Col [col].shared1.thickness ;
1295
+ }
1296
+ else
1297
+ {
1298
+ /* === Prepare for supercolumn detection ==================== */
1299
+
1300
+ COLAMD_DEBUG4 (("Preparing supercol detection for Col: %d.\n", col)) ;
1301
+
1302
+ /* save score so far */
1303
+ Col [col].shared2.score = cur_score ;
1304
+
1305
+ /* add column to hash table, for supercolumn detection */
1306
+ hash %= n_col + 1 ;
1307
+
1308
+ COLAMD_DEBUG4 ((" Hash = %d, n_col = %d.\n", hash, n_col)) ;
1309
+ COLAMD_ASSERT (hash <= n_col) ;
1310
+
1311
+ head_column = head [hash] ;
1312
+ if (head_column > COLAMD_EMPTY)
1313
+ {
1314
+ /* degree list "hash" is non-empty, use prev (shared3) of */
1315
+ /* first column in degree list as head of hash bucket */
1316
+ first_col = Col [head_column].shared3.headhash ;
1317
+ Col [head_column].shared3.headhash = col ;
1318
+ }
1319
+ else
1320
+ {
1321
+ /* degree list "hash" is empty, use head as hash bucket */
1322
+ first_col = - (head_column + 2) ;
1323
+ head [hash] = - (col + 2) ;
1324
+ }
1325
+ Col [col].shared4.hash_next = first_col ;
1326
+
1327
+ /* save hash function in Col [col].shared3.hash */
1328
+ Col [col].shared3.hash = (Index) hash ;
1329
+ COLAMD_ASSERT (COL_IS_ALIVE (col)) ;
1330
+ }
1331
+ }
1332
+
1333
+ /* The approximate external column degree is now computed. */
1334
+
1335
+ /* === Supercolumn detection ======================================== */
1336
+
1337
+ COLAMD_DEBUG3 (("** Supercolumn detection phase. **\n")) ;
1338
+
1339
+ Eigen::internal::detect_super_cols (Col, A, head, pivot_row_start, pivot_row_length) ;
1340
+
1341
+ /* === Kill the pivotal column ====================================== */
1342
+
1343
+ KILL_PRINCIPAL_COL (pivot_col) ;
1344
+
1345
+ /* === Clear mark =================================================== */
1346
+
1347
+ tag_mark += (max_deg + 1) ;
1348
+ if (tag_mark >= max_mark)
1349
+ {
1350
+ COLAMD_DEBUG2 (("clearing tag_mark\n")) ;
1351
+ tag_mark = Eigen::internal::clear_mark (n_row, Row) ;
1352
+ }
1353
+
1354
+ /* === Finalize the new pivot row, and column scores ================ */
1355
+
1356
+ COLAMD_DEBUG3 (("** Finalize scores phase. **\n")) ;
1357
+
1358
+ /* for each column in pivot row */
1359
+ rp = &A [pivot_row_start] ;
1360
+ /* compact the pivot row */
1361
+ new_rp = rp ;
1362
+ rp_end = rp + pivot_row_length ;
1363
+ while (rp < rp_end)
1364
+ {
1365
+ col = *rp++ ;
1366
+ /* skip dead columns */
1367
+ if (COL_IS_DEAD (col))
1368
+ {
1369
+ continue ;
1370
+ }
1371
+ *new_rp++ = col ;
1372
+ /* add new pivot row to column */
1373
+ A [Col [col].start + (Col [col].length++)] = pivot_row ;
1374
+
1375
+ /* retrieve score so far and add on pivot row's degree. */
1376
+ /* (we wait until here for this in case the pivot */
1377
+ /* row's degree was reduced due to mass elimination). */
1378
+ cur_score = Col [col].shared2.score + pivot_row_degree ;
1379
+
1380
+ /* calculate the max possible score as the number of */
1381
+ /* external columns minus the 'k' value minus the */
1382
+ /* columns thickness */
1383
+ max_score = n_col - k - Col [col].shared1.thickness ;
1384
+
1385
+ /* make the score the external degree of the union-of-rows */
1386
+ cur_score -= Col [col].shared1.thickness ;
1387
+
1388
+ /* make sure score is less or equal than the max score */
1389
+ cur_score = COLAMD_MIN (cur_score, max_score) ;
1390
+ COLAMD_ASSERT (cur_score >= 0) ;
1391
+
1392
+ /* store updated score */
1393
+ Col [col].shared2.score = cur_score ;
1394
+
1395
+ /* === Place column back in degree list ========================= */
1396
+
1397
+ COLAMD_ASSERT (min_score >= 0) ;
1398
+ COLAMD_ASSERT (min_score <= n_col) ;
1399
+ COLAMD_ASSERT (cur_score >= 0) ;
1400
+ COLAMD_ASSERT (cur_score <= n_col) ;
1401
+ COLAMD_ASSERT (head [cur_score] >= COLAMD_EMPTY) ;
1402
+ next_col = head [cur_score] ;
1403
+ Col [col].shared4.degree_next = next_col ;
1404
+ Col [col].shared3.prev = COLAMD_EMPTY ;
1405
+ if (next_col != COLAMD_EMPTY)
1406
+ {
1407
+ Col [next_col].shared3.prev = col ;
1408
+ }
1409
+ head [cur_score] = col ;
1410
+
1411
+ /* see if this score is less than current min */
1412
+ min_score = COLAMD_MIN (min_score, cur_score) ;
1413
+
1414
+ }
1415
+
1416
+ /* === Resurrect the new pivot row ================================== */
1417
+
1418
+ if (pivot_row_degree > 0)
1419
+ {
1420
+ /* update pivot row length to reflect any cols that were killed */
1421
+ /* during super-col detection and mass elimination */
1422
+ Row [pivot_row].start = pivot_row_start ;
1423
+ Row [pivot_row].length = (Index) (new_rp - &A[pivot_row_start]) ;
1424
+ Row [pivot_row].shared1.degree = pivot_row_degree ;
1425
+ Row [pivot_row].shared2.mark = 0 ;
1426
+ /* pivot row is no longer dead */
1427
+ }
1428
+ }
1429
+
1430
+ /* === All principal columns have now been ordered ====================== */
1431
+
1432
+ return (ngarbage) ;
1433
+ }
1434
+
1435
+
1436
+ /* ========================================================================== */
1437
+ /* === order_children ======================================================= */
1438
+ /* ========================================================================== */
1439
+
1440
+ /*
1441
+ The find_ordering routine has ordered all of the principal columns (the
1442
+ representatives of the supercolumns). The non-principal columns have not
1443
+ yet been ordered. This routine orders those columns by walking up the
1444
+ parent tree (a column is a child of the column which absorbed it). The
1445
+ final permutation vector is then placed in p [0 ... n_col-1], with p [0]
1446
+ being the first column, and p [n_col-1] being the last. It doesn't look
1447
+ like it at first glance, but be assured that this routine takes time linear
1448
+ in the number of columns. Although not immediately obvious, the time
1449
+ taken by this routine is O (n_col), that is, linear in the number of
1450
+ columns. Not user-callable.
1451
+ */
1452
+ template <typename Index>
1453
+ static inline void order_children
1454
+ (
1455
+ /* === Parameters ======================================================= */
1456
+
1457
+ Index n_col, /* number of columns of A */
1458
+ colamd_col<Index> Col [], /* of size n_col+1 */
1459
+ Index p [] /* p [0 ... n_col-1] is the column permutation*/
1460
+ )
1461
+ {
1462
+ /* === Local variables ================================================== */
1463
+
1464
+ Index i ; /* loop counter for all columns */
1465
+ Index c ; /* column index */
1466
+ Index parent ; /* index of column's parent */
1467
+ Index order ; /* column's order */
1468
+
1469
+ /* === Order each non-principal column ================================== */
1470
+
1471
+ for (i = 0 ; i < n_col ; i++)
1472
+ {
1473
+ /* find an un-ordered non-principal column */
1474
+ COLAMD_ASSERT (COL_IS_DEAD (i)) ;
1475
+ if (!COL_IS_DEAD_PRINCIPAL (i) && Col [i].shared2.order == COLAMD_EMPTY)
1476
+ {
1477
+ parent = i ;
1478
+ /* once found, find its principal parent */
1479
+ do
1480
+ {
1481
+ parent = Col [parent].shared1.parent ;
1482
+ } while (!COL_IS_DEAD_PRINCIPAL (parent)) ;
1483
+
1484
+ /* now, order all un-ordered non-principal columns along path */
1485
+ /* to this parent. collapse tree at the same time */
1486
+ c = i ;
1487
+ /* get order of parent */
1488
+ order = Col [parent].shared2.order ;
1489
+
1490
+ do
1491
+ {
1492
+ COLAMD_ASSERT (Col [c].shared2.order == COLAMD_EMPTY) ;
1493
+
1494
+ /* order this column */
1495
+ Col [c].shared2.order = order++ ;
1496
+ /* collaps tree */
1497
+ Col [c].shared1.parent = parent ;
1498
+
1499
+ /* get immediate parent of this column */
1500
+ c = Col [c].shared1.parent ;
1501
+
1502
+ /* continue until we hit an ordered column. There are */
1503
+ /* guarranteed not to be anymore unordered columns */
1504
+ /* above an ordered column */
1505
+ } while (Col [c].shared2.order == COLAMD_EMPTY) ;
1506
+
1507
+ /* re-order the super_col parent to largest order for this group */
1508
+ Col [parent].shared2.order = order ;
1509
+ }
1510
+ }
1511
+
1512
+ /* === Generate the permutation ========================================= */
1513
+
1514
+ for (c = 0 ; c < n_col ; c++)
1515
+ {
1516
+ p [Col [c].shared2.order] = c ;
1517
+ }
1518
+ }
1519
+
1520
+
1521
+ /* ========================================================================== */
1522
+ /* === detect_super_cols ==================================================== */
1523
+ /* ========================================================================== */
1524
+
1525
+ /*
1526
+ Detects supercolumns by finding matches between columns in the hash buckets.
1527
+ Check amongst columns in the set A [row_start ... row_start + row_length-1].
1528
+ The columns under consideration are currently *not* in the degree lists,
1529
+ and have already been placed in the hash buckets.
1530
+
1531
+ The hash bucket for columns whose hash function is equal to h is stored
1532
+ as follows:
1533
+
1534
+ if head [h] is >= 0, then head [h] contains a degree list, so:
1535
+
1536
+ head [h] is the first column in degree bucket h.
1537
+ Col [head [h]].headhash gives the first column in hash bucket h.
1538
+
1539
+ otherwise, the degree list is empty, and:
1540
+
1541
+ -(head [h] + 2) is the first column in hash bucket h.
1542
+
1543
+ For a column c in a hash bucket, Col [c].shared3.prev is NOT a "previous
1544
+ column" pointer. Col [c].shared3.hash is used instead as the hash number
1545
+ for that column. The value of Col [c].shared4.hash_next is the next column
1546
+ in the same hash bucket.
1547
+
1548
+ Assuming no, or "few" hash collisions, the time taken by this routine is
1549
+ linear in the sum of the sizes (lengths) of each column whose score has
1550
+ just been computed in the approximate degree computation.
1551
+ Not user-callable.
1552
+ */
1553
+ template <typename Index>
1554
+ static void detect_super_cols
1555
+ (
1556
+ /* === Parameters ======================================================= */
1557
+
1558
+ colamd_col<Index> Col [], /* of size n_col+1 */
1559
+ Index A [], /* row indices of A */
1560
+ Index head [], /* head of degree lists and hash buckets */
1561
+ Index row_start, /* pointer to set of columns to check */
1562
+ Index row_length /* number of columns to check */
1563
+ )
1564
+ {
1565
+ /* === Local variables ================================================== */
1566
+
1567
+ Index hash ; /* hash value for a column */
1568
+ Index *rp ; /* pointer to a row */
1569
+ Index c ; /* a column index */
1570
+ Index super_c ; /* column index of the column to absorb into */
1571
+ Index *cp1 ; /* column pointer for column super_c */
1572
+ Index *cp2 ; /* column pointer for column c */
1573
+ Index length ; /* length of column super_c */
1574
+ Index prev_c ; /* column preceding c in hash bucket */
1575
+ Index i ; /* loop counter */
1576
+ Index *rp_end ; /* pointer to the end of the row */
1577
+ Index col ; /* a column index in the row to check */
1578
+ Index head_column ; /* first column in hash bucket or degree list */
1579
+ Index first_col ; /* first column in hash bucket */
1580
+
1581
+ /* === Consider each column in the row ================================== */
1582
+
1583
+ rp = &A [row_start] ;
1584
+ rp_end = rp + row_length ;
1585
+ while (rp < rp_end)
1586
+ {
1587
+ col = *rp++ ;
1588
+ if (COL_IS_DEAD (col))
1589
+ {
1590
+ continue ;
1591
+ }
1592
+
1593
+ /* get hash number for this column */
1594
+ hash = Col [col].shared3.hash ;
1595
+ COLAMD_ASSERT (hash <= n_col) ;
1596
+
1597
+ /* === Get the first column in this hash bucket ===================== */
1598
+
1599
+ head_column = head [hash] ;
1600
+ if (head_column > COLAMD_EMPTY)
1601
+ {
1602
+ first_col = Col [head_column].shared3.headhash ;
1603
+ }
1604
+ else
1605
+ {
1606
+ first_col = - (head_column + 2) ;
1607
+ }
1608
+
1609
+ /* === Consider each column in the hash bucket ====================== */
1610
+
1611
+ for (super_c = first_col ; super_c != COLAMD_EMPTY ;
1612
+ super_c = Col [super_c].shared4.hash_next)
1613
+ {
1614
+ COLAMD_ASSERT (COL_IS_ALIVE (super_c)) ;
1615
+ COLAMD_ASSERT (Col [super_c].shared3.hash == hash) ;
1616
+ length = Col [super_c].length ;
1617
+
1618
+ /* prev_c is the column preceding column c in the hash bucket */
1619
+ prev_c = super_c ;
1620
+
1621
+ /* === Compare super_c with all columns after it ================ */
1622
+
1623
+ for (c = Col [super_c].shared4.hash_next ;
1624
+ c != COLAMD_EMPTY ; c = Col [c].shared4.hash_next)
1625
+ {
1626
+ COLAMD_ASSERT (c != super_c) ;
1627
+ COLAMD_ASSERT (COL_IS_ALIVE (c)) ;
1628
+ COLAMD_ASSERT (Col [c].shared3.hash == hash) ;
1629
+
1630
+ /* not identical if lengths or scores are different */
1631
+ if (Col [c].length != length ||
1632
+ Col [c].shared2.score != Col [super_c].shared2.score)
1633
+ {
1634
+ prev_c = c ;
1635
+ continue ;
1636
+ }
1637
+
1638
+ /* compare the two columns */
1639
+ cp1 = &A [Col [super_c].start] ;
1640
+ cp2 = &A [Col [c].start] ;
1641
+
1642
+ for (i = 0 ; i < length ; i++)
1643
+ {
1644
+ /* the columns are "clean" (no dead rows) */
1645
+ COLAMD_ASSERT (ROW_IS_ALIVE (*cp1)) ;
1646
+ COLAMD_ASSERT (ROW_IS_ALIVE (*cp2)) ;
1647
+ /* row indices will same order for both supercols, */
1648
+ /* no gather scatter nessasary */
1649
+ if (*cp1++ != *cp2++)
1650
+ {
1651
+ break ;
1652
+ }
1653
+ }
1654
+
1655
+ /* the two columns are different if the for-loop "broke" */
1656
+ if (i != length)
1657
+ {
1658
+ prev_c = c ;
1659
+ continue ;
1660
+ }
1661
+
1662
+ /* === Got it! two columns are identical =================== */
1663
+
1664
+ COLAMD_ASSERT (Col [c].shared2.score == Col [super_c].shared2.score) ;
1665
+
1666
+ Col [super_c].shared1.thickness += Col [c].shared1.thickness ;
1667
+ Col [c].shared1.parent = super_c ;
1668
+ KILL_NON_PRINCIPAL_COL (c) ;
1669
+ /* order c later, in order_children() */
1670
+ Col [c].shared2.order = COLAMD_EMPTY ;
1671
+ /* remove c from hash bucket */
1672
+ Col [prev_c].shared4.hash_next = Col [c].shared4.hash_next ;
1673
+ }
1674
+ }
1675
+
1676
+ /* === Empty this hash bucket ======================================= */
1677
+
1678
+ if (head_column > COLAMD_EMPTY)
1679
+ {
1680
+ /* corresponding degree list "hash" is not empty */
1681
+ Col [head_column].shared3.headhash = COLAMD_EMPTY ;
1682
+ }
1683
+ else
1684
+ {
1685
+ /* corresponding degree list "hash" is empty */
1686
+ head [hash] = COLAMD_EMPTY ;
1687
+ }
1688
+ }
1689
+ }
1690
+
1691
+
1692
+ /* ========================================================================== */
1693
+ /* === garbage_collection =================================================== */
1694
+ /* ========================================================================== */
1695
+
1696
+ /*
1697
+ Defragments and compacts columns and rows in the workspace A. Used when
1698
+ all avaliable memory has been used while performing row merging. Returns
1699
+ the index of the first free position in A, after garbage collection. The
1700
+ time taken by this routine is linear is the size of the array A, which is
1701
+ itself linear in the number of nonzeros in the input matrix.
1702
+ Not user-callable.
1703
+ */
1704
+ template <typename Index>
1705
+ static Index garbage_collection /* returns the new value of pfree */
1706
+ (
1707
+ /* === Parameters ======================================================= */
1708
+
1709
+ Index n_row, /* number of rows */
1710
+ Index n_col, /* number of columns */
1711
+ Colamd_Row<Index> Row [], /* row info */
1712
+ colamd_col<Index> Col [], /* column info */
1713
+ Index A [], /* A [0 ... Alen-1] holds the matrix */
1714
+ Index *pfree /* &A [0] ... pfree is in use */
1715
+ )
1716
+ {
1717
+ /* === Local variables ================================================== */
1718
+
1719
+ Index *psrc ; /* source pointer */
1720
+ Index *pdest ; /* destination pointer */
1721
+ Index j ; /* counter */
1722
+ Index r ; /* a row index */
1723
+ Index c ; /* a column index */
1724
+ Index length ; /* length of a row or column */
1725
+
1726
+ /* === Defragment the columns =========================================== */
1727
+
1728
+ pdest = &A[0] ;
1729
+ for (c = 0 ; c < n_col ; c++)
1730
+ {
1731
+ if (COL_IS_ALIVE (c))
1732
+ {
1733
+ psrc = &A [Col [c].start] ;
1734
+
1735
+ /* move and compact the column */
1736
+ COLAMD_ASSERT (pdest <= psrc) ;
1737
+ Col [c].start = (Index) (pdest - &A [0]) ;
1738
+ length = Col [c].length ;
1739
+ for (j = 0 ; j < length ; j++)
1740
+ {
1741
+ r = *psrc++ ;
1742
+ if (ROW_IS_ALIVE (r))
1743
+ {
1744
+ *pdest++ = r ;
1745
+ }
1746
+ }
1747
+ Col [c].length = (Index) (pdest - &A [Col [c].start]) ;
1748
+ }
1749
+ }
1750
+
1751
+ /* === Prepare to defragment the rows =================================== */
1752
+
1753
+ for (r = 0 ; r < n_row ; r++)
1754
+ {
1755
+ if (ROW_IS_ALIVE (r))
1756
+ {
1757
+ if (Row [r].length == 0)
1758
+ {
1759
+ /* this row is of zero length. cannot compact it, so kill it */
1760
+ COLAMD_DEBUG3 (("Defrag row kill\n")) ;
1761
+ KILL_ROW (r) ;
1762
+ }
1763
+ else
1764
+ {
1765
+ /* save first column index in Row [r].shared2.first_column */
1766
+ psrc = &A [Row [r].start] ;
1767
+ Row [r].shared2.first_column = *psrc ;
1768
+ COLAMD_ASSERT (ROW_IS_ALIVE (r)) ;
1769
+ /* flag the start of the row with the one's complement of row */
1770
+ *psrc = ONES_COMPLEMENT (r) ;
1771
+
1772
+ }
1773
+ }
1774
+ }
1775
+
1776
+ /* === Defragment the rows ============================================== */
1777
+
1778
+ psrc = pdest ;
1779
+ while (psrc < pfree)
1780
+ {
1781
+ /* find a negative number ... the start of a row */
1782
+ if (*psrc++ < 0)
1783
+ {
1784
+ psrc-- ;
1785
+ /* get the row index */
1786
+ r = ONES_COMPLEMENT (*psrc) ;
1787
+ COLAMD_ASSERT (r >= 0 && r < n_row) ;
1788
+ /* restore first column index */
1789
+ *psrc = Row [r].shared2.first_column ;
1790
+ COLAMD_ASSERT (ROW_IS_ALIVE (r)) ;
1791
+
1792
+ /* move and compact the row */
1793
+ COLAMD_ASSERT (pdest <= psrc) ;
1794
+ Row [r].start = (Index) (pdest - &A [0]) ;
1795
+ length = Row [r].length ;
1796
+ for (j = 0 ; j < length ; j++)
1797
+ {
1798
+ c = *psrc++ ;
1799
+ if (COL_IS_ALIVE (c))
1800
+ {
1801
+ *pdest++ = c ;
1802
+ }
1803
+ }
1804
+ Row [r].length = (Index) (pdest - &A [Row [r].start]) ;
1805
+
1806
+ }
1807
+ }
1808
+ /* ensure we found all the rows */
1809
+ COLAMD_ASSERT (debug_rows == 0) ;
1810
+
1811
+ /* === Return the new value of pfree ==================================== */
1812
+
1813
+ return ((Index) (pdest - &A [0])) ;
1814
+ }
1815
+
1816
+
1817
+ /* ========================================================================== */
1818
+ /* === clear_mark =========================================================== */
1819
+ /* ========================================================================== */
1820
+
1821
+ /*
1822
+ Clears the Row [].shared2.mark array, and returns the new tag_mark.
1823
+ Return value is the new tag_mark. Not user-callable.
1824
+ */
1825
+ template <typename Index>
1826
+ static inline Index clear_mark /* return the new value for tag_mark */
1827
+ (
1828
+ /* === Parameters ======================================================= */
1829
+
1830
+ Index n_row, /* number of rows in A */
1831
+ Colamd_Row<Index> Row [] /* Row [0 ... n_row-1].shared2.mark is set to zero */
1832
+ )
1833
+ {
1834
+ /* === Local variables ================================================== */
1835
+
1836
+ Index r ;
1837
+
1838
+ for (r = 0 ; r < n_row ; r++)
1839
+ {
1840
+ if (ROW_IS_ALIVE (r))
1841
+ {
1842
+ Row [r].shared2.mark = 0 ;
1843
+ }
1844
+ }
1845
+ return (1) ;
1846
+ }
1847
+
1848
+
1849
+ } // namespace internal
1850
+ #endif