Added Project and Report
This commit is contained in:
339
Lessons/11-23/SGM.jl
Normal file
339
Lessons/11-23/SGM.jl
Normal file
@ -0,0 +1,339 @@
|
||||
using LinearAlgebra, Printf, Plots
|
||||
|
||||
function SGM(f;
|
||||
x::Union{Nothing, Vector}=nothing,
|
||||
eps::Real=1e-6,
|
||||
astart::Real=1e-4,
|
||||
tau::Real=0.96,
|
||||
MaxFeval::Integer=300,
|
||||
MInf::Real=-Inf,
|
||||
mina::Real=1e-16,
|
||||
plt::Union{Plots.Plot, Nothing}=nothing,
|
||||
plotatend::Bool=true,
|
||||
Plotf::Integer=0,
|
||||
printing::Bool=true)::Tuple{AbstractArray, String}
|
||||
# function [ x , status ] = SGM( f , x , eps , astart , tau , MaxFeval ,
|
||||
# MInf , mina )
|
||||
#
|
||||
# Apply the classical Subgradient Method for the minimization of the
|
||||
# provided function f, which must have the following interface:
|
||||
#
|
||||
# [ v , g ] = f( x )
|
||||
#
|
||||
# Input:
|
||||
#
|
||||
# - x is either a [ n x 1 ] real (column) vector denoting the input of
|
||||
# f(), or [] (empty).
|
||||
#
|
||||
# Output:
|
||||
#
|
||||
# - v (real, scalar): if x == [] this is the best known lower bound on
|
||||
# the unconstrained global optimum of f(); it can be -Inf if either f()
|
||||
# is not bounded below, or no such information is available. If x ~= []
|
||||
# then v = f(x).
|
||||
#
|
||||
# - g (real, [ n x 1 ] real vector): this also depends on x. if x == []
|
||||
# this is the standard starting point from which the algorithm should
|
||||
# start, otherwise it is a subgradient of f() at x (possibly the
|
||||
# gradient, but you should not apply this algorithm to a differentiable
|
||||
# f)
|
||||
#
|
||||
# The other [optional] input parameters are:
|
||||
#
|
||||
# - x (either [ n x 1 ] real vector or [], default []): starting point.
|
||||
# If x == [], the default starting point provided by f() is used.
|
||||
#
|
||||
# - eps (real scalar, optional, default value 1e-6): the accuracy in the
|
||||
# stopping criterion. If eps > 0, then a target-level Polyak stepsize
|
||||
# with nonvanishing threshold is used, and eps is taken as the minimum
|
||||
# *relative* value for the displacement, i.e.,
|
||||
#
|
||||
# delta^i >= eps * max( abs( f( x^i ) ) , 1 )
|
||||
#
|
||||
# is used as the minimum value for the displacement. If eps < 0 and
|
||||
# v_* = f( [] ) > -Inf, then the algorithm "cheats" and it does an
|
||||
# *exact* Polyak stepsize with termination criteria
|
||||
#
|
||||
# ( f^i_{ref} - v_* ) <= ( - eps ) * max( abs( v_* ) , 1 )
|
||||
#
|
||||
# Finally, if eps == 0 the algorithm rather uses a DSS (diminishing
|
||||
# square-summable) stepsize, i.e., astart * ( 1 / i ) [see below]
|
||||
#
|
||||
# - astart (real scalar, optional, default value 1e-4): if eps > 0, i.e.,
|
||||
# a target-level Polyak stepsize with nonvanishing threshold is used,
|
||||
# then astart is used as the relative value to which the displacement is
|
||||
# reset each time f( x^{i + 1} ) <= f^i_{ref} - delta^i, i.e.,
|
||||
#
|
||||
# delta^{i + 1} = astart * max( abs( f^{i + 1}_{ref} ) , 1 )
|
||||
#
|
||||
# If eps == 0, i.e. a diminishing square-summable) stepsize is used, then
|
||||
# astart is used as the fixed scaling factor for the stepsize sequence
|
||||
# astart * ( 1 / i ).
|
||||
#
|
||||
# - tau (real scalar, optional, default value 0.95): if eps > 0, i.e.,
|
||||
# a target-level Polyak stepsize with nonvanishing threshold is used,
|
||||
# then delta^{i + 1} = delta^i * tau each time
|
||||
# f( x^{i + 1} ) > f^i_{ref} - delta^i
|
||||
#
|
||||
# - MaxFeval (integer scalar, optional, default value 300): the maximum
|
||||
# number of function evaluations (hence, iterations, since there is
|
||||
# exactly one function evaluation per iteration).
|
||||
#
|
||||
# - MInf (real scalar, optional, default value -Inf): if the algorithm
|
||||
# determines a value for f() <= MInf this is taken as an indication that
|
||||
# the problem is unbounded below and computation is stopped
|
||||
# (a "finite -Inf").
|
||||
#
|
||||
# - mina (real scalar, optional, default value 1e-16): if the algorithm
|
||||
# determines a stepsize value <= mina, this is taken as the fact that the
|
||||
# algorithm has already obtained the most it can and computation is
|
||||
# stopped. It is legal to take mina = 0.
|
||||
#
|
||||
# Output:
|
||||
#
|
||||
# - x ([ n x 1 ] real column vector): the best solution found so far.
|
||||
#
|
||||
# - status (string): a string describing the status of the algorithm at
|
||||
# termination
|
||||
#
|
||||
# = 'optimal': the algorithm terminated having proven that x is a(n
|
||||
# approximately) optimal solution; this only happens when "cheating",
|
||||
# i.e., explicitly uses v_* = f( [] ) > -Inf, unless in the very
|
||||
# unlikely case that f() spontaneously produces an almost-null
|
||||
# subgradient
|
||||
#
|
||||
# = 'unbounded': the algorithm has determined an extrenely large negative
|
||||
# value for f() that is taken as an indication that the problem is
|
||||
# unbounded below (a "finite -Inf", see MInf above)
|
||||
#
|
||||
# = 'stopped': the algorithm terminated having exhausted the maximum
|
||||
# number of iterations: x is the bast solution found so far, but not
|
||||
# necessarily the optimal one
|
||||
#
|
||||
#{
|
||||
# =======================================
|
||||
# Author: Antonio Frangioni
|
||||
# Date: 17-11-22
|
||||
# Version 1.11
|
||||
# Copyright Antonio Frangioni
|
||||
# =======================================
|
||||
#}
|
||||
|
||||
# Plotf = 1;
|
||||
# 0 = nothing is plotted
|
||||
# 1 = the level sets of f and the trajectory are plotted (when n = 2)
|
||||
# 2 = the function value / gap are plotted
|
||||
|
||||
Interactive = false # if we pause at every iteration
|
||||
|
||||
# reading and checking input- - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
local gap
|
||||
PXY = Matrix{Real}(undef, 2, 0)
|
||||
|
||||
status = "error"
|
||||
|
||||
if isnothing(x)
|
||||
(fStar, x, _) = f(nothing)
|
||||
else
|
||||
(fStar, _, _) = f(nothing)
|
||||
end
|
||||
|
||||
n = size(x, 1)
|
||||
|
||||
if eps < 0 && fStar == - Inf
|
||||
# no way of cheating since the true optimal value is unknonw
|
||||
eps = - eps # revert to ordinary target level stepsize
|
||||
end
|
||||
|
||||
if astart ≤ 0
|
||||
error("astart must be > 0")
|
||||
end
|
||||
|
||||
if tau ≤ 0 || tau ≥ 1
|
||||
error("tau is not in (0 ,1)")
|
||||
end
|
||||
|
||||
if mina < 0
|
||||
error("mina is < 0")
|
||||
end
|
||||
|
||||
# initializations - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
if printing
|
||||
@printf("Subradient method\n")
|
||||
if fStar > - Inf
|
||||
@printf("iter\trel gap\t\tbest gap\t|| g(x) ||\ta\n\n")
|
||||
else
|
||||
@printf("iter\tf(x)\t\tf best\t\t|| g(x) ||\ta\n\n")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if Plotf == 2
|
||||
gap = []
|
||||
end
|
||||
if Plotf > 1 && isnothing(plt)
|
||||
plt = plot(xlims=(0, MaxFeval))
|
||||
elseif isnothing(plt)
|
||||
plt = plot()
|
||||
end
|
||||
|
||||
# main loop - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
iter = 1
|
||||
xref = x
|
||||
fref = Inf # best f-value found so far
|
||||
if eps > 0
|
||||
delta = 0 # required displacement from fref
|
||||
end
|
||||
|
||||
while true
|
||||
|
||||
# compute function and subgradient- - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
(v, g, _) = f(x)
|
||||
ng = norm(g)
|
||||
|
||||
if eps > 0 # target-level stepsize
|
||||
if v ≤ fref - delta # found a "significantly" better point
|
||||
delta = astart * max(abs(v), 1) # reset delta
|
||||
else # decrease delta
|
||||
delta = max(delta * tau, eps * max(abs(min(v, fref)), 1))
|
||||
end
|
||||
end
|
||||
|
||||
if v < fref # found a better f-value (however slightly better)
|
||||
fref = v # update fref
|
||||
xref = x # this is the incumbent solution
|
||||
end
|
||||
|
||||
# output statistics - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
if fStar > -Inf
|
||||
gapk = (v - fStar)/max(abs(fStar), 1)
|
||||
bstgapk = (fref - fStar)/max(abs(fStar), 1)
|
||||
|
||||
if printing
|
||||
@printf("%4d\t%1.4e\t%1.4e\t%1.4e", iter, gapk, bstgapk, ng)
|
||||
end
|
||||
|
||||
if Plotf == 2
|
||||
push!(gap, gapk)
|
||||
end
|
||||
else
|
||||
if printing
|
||||
@printf("%4d\t%1.8e\t%1.8e\t\t%1.4e", iter, fref, v, ng)
|
||||
end
|
||||
|
||||
if Plotf == 2
|
||||
push!(gap, v)
|
||||
end
|
||||
end
|
||||
|
||||
# stopping criteria - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
if eps < 0 && fref - fStar ≤ - eps * max(abs(fStar), 1)
|
||||
xref = x
|
||||
status = "optimal"
|
||||
if printing
|
||||
@printf("\n")
|
||||
end
|
||||
|
||||
break
|
||||
end
|
||||
|
||||
if ng < 1e-12 # unlikely, but it could happen
|
||||
xref = x
|
||||
status = "optimal"
|
||||
if printing
|
||||
@printf("\n")
|
||||
end
|
||||
|
||||
break;
|
||||
end
|
||||
|
||||
if iter > MaxFeval
|
||||
status = "stopped"
|
||||
if printing
|
||||
@printf("\n")
|
||||
end
|
||||
|
||||
break
|
||||
end
|
||||
|
||||
# compute stepsize- - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
if eps > 0 # Polyak stepsize with target level
|
||||
a = ( v - fref + delta ) / ( ng * ng )
|
||||
elseif eps < 0 # true Polyak stepsize (cheating)
|
||||
a = ( v - fStar ) / ( ng * ng )
|
||||
else # diminishing square-summable stepsize
|
||||
a = astart * ( 1 / iter )
|
||||
end
|
||||
|
||||
# output statistics - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
if printing
|
||||
@printf("\t%1.4e", a)
|
||||
@printf("\n")
|
||||
end
|
||||
|
||||
if a ≤ mina
|
||||
status = "stopped"
|
||||
if printing
|
||||
@printf("\n")
|
||||
end
|
||||
|
||||
break
|
||||
end
|
||||
|
||||
if v ≤ MInf
|
||||
status = "unbounded"
|
||||
if printing
|
||||
@printf("\n")
|
||||
end
|
||||
|
||||
break
|
||||
end
|
||||
|
||||
# compute new point - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
# possibly plot the trajectory
|
||||
if n == 2 && Plotf == 1
|
||||
PXY = hcat(PXY, hcat(x, x - a * g))
|
||||
end
|
||||
|
||||
x = x - a * g
|
||||
|
||||
# iterate - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
iter += 1;
|
||||
|
||||
if Interactive
|
||||
readline()
|
||||
end
|
||||
end
|
||||
|
||||
# end of main loop- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
x = xref # return point corresponding to best value found so far
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
if plotatend
|
||||
if Plotf ≥ 2
|
||||
plot!(plt, gap)
|
||||
elseif Plotf == 1 && n == 2
|
||||
plot!(plt, PXY[1, :], PXY[2, :])
|
||||
end
|
||||
display(plt)
|
||||
end
|
||||
|
||||
return (x, status)
|
||||
end # the end- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Reference in New Issue
Block a user