Skip to content

Commit 2fc4c5b

Browse files
authored
Merge pull request #15 from ranjanan/standard_strength
Smoothed Aggregation
2 parents 8084a3e + be9c106 commit 2fc4c5b

File tree

8 files changed

+600
-15
lines changed

8 files changed

+600
-15
lines changed

README.md

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,15 @@ ml = ruge_stuben(A) # Construct a Ruge-Stuben solver
3434
solve(ml, A * ones(1000)) # should return ones(1000)
3535
```
3636

37-
## Roadmap
37+
### As a Preconditioner
38+
You can use AMG as a preconditioner for Krylov methods such as Conjugate Gradients.
39+
```julia
40+
import IterativeSolvers: cg
41+
p = aspreconditioner(ml)
42+
c = cg(A, A*ones(1000), Pl = p)
43+
```
44+
45+
## Features and Roadmap
3846

3947
This package currently supports:
4048
1. Ruge-Stuben Solver
@@ -43,9 +51,14 @@ This package currently supports:
4351
4. Gauss-Siedel smoothers
4452
5. V cycle multigrid
4553

46-
In the future, this package will support
54+
The following have experimental support:
4755
1. SmoothedAggregation Solver
4856
2. Standard Strength of Conneciton
49-
3. Other splitting methods (like CLJP)
50-
4. SOR, Jacobi smoothers
51-
5. W, F, AMLI cycles
57+
58+
In the future, this package will support:
59+
1. Other splitting methods (like CLJP)
60+
2. SOR, Jacobi smoothers
61+
3. W, F, AMLI cycles
62+
63+
#### Acknowledgements
64+
This package has been heavily inspired by the [`PyAMG`](http://github.com/pyamg/pyamg) project.

src/AMG.jl

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
module AMG
22

33
import IterativeSolvers: gauss_seidel!
4+
using Base.Threads
5+
6+
include("utils.jl")
7+
export approximate_spectral_radius
48

59
include("strength.jl")
6-
export strength_of_connection, Classical
10+
export strength_of_connection, Classical, SymmetricStrength
711

812
include("splitting.jl")
913
export split_nodes, RS
@@ -12,14 +16,21 @@ include("gallery.jl")
1216
export poisson
1317

1418
include("smoother.jl")
15-
export GaussSeidel, SymmetricSweep, ForwardSweep, BackwardSweep
19+
export GaussSeidel, SymmetricSweep, ForwardSweep, BackwardSweep,
20+
smooth_prolongator, JacobiProlongation
1621

1722
include("multilevel.jl")
1823
export solve
1924

2025
include("classical.jl")
2126
export ruge_stuben
2227

28+
include("aggregate.jl")
29+
export aggregation, StandardAggregation
30+
31+
include("aggregation.jl")
32+
export fit_candidates, smoothed_aggregation
33+
2334
include("preconditioner.jl")
2435
export aspreconditioner
2536

src/aggregate.jl

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
struct StandardAggregation
2+
end
3+
4+
function aggregation(::StandardAggregation, S)
5+
6+
n = size(S, 1)
7+
x = zeros(Int, n)
8+
y = zeros(Int, n)
9+
10+
next_aggregate = 1
11+
12+
for i = 1:n
13+
if x[i] != 0
14+
continue
15+
end
16+
17+
has_agg_neighbors = false
18+
has_neighbors = false
19+
20+
for j in nzrange(S, i)
21+
row = S.rowval[j]
22+
if row != i
23+
has_neighbors = true
24+
if x[row] != 0
25+
has_agg_neighbors = true
26+
break
27+
end
28+
end
29+
end
30+
31+
if !has_neighbors
32+
x[i] = -n
33+
elseif !has_agg_neighbors
34+
x[i] = next_aggregate
35+
y[next_aggregate] = i
36+
37+
for j in nzrange(S, i)
38+
row = S.rowval[j]
39+
x[row] = next_aggregate
40+
end
41+
42+
next_aggregate += 1
43+
end
44+
end
45+
46+
47+
# Pass 2
48+
for i = 1:n
49+
if x[i] != 0
50+
continue
51+
end
52+
53+
for j in nzrange(S, i)
54+
row = S.rowval[j]
55+
x_row = x[row]
56+
if x_row > 0
57+
x[i] = -x_row
58+
break
59+
end
60+
end
61+
end
62+
63+
next_aggregate -= 1
64+
65+
# Pass 3
66+
for i = 1:n
67+
xi = x[i]
68+
if xi != 0
69+
if xi > 0
70+
x[i] = xi - 1
71+
elseif xi == -n
72+
x[i] = -1
73+
else
74+
x[i] = -xi - 1
75+
end
76+
continue
77+
end
78+
79+
x[i] = next_aggregate
80+
y[next_aggregate + 1] = i
81+
82+
for j in nzrange(S, i)
83+
row = S.rowval[j]
84+
85+
if x[row] == 0
86+
x[row] = next_aggregate
87+
end
88+
end
89+
90+
next_aggregate += 1
91+
end
92+
93+
y = y[1:next_aggregate]
94+
M,N = (n, next_aggregate)
95+
96+
Tp = collect(1:n+1)
97+
x .= x .+ 1
98+
Tx = ones(length(x))
99+
100+
SparseMatrixCSC(N, M, Tp, x, Tx)
101+
end

src/aggregation.jl

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
function smoothed_aggregation{Tv,Ti}(A::SparseMatrixCSC{Tv,Ti},
2+
symmetry = HermitianSymmetry(),
3+
strength = SymmetricStrength(),
4+
aggregate = StandardAggregation(),
5+
smooth = JacobiProlongation(4.0/3.0),
6+
presmoother = GaussSeidel(),
7+
postsmoother = GaussSeidel(),
8+
improve_candidates = GaussSeidel(4),
9+
max_levels = 10,
10+
max_coarse = 10,
11+
diagonal_dominance = false,
12+
keep = false,
13+
coarse_solver = Pinv())
14+
15+
16+
n = size(A, 1)
17+
# B = kron(ones(n, 1), eye(1))
18+
B = ones(n)
19+
20+
#=max_levels, max_coarse, strength =
21+
levelize_strength_or_aggregation(max_levels, max_coarse, strength)
22+
max_levels, max_coarse, aggregate =
23+
levelize_strength_or_aggregation(max_levels, max_coarse, aggregate)
24+
25+
improve_candidates =
26+
levelize_smooth_or_improve_candidates(improve_candidates, max_levels)=#
27+
# str = [stength for _ in 1:max_levels - 1]
28+
# agg = [aggregate for _ in 1:max_levels - 1]
29+
# sm = [smooth for _ in 1:max_levels]
30+
31+
levels = Vector{Level{Tv,Ti}}()
32+
bsr_flag = false
33+
34+
while length(levels) < max_levels # && size(A, 1) > max_coarse
35+
A, B, bsr_flag = extend_hierarchy!(levels, strength, aggregate, smooth,
36+
improve_candidates, diagonal_dominance,
37+
keep, A, B, symmetry, bsr_flag)
38+
if size(A, 1) <= max_coarse
39+
break
40+
end
41+
end
42+
#=A, B = extend_hierarchy!(levels, strength, aggregate, smooth,
43+
improve_candidates, diagonal_dominance,
44+
keep, A, B, symmetry)=#
45+
MultiLevel(levels, A, presmoother, postsmoother)
46+
end
47+
48+
struct HermitianSymmetry
49+
end
50+
51+
function extend_hierarchy!(levels, strength, aggregate, smooth,
52+
improve_candidates, diagonal_dominance, keep,
53+
A, B,
54+
symmetry, bsr_flag)
55+
56+
# Calculate strength of connection matrix
57+
S = strength_of_connection(strength, A, bsr_flag)
58+
59+
# Aggregation operator
60+
AggOp = aggregation(aggregate, S')
61+
62+
# b = zeros(eltype(A), size(A, 1))
63+
64+
# Improve candidates
65+
# relax!(improve_candidates, A, B, b)
66+
T, B = fit_candidates(AggOp, B)
67+
68+
P = smooth_prolongator(smooth, A, T, S, B)
69+
R = construct_R(symmetry, P)
70+
push!(levels, Level(A, P, R))
71+
72+
A = R * A * P
73+
74+
dropzeros!(A)
75+
76+
bsr_flag = true
77+
78+
A, B, bsr_flag
79+
end
80+
construct_R(::HermitianSymmetry, P) = P'
81+
82+
function fit_candidates(AggOp, B, tol = 1e-10)
83+
84+
# K1 = Int(size(B, 1) / N_fine)
85+
# K2 = size(B, 2)
86+
87+
A = AggOp.'
88+
89+
n_coarse = size(A, 2)
90+
n_fine = size(A, 1)
91+
n_col = n_coarse
92+
93+
# R = zeros(eltype(B), N_coarse, K2, K2)
94+
R = zeros(eltype(B), n_coarse)
95+
# Qx = zeros(eltype(B), nnz(AggOp), K1, K2)
96+
Qx = zeros(eltype(B), nnz(A))
97+
98+
99+
# R = vec(R)
100+
# Qx = vec(Qx)
101+
102+
# n_row = N_fine
103+
# n_col = N_coarse
104+
105+
# BS = K1 * K2
106+
107+
#=for i = 1:n_col
108+
Ax_start = 1 + BS * A.colptr[i]
109+
110+
for j in nzrange(A, i)
111+
B_start = 1 + BS * A.rowval[j]
112+
B_end = B_start + BS
113+
@show B_start
114+
@show B_end
115+
for ind in B_start:B_end
116+
A.nzval[ind + Ax_start] = B[ind]
117+
end
118+
Ax_start += BS
119+
end
120+
end=#
121+
# copy!(A.nzval, B)
122+
copy!(Qx, B)
123+
# @show size(A.nzval)
124+
# @show size(B)
125+
126+
for i = 1:n_col
127+
norm_i = norm_col(A, Qx, i)
128+
# norm_i = norm(A[:,i])
129+
threshold_i = tol * norm_i
130+
if norm_i > threshold_i
131+
scale = 1 / norm_i
132+
R[i] = norm_i
133+
else
134+
scale = 0
135+
R[i] = 0
136+
end
137+
for j in nzrange(A, i)
138+
row = A.rowval[j]
139+
Qx[row] *= scale
140+
end
141+
#=col_start = A.colptr[i]
142+
col_end = A.colptr[i+1]
143+
144+
Ax_start = 1 + BS * col_start
145+
Ax_end = 1 + BS * col_end
146+
R_start = 1 + i * K2 * K2
147+
148+
for bj = 1:K2
149+
norm_j = zero(eltype(A))
150+
Ax_col = Ax_start + bj
151+
while Ax_col < Ax_end
152+
norm_j += norm(A.nzval[Ax_col])
153+
Ax_col += K2
154+
end
155+
norm_j = sqrt(norm_j)
156+
157+
threshold_j = tol * norm_j
158+
159+
for bi = 1:bj
160+
dot_prod = zero(eltype(A))
161+
162+
Ax_bi = Ax_start + bj
163+
Ax_bj = Ax_start + bj
164+
while Ax_bi < Ax_end
165+
dot_prod += dot(A.nzval[Ax_bj], A.nzval[Ax_bi])
166+
Ax_bi += K2
167+
Ax_bj += K2
168+
end
169+
170+
Ax_bi = Ax_start + bi;
171+
Ax_bj = Ax_start + bj;
172+
while Ax_bi < Ax_end
173+
A.nzval[Ax_bj] -= dot_prod * A.nzval[Ax_bi]
174+
Ax_bi += K2
175+
Ax_bj += K2
176+
end
177+
178+
R[R_start + K2 * bi + bj] = dot_prod
179+
end
180+
181+
norm_j = zero(eltype(A))
182+
Ax_bj = Ax_start + bj
183+
while Ax_bj < Ax_end
184+
norm_j += norm(A.nzval[Ax_bj])
185+
Ax_bj += K2
186+
norm_j = sqrt(norm_j)
187+
end
188+
189+
if norm_j > threshold_j
190+
scale = 1 / norm_j
191+
R[R_start + K2 * bj + bj] = norm_j
192+
else
193+
scale = zero(eltype(A))
194+
R[R_start + K2 * bj + bj] = 0
195+
end
196+
197+
Ax_bj = Ax_start + bj
198+
while Ax_bj < Ax_end
199+
A.nzval[Ax_bj] *= scale
200+
Ax_bj += K2
201+
end
202+
end=#
203+
end
204+
205+
#Q = SparseMatrixCSC(N_coarse, N_fine,
206+
#.colptr, A.rowval, Qx)
207+
208+
#R = reshape(R, N_coarse, K2)
209+
SparseMatrixCSC(size(A)..., A.colptr, A.rowval, Qx), R
210+
end
211+
function norm_col(A, Qx, i)
212+
s = zero(eltype(A))
213+
for j in nzrange(A, i)
214+
val = Qx[A.rowval[j]]
215+
s += val*val
216+
end
217+
sqrt(s)
218+
end

0 commit comments

Comments
 (0)