|
| 1 | + |
| 2 | +""" |
| 3 | +$(TYPEDEF) |
| 4 | +
|
| 5 | +Struct to hold sparse matrix in the linked list format. |
| 6 | +
|
| 7 | +Modeled after the linked list sparse matrix format described in |
| 8 | +the [whitepaper](https://www-users.cs.umn.edu/~saad/software/SPARSKIT/paper.ps) |
| 9 | +and the [SPARSEKIT2 source code](https://www-users.cs.umn.edu/~saad/software/SPARSKIT/SPARSKIT2.tar.gz) |
| 10 | +by Y. Saad. He writes "This is one of the oldest data structures used for sparse matrix computations." |
| 11 | +
|
| 12 | +The relevant source [formats.f](https://salsa.debian.org/science-team/sparskit/blob/master/FORMATS/formats.f) |
| 13 | +is also available in the debian/science gitlab. |
| 14 | +
|
| 15 | +Probably this format was around already in SPARSPAK by E.Chu, A.George and J.Liu, however this is |
| 16 | +hard to verify, as it indeed appears that the source code of SPARSPAK [vanished from the internet](http://www.netlib.org/sparspak/readme). |
| 17 | +
|
| 18 | +The advantage of the linked list structure is the fact that upon insertion |
| 19 | +of a new entry, the arrays describing the structure grow at their respective ends and |
| 20 | +can be conveniently updated via `push!`. Now copying of existing data is necessary. |
| 21 | +
|
| 22 | +$(TYPEDFIELDS) |
| 23 | +""" |
| 24 | +mutable struct SparseMatrixLNK{Tv,Ti<:Integer} <: AbstractSparseMatrix{Tv,Ti} |
| 25 | + |
| 26 | + """ |
| 27 | + Number of rows |
| 28 | + """ |
| 29 | + m::Ti |
| 30 | + |
| 31 | + |
| 32 | + """ |
| 33 | + Number of columns |
| 34 | + """ |
| 35 | + n::Ti |
| 36 | + |
| 37 | + |
| 38 | + """ |
| 39 | + Number of nonzeros |
| 40 | + """ |
| 41 | + nnz::Ti |
| 42 | + |
| 43 | + |
| 44 | + """ |
| 45 | + Linked list of column entries. Initial length is n, |
| 46 | + it grows with each new entry. |
| 47 | + |
| 48 | + colptr[index] contains the next |
| 49 | + index in the list or zero, in the later case terminating the list which |
| 50 | + starts at index 1<=j<=n for each column j. |
| 51 | + """ |
| 52 | + colptr::Vector{Ti} |
| 53 | + |
| 54 | + |
| 55 | + """ |
| 56 | + Row numbers. For each index it contains the zero (initial state) |
| 57 | + or the row numbers corresponding to the column entry list in colptr. |
| 58 | +
|
| 59 | + Initial length is n, |
| 60 | + it grows with each new entry. |
| 61 | + """ |
| 62 | + rowval::Vector{Ti} |
| 63 | + |
| 64 | + """ |
| 65 | + Nonzero entry values correspondin to each pair |
| 66 | + (colptr[index],rowval[index]) |
| 67 | +
|
| 68 | + Initial length is n, it grows with each new entry. |
| 69 | + """ |
| 70 | + nzval::Vector{Tv} |
| 71 | +end |
| 72 | + |
| 73 | + |
| 74 | + |
| 75 | +""" |
| 76 | +$(SIGNATURES) |
| 77 | + |
| 78 | +Constructor of empty extension |
| 79 | +""" |
| 80 | +SparseMatrixLNK{Tv,Ti}(m::Integer, n::Integer) where {Tv,Ti<:Integer} = SparseMatrixLNK{Tv,Ti}(m,n,0,zeros(Ti,n),zeros(Ti,n),zeros(Tv,n)) |
| 81 | + |
| 82 | + |
| 83 | + |
| 84 | + |
| 85 | +""" |
| 86 | +$(SIGNATURES) |
| 87 | + |
| 88 | +Return value stored for entry or zero if not found |
| 89 | +""" |
| 90 | +function Base.getindex(E::SparseMatrixLNK{Tv,Ti},i::Integer, j::Integer) where {Tv,Ti<:Integer} |
| 91 | + |
| 92 | + if !((1 <= i <= E.m) & (1 <= j <= E.n)) |
| 93 | + throw(BoundsError(E, (i,j))) |
| 94 | + end |
| 95 | + |
| 96 | + k=j |
| 97 | + while k>0 |
| 98 | + if E.rowval[k]==i |
| 99 | + return E.nzval[k] |
| 100 | + end |
| 101 | + k=E.colptr[k] |
| 102 | + end |
| 103 | + |
| 104 | + return zero(Tv) |
| 105 | +end |
| 106 | + |
| 107 | + |
| 108 | + |
| 109 | +""" |
| 110 | +$(SIGNATURES) |
| 111 | + |
| 112 | +Update value of existing entry, otherwise extend matrix. |
| 113 | +""" |
| 114 | +function Base.setindex!(E::SparseMatrixLNK{Tv,Ti}, _v, _i::Integer, _j::Integer) where {Tv,Ti<:Integer} |
| 115 | + v = convert(Tv, _v) |
| 116 | + i = convert(Ti, _i) |
| 117 | + j = convert(Ti, _j) |
| 118 | + |
| 119 | + if !((1 <= i <= E.m) & (1 <= j <= E.n)) |
| 120 | + throw(BoundsError(E, (i,j))) |
| 121 | + end |
| 122 | + |
| 123 | + # Set the first column entry if it was not yet set. |
| 124 | + if E.rowval[j]==0 |
| 125 | + E.rowval[j]=i |
| 126 | + E.nzval[j]=v |
| 127 | + E.nnz+=1 |
| 128 | + return E |
| 129 | + end |
| 130 | + |
| 131 | + # Traverse list for existing entry |
| 132 | + k=j |
| 133 | + k0=j |
| 134 | + while k>0 |
| 135 | + # Update value and return if entry has been found |
| 136 | + if E.rowval[k]==i |
| 137 | + E.nzval[k]=v |
| 138 | + return E |
| 139 | + end |
| 140 | + k0=k |
| 141 | + # Next element in the list |
| 142 | + k=E.colptr[k] |
| 143 | + end |
| 144 | + |
| 145 | + # Append entry if not found |
| 146 | + push!(E.nzval,v) |
| 147 | + push!(E.rowval,i) |
| 148 | + |
| 149 | + # Shift the end of the list |
| 150 | + push!(E.colptr,0) |
| 151 | + E.colptr[k0]=length(E.nzval) |
| 152 | + |
| 153 | + # Update number of nonzero entries |
| 154 | + E.nnz+=1 |
| 155 | + return E |
| 156 | +end |
| 157 | + |
| 158 | + |
| 159 | +""" |
| 160 | +$(SIGNATURES) |
| 161 | +
|
| 162 | +Return tuple containing size of the matrix. |
| 163 | +""" |
| 164 | +Base.size(E::SparseMatrixLNK) = (E.m, E.n) |
| 165 | + |
| 166 | + |
| 167 | +""" |
| 168 | +$(SIGNATURES) |
| 169 | +
|
| 170 | +Return number of nonzero entries. |
| 171 | +""" |
| 172 | +SparseArrays.nnz(E::SparseMatrixLNK)=E.nnz |
| 173 | + |
| 174 | + |
| 175 | +""" |
| 176 | +$(SIGNATURES) |
| 177 | +
|
| 178 | +Dummy flush! method for Sparse matrix extension. Just |
| 179 | +used in test methods |
| 180 | +""" |
| 181 | +function flush!(M::SparseMatrixLNK{Tv, Ti}) where{Tv, Ti} |
| 182 | + return M |
| 183 | +end |
| 184 | + |
0 commit comments