-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SparseCSCInterface sparspaklu! check sparsity pattern #27
Closed
Closed
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
6c84869
SparseCSCInterface sparspaklu! check sparsity pattern
sjdaines 9cb50eb
Fix some more cases of ErrorException created but not thrown
sjdaines 86e76da
Add tests for asymmetric CSC matrix
sjdaines 9f99dca
sparspaklu! compare colptr and rowval to check sparsity pattern hasn'…
sjdaines b0ef3d6
Update sparspaklu! to use allow_pattern_change option
sjdaines bf1502e
doc wording
sjdaines File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
module SparseCSCInterface | ||
using SparseArrays, LinearAlgebra | ||
import SparseArrays, LinearAlgebra | ||
using ..SpkGraph: Graph | ||
using ..SpkOrdering: Ordering | ||
using ..SpkETree: ETree | ||
|
@@ -8,7 +8,22 @@ using ..SpkSparseSolver: SparseSolver, findorder!,symbolicfactor!,inmatrix!,fact | |
import ..SpkSparseSolver: solve! | ||
import ..SpkSparseBase: _inmatrix! | ||
|
||
""" | ||
Graph(m::SparseMatrixCSC, diagonal=false) -> g::Graph | ||
|
||
Construct a graph from a problem object. | ||
|
||
It does not check that the problem object contains a structurally | ||
symmetric matrix, since sometimes only the lower or upper triangle of | ||
a symmetric matrix may be stored. There are routines in the SpkGraph module to | ||
make a given graph object structurally symmetric. | ||
|
||
Input: | ||
- `m` - the sparse matrix, used to create the graph | ||
- `diagonal` - indicates that the diagonal elements are included. If | ||
diagonal is not given, the adjacency structure does not include | ||
the diagonal elements. | ||
""" | ||
function Graph(m::SparseMatrixCSC{FT,IT}, diagonal=false) where {FT,IT} | ||
nv = size(m,1) | ||
nrows = size(m,2) | ||
|
@@ -18,7 +33,7 @@ function Graph(m::SparseMatrixCSC{FT,IT}, diagonal=false) where {FT,IT} | |
|
||
|
||
if (diagonal) | ||
nedges = nnz(m) | ||
nedges = SparseArrays.nnz(m) | ||
else | ||
dedges=0 | ||
for i in 1:ncols | ||
|
@@ -29,7 +44,7 @@ function Graph(m::SparseMatrixCSC{FT,IT}, diagonal=false) where {FT,IT} | |
end | ||
end | ||
end | ||
nedges = nnz(m) - dedges | ||
nedges = SparseArrays.nnz(m) - dedges | ||
end | ||
|
||
#jf if diagonal == true, we possibly can just use colptr & rowval | ||
|
@@ -56,8 +71,6 @@ function Graph(m::SparseMatrixCSC{FT,IT}, diagonal=false) where {FT,IT} | |
end | ||
|
||
|
||
|
||
|
||
function _SparseBase(m::SparseMatrixCSC{FT,IT}) where {IT,FT} | ||
maxblocksize = 30 # This can be set by the user | ||
|
||
|
@@ -194,19 +207,19 @@ end | |
Solves linear system defined with sparse solver and provides the solution in rhs. | ||
""" | ||
function solve!(s::SparseSolver{IT,FT}, rhs) where {IT,FT} | ||
findorder!(s) || ErrorException("Finding Order.") | ||
symbolicfactor!(s) || ErrorException("Symbolic Factorization.") | ||
inmatrix!(s) || ErrorException("Matrix input.") | ||
factor!(s) || ErrorException("Numerical Factorization.") | ||
triangularsolve!(s,rhs) || ErrorException("Triangular Solve.") | ||
findorder!(s) || error("Finding Order.") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch with the exceptions! |
||
symbolicfactor!(s) || error("Symbolic Factorization.") | ||
inmatrix!(s) || error("Matrix input.") | ||
factor!(s) || error("Numerical Factorization.") | ||
triangularsolve!(s,rhs) || error("Triangular Solve.") | ||
return true | ||
end | ||
|
||
######################################################################### | ||
# SparspakLU | ||
|
||
""" | ||
sparspaklu(m; factorize=true) | ||
sparspaklu(m::SparseMatrixCSC; factorize=true) -> lu::SparseSolver | ||
|
||
If `factorize==true`, calculate LU factorization using Sparspak. Steps | ||
are `findorder`, `symbolicfactor`, `factor`. | ||
|
@@ -220,39 +233,52 @@ which has methods for `LinearAlgebra.ldiv!` and "backslash". | |
function sparspaklu(m::SparseMatrixCSC{FT,IT};factorize=true) where {FT,IT} | ||
lu=SparseSolver(m) | ||
if factorize | ||
findorder!(lu) || ErrorException("Finding Order.") | ||
symbolicfactor!(lu) || ErrorException("Symbolic Factorization.") | ||
inmatrix!(lu) || ErrorException("Matrix input.") | ||
factor!(lu) || ErrorException("Numerical Factorization.") | ||
findorder!(lu) || error("Finding Order.") | ||
symbolicfactor!(lu) || error("Symbolic Factorization.") | ||
inmatrix!(lu) || error("Matrix input.") | ||
factor!(lu) || error("Numerical Factorization.") | ||
end | ||
lu | ||
end | ||
|
||
|
||
""" | ||
sparspaklu!(lu,m) | ||
sparspaklu!(lu::SparseSolver, m::SparseMatrixCSC; allow_pattern_change=true) -> lu::SparseSolver | ||
|
||
Calculate LU factorization of a sparse matrix `m`, reusing ordering and symbolic | ||
factorization `lu`, if that was previously calculated. | ||
|
||
Calculate LU factorization, reusing ordering and symbolic | ||
factorization from lu, if that was previously calculated. | ||
If `allow_pattern_change = true` (the default) the sparse matrix `m` may have a nonzero pattern | ||
different to that of the matrix used to create the LU factorization `lu`, in which case the ordering | ||
and symbolic factorization are updated. | ||
|
||
Currently, it is assumed that, if size and number of nonzeros didn't | ||
change, the sparsity patterns of `m` and `p` are the same, probably | ||
leading to errors elsewhere if the patterns nevertheless differ. | ||
If `allow_pattern_change = false` an error is thrown if the nonzero pattern of `m` is different to that | ||
of the matrix used to create the LU factorization `lu`. | ||
|
||
If `lu` has not been factorized (ie it has just been created with option `factorize = false`) then | ||
`lu` is always updated from `m` and `allow_pattern_change` is ignored. | ||
|
||
""" | ||
function sparspaklu!(lu::SparseSolver{IT,FT}, m::SparseMatrixCSC{FT,IT}) where {FT,IT} | ||
# jf: Do we need a better test here ? Not sure as that may be expensive. | ||
if lu.slvr.n != size(m,1) || lu.slvr.n != size(m,2) || lu.slvr.nnz != nnz(m) | ||
lu=SparseSolver(m) | ||
end | ||
function sparspaklu!(lu::SparseSolver{IT,FT}, m::SparseMatrixCSC{FT,IT}; allow_pattern_change=true) where {FT,IT} | ||
|
||
pattern_changed = (SparseArrays.getcolptr(m) != SparseArrays.getcolptr(lu.p)) || (SparseArrays.getrowval(m) != SparseArrays.getrowval(lu.p)) | ||
|
||
if pattern_changed | ||
if allow_pattern_change || !lu._symbolicdone | ||
copy!(lu, SparseSolver(m)) | ||
else | ||
error("'allow_pattern_change=false', but sparsity pattern of matrix 'm' does not match that used to create 'lu'") | ||
end | ||
end | ||
|
||
lu.p=m | ||
lu._orderdone || ( findorder!(lu) || ErrorException("Finding Order.") ) | ||
lu._symbolicdone || ( symbolicfactor!(lu) || ErrorException("Symbolic Factorization.") ) | ||
lu._orderdone || ( findorder!(lu) || error("Finding Order.") ) | ||
lu._symbolicdone || ( symbolicfactor!(lu) || error("Symbolic Factorization.") ) | ||
lu._inmatrixdone = false | ||
lu._factordone = false | ||
lu._trisolvedone = false | ||
inmatrix!(lu) || ErrorException("Matrix input.") | ||
factor!(lu) || ErrorException("Numerical Factorization.") | ||
inmatrix!(lu) || error("Matrix input.") | ||
factor!(lu) || error("Numerical Factorization.") | ||
lu | ||
end | ||
|
||
|
@@ -276,7 +302,7 @@ Overwriting left division for SparseSolver. | |
The solution is returned in `v`, which is also the right hand side vector. | ||
""" | ||
function LinearAlgebra.ldiv!(lu::SparseSolver{IT,FT}, v) where {IT,FT} | ||
solve!(lu, v) || ErrorException("Triangular Solve.") | ||
solve!(lu, v) || error("Triangular Solve.") | ||
lu._trisolvedone = false | ||
v | ||
end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is an import necessary? Are we adding methods?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I looked at this the other way around:
import
is safer than an unqualifiedusing
, with the only difference being that it avoids importing many unknown and unused methods into the namespace with possibility of name clashes etc?In this case, the only effect of this change was to enforce
SparseArrays.nnz
which looks like what was intended, and caught a couple of places where an unqualifiednnz
was inadvertently used which then was potentially confusing (well confused me anyway!).Many thanks for fantastic work making this package available btw!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point.