tomoto 0.1.0

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