|
| 1 | +#=function mg(a::SparseMatrixCSC, b::Vector, x = zeros(size(b))) |
| 2 | +
|
| 3 | + r = a*x - b |
| 4 | + |
| 5 | + # Smoothing steps |
| 6 | + smooth!(x, A, b) |
| 7 | +
|
| 8 | + # Coarsening steps |
| 9 | + while level < nlevels |
| 10 | + Ac[level] = coarsen(A[level-1]) |
| 11 | + f[level] = coarse(f[level-1]) |
| 12 | + end |
| 13 | + x = solve(A[end], f[end]) |
| 14 | +
|
| 15 | + # Interpolation step |
| 16 | + interpolate!(x, nlevels) |
| 17 | +
|
| 18 | + if norm(r) < tol |
| 19 | + break |
| 20 | + end |
| 21 | +
|
| 22 | + x |
| 23 | +end |
| 24 | +
|
| 25 | +struct Level |
| 26 | + A::SparseMatrixCSC |
| 27 | + R::RestrictionMatrix |
| 28 | + P::ProlongationMatrix |
| 29 | +end |
| 30 | +
|
| 31 | +struct RestrictionMatrix |
| 32 | + r::SparseMatrixCSC |
| 33 | +end |
| 34 | +
|
| 35 | +struct ProlongationMatrix |
| 36 | + p::SparseMatrixCSC |
| 37 | +end=# |
| 38 | + |
| 39 | +function classical(A::SparseMatrixCSC, θ::Float64) |
| 40 | + |
| 41 | + I = Int[] |
| 42 | + J = Int[] |
| 43 | + V = Float64[] |
| 44 | + |
| 45 | + m, n = size(A) |
| 46 | + |
| 47 | + for i = 1:n |
| 48 | + neighbors = A[:,i] |
| 49 | + m = find_max_off_diag(neighbors, i) |
| 50 | + threshold = θ * m |
| 51 | + for j in nzrange(A, i) |
| 52 | + row = A.rowval[j] |
| 53 | + val = A.nzval[j] |
| 54 | + if abs(val) >= threshold |
| 55 | + push!(I, row) |
| 56 | + push!(J, i) |
| 57 | + push!(V, abs(val)) |
| 58 | + end |
| 59 | + end |
| 60 | + end |
| 61 | + S = sparse(I, J, V) |
| 62 | + |
| 63 | + scale_cols_by_largest_entry(S) |
| 64 | +end |
| 65 | + |
| 66 | +function find_max_off_diag(neighbors, col) |
| 67 | + max_offdiag = 0 |
| 68 | + for (i,v) in enumerate(neighbors) |
| 69 | + if col != i |
| 70 | + max_offdiag = max(max_offdiag, abs(v)) |
| 71 | + end |
| 72 | + end |
| 73 | + max_offdiag |
| 74 | +end |
| 75 | + |
| 76 | +function scale_cols_by_largest_entry(A::SparseMatrixCSC) |
| 77 | + |
| 78 | + m,n = size(A) |
| 79 | + |
| 80 | + I = zeros(Int, size(A.nzval)) |
| 81 | + J = similar(I) |
| 82 | + V = zeros(size(A.nzval)) |
| 83 | + |
| 84 | + k = 1 |
| 85 | + for i = 1:n |
| 86 | + m = maximum(A[:,i]) |
| 87 | + for j in nzrange(A, i) |
| 88 | + row = A.rowval[j] |
| 89 | + val = A.nzval[j] |
| 90 | + I[k] = row |
| 91 | + J[k] = i |
| 92 | + V[k] = val / m |
| 93 | + k += 1 |
| 94 | + end |
| 95 | + end |
| 96 | + |
| 97 | + sparse(I,J,V) |
| 98 | +end |
| 99 | + |
| 100 | +function RS(S::SparseMatrixCSC) |
| 101 | + |
| 102 | + m,n = size(S) |
| 103 | + |
| 104 | + n_nodes = n |
| 105 | + lambda = zeros(Int, n) |
| 106 | + Tp = S.colptr |
| 107 | + Tj = S.rowval |
| 108 | + Sp = Tp |
| 109 | + Sj = Tj |
| 110 | + |
| 111 | + # compute lambdas |
| 112 | + for i = 1:n |
| 113 | + lambda[i] = Tp[i+1] - Tp[i] |
| 114 | + end |
| 115 | + |
| 116 | + interval_ptr = zeros(Int, n+1) |
| 117 | + interval_count = zeros(Int, n+1) |
| 118 | + index_to_node = zeros(Int,n) |
| 119 | + node_to_index = zeros(Int,n) |
| 120 | + |
| 121 | + for i = 1:n |
| 122 | + interval_count[lambda[i]+1] += 1 |
| 123 | + end |
| 124 | + csum = 0 |
| 125 | + for i = 1:n |
| 126 | + interval_ptr[i] = csum |
| 127 | + csum += interval_count[i] |
| 128 | + interval_count[i] = 0 |
| 129 | + end |
| 130 | + for i = 1:n |
| 131 | + lambda_i = lambda[i]+1 |
| 132 | + index = interval_ptr[lambda_i] + interval_count[lambda_i] |
| 133 | + index_to_node[index+1] = i |
| 134 | + node_to_index[i] = index+1 |
| 135 | + interval_count[lambda_i] += 1 |
| 136 | + end |
| 137 | + splitting = fill(2, n) |
| 138 | + |
| 139 | + # all nodes with no neighbors become F nodes |
| 140 | + for i = 1:n |
| 141 | + # check if diagonal or check if no neighbors |
| 142 | + if lambda[i] == 0 || (lambda[i] == 1 && Tj[Tp[i]] == i) |
| 143 | + splitting[i] = F_NODE |
| 144 | + end |
| 145 | + end |
| 146 | + |
| 147 | + # Now add elements to C and F, in descending order of lambda |
| 148 | + for top_index = n_nodes:-1:1 |
| 149 | + i = index_to_node[top_index] |
| 150 | + lambda_i = lambda[i] + 1 |
| 151 | + |
| 152 | + # if (n_nodes == 4) |
| 153 | + # std::cout << "selecting node #" << i << " with lambda " << lambda[i] << std::endl; |
| 154 | + |
| 155 | + # remove i from its interval |
| 156 | + interval_count[lambda_i] -= 1 |
| 157 | + |
| 158 | + if splitting[i] == F_NODE |
| 159 | + continue |
| 160 | + else |
| 161 | + |
| 162 | + @assert splitting[i] == U_NODE |
| 163 | + |
| 164 | + splitting[i] = C_NODE |
| 165 | + |
| 166 | + # For each j in S^T_i /\ U |
| 167 | + for jj = Tp[i]:Tp[i+1]-1 |
| 168 | + |
| 169 | + j = Tj[jj] |
| 170 | + |
| 171 | + if splitting[j] == U_NODE |
| 172 | + splitting[j] = F_NODE |
| 173 | + |
| 174 | + # For each k in S_j /\ U |
| 175 | + for kk = Sp[j]: Sp[j+1]-1 |
| 176 | + k = Sj[kk] |
| 177 | + |
| 178 | + if splitting[k] == U_NODE |
| 179 | + # move k to the end of its current interval |
| 180 | + lambda[k] >= n_nodes - 1 && continue |
| 181 | + |
| 182 | + lambda_k = lambda[k] + 1 |
| 183 | + old_pos = node_to_index[k] |
| 184 | + new_pos = interval_ptr[lambda_k] + interval_count[lambda_k]# - 1 |
| 185 | + |
| 186 | + node_to_index[index_to_node[old_pos]] = new_pos |
| 187 | + node_to_index[index_to_node[new_pos]] = old_pos |
| 188 | + (index_to_node[old_pos], index_to_node[new_pos]) = (index_to_node[new_pos], index_to_node[old_pos]) |
| 189 | + |
| 190 | + # update intervals |
| 191 | + interval_count[lambda_k] -= 1 |
| 192 | + interval_count[lambda_k+1] += 1 # invalid write! |
| 193 | + interval_ptr[lambda_k+1] = new_pos - 1 |
| 194 | + |
| 195 | + # increment lambda_k |
| 196 | + lambda[k] += 1 |
| 197 | + end |
| 198 | + end |
| 199 | + end |
| 200 | + end |
| 201 | + |
| 202 | + # For each j in S_i /\ U |
| 203 | + for jj = Sp[i]: Sp[i+1]-1 |
| 204 | + |
| 205 | + j = Sj[jj] |
| 206 | + |
| 207 | + if splitting[j] == U_NODE # decrement lambda for node j |
| 208 | + |
| 209 | + lambda[j] == 0 && continue |
| 210 | + |
| 211 | + # assert(lambda[j] > 0);//this would cause problems! |
| 212 | + |
| 213 | + # move j to the beginning of its current interval |
| 214 | + lambda_j = lambda[j] + 1 |
| 215 | + old_pos = node_to_index[j] |
| 216 | + new_pos = interval_ptr[lambda_j] |
| 217 | + |
| 218 | + node_to_index[index_to_node[old_pos]] = new_pos |
| 219 | + node_to_index[index_to_node[new_pos]] = old_pos |
| 220 | + (index_to_node[old_pos],index_to_node[new_pos]) = (index_to_node[new_pos],index_to_node[old_pos]) |
| 221 | + |
| 222 | + # update intervals |
| 223 | + interval_count[lambda_j] -= 1 |
| 224 | + interval_count[lambda_j-1] += 1 |
| 225 | + interval_ptr[lambda_j] += 1 |
| 226 | + interval_ptr[lambda_j-1] = interval_ptr[lambda_j] - interval_count[lambda_j-1] |
| 227 | + |
| 228 | + # decrement lambda_j |
| 229 | + lambda[j] -= 1 |
| 230 | + end |
| 231 | + end |
| 232 | + end |
| 233 | + end |
| 234 | + splitting |
| 235 | +end |
| 236 | +poisson(n) = sparse(Tridiagonal(fill(-1, n-1), fill(2, n), fill(-1, n-1))) |
0 commit comments