Advertisement
Guest User

Untitled

a guest
Dec 5th, 2016
58
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.05 KB | None | 0 0
  1. # By Steve Vavasis 2016
  2. # MIT License:
  3. #> Permission is hereby granted, free of charge, to any person obtaining
  4. #> a copy of this software and associated documentation files (the
  5. #> "Software"), to deal in the Software without restriction, including
  6. #> without limitation the rights to use, copy, modify, merge, publish,
  7. #> distribute, sublicense, and/or sell copies of the Software, and to
  8. #> permit persons to whom the Software is furnished to do so, subject to
  9. #> the following conditions:
  10. #>
  11. #> The above copyright notice and this permission notice shall be
  12. #> included in all copies or substantial portions of the Software.
  13. #>
  14. #> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  15. #> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  16. #> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  17. #> NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  18. #> LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  19. #> OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  20. #> WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21.  
  22.  
  23. module MySparseExtensions
  24.  
  25.  
  26. import Base.sparse
  27.  
  28.  
  29. if VERSION < v"0.5"
  30. import Base.SparseMatrix.CHOLMOD.FactorComponent
  31. import Base.SparseMatrix.CHOLMOD.Factor
  32. import Base.SparseMatrix.CHOLMOD.CHOLMODException
  33. import Base.SparseMatrix.CHOLMOD.common
  34. import Base.SparseMatrix.CHOLMOD.C_Sparse
  35. import Base.SparseMatrix.CHOLMOD.Sparse
  36. import Base.SparseMatrix.CHOLMOD.free_sparse!
  37. import Base.SparseMatrix.CHOLMOD.increment
  38. import Base.SparseMatrix.CHOLMOD.SuiteSparse_long
  39. import Base.SparseMatrix.CHOLMOD.defaults
  40. import Base.SparseMatrix.CHOLMOD.fact_
  41. import Base.SparseMatrix.CHOLMOD.set_print_level
  42. import Base.SparseMatrix.CHOLMOD.common_final_ll
  43. import Base.SparseMatrix.SPQR.ORDERING_DEFAULT
  44. import Base.SparseMatrix.CHOLMOD.get_perm
  45. else
  46. import Base.SparseArrays.CHOLMOD.FactorComponent
  47. import Base.SparseArrays.CHOLMOD.Factor
  48. import Base.SparseArrays.CHOLMOD.CHOLMODException
  49. import Base.SparseArrays.CHOLMOD.common
  50. import Base.SparseArrays.CHOLMOD.C_Sparse
  51. import Base.SparseArrays.CHOLMOD.Sparse
  52. import Base.SparseArrays.CHOLMOD.free_sparse!
  53. import Base.SparseArrays.CHOLMOD.increment
  54. import Base.SparseArrays.CHOLMOD.SuiteSparse_long
  55. import Base.SparseArrays.CHOLMOD.defaults
  56. import Base.SparseArrays.CHOLMOD.fact_
  57. import Base.SparseArrays.CHOLMOD.set_print_level
  58. import Base.SparseArrays.CHOLMOD.common_final_ll
  59. import Base.SparseArrays.SPQR.ORDERING_DEFAULT
  60. import Base.SparseArrays.CHOLMOD.get_perm
  61. end
  62.  
  63.  
  64. ## Retrieve PtL factor from sparse Cholesky factorization
  65. ## See example below for usage
  66.  
  67. function sparse{Tv}(FC::FactorComponent{Tv,:PtL})
  68. F = Factor(FC)
  69. s = unsafe_load(F.p)
  70. s.is_ll != 0 || throw(CHOLMODException("sparse: supported for :PtL only on LLt factorizations"))
  71. s.is_super == 0 || throw(CHOLMODException("sparse: cannot invoke sparse() on supernodal factor; use change_factor! first"))
  72. s.n == s.minor || throw(CHOLMODException("sparse: cannot invoke sparse() on incomplete factor"))
  73. nnz = s.nzmax
  74. is = zeros(Int, nnz)
  75. js = zeros(Int, nnz)
  76. for oldcolnum = 1 : s.n
  77. newcolnum = unsafe_load(s.Perm, oldcolnum) + 1
  78. estart = unsafe_load(s.p, oldcolnum) + 1
  79. eend = unsafe_load(s.p, oldcolnum + 1)
  80. for pos = estart : eend
  81. js[pos] = newcolnum
  82. oldrownum = unsafe_load(s.i, pos) + 1
  83. newrownum = unsafe_load(s.Perm, oldrownum) + 1
  84. is[pos] = newrownum
  85. end
  86. end
  87. sparse(is, js, pointer_to_array(s.x, nnz, false), s.n, s.n)
  88. end
  89.  
  90. ## Retrieve R and colprm factor from sparse QR. See below
  91. ## for usage.
  92.  
  93. function qrfact_get_r_colperm(A::SparseMatrixCSC{Float64, Int},
  94. tol::Float64,
  95. ordering = ORDERING_DEFAULT)
  96. Aw = Sparse(A,0)
  97. s = unsafe_load(Aw.p)
  98. if s.stype != 0
  99. throw(ArgumentError("stype must be zero"))
  100. end
  101. ptr_R = Ref{Ptr{C_Sparse{Float64}}}()
  102. ptr_E = Ref{Ptr{SuiteSparse_long}}()
  103. cc = common()
  104. rk = ccall((:SuiteSparseQR_C, :libspqr), Clong,
  105. (Cint, #ordering
  106. Cdouble, #tol
  107. Clong, #econ
  108. Cint, #getCTX
  109. Ptr{C_Sparse{Float64}}, # A
  110. Ptr{Void}, #Bsparse
  111. Ptr{Void}, #Bdense
  112. Ptr{Void}, #Zsparse
  113. Ptr{Void}, #Zdense
  114. Ptr{Void}, #R
  115. Ptr{Void}, #E
  116. Ptr{Void}, #H
  117. Ptr{Void}, #HPInv
  118. Ptr{Void}, #HTau
  119. Ptr{Void}), #cc
  120. ordering, #ordering
  121. tol, #tol
  122. 1000000000, #econ
  123. 0, #getCTX
  124. get(Aw.p), # A
  125. C_NULL, #Bsparse
  126. C_NULL, #Bdense
  127. C_NULL, #Zsparse
  128. C_NULL, #Zdense
  129. ptr_R, #R
  130. ptr_E, #E
  131. C_NULL, #H
  132. C_NULL, #HPInv
  133. C_NULL, #HTau
  134. cc) #cc
  135. R = ptr_R[]
  136. E = ptr_E[]
  137. if E != C_NULL
  138. colprm = pointer_to_array(E, size(A,2), false) + 1
  139. else
  140. colprm = collect(1:size(A,2))
  141. end
  142. R1 = unsafe_load(R)
  143. if R1.stype != 0
  144. throw(ArgumentError("matrix has stype != 0. Convert to matrix with stype == 0 before converting to SparseMatrixCSC"))
  145. end
  146. maxrownum = 0
  147. for entryind = 1 : R1.nzmax
  148. maxrownum = max(maxrownum, unsafe_load(R1.i, entryind) + 1)
  149. end
  150. R_cvt = SparseMatrixCSC(maxrownum,
  151. R1.ncol,
  152. increment(pointer_to_array(R1.p, (R1.ncol + 1,), false)),
  153. increment(pointer_to_array(R1.i, (R1.nzmax,), false)),
  154. copy(pointer_to_array(R1.x, (R1.nzmax,), false)))
  155. free_sparse!(R)
  156. ccall((:cholmod_l_free, :libcholmod), Ptr{Void}, (Csize_t, Csize_t, Ptr{Void}, Ptr{Void}),
  157. size(A,2), sizeof(SuiteSparse_long), E, cc)
  158. R_cvt, colprm
  159. end
  160.  
  161. ## Obtain right null vector from squeezed R factor
  162.  
  163. function rightnullvec{Tv}(R::SparseMatrixCSC{Tv,Int},
  164. colperm::Array{Int,1})
  165. m = size(R,1)
  166. n = size(R,2)
  167. if m >= n
  168. error("Right null vector cannot be computed if m>=n")
  169. end
  170. # find the first squeezed row
  171. squeezepos = m + 1
  172. for i = 1 : m
  173. if R[i,i] == 0.0
  174. squeezepos = i
  175. break
  176. end
  177. end
  178. nullvec = zeros(n)
  179. nullvec[squeezepos] = 1.0
  180. b = full(R[:,squeezepos])
  181. if norm(b[squeezepos:end]) > 0.0
  182. error("R must be upper triangular")
  183. end
  184. # solve for the column of the squeezed row
  185. # in terms of preceding columns using back
  186. # substitution. For efficiency, work directly
  187. # on the fields of the sparse matrix R.
  188. for j = squeezepos - 1 : -1 : 1
  189. startp = R.colptr[j]
  190. endp = R.colptr[j+1] - 1
  191. if R.rowval[endp] != j
  192. error("R must be upper triangular")
  193. end
  194. coef = b[j] / R.nzval[endp]
  195. for pos = startp : endp
  196. i = R.rowval[pos]
  197. b[i] -= coef * R.nzval[pos]
  198. end
  199. nullvec[j] = -coef
  200. end
  201. nullvec_permute = zeros(n)
  202. nullvec_permute[colperm] = nullvec
  203. nullvec_permute
  204. end
  205.  
  206.  
  207.  
  208.  
  209. function cholfactLPs(A::SparseMatrixCSC{Float64, Int}; kws...)
  210. cm = defaults(common()) # setting the common struct to default values. Should only be done when creating new factorization.
  211. set_print_level(cm, 0) # no printing from CHOLMOD by default
  212.  
  213. # Makes it an LLt
  214. unsafe_store!(common_final_ll, 1)
  215. F = fact_(Sparse(A), cm; kws...)
  216. s = unsafe_load(get(F.p))
  217. s.minor < size(A, 1) && return spzeros(0,0), Int[], false
  218. return sparse(F[:L]), get_perm(F), true
  219. end
  220.  
  221. function forwsub_!(Lis, Ljs, Les, rhs)
  222. n = length(rhs)
  223. nnz = length(Lis)
  224. @assert minimum(Lis - Ljs) == 0
  225. pos = 1
  226. for j = 1 : n
  227. @assert Lis[pos] == j && Ljs[pos] == j
  228. rhs[j] /= Les[pos]
  229. pos += 1
  230. while pos <= nnz && Ljs[pos] == j
  231. rhs[Lis[pos]] -= rhs[j] * Les[pos]
  232. pos += 1
  233. end
  234. end
  235. nothing
  236. end
  237.  
  238.  
  239. function forwsub(L, rhs)
  240. x = rhs[:]
  241. is, js, es = findnz(L)
  242. forwsub_!(is, js, es, x)
  243. x
  244. end
  245.  
  246.  
  247. function backwsub_!(Lis, Ljs, Les, rhs)
  248. n = length(rhs)
  249. nnz = length(Lis)
  250. @assert minimum(Lis - Ljs) == 0
  251. pos = nnz
  252. for j = n : -1 : 1
  253. t = rhs[j]
  254. while pos > 0 && Ljs[pos] == j && Lis[pos] > j
  255. t -= Les[pos] * rhs[Lis[pos]]
  256. pos -= 1
  257. end
  258. @assert Lis[pos] == j && Ljs[pos] == j
  259. rhs[j] = t / Les[pos]
  260. pos -= 1
  261. end
  262. nothing
  263. end
  264.  
  265.  
  266. function cholsolve(L, prm, rhs)
  267. n = size(L,1)
  268. is, js, es = findnz(L)
  269. r2 = rhs[prm]
  270. forwsub_!(is, js, es, r2)
  271. backwsub_!(is, js, es, r2)
  272. sol = zeros(n)
  273. sol[prm] = r2
  274. sol
  275. end
  276.  
  277.  
  278.  
  279.  
  280.  
  281.  
  282.  
  283. function cholfactPtL(A)
  284. n = size(A,1)
  285. F = cholfact((A + A') / 2)
  286. L0 = sparse(F[:L])
  287. is, js, es = findnz(L0)
  288. p = get_perm(F)
  289. sparse(p[is], p[js], es, n, n)
  290. end
  291.  
  292.  
  293.  
  294.  
  295.  
  296. function test()
  297. A = [2.0 1.0 1.0 0.0
  298. 1.0 1.0 0.5 0.0
  299. 1.0 0.5 1.0 0.2
  300. 0.0 0.0 0.2 1.5]
  301. As = sparse(A)
  302. F = cholfact(As)
  303. PtL = sparse(F[:PtL])
  304. println("norm of difference A - PtL * PtL' = ", norm(As - PtL * PtL',1), " (should be close to 0)")
  305.  
  306. L, prm, success = cholfactLPs(As)
  307. @assert success
  308. println("prm = ", prm)
  309. println("L = ", L)
  310. b = [4.3,-2.2,8.8,7.1]
  311. x = cholsolve(L, prm, b)
  312. println("x = ", x, " norm(A*x - b) = ", norm(A * x - b), " (should be close to 0)")
  313. Ainit = [0.0 6.0 -3.1
  314. 6.0 0.0 2.2
  315. 6.3 0.0 0.0
  316. 2.2 0.0 0.0]
  317. A = hcat(Ainit, Ainit * [2.0,2.1,2.2], Ainit * [3.0,3.1,3.2])
  318. As = sparse(A)
  319. R, colprm = qrfact_get_r_colperm(As, 1.0e-14)
  320. @assert size(R,1) == 3 && size(R,2) == 5
  321. v = rightnullvec(R,colprm)
  322. println("residual norm of right null vec = ", norm(As * v) / norm(v), " (should be close to 0)")
  323. nothing
  324. end
  325.  
  326.  
  327.  
  328.  
  329.  
  330. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement