Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
/Manifest.toml
test.jl

docs/Manifest.toml
ext/Manifest.toml
docs/build
example_data/d_t2/
12 changes: 4 additions & 8 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a"
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
QuadraticModels = "f468eda6-eac5-11e8-05a5-ff9e497bcd19"
RipQP = "1e40b3f8-35eb-4cd8-8edd-3e515bb9de08"
NonNegLeastSquares = "b7351bd1-99d9-5c5d-8786-f205a815c4d7"

[extensions]
gui_ext = "GLMakie"
nnls_ext = "NonNegLeastSquares"
tikhonov_jump_ext = "JuMP"
tikhonov_ripqp_ext = ["RipQP", "QuadraticModels"]

Expand All @@ -28,6 +30,7 @@ DelimitedFiles = "1"
GLMakie = "0.11, 0.12, 0.13"
JuMP = "1"
NativeFileDialog = "0.2"
NonNegLeastSquares = "0.4.1"
Optim = "1.10.0"
PolygonOps = "0.1"
QuadraticModels = "0.9"
Expand All @@ -43,11 +46,4 @@ SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = [
"Test",
"GLMakie",
"NMRInversions",
"Random",
"SparseArrays",
"LinearAlgebra"
]
test = ["Test", "GLMakie", "NMRInversions", "Random", "SparseArrays", "LinearAlgebra"]
8 changes: 8 additions & 0 deletions docs/src/types_structs.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ cdL1
optim_nnls
```

The following are also implemented through
external package extensions.

```@docs
nnls
jump_nnls
```

## Finding optimal alpha
These are methods for finding the optimal regularization parameter.
They can be used as input to the `invert` function as the 'alpha' argument
Expand Down
14 changes: 11 additions & 3 deletions ext/Manifest.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# This file is machine-generated - editing it directly is not advised

julia_version = "1.12.4"
julia_version = "1.12.5"
manifest_format = "2.0"
project_hash = "36034e3e9c89d48d9c539f2b0060983a7836f13f"
project_hash = "55fd022efc13f657a37564ea8957b17208f5633d"

[[deps.ADTypes]]
git-tree-sha1 = "f7304359109c768cf32dc5fa2d371565bb63b68a"
Expand Down Expand Up @@ -1069,16 +1069,18 @@ version = "7.10.0"
deps = ["DelimitedFiles", "LinearAlgebra", "NativeFileDialog", "Optim", "Pkg", "PolygonOps", "SparseArrays"]
path = ".."
uuid = "55c20db2-0166-4687-95c3-62a9c7afb29b"
version = "1.2.0"
version = "1.3.0"

[deps.NMRInversions.extensions]
gui_ext = "GLMakie"
nnls_ext = "NonNegLeastSquares"
tikhonov_jump_ext = "JuMP"
tikhonov_ripqp_ext = ["RipQP", "QuadraticModels"]

[deps.NMRInversions.weakdeps]
GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a"
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
NonNegLeastSquares = "b7351bd1-99d9-5c5d-8786-f205a815c4d7"
QuadraticModels = "f468eda6-eac5-11e8-05a5-ff9e497bcd19"
RipQP = "1e40b3f8-35eb-4cd8-8edd-3e515bb9de08"

Expand Down Expand Up @@ -1110,6 +1112,12 @@ version = "1.1.1"
uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908"
version = "1.3.0"

[[deps.NonNegLeastSquares]]
deps = ["LinearAlgebra", "SparseArrays"]
git-tree-sha1 = "cdc11138e74a0dd0b82e7d64eb1350fdf049d3b1"
uuid = "b7351bd1-99d9-5c5d-8786-f205a815c4d7"
version = "0.4.1"

[[deps.Observables]]
git-tree-sha1 = "7438a59546cf62428fc9d1bc94729146d37a7225"
uuid = "510215fc-4207-5dde-b226-833fc4488ee2"
Expand Down
1 change: 1 addition & 0 deletions ext/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
NMRInversions = "55c20db2-0166-4687-95c3-62a9c7afb29b"
NativeFileDialog = "e1fe445b-aa65-4df4-81c1-2041507f0fd4"
NonNegLeastSquares = "b7351bd1-99d9-5c5d-8786-f205a815c4d7"
PolygonOps = "647866c9-e3ac-4575-94e7-e3d426903924"
28 changes: 28 additions & 0 deletions ext/nnls_ext.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module nnls_ext

using NMRInversions
using LinearAlgebra, NonNegLeastSquares

function NMRInversions.solve_regularization(K::AbstractMatrix, g::AbstractVector, α::Real, solver::nnls)

L = if isa(solver.L,Int)
NMRInversions.Γ(size(K, 2), solver.L)
else
if size(solver.L, 2) == size(K, 2)
solver.L
else
throw("Size mismatch between `solver.L` and the Kernel.")
end
end

A = [K; √(α) .* L]
b = [g; zeros(size(A, 1) - size(g, 1))]

f = vec(nonneg_lsq(A, b ; alg=solver.algorithm))

r = K * f - g

return f, r
end

end
33 changes: 12 additions & 21 deletions ext/tikhonov_jump_ext.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,22 @@ using NMRInversions, JuMP, LinearAlgebra, SparseArrays
# import JuMP: @constraints
# import JuMP: @objective

export jump_nnls
"""
jump_nnls(order, solver)
Jump non-negative least squares method for tikhonov (L2) regularization,
implemented using the JuMP extension.
All around effective, but can be slow for large problems, such as 2D inversions,
unless a powerful solver like gurobi is used.

- `solver` is passed directly into JuMP.
- `order` determines the tikhonov finite-difference matrix. \
If 0 is chosen, the identity matrix is used.

This one is still experimental and not well-tested,
please submit an issue if you encounter any difficulties.
"""
struct jump_nnls <: regularization_solver
order::Int
solver::Symbol
end

function NMRInversions.solve_regularization(K::AbstractMatrix, g::AbstractVector,
α::Real, solver::Type{jump_nnls})

A = sparse([K; √(α) .* NMRInversions.Γ(size(K, 2), solver.order)])
b = sparse([g; zeros(size(A, 1) - size(g, 1))])
L = if isa(solver.L,Int)
NMRInversions.Γ(size(K, 2), solver.L)
else
if size(solver.L, 2) == size(K, 2)
solver.L
else
throw("Size mismatch between `solver.L` and the Kernel.")
end
end

A = [K; √(α) .* L]
b = [g; zeros(size(A, 1) - size(g, 1))]

@eval model = JuMP.Model($(solver.solver).Optimizer)
set_silent(model)
Expand Down
2 changes: 1 addition & 1 deletion src/brd.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Optim

"""
brd
brd()
Solver for tikhonov (L2) regularization, following \
[this paper](https://doi.org/10.1109/78.995059)
[Venka2002](@cite).
Expand Down
4 changes: 2 additions & 2 deletions src/optim_least_squares.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ using Optim

export optim_nnls
"""
optim_nnls(order)
optim_nnls(; L, algorithm, opts)
Simple non-negative least squares method for regularization,
implemented using Optim.jl.
All around effective, but can be slow for large problems, such as 2D inversions.
Expand Down Expand Up @@ -31,7 +31,7 @@ function solve_regularization(K::AbstractMatrix, g::AbstractVector, α::Real, so
if size(solver.L, 2) == size(K, 2)
solver.L
else
throw("Size mismatch between `optim_nnls.L` and the Kernel.")
throw("Size mismatch between `solver.L` and the Kernel.")
end
end

Expand Down
52 changes: 52 additions & 0 deletions src/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -191,3 +191,55 @@ mutable struct expfit_struct
eqn::String
title::String
end


# define structs for extension solvers
function solve_regularization(K, g, α, solver::regularization_solver)
error("The package needed for $(typeof(solver)) is not loaded.")
end

export nnls
"""
nnls(; L, algorithm)
Non-negative least squares method for regularization,
implemented using the `NonNegLeastSquares` package extension.
Decent speed for small, 1D regularizations, but very slow for larger, 2D problems.
It can be used as a "solver" for invert function.

- `L` determines the tikhonov matrix.\
Can be either a matrix or an integer `n`. The latter will create a finite difference matrix\
of order `n`, which means that the penalty term will be the `n`'th derivative of the distribution.\
Defaults to `0`, where `L` becomes the Identity matrix.
- `algorithm` is one of:
* `:nnls`
* `:fnnls`
* `:pivot`
"""
struct nnls <: regularization_solver
L::Union{Int, AbstractMatrix}
algorithm::Symbol
end
nnls(;L=0, algorithm=:nnls) = nnls(L, algorithm)


export jump_nnls
"""
jump_nnls(L, solver)
Jump non-negative least squares method for tikhonov (L2) regularization,
implemented using the JuMP package extension.
All around effective, but can be slow for large problems, such as 2D inversions,
unless a powerful solver like gurobi is used.

- `L` determines the tikhonov matrix.\
Can be either a matrix or an integer `n`. The latter will create a finite difference matrix\
of order `n`, which means that the penalty term will be the `n`'th derivative of the distribution.\
Defaults to `0`, where `L` becomes the Identity matrix.
- `solver` is passed directly into JuMP, see its documentation for available options.

This one is still experimental and not well-tested,
please submit an issue if you encounter any difficulties.
"""
struct jump_nnls <: regularization_solver
order::Int
solver::Symbol
end
Loading