Files
cmdla/10-12/GRS.jl

187 lines
4.8 KiB
Julia
Raw Normal View History

2023-10-29 02:06:02 +01:00
using Plots
using LinearAlgebra
using Printf
function GRS(f;
rangeplt::Union{Nothing, Tuple{Real, Real}}=nothing,
delta::Real=1e-6,
MaxFeval::Integer=100,
plt::Union{Plots.Plot, Nothing}=nothing,
plotatend::Bool=true,
Plotg::Integer=0
)::Tuple{Real, String}
# Plotg
# 0 = nothing is plotted
# 1 = the function value / gap are plotted
# 2 = the function and the test points used are plotted
resolution = 1000
Interactive = false # if we pause at every iteration
# reading and checking input- - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
if rangeplt == nothing
(fStar, _, _, rangeplt) = f(nothing)
else
fStar = -Inf
end
xm = rangeplt[1] # x_-
xp = rangeplt[2] # x_+
if xm > xp
throw(ArgumentError("rangeplt is empty"))
return (NaN, "empty")
end
if MaxFeval < 2
throw(ArgumentError("At least two function computations are required"))
return (NaN, "empty")
end
# initializations - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
r = (sqrt( 5 ) - 1)/2
xmp = xm + (1 - r) * (xp - xm) # x'_-
xpp = xm + r * (xp - xm) # x'_+
fxmp = f(xmp)[1] # f(x'_-)
fxpp = f(xpp)[1] # f(x'_+)
feval = 2
if fxmp fxpp
fx = fxmp
else
fx = fxpp
end
status = "optimal"
if Plotg > 0
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)
end
print("Golden ratio search\n")
if fStar > -Inf
print("feval\trel gap\t\tx_-\t\tx_+\n")
else
print("feval\tfbest\t\tx_-\t\tx_+\n")
end
# main loop - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
while xp - xm > delta
# output statistics - - - - - - - - - - - - - - - - - - - - - - - - - -
if fStar > -Inf
gapk = (fx - fStar) / max(abs(fStar), 1)
if Plotg == 1
push!(gap, gapk)
end
else
gapk = fx
end
@printf("%4d\t%1.4e\t%1.8e\t%1.8e\n", feval, gapk, xm, xp)
if Plotg == 2
xbot = xm - ( xp - xm ) / 20;
xtop = xp + ( xp - xm ) / 20;
if !isempty(plt.series_list)
plt.series_list[end][:linealpha] = 0
end
xx = range(xbot, xtop, resolution)
yy = map(v -> v[1], f.(xx))
xlims!(plt, (xbot, xtop))
old_ylims = ylims(plt)
ylims!(plt, (old_ylims[1], max(fxmp, fxpp)))
plot!(plt, xx, yy)
# old_xticks = xticks(plt[1])
new_xticks = ([xbot, xm, xmp, xpp, xp, xtop],
[@sprintf("%1.1g", xbot), "x-", "x''-", "x''+", "x+", @sprintf("%1.1g", xtop)])
# keep_indices = findall(x -> all(x .≠ new_xticks[1]), old_xticks[1])
# merged_xticks = (old_xticks[1][keep_indices] new_xticks[1],
# old_xticks[2][keep_indices] new_xticks[2])
# xticks!(merged_xticks)
xticks!(plt, new_xticks)
end
# stopping criteria - - - - - - - - - - - - - - - - - - - - - - - - - -
if feval > MaxFeval
status = "stopped"
break
end
# main logic- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
if fxmp <= fxpp
xp = xpp
xpp = xmp
xmp = xm + (1 - r) * (xp - xm)
fxpp = fxmp
fx = fxmp
fxmp = f(xmp)[1]
else
xm = xmp
xmp = xpp
xpp = xm + r * (xp - xm)
fxmp = fxpp
fx = fxpp
fxpp = f(xpp)[1]
end
feval += 1
if Plotg 0 && Interactive
IJulia.clear_output(wait=true)
display(plt)
sleep(0.1)
readline()
end
# iterate - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
end
# end of main loop- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# select final answer
if fxmp fxpp
x = xmp
else
x = xpp
end
if Plotg == 1
plot!(plt,
gap,
linewidth=2)
end
if plotatend && Plotg 0
display(plt)
end
(x, status)
end