first commit with current lessons
This commit is contained in:
206
10-12/UNM.jl
Normal file
206
10-12/UNM.jl
Normal file
@ -0,0 +1,206 @@
|
||||
using LinearAlgebra
|
||||
using Printf
|
||||
using Plots
|
||||
using LaTeXStrings
|
||||
|
||||
function UNM(f;
|
||||
x::Union{Nothing, Real}=nothing,
|
||||
eps::Real=1e-6,
|
||||
finf::Real=1e+8,
|
||||
MaxFeval::Integer=30,
|
||||
plt::Union{Plots.Plot, Nothing}=nothing,
|
||||
plotatend::Bool=true,
|
||||
Plotg::Integer=0
|
||||
)::Tuple{Real, String}
|
||||
|
||||
# Plotg
|
||||
# 1 = the function value / gap are plotted
|
||||
# 2 = the function and the second-order model are plotted
|
||||
# 3 = the function, the first-order model and the second-order model are
|
||||
# plotted (the first-order model has no role in the algorithm, but
|
||||
# this shows how much better the second-order model is than the
|
||||
# first-order one)
|
||||
|
||||
resolution = 1000
|
||||
|
||||
Interactive = false
|
||||
|
||||
# reading and checking input- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
(fStar, _, _, rangeplt) = f(nothing)
|
||||
|
||||
if x == nothing
|
||||
x = rangeplt[1]
|
||||
end
|
||||
|
||||
if finf ≤ 0
|
||||
throw(DomainError(finf, "finf must be in > 0"))
|
||||
end
|
||||
|
||||
if MaxFeval < 2
|
||||
throw(ArgumentError("At least two function computations are required"))
|
||||
return (NaN, "empty")
|
||||
end
|
||||
|
||||
# initializations - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
feval = 0
|
||||
status = "optimal"
|
||||
fbest = Inf
|
||||
|
||||
if Plotg == 1
|
||||
gap = []
|
||||
end
|
||||
|
||||
if Plotg == 1 && plt == nothing
|
||||
plt = plot(yscale = :log,
|
||||
xlims=(0, 35),
|
||||
ylims=(1e-15, Inf),
|
||||
guidefontsize=16)
|
||||
elseif Plotg == 2 && plt == nothing
|
||||
plt = plot(legend = false)
|
||||
elseif Plotg == 3 && plt == nothing
|
||||
plt = plot(legend = false)
|
||||
end
|
||||
|
||||
|
||||
println("Univariate Newton's Method")
|
||||
|
||||
if fStar > -Inf
|
||||
println("feval\trel gap\t\tx\t\tf(x)\t\tf'(x)\t\tf''(x)")
|
||||
else
|
||||
println("feval\tfbest\t\tx\t\tf'(x)\t\tf'(x)\t\tf''(x)")
|
||||
end
|
||||
|
||||
# main loop - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
while true
|
||||
# compute f(x), f'(x), f''(x) - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
(fx, f1x, f2x) = f(x)
|
||||
|
||||
feval += 1
|
||||
|
||||
if fx < fbest
|
||||
fbest = fx
|
||||
end
|
||||
|
||||
if abs(f2x) ≤ 1e-16
|
||||
status = "stopped"
|
||||
@printf("numerical issue: f''(x) = %1.4e\n", f2x)
|
||||
break
|
||||
end
|
||||
|
||||
# main logic- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
xn = x - f1x/f2x
|
||||
|
||||
# output statistics - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
if fStar > -Inf
|
||||
gapk = (fbest - fStar) / max(abs(fStar), 1)
|
||||
|
||||
if Plotg == 1
|
||||
push!(gap, gapk)
|
||||
end
|
||||
else
|
||||
gapk = fbest
|
||||
end
|
||||
|
||||
@printf("%4d\t%1.4e\t%1.8e\t%1.4e\t%1.4e\t%1.4e\n", feval, gapk, x, fx, f1x, f2x)
|
||||
|
||||
if Plotg > 1
|
||||
xm = min(x, xn) - abs(x - xn) / 5
|
||||
xp = max(x, xn) + abs(x - xn) / 5
|
||||
|
||||
xx = range(xm, xp, resolution)
|
||||
yy = map(v -> v[1], f.(xx))
|
||||
|
||||
for e in plt.series_list
|
||||
e[:linealpha] = 0
|
||||
end
|
||||
|
||||
old_ylims = ylims(plt)
|
||||
ylims!(plt, (minimum(yy), max(yy[1], yy[end])))
|
||||
|
||||
xlims!(plt, (xm, xp))
|
||||
|
||||
plot!(plt, xx, yy)
|
||||
|
||||
if Plotg == 3
|
||||
# first-order model is
|
||||
# f( y ) = f( x ) + f'( x )( y - x )
|
||||
# = [ f( x ) - f'( x ) x ]
|
||||
# + f'( x ) y
|
||||
b = f1x
|
||||
c = fx - f1x*x
|
||||
|
||||
yy = b .* xx .+ c
|
||||
plot!(plt, xx, yy)
|
||||
end
|
||||
# second-order model is
|
||||
# f( y ) = f( x ) + f'( x )( y - x ) + f''( x )( y - x )^2 / 2
|
||||
# = [ f( x ) - f'( x ) x + f''( x ) x^2 / 2 ]
|
||||
# + [ f'( x ) - f''( x ) x ] y
|
||||
# + f''( x )y^2 / 2
|
||||
a = f2x/2
|
||||
b = f1x - f2x*x
|
||||
c = fx - f1x*x + f2x*x^2 / 2
|
||||
|
||||
yy = @. a * xx^2 + b * xx + c
|
||||
plot!(plt, xx, yy)
|
||||
|
||||
new_xticks = []
|
||||
if x < xn
|
||||
new_xticks = ([xm, x, xn, xp],
|
||||
[@sprintf("%1.1g", xm), L"x^k", L"x^{k+1}", @sprintf("%1.1g", xp)])
|
||||
else
|
||||
new_xticks = ([xm, xn, x, xp],
|
||||
[@sprintf("%1.1g", xm), L"x^{k+1}", L"x^k", @sprintf("%1.1g", xp)])
|
||||
end
|
||||
xticks!(plt, new_xticks)
|
||||
end
|
||||
|
||||
# stopping criteria - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
if abs(f1x) ≤ eps
|
||||
break
|
||||
end
|
||||
|
||||
if feval > MaxFeval
|
||||
status = "stopped"
|
||||
break
|
||||
end
|
||||
|
||||
if abs(fx) > finf
|
||||
status = "error"
|
||||
break
|
||||
end
|
||||
|
||||
if Plotg ≠ 0 && Interactive
|
||||
IJulia.clear_output(wait=true)
|
||||
display(plt)
|
||||
sleep(0.1)
|
||||
readline()
|
||||
end
|
||||
|
||||
# iterate - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
x = xn
|
||||
end
|
||||
|
||||
if Plotg == 1
|
||||
plot!(plt,
|
||||
gap,
|
||||
linewidth=2)
|
||||
end
|
||||
|
||||
if plotatend && Plotg ≠ 0
|
||||
display(plt)
|
||||
end
|
||||
|
||||
(x, status)
|
||||
end
|
||||
Reference in New Issue
Block a user