forked from JuliaSmoothOptimizers/RegularizedOptimization.jl
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutils.jl
More file actions
132 lines (116 loc) · 4.26 KB
/
utils.jl
File metadata and controls
132 lines (116 loc) · 4.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
export RegularizedExecutionStats
import SolverCore.GenericExecutionStats
function power_method!(B::M, v₀::S, v₁::S, max_iter::Int = 1) where{M, S}
@assert max_iter >= 1 "max_iter must be at least 1."
mul!(v₁, B, v₀)
normalize!(v₁) # v1 = B*v0 / ‖B*v0‖
for i = 2:max_iter
v₀ .= v₁ # v0 = v1
mul!(v₁, B, v₀)
normalize!(v₁)
end
mul!(v₁, B, v₀)
return abs(dot(v₀, v₁))
end
# use Arpack to obtain largest eigenvalue in magnitude with a minimum of robustness
function LinearAlgebra.opnorm(B; kwargs...)
m, n = size(B)
opnorm_fcn = m == n ? opnorm_eig : opnorm_svd
return opnorm_fcn(B; kwargs...)
end
function opnorm_eig(B; max_attempts::Int = 3)
have_eig = false
attempt = 0
λ = zero(eltype(B))
n = size(B, 1)
nev = 1
ncv = max(20, 2 * nev + 1)
while !(have_eig || attempt >= max_attempts)
attempt += 1
try
# Estimate largest eigenvalue in absolute value
d, nconv, niter, nmult, resid =
eigs(B; nev = nev, ncv = ncv, which = :LM, ritzvec = false, check = 1)
# Check if eigenvalue has converged
have_eig = nconv == 1
if have_eig
λ = abs(d[1]) # Take absolute value of the largest eigenvalue
break # Exit loop if successful
else
# Increase NCV for the next attempt if convergence wasn't achieved
ncv = min(2 * ncv, n)
end
catch e
if occursin("XYAUPD_Exception", string(e)) && ncv < n
@warn "Arpack error: $e. Increasing NCV to $ncv and retrying."
ncv = min(2 * ncv, n) # Increase NCV but don't exceed matrix size
else
rethrow(e) # Re-raise if it's a different error
end
end
end
return λ, have_eig
end
function opnorm_svd(J; max_attempts::Int = 3)
have_svd = false
attempt = 0
σ = zero(eltype(J))
n = min(size(J)...) # Minimum dimension of the matrix
nsv = 1
ncv = 10
while !(have_svd || attempt >= max_attempts)
attempt += 1
try
# Estimate largest singular value
s, nconv, niter, nmult, resid = svds(J; nsv = nsv, ncv = ncv, ritzvec = false, check = 1)
# Check if singular value has converged
have_svd = nconv >= 1
if have_svd
σ = maximum(s.S) # Take the largest singular value
break # Exit loop if successful
else
# Increase NCV for the next attempt if convergence wasn't achieved
ncv = min(2 * ncv, n)
end
catch e
if occursin("XYAUPD_Exception", string(e)) && ncv < n
@warn "Arpack error: $e. Increasing NCV to $ncv and retrying."
ncv = min(2 * ncv, n) # Increase NCV but don't exceed matrix size
else
rethrow(e) # Re-raise if it's a different error
end
end
end
return σ, have_svd
end
ShiftedProximalOperators.iprox!(
y::AbstractVector,
ψ::ShiftedProximableFunction,
g::AbstractVector,
D::AbstractDiagonalQuasiNewtonOperator,
) = iprox!(y, ψ, g, D.d)
ShiftedProximalOperators.iprox!(
y::AbstractVector,
ψ::ShiftedProximableFunction,
g::AbstractVector,
D::SpectralGradient,
) = iprox!(y, ψ, g, fill!(similar(g), D.d[1]))
LinearAlgebra.diag(op::AbstractDiagonalQuasiNewtonOperator) = copy(op.d)
LinearAlgebra.diag(op::SpectralGradient{T}) where {T} = zeros(T, op.nrow) .* op.d[1]
"""
GenericExecutionStats(reg_nlp :: AbstractRegularizedNLPModel{T, V})
Construct a GenericExecutionStats object from an AbstractRegularizedNLPModel.
More specifically, construct a GenericExecutionStats on the NLPModel of reg_nlp and add three solver_specific entries namely :smooth_obj, :nonsmooth_obj and :xi.
This is useful for reducing the number of allocations when calling solve!(..., reg_nlp, stats) and should be used by default.
Warning: This should *not* be used when adding other solver_specific entries that do not have the current scalar type.
"""
function RegularizedExecutionStats(reg_nlp::AbstractRegularizedNLPModel{T, V}) where {T, V}
stats = GenericExecutionStats(reg_nlp.model, solver_specific = Dict{Symbol, T}())
set_solver_specific!(stats, :smooth_obj, T(Inf))
set_solver_specific!(stats, :nonsmooth_obj, T(Inf))
set_solver_specific!(stats, :sigma, T(Inf))
set_solver_specific!(stats, :sigma_cauchy, T(Inf))
set_solver_specific!(stats, :radius, T(Inf))
set_solver_specific!(stats, :prox_evals, T(Inf))
return stats
end