Skip to content

Commit 03a0960

Browse files
committed
Replace _slice by Base.:+, now fully fledged addition
1 parent 9cdc9f0 commit 03a0960

File tree

8 files changed

+254
-144
lines changed

8 files changed

+254
-144
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Without an intermediate data structure, efficient successive insertion/update of
1212

1313
The later is modeled after the linked list sparse matrix format described in the [whitepaper](https://www-users.cs.umn.edu/~saad/software/SPARSKIT/paper.ps) by Y. Saad. See also exercise P.3-16 in his [book](https://www-users.cs.umn.edu/~saad/IterMethBook_2ndEd.pdf).
1414

15-
Any linear algebra method on `ExtendableSparseMatrix` starts with a `flush!` method which splices the LNK entries and the existing CSC entries into a new CSC struct and resets the LNK struct.
15+
Any linear algebra method on `ExtendableSparseMatrix` starts with a `flush!` method which adds the LNK entries and the existing CSC entries into a new CSC struct and resets the LNK struct.
1616

1717
`ExtendableSparseMatrix` is aimed to work as a drop-in replacement to `SparseMatrixCSC` in finite element and finite volume codes especally in those cases where the sparsity structure is hard to detect a priori and where working with an intermediadte COO representation appears to be not convenient.
1818

docs/make.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ using Documenter, ExtendableSparse
33

44
makedocs(sitename="ExtendableSparse.jl",
55
modules = [ExtendableSparse],
6-
doctest = false,
6+
doctest = true,
77
clean = true,
88
authors = "J. Fuhrmann",
99
repo="https://github.com/j-fu/ExtendableSparse.jl",

docs/src/changes.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
# Changes
2+
3+
## dev
4+
- What used to be `_splice` is now `+` and allows now real addition (resulting in a CSC matrix)
5+
- Added constructors of LNK matrix from CSC matrix and vice versa
6+
- reorganized tests
7+
28
## v0.2.1 Dec 22, 2019
39
- Tried to track down the source from which I learned the linked list based struct in order
410
to document this. Ended up with SPARSEKIT of Y.Saad, however I believe this

docs/src/example.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,35 @@
11
# Examples
22

3+
4+
## Usage idea
35
An `ExtendableSparseMatrix` can serve as a drop-in replacement for
46
`SparseMatrixCSC`, albeit with faster assembly.
57

8+
9+
```jldoctest
10+
using ExtendableSparse
11+
function example(n,bandwidth)
12+
A=ExtendableSparseMatrix(n,n);
13+
aii=0.0
14+
for i=1:n
15+
for j=max(1,i-bandwidth):5:min(n,i+bandwidth)
16+
aij=-rand()
17+
A[i,j]=aij
18+
aii+=abs(aij)
19+
end
20+
A[i,i]=aii+0.1
21+
end
22+
b=rand(n)
23+
x=A\b
24+
A*x≈ b
25+
end
26+
example(1000,100)
27+
# output
28+
true
29+
```
30+
31+
32+
## Benchmark
633
The code below provides a small benchmark example.
734
```julia
835
using ExtendableSparse
@@ -35,7 +62,7 @@ b=rand(n);
3562
The function [`sprand_sdd!`](@ref) fills a
3663
sparse matrix with random entries such that it becomes strictly diagonally
3764
dominant and thus invertible and has a fixed number of nonzeros in
38-
its rows. Its bandwidth is bounded by 2*sqrt(n), therefore it
65+
its rows (similar to the method in the first example). Its bandwidth is bounded by 2*sqrt(n), therefore it
3966
resembles a typical matrix of a 2D piecewise linear FEM discretization.
4067
For filling a matrix a, the method conveniently albeit naively
4168
uses just `a[i,j]=value`. This approach is considerably faster with

src/extendable.jl

Lines changed: 12 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -138,132 +138,30 @@ Size of ExtendableSparseMatrix.
138138
Base.size(ext::ExtendableSparseMatrix) = (ext.cscmatrix.m, ext.cscmatrix.n)
139139

140140

141-
"""
142-
$(SIGNATURES)
143-
144-
Number of nonzeros of ExtendableSparseMatrix.
145-
"""
146-
function SparseArrays.nnz(ext::ExtendableSparseMatrix)
147-
ennz=0
148-
if ext.lnkmatrix!=nothing
149-
ennz=nnz(ext.lnkmatrix)
150-
end
151-
return nnz(ext.cscmatrix)+ennz
152-
end
153-
154-
155-
156-
# Struct holding pair of value and row
157-
# number, for sorting
158-
struct ColEntry{Tv,Ti<:Integer}
159-
rowval::Ti
160-
nzval::Tv
161-
end
162-
163-
# Comparison method for sorting
164-
Base.isless(x::ColEntry{Tv, Ti},y::ColEntry{Tv, Ti}) where {Tv,Ti<:Integer} = (x.rowval<y.rowval)
165-
166-
"""
167-
$(SIGNATURES)
168-
169-
Create new CSC matrix with sorted entries from a SparseMatrixCSC csc and
170-
[`SparseMatrixLNK`](@ref) lnk.
171-
172-
This method assumes that there are no entries with the same
173-
indices in lnk and csc, therefore it appears too dangerous for general use and
174-
so we don't export it. A generalization appears to be possible, though.
175-
"""
176-
function _splice(lnk::SparseMatrixLNK{Tv,Ti},csc::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti<:Integer}
177-
@assert(csc.m==lnk.m)
178-
@assert(csc.n==lnk.n)
179-
180-
xnnz=nnz(csc)+nnz(lnk)
181-
colptr=Vector{Ti}(undef,csc.n+1)
182-
rowval=Vector{Ti}(undef,xnnz)
183-
nzval=Vector{Tv}(undef,xnnz)
184-
185-
# Detect the maximum column length of lnk
186-
lnk_maxcol=0
187-
for j=1:csc.n
188-
lcol=0
189-
k=j
190-
while k>0
191-
lcol+=1
192-
k=lnk.colptr[k]
193-
end
194-
lnk_maxcol=max(lcol,lnk_maxcol)
195-
end
196-
197-
# pre-allocate column data
198-
col=[ColEntry{Tv,Ti}(0,0) for i=1:lnk_maxcol]
199-
200-
201-
202-
inz=1 # counts the nonzero entries in the new matrix
203-
204-
# loop over all columns
205-
for j=1:csc.n
206-
# put extension entries into col and sort them
207-
k=j
208-
l_lnk_col=0
209-
while k>0
210-
if lnk.rowval[k]>0
211-
l_lnk_col+=1
212-
col[l_lnk_col]=ColEntry(lnk.rowval[k],lnk.nzval[k])
213-
end
214-
k=lnk.colptr[k]
215-
end
216-
sort!(col,1,l_lnk_col, Base.QuickSort, Base.Forward)
217-
218-
219-
# jointly sort lnk and csc entries into new matrix data
220-
colptr[j]=inz
221-
jcol=1 # counts the entries in col
222-
jcsc=csc.colptr[j] # counts entries in csc
223-
while true
224-
225-
# Insert entries from csc into new structure
226-
# if the row number is before col[jcol]
227-
if ( nnz(csc)>0 && (jcsc<csc.colptr[j+1]) ) &&
228-
(
229-
(jcol<=l_lnk_col && csc.rowval[jcsc]<col[jcol].rowval) ||
230-
(jcol>l_lnk_col)
231-
)
232-
rowval[inz]=csc.rowval[jcsc]
233-
nzval[inz]=csc.nzval[jcsc]
234-
jcsc+=1
235-
inz+=1
236-
237-
# Otherwise, insert next entry from col
238-
elseif jcol<=l_lnk_col
239-
rowval[inz]=col[jcol].rowval
240-
nzval[inz]=col[jcol].nzval
241-
jcol+=1
242-
inz+=1
243-
else
244-
break
245-
end
246-
end
247-
end
248-
colptr[csc.n+1]=inz
249-
SparseMatrixCSC{Tv,Ti}(csc.m,csc.n,colptr,rowval,nzval)
250-
end
251-
252141

253142
"""
254143
$(SIGNATURES)
255144
256-
If there are new entries in extension, create new CSC matrix using [`_splice`](@ref)
257-
and reset linked list based extension.
145+
If there are new entries in extension, create new CSC matrix by adding the
146+
cscmatrix and linked list matrix and reset the linked list based extension.
258147
"""
259148
function flush!(ext::ExtendableSparseMatrix{Tv,Ti}) where {Tv, Ti<:Integer}
260149
if ext.lnkmatrix!=nothing && nnz(ext.lnkmatrix)>0
261-
ext.cscmatrix=_splice(ext.lnkmatrix,ext.cscmatrix)
150+
ext.cscmatrix=ext.lnkmatrix+ext.cscmatrix
262151
ext.lnkmatrix=nothing
263152
end
264153
return ext
265154
end
266155

156+
"""
157+
$(SIGNATURES)
158+
159+
[`flush!`](@ref) and return number of nonzeros in ext.cscmatrix.
160+
"""
161+
function SparseArrays.nnz(ext::ExtendableSparseMatrix)
162+
@inbounds flush!(ext)
163+
return nnz(ext.cscmatrix)
164+
end
267165

268166

269167
"""

0 commit comments

Comments
 (0)