{
"cells": [
{
"cell_type": "code",
"execution_count": 27,
"id": "cb5170b7-6a4c-415f-8675-8382c5ce837c",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"NWTN (generic function with 1 method)"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"using LinearAlgebra, Printf, Plots\n",
"\n",
"function NWTN(f;\n",
" x::Union{Nothing, Vector}=nothing,\n",
" eps::Real=1e-6,\n",
" MaxFeval::Integer=1000,\n",
" m1::Real=1e-4,\n",
" m2::Real=0.9,\n",
" delta::Real=1e-6,\n",
" tau::Real=0.9,\n",
" sfgrd::Real=0.2,\n",
" MInf::Real=-Inf,\n",
" mina::Real=1e-16,\n",
" plt::Union{Plots.Plot, Nothing}=nothing,\n",
" plotatend::Bool=true,\n",
" Plotf::Integer=0,\n",
" printing::Bool=true)::Tuple{AbstractArray, String}\n",
"\n",
" \n",
" # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
" # inner functions - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
" # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
"\n",
" function f2phi(alpha, derivate=false)\n",
" # computes and returns the value of the tomography at alpha\n",
" #\n",
" # phi( alpha ) = f( x + alpha * d )\n",
" #\n",
" # if Plotf > 2 saves the data in gap() for plotting\n",
" #\n",
" # if the second output parameter is required, put there the derivative\n",
" # of the tomography in alpha\n",
" #\n",
" # phi'( alpha ) = < \\nabla f( x + alpha * d ) , d >\n",
" #\n",
" # saves the point in lastx, the gradient in lastg, the Hessian in lasth,\n",
" # and increases feval\n",
" \n",
" lastx = x + alpha * d\n",
" phi, lastg, lastH = f(lastx)\n",
" \n",
" if Plotf > 2\n",
" if fStar > - Inf\n",
" push!(gap, (phi - fStar) / max(abs(fStar), 1))\n",
" else\n",
" push!(gap, phi)\n",
" end\n",
" end\n",
"\n",
" feval += 1\n",
"\n",
" if derivate\n",
" return (phi, dot(d, lastg))\n",
" end\n",
" return (phi, nothing)\n",
" end\n",
"\n",
" # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
" # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
" \n",
" function ArmijoWolfeLS(phi0, phip0, as, m1, m2, tau)\n",
" # performs an Armijo-Wolfe Line Search.\n",
" #\n",
" # phi0 = phi( 0 ), phip0 = phi'( 0 ) < 0\n",
" #\n",
" # as > 0 is the first value to be tested: if phi'( as ) < 0 then as is\n",
" # divided by tau < 1 (hence it is increased) until this does not happen\n",
" # any longer\n",
" #\n",
" # m1 and m2 are the standard Armijo-Wolfe parameters; note that the strong\n",
" # Wolfe condition is used\n",
" #\n",
" # returns the optimal step and the optimal f-value\n",
" \n",
" lsiter = 1 # count iterations of first phase\n",
" local phips, phia\n",
" while feval ≤ MaxFeval \n",
" phia, phips = f2phi(as, true)\n",
" \n",
" if (phia ≤ phi0 + m1 * as * phip0) && (abs(phips) ≤ - m2 * phip0)\n",
" if printing\n",
" @printf(\" %2d\", lsiter)\n",
" end\n",
" a = as;\n",
" return (a, phia) # Armijo + strong Wolfe satisfied, we are done\n",
" \n",
" end\n",
" if phips ≥ 0\n",
" break\n",
" end\n",
" as = as / tau\n",
" lsiter += 1\n",
" end \n",
"\n",
" if printing\n",
" @printf(\" %2d \", lsiter)\n",
" end\n",
" lsiter = 1 # count iterations of second phase\n",
" \n",
" am = 0\n",
" a = as\n",
" phipm = phip0\n",
" while (feval ≤ MaxFeval ) && ((as - am)) > mina && (phips > 1e-12)\n",
" \n",
" # compute the new value by safeguarded quadratic interpolation\n",
" a = (am * phips - as * phipm) / (phips - phipm)\n",
" a = max(am + ( as - am ) * sfgrd, min(as - ( as - am ) * sfgrd, a))\n",
" \n",
" # compute phi(a)\n",
" phia, phip = f2phi(a, true)\n",
" \n",
" if (phia ≤ phi0 + m1 * a * phip0) && (abs(phip) ≤ -m2 * phip0)\n",
" break # Armijo + strong Wolfe satisfied, we are done\n",
" end\n",
" \n",
" # restrict the interval based on sign of the derivative in a\n",
" if phip < 0\n",
" am = a\n",
" phipm = phip\n",
" else\n",
" as = a\n",
" if as ≤ mina\n",
" break\n",
" end\n",
" phips = phip\n",
" end\n",
" lsiter += 1\n",
" end\n",
"\n",
" if printing\n",
" @printf(\"%2d\", lsiter)\n",
" end\n",
" return (a, phia)\n",
" end\n",
"\n",
" # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
"\n",
" function BacktrackingLS(phi0, phip0, as, m1, tau)\n",
" # performs a Backtracking Line Search.\n",
" #\n",
" # phi0 = phi( 0 ), phip0 = phi'( 0 ) < 0\n",
" #\n",
" # as > 0 is the first value to be tested, which is decreased by\n",
" # multiplying it by tau < 1 until the Armijo condition with parameter\n",
" # m1 is satisfied\n",
" #\n",
" # returns the optimal step and the optimal f-value\n",
" \n",
" lsiter = 1 # count ls iterations\n",
" while feval ≤ MaxFeval && as > mina\n",
" phia, _ = f2phi(as)\n",
" if phia ≤ phi0 + m1 * as * phip0 # Armijo satisfied\n",
" break # we are done\n",
" end\n",
" as *= tau\n",
" lsiter += 1\n",
" end\n",
"\n",
" if printing\n",
" @printf(\" %2d\", lsiter)\n",
" end\n",
"\n",
" return (as, phia)\n",
" end\n",
" \n",
" # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
" # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
"\n",
" #Plotf = 2\n",
" # 0 = nothing is plotted\n",
" # 1 = the level sets of f and the trajectory are plotted (when n = 2)\n",
" # 2 = the function value / gap are plotted, iteration-wise\n",
" # 3 = the function value / gap are plotted, function-evaluation-wise\n",
"\n",
" Interactive = false\n",
"\n",
" PXY = Matrix{Real}(undef, 2, 0)\n",
"\n",
" local gap\n",
" if Plotf > 1\n",
" if Plotf == 2\n",
" MaxIter = 50 # expected number of iterations for the gap plot\n",
" else\n",
" MaxIter = 70 # expected number of iterations for the gap plot\n",
" end\n",
" gap = []\n",
" end\n",
"\n",
" if Plotf == 2 && plt == nothing\n",
" plt = plot(xlims=(0, MaxIter), ylims=(1e-15, 1e+1))\n",
" end\n",
" if Plotf > 1 && plt == nothing\n",
" plt = plot(xlims=(0, MaxIter))\n",
" end\n",
" if plt == nothing\n",
" plt = plot()\n",
" end\n",
"\n",
" local fStar\n",
" if isnothing(x)\n",
" (fStar, x, _) = f(nothing)\n",
" else\n",
" (fStar, _, _) = f(nothing)\n",
" end\n",
"\n",
" n = size(x, 1)\n",
"\n",
" if m1 ≤ 0 || m1 ≥ 1\n",
" throw(ArgumentError(\"m1 is not in (0 ,1)\"))\n",
" end\n",
"\n",
" AWLS = (m2 > 0 && m2 < 1)\n",
"\n",
" if delta < 0\n",
" throw(ArgumentError(\"delta must be ≥ 0\"))\n",
" end\n",
"\n",
" if tau ≤ 0 || tau ≥ 1\n",
" throw(ArgumentError(\"tau is not in (0 ,1)\"))\n",
" end\n",
"\n",
" if sfgrd ≤ 0 || sfgrd ≥ 1\n",
" throw(ArgumentError(\"sfgrd is not in (0, 1)\"))\n",
" end\n",
"\n",
" if mina < 0\n",
" throw(ArgumentError(\"mina must be ≥ 0\"))\n",
" end\n",
"\n",
" # \"global\" variables- - - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
" # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
" \n",
" lastx = zeros(n) # last point visited in the line search\n",
" lastg = zeros(n) # gradient of lastx\n",
" lastH = zeros(n, n) # Hessian of lastx\n",
" d = zeros(n) # Newton's direction\n",
" feval = 0 # f() evaluations count (\"common\" with LSs)\n",
"\n",
" status = \"error\"\n",
" \n",
" # initializations - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
" # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
"\n",
" if fStar > -Inf\n",
" prevv = Inf\n",
" end\n",
"\n",
" if printing\n",
" @printf(\"Newton's method\\n\")\n",
" if fStar > -Inf\n",
" @printf(\"feval\\trel gap\\t\\t|| g(x) ||\\trate\\t\\tdelta\")\n",
" else\n",
" @printf(\"feval\\tf(x)\\t\\t\\t|| g(x) ||\\tdelta\")\n",
" end\n",
" @printf(\"\\t\\tls it\\ta*\")\n",
" @printf(\"\\n\\n\")\n",
" end\n",
"\n",
" \n",
" v, _ = f2phi(0)\n",
" ng = norm(lastg)\n",
" if eps < 0\n",
" ng0 = -ng # norm of first subgradient: why is there a \"-\"? ;-)\n",
" else\n",
" ng0 = 1 # un-scaled stopping criterion\n",
" end\n",
"\n",
" # main loop - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
" # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
"\n",
" while true\n",
"\n",
" # output statistics - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
" \n",
" if fStar > -Inf\n",
" gapk = ( v - fStar ) / max(abs( fStar ), 1)\n",
"\n",
" if printing\n",
" @printf(\"%4d\\t%1.4e\\t%1.4e\", feval, gapk, ng)\n",
" if prevv < Inf\n",
" @printf(\"\\t%1.4e\", ( v - fStar ) / ( prevv - fStar ))\n",
" else\n",
" @printf(\"\\t\\t\")\n",
" end\n",
" end\n",
" prevv = v\n",
" \n",
" if Plotf > 1\n",
" if Plotf ≥ 2\n",
" push!(gap, gapk)\n",
" end\n",
" end\n",
" else\n",
" if printing\n",
" @printf(\"%4d\\t%1.8e\\t\\t%1.4e\", feval, v, ng)\n",
" end\n",
" \n",
" if Plotf > 1\n",
" if Plotf ≥ 2\n",
" push!(gap, v)\n",
" end\n",
" end\n",
" end\n",
"\n",
" # stopping criteria - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
"\n",
" if ng ≤ eps * ng0\n",
" status = \"optimal\"\n",
" break\n",
" end\n",
" \n",
" if feval > MaxFeval\n",
" status = \"stopped\"\n",
" break\n",
" end\n",
" \n",
" # compute Newton's direction- - - - - - - - - - - - - - - - - - - - - -\n",
"\n",
" lambdan = eigmin(lastH) # smallest eigenvalue\n",
" if lambdan < delta\n",
" if printing\n",
" @printf(\"\\t%1.4e\", delta - lambdan)\n",
" end\n",
" lastH = lastH + (delta - lambdan) * I\n",
" else\n",
" if printing\n",
" @printf(\"\\t0.00e+00\")\n",
" end\n",
" end\n",
" d = -lastH \\ lastg\n",
" phip0 = lastg' * d\n",
" \n",
" # compute step size - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
" # in Newton's method, the default initial stepsize is 1\n",
" \n",
" if AWLS\n",
" a, v = ArmijoWolfeLS(v, phip0, 1, m1, m2, tau)\n",
" else\n",
" a, v = BacktrackingLS(v, phip0, 1, m1, tau)\n",
" end\n",
" \n",
" # output statistics - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
"\n",
" if printing\n",
" @printf(\"\\t%1.2e\", a)\n",
" @printf(\"\\n\")\n",
" end\n",
" \n",
" if a ≤ mina\n",
" status = \"error\"\n",
" break\n",
" end\n",
" \n",
" if v ≤ MInf\n",
" status = \"unbounded\"\n",
" break\n",
" end\n",
" \n",
" # compute new point - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
" \n",
" # possibly plot the trajectory\n",
" if n == 2 && Plotf == 1\n",
" PXY = hcat(PXY, hcat(x, lastx))\n",
" end\n",
" \n",
" x = lastx\n",
" ng = norm(lastg)\n",
"\n",
" # iterate - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
" \n",
" if Interactive\n",
" readline()\n",
" end\n",
" end\n",
"\n",
" if plotatend\n",
" if Plotf ≥ 2\n",
" plot!(plt, gap)\n",
" elseif Plotf == 1 && n == 2\n",
" plot!(plt, PXY[1, :], PXY[2, :])\n",
" end\n",
" display(plt)\n",
" end\n",
"\n",
" # end of main loop- - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
" # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n",
" return (x, status)\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "9fa92a74-19bc-46b3-92de-d39aa74f0075",
"metadata": {},
"outputs": [],
"source": [
"include(\"./TestFunctions/TestFunctions.jl\")\n",
"TF = TestFunctions();"
]
},
{
"cell_type": "code",
"execution_count": 29,
"id": "14e530e5-1b32-4a3e-ac62-b67fd8723f06",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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x4wZ880331T9xbhDkWWZc/7ZZ5917dr1jhusWrWqfv36ps3Wr18fHh5uegwW0b59+y+++ML0uFu3bh9//PEtG3z33Xc9evSweV3aJMtyeHj4unXrTI8bNGjw448/3rLNCy+8MHbsWNPjiRMnjhw50tZVald+fr67u3tqairnvLi42MvLKykp6ZZtnnnmmWnTpqlRnfaZDt0ffvhh796977jB8uXLmzRpoigK53z16tX16tUzPa4CB+sI73sR5a5du7p162barHv37ufPn09PT7dJadpXUVGxb9++uLg405dxcXE7d+68fbPMzMzZs2cvXLgwJyfHtgVqTXp6+rlz57p3705EjLFu3brdvsN37dp1398IVE1CQoKPj0+DBg2IyM3NrX379rt27brjZrNmzVqxYoX564GAOe57tN+5c2dcXJwgCEQUFxd34sSJKt8Sx8GC8L6ysrIqlz5ydnb29vbOyspStyTNyMnJURTF39/f9GVAQMDt+9bT07NZs2b5+fnr1q1r0KBBYmKizcvUjqysLC8vr8pxqYCAgMzMzNu3qfzA+/v7Z2dncyyRYSHZ2dk3r6N2x/0fGhoaGBiYn5//wQcftGjR4tq1a7atUddu/vB7eHi4ublV+Whvd0E4a9Ysw218fHzM/HaDwSDLcuWXFRUVTk5O1qlUm/71r3/dvv9jYmKIyLSmVOUw1R33bZ8+fZYuXTpt2rQ1a9aMHDly8uTJNq5fS4xG482DghUVFbcvq2YwGCq3kSTJYDCY/kCGh3f7weT2/f/6669//vnn77///r59+1xdXb/66ivb1qhrt/wDkSSpykd7uwvCiRMnSre5evWqmd9umsdhelxQUFBUVHT7zEa4hy+//PL2/f/nn38SUY0aNYxGY+XuzcjIuPeM0Hbt2mH6wMMIDg4uLi6unJF0xx0eEhJS2aZkZGSEhITYtERNCw4OzszMrOyw7/2BF0WxTZs2+MDb0s0f/tzc3PLy8iof7e0uCKtm+/btBQUFRBQfH//LL78UFRUR0apVq2JiYjB931IYY3369Fm5ciURSZK0Zs2afv36EdH169e3bdtWXl5ORJXTRDnn69evx2z+hxEcHBwTE7Nq1SoiKioq2rRpk2mHFxQUbN++3bRNfHy86TdCRCtXroyPj1erWu1p1aqVKIqmXZ2RkbF///5HH32UiLKzs//44w/TNqWlpaYHJSUlW7duxQfe2jjn27ZtKywsJKL4+PgNGzaUlJQQ0apVq9q3b+/r61v1n+tAtm7d2rJly7CwME9Pz5YtW77++uum5xlju3fvNj0eOHBg06ZNR44cWb169c2bN6tXrAYlJSVVr1592LBhbdu2jY2NLSsr45yfO3eOiEx/O/fv379Lly4jRoxo3rx5RETEqVOn1C7Zsf32229+fn4jR45s2rTpwIEDTU/u3r2bMWZ6fOnSpaioqJ49e/bv379WrVoXL15Ur1gNWrhwob+//5gxYyIiIiZMmGB6cvHixZGRkabHQUFBffv2HT58eGhoaFxcnOlfBFjEpk2bvHv3jgAAAWZJREFUWrZsGRoa6u3t3bJlyylTpnDOKyoqiOjAgQOcc0VR+vbt27x585EjR/r5+e3YsaPKr+Vgd5+4evXqzScffH19w8PDiejgwYMNGjTw8PAgIs75zp07s7OzY2NjQ0NDVatVoy5durR9+/Zq1ap16dLFNGpYXl6enJwcHR1tNBqvXr164MCBvLy84ODgtm3bYoD24V28eHHPnj2BgYGdOnUyjf8VFRUdO3bskUceMW1QUlKyZcsWWZa7d++OO3Ra3IkTJxITE+vUqdOqVSvTM5cvX87KymrSpAkRpaenJyUllZWVRUZGtmjRQtVKtSYvL+/s2bOVX/r5+dWuXZuIDhw40KhRI9P9CBVF2bFjR25ubseOHR9mFMzBghAAAMCyNDJGCAAAUDUIQgAA0DUEIQAA6BqCEAAAdA1BCAAAuoYgBAAAXUMQAgCAriEIAQBA1xCEAACgawhCAADQNQQhAADo2v8DJhMMqV8JuGEAAAAASUVORK5CYII=",
"image/svg+xml": [
"\n",
"\n"
],
"text/html": [
"\n",
"\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"([0.9999999959286234, 0.9999999907475938], \"optimal\")"
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"NWTN(TF[6], printing=false, plotatend=true, Plotf=1)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ae61290b-22fa-493a-9b56-3a7458e3b3ed",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.9.4",
"language": "julia",
"name": "julia-1.9"
},
"language_info": {
"file_extension": ".jl",
"mimetype": "application/julia",
"name": "julia",
"version": "1.9.4"
}
},
"nbformat": 4,
"nbformat_minor": 5
}