Skip to content

Commit

Permalink
Update Tikhonov matrix for Kaczmarz
Browse files Browse the repository at this point in the history
  • Loading branch information
nHackel committed Feb 28, 2024
1 parent 2ba651f commit d34d4a4
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 29 deletions.
58 changes: 31 additions & 27 deletions src/Kaczmarz.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ mutable struct Kaczmarz{matT,R,T,U,RN} <: AbstractRowActionSolver
rowIndexCycle::Vector{Int64}
x::Vector{T}
vl::Vector{T}
εw::Vector{T}
εw::T
τl::T
αl::T
randomized::Bool
Expand All @@ -20,7 +20,6 @@ mutable struct Kaczmarz{matT,R,T,U,RN} <: AbstractRowActionSolver
shuffleRows::Bool
seed::Int64
iterations::Int64
regMatrix::Union{Nothing,Vector{U}} # Tikhonov regularization matrix
normalizeReg::AbstractRegularizationNormalization
end

Expand Down Expand Up @@ -51,17 +50,10 @@ function Kaczmarz(A
, shuffleRows::Bool = false
, seed::Int = 1234
, iterations::Int = 10
, regMatrix = nothing
)

T = real(eltype(A))

# Apply Tikhonov regularization matrix
if regMatrix !== nothing
regMatrix = T.(regMatrix) # make sure regMatrix has the same element type as A
A = transpose(1 ./ sqrt.(regMatrix)) .* A # apply Tikhonov regularization to system matrix
end

# Prepare regularization terms
reg = isa(reg, AbstractVector) ? reg : [reg]
reg = normalize(Kaczmarz, normalizeReg, reg, A, nothing)
Expand All @@ -73,6 +65,11 @@ function Kaczmarz(A
deleteat!(reg, idx)
end

# Tikhonov matrix is only valid with NoNormalization or SystemMatrixBasedNormalization
if λ(L2) isa Vector && !(normalizeReg isa NoNormalization || normalizeReg isa SystemMatrixBasedNormalization)
error("Tikhonov matrix for Kaczmarz is only valid with no or system matrix based normalization")

Check warning on line 70 in src/Kaczmarz.jl

View check run for this annotation

Codecov / codecov/patch

src/Kaczmarz.jl#L70

Added line #L70 was not covered by tests
end

indices = findsinks(AbstractProjectionRegularization, reg)
other = AbstractRegularization[reg[i] for i in indices]
deleteat!(reg, indices)
Expand All @@ -84,7 +81,7 @@ function Kaczmarz(A
other = identity.(other)

# setup denom and rowindex
denom, rowindex = initkaczmarz(A, λ(L2))
A, denom, rowindex = initkaczmarz(A, λ(L2))
rowIndexCycle = collect(1:length(rowindex))
probabilities = eltype(denom)[]
if randomized
Expand All @@ -97,13 +94,13 @@ function Kaczmarz(A
u = zeros(eltype(A),M)
x = zeros(eltype(A),N)
vl = zeros(eltype(A),M)
εw = zeros(eltype(A), length(rowindex))
εw = zero(eltype(A))
τl = zero(eltype(A))
αl = zero(eltype(A))

return Kaczmarz(A, u, L2, other, denom, rowindex, rowIndexCycle, x, vl, εw, τl, αl,
randomized, subMatrixSize, probabilities, shuffleRows,
Int64(seed), iterations, regMatrix,
Int64(seed), iterations,
normalizeReg)
end

Expand All @@ -121,7 +118,8 @@ function init!(solver::Kaczmarz, b; x0 = 0)

# λ changed => recompute denoms
if λ_ != λ_prev
solver.denom, solver.rowindex = initkaczmarz(solver.A, λ_)
# A must be unchanged, since we do not store the original SM
_, solver.denom, solver.rowindex = initkaczmarz(solver.A, λ_)
solver.rowIndexCycle = collect(1:length(rowindex))
if solver.randomized
solver.probabilities = T.(rowProbabilities(solver.A, rowindex))

Check warning on line 125 in src/Kaczmarz.jl

View check run for this annotation

Codecov / codecov/patch

src/Kaczmarz.jl#L122-L125

Added lines #L122 - L125 were not covered by tests
Expand All @@ -140,17 +138,18 @@ function init!(solver::Kaczmarz, b; x0 = 0)
solver.vl .= 0

solver.u .= b
solver.ɛw .= sqrt.(λ_)
if λ_ isa Vector
solver.ɛw = 0
else
solver.ɛw = sqrt(λ_)
end
end


function solversolution(solver::Kaczmarz)
# backtransformation of solution with Tikhonov matrix
if solver.regMatrix !== nothing
return solver.x .* (1 ./ sqrt.(solver.regMatrix))
end
return solver.x
function solversolution(solver::Kaczmarz{matT, RN}) where {matT, R<:L2Regularization{<:Vector}, RN <: Union{R, AbstractNestedRegularization{<:R}}}
return solver.x .* (1 ./ sqrt.(λ(solver.L2)))
end
solversolution(solver::Kaczmarz) = solver.x
solverconvergence(solver::Kaczmarz) = (; :residual => norm(solver.vl))

function iterate(solver::Kaczmarz, iteration::Int=0)
Expand All @@ -177,9 +176,9 @@ end
iterate_row_index(solver::Kaczmarz, A::AbstractLinearSolver, row, index) = iterate_row_index(solver, Matrix(A[row, :]), row, index)

Check warning on line 176 in src/Kaczmarz.jl

View check run for this annotation

Codecov / codecov/patch

src/Kaczmarz.jl#L176

Added line #L176 was not covered by tests
function iterate_row_index(solver::Kaczmarz, A, row, index)
solver.τl = dot_with_matrix_row(A,solver.x,row)
solver.αl = solver.denom[index]*(solver.u[row]-solver.τl-solver.ɛw[index]*solver.vl[row])
solver.αl = solver.denom[index]*(solver.u[row]-solver.τl-solver.ɛw*solver.vl[row])
kaczmarz_update!(A,solver.x,row,solver.αl)
solver.vl[row] += solver.αl*solver.ɛw[index]
solver.vl[row] += solver.αl*solver.ɛw
end

@inline done(solver::Kaczmarz,iteration::Int) = iteration>=solver.iterations
Expand Down Expand Up @@ -208,23 +207,28 @@ end
This function saves the denominators to compute αl in denom and the rowindices,
which lead to an update of x in rowindex.
"""
initkaczmarz(A, λ::Number) = initkaczmarz(A, Iterators.repeated(λ, size(A, 2)))
function initkaczmarz(A,λ)
T = real(eltype(A))
denom = T[]
rowindex = Int64[]
@assert length(λ) == size(A, 2)

for (i, λrow) in enumerate)
for i = 1:size(A, 1)
= rownorm²(A,i)
if>0
push!(denom,1/(s²+λrow))
push!(denom,1/(s²+λ))
push!(rowindex,i)
end
end
denom, rowindex
return A, denom, rowindex
end
function initkaczmarz(A, λ::Vector)
λ = real(eltype(A)).(λ)
A = initikhonov(A, λ)
return initkaczmarz(A, 0)
end

initikhonov(A, λ) = transpose((1 ./ sqrt.(λ)) .* transpose(A)) # optimize structure for row access
initikhonov(prod::ProdOp{Tc, WeightingOp{T}, matT}, λ) where {T, Tc<:Union{T, Complex{T}}, matT} = ProdOp(prod.A, initikhonov(prod.B, λ))

Check warning on line 231 in src/Kaczmarz.jl

View check run for this annotation

Codecov / codecov/patch

src/Kaczmarz.jl#L231

Added line #L231 was not covered by tests
### kaczmarz_update! ###

"""
Expand Down
4 changes: 2 additions & 2 deletions test/testKaczmarz.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ end
regMatrix = rand(2) # Tikhonov matrix

solver = Kaczmarz
S = createLinearSolver(solver, A, iterations=200, regMatrix=regMatrix)
S = createLinearSolver(solver, A, iterations=200, reg=[L2Regularization(regMatrix)])
x_approx = solve!(S,b)
#@info "Testing solver $solver ...: $x == $x_approx"
@test norm(x - x_approx) / norm(x) 0 atol=0.1
Expand All @@ -61,7 +61,7 @@ end
# @show A, x, regMatrix
# use regularization matrix

S = createLinearSolver(solver, A, iterations=100, regMatrix=regMatrix)
S = createLinearSolver(solver, A, iterations=100, reg=[L2Regularization(regMatrix)])
x_matrix = solve!(S,b)

# use standard reconstruction
Expand Down

0 comments on commit d34d4a4

Please sign in to comment.