Skip to content

Commit 59f9b79

Browse files
committed
- added Newton's method for minimization
1 parent 2096259 commit 59f9b79

2 files changed

Lines changed: 307 additions & 0 deletions

File tree

examples/Newton_minimization.html

Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
<!doctype html>
2+
<html class="no-js" lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<style>
6+
body {font-family: Helvetica, sans-serif;}
7+
table {background-color:#CCDDEE;text-align:left}
8+
</style>
9+
<script type="text/x-mathjax-config">
10+
MathJax.Hub.Config({
11+
extensions: ["tex2jax.js"],
12+
jax: ["input/TeX", "output/HTML-CSS"],
13+
tex2jax: {
14+
inlineMath: [ ['$','$'], ["\\(","\\)"] ],
15+
displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
16+
processEscapes: true
17+
},
18+
"HTML-CSS": { fonts: ["TeX"] }
19+
});
20+
</script>
21+
<script type="text/javascript" aync src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/MathJax.js"></script>
22+
<script src="https://cdn.plot.ly/plotly-2.5.1.min.js"></script>
23+
<title>Newton's method for minimization</title>
24+
</head>
25+
<body>
26+
<main>
27+
<h1 style="text-align:center">Newton's method for minimization</h1>
28+
<table style="align_center;border-radius: 20px;padding: 20px;margin:auto">
29+
<col width="1000">
30+
<tr>
31+
<td>
32+
<div id="plotOutput" style="width: 1000px; height: 600px;border:2px solid #000000;border-radius: 0px;background-color:#EEEEEE"></div>
33+
</td>
34+
</tr>
35+
<tr>
36+
<td><table style="margin:20px">
37+
<col width="200" style="padding-right:10px">
38+
<col width="100">
39+
<tr>
40+
<td><label for="newton_steps">Newton steps</label></td>
41+
<td><input type="text" id="textInput" value="1" readonly></td>
42+
</tr>
43+
<tr>
44+
<td></td>
45+
<td><input onchange="document.getElementById('textInput').value=this.value;plot.reset()" id="newton_steps" value="1" type="range" min="1" max="50" step="1"></td>
46+
</tr>
47+
<tr>
48+
<td><label for="fct">Function</label></td>
49+
<td><select onchange="plot.reset()" id="fct" size="1">
50+
<option selected="selected">Quartic function</option>
51+
<option>Sinusoidal function</option>
52+
<option>Exponential function</option>
53+
<option>Logarithmic function</option>
54+
</select>
55+
</td>
56+
</tr>
57+
</table></td>
58+
</tr>
59+
60+
<tr><td>
61+
<h2>Newton's method for minimization</h2>
62+
63+
<p>Newton's method can be used to find the minimum of a function $f(x)$. At a minimum the derivative vanishes, $f'(x^*) = 0$, so minimization reduces to finding the root of $f'(x)$.</p>
64+
65+
<p>At each iterate $x_n$ a quadratic (second-order Taylor) approximation is formed:</p>
66+
$$q(x) = f(x_n) + f'(x_n)(x-x_n) + \frac{1}{2}f''(x_n)(x-x_n)^2$$
67+
<p>The next iterate $x_{n+1}$ is the minimizer of $q(x)$, giving the update rule:</p>
68+
$$\begin{equation*}
69+
x_{n+1} = x_{n} - \frac{f'(x_n)}{f''(x_n)}
70+
\end{equation*}$$
71+
<p>The green curves show the quadratic approximation at each step. Provided $f''(x_n) > 0$ and $x_0$ is close enough to a local minimum, the method converges rapidly.</p>
72+
</td></tr>
73+
</table>
74+
75+
</main>
76+
77+
<script id="simulation_code" type="text/javascript">
78+
class Plot
79+
{
80+
constructor()
81+
{
82+
this.reset();
83+
this.num_newton_steps = 1;
84+
}
85+
86+
reset()
87+
{
88+
this.num_newton_steps = parseInt(document.getElementById('newton_steps').value);
89+
this.fct = document.getElementById('fct').value;
90+
this.plotFunctions();
91+
}
92+
93+
// f(x) = x^4 - 4x^2 + 2 (two minima at x = ±√2 ≈ ±1.414)
94+
quartic_function(x)
95+
{
96+
return x*x*x*x - 4*x*x + 2;
97+
}
98+
grad_quartic_function(x)
99+
{
100+
return 4*x*x*x - 8*x;
101+
}
102+
hess_quartic_function(x)
103+
{
104+
return 12*x*x - 8;
105+
}
106+
107+
// f(x) = 0.5x^2 + 2sin(x) (local minimum near x ≈ -1.03)
108+
sinusoidal_function(x)
109+
{
110+
return 0.5*x*x + 2*Math.sin(x);
111+
}
112+
grad_sinusoidal_function(x)
113+
{
114+
return x + 2*Math.cos(x);
115+
}
116+
hess_sinusoidal_function(x)
117+
{
118+
return 1 - 2*Math.sin(x);
119+
}
120+
121+
// f(x) = exp(x) - 3x (minimum at x = ln 3 ≈ 1.099)
122+
exponential_function(x)
123+
{
124+
return Math.exp(x) - 3*x;
125+
}
126+
grad_exponential_function(x)
127+
{
128+
return Math.exp(x) - 3;
129+
}
130+
hess_exponential_function(x)
131+
{
132+
return Math.exp(x);
133+
}
134+
135+
// f(x) = x²/2 - 3·ln(x+4) (minimum at x = -2+√7 ≈ 0.646)
136+
// Strictly convex; the log term makes the quadratic approximations
137+
// visibly different from the true curve.
138+
logarithmic_function(x)
139+
{
140+
return 0.5*x*x - 3*Math.log(x + 4);
141+
}
142+
grad_logarithmic_function(x)
143+
{
144+
return x - 3/(x + 4);
145+
}
146+
hess_logarithmic_function(x)
147+
{
148+
return 1 + 3/((x + 4)*(x + 4));
149+
}
150+
151+
newton_step(grad_f, hess_f, x)
152+
{
153+
const h = hess_f(x);
154+
if (Math.abs(h) < 1e-10)
155+
return x;
156+
return x - grad_f(x) / h;
157+
}
158+
159+
computeData(fct, grad_fct, hess_fct, x0, data)
160+
{
161+
let xValues = [];
162+
let yValues = [];
163+
164+
let x = -3;
165+
let num_steps = 5000;
166+
for (let i = 0; i <= num_steps; i++)
167+
{
168+
xValues.push(x);
169+
yValues.push(fct(x));
170+
x += 6 / num_steps;
171+
}
172+
173+
// Collect Newton iterates: x_0, x_1, ..., x_{num_newton_steps}
174+
let iterates = [x0];
175+
let current_x = x0;
176+
for (let i = 0; i < this.num_newton_steps; i++)
177+
{
178+
current_x = this.newton_step(grad_fct, hess_fct, current_x);
179+
iterates.push(current_x);
180+
}
181+
182+
// Main function trace
183+
data.push({
184+
x: xValues,
185+
y: yValues,
186+
name: "f(x)",
187+
showlegend: true,
188+
line: { color: 'rgb(31, 119, 180)', width: 2 }
189+
});
190+
191+
// For each Newton step: draw the local quadratic approximation and
192+
// a vertical dashed line marking the current iterate x_n
193+
for (let i = 0; i < this.num_newton_steps; i++)
194+
{
195+
const xn = iterates[i];
196+
const xn1 = iterates[i + 1];
197+
const fn = fct(xn);
198+
const gn = grad_fct(xn);
199+
const hn = hess_fct(xn);
200+
201+
// q(x) = f(xn) + f'(xn)(x-xn) + 0.5*f''(xn)(x-xn)^2
202+
// drawn over a range that covers both xn and xn1
203+
const lo = Math.min(xn, xn1) - 0.4;
204+
const hi = Math.max(xn, xn1) + 0.4;
205+
const qx = [], qy = [];
206+
for (let j = 0; j <= 200; j++)
207+
{
208+
const xq = lo + j * (hi - lo) / 200;
209+
const dx = xq - xn;
210+
qx.push(xq);
211+
qy.push(fn + gn * dx + 0.5 * hn * dx * dx);
212+
}
213+
data.push({
214+
x: qx,
215+
y: qy,
216+
line: { color: 'rgb(0, 150, 0)', width: 2 },
217+
name: "quadratic approx.",
218+
showlegend: i == 0
219+
});
220+
221+
// Vertical dashed line from x-axis up to f(x_n)
222+
data.push({
223+
type: 'line',
224+
x: [xn, xn],
225+
y: [0, fn],
226+
line: { color: 'rgb(0, 0, 0)', width: 2, dash: 'dash' },
227+
text: ["x_" + i.toString(), ""],
228+
textposition: "bottom center",
229+
mode: 'lines+markers+text',
230+
name: "x_n",
231+
showlegend: i == 0
232+
});
233+
}
234+
235+
// Vertical dashed line for the final iterate
236+
const xFinal = iterates[this.num_newton_steps];
237+
const fFinal = fct(xFinal);
238+
data.push({
239+
type: 'line',
240+
x: [xFinal, xFinal],
241+
y: [0, fFinal],
242+
line: { color: 'rgb(0, 0, 0)', width: 2, dash: 'dash' },
243+
text: ["x_" + this.num_newton_steps.toString(), ""],
244+
textposition: "bottom center",
245+
mode: 'lines+markers+text',
246+
name: "x_n",
247+
showlegend: false
248+
});
249+
}
250+
251+
plotFunctions()
252+
{
253+
var data = [];
254+
if (this.fct == "Quartic function")
255+
{
256+
this.computeData(
257+
this.quartic_function,
258+
this.grad_quartic_function,
259+
this.hess_quartic_function,
260+
2.5, data)
261+
}
262+
263+
if (this.fct == "Sinusoidal function")
264+
{
265+
this.computeData(
266+
this.sinusoidal_function,
267+
this.grad_sinusoidal_function,
268+
this.hess_sinusoidal_function,
269+
-2.5, data)
270+
}
271+
272+
if (this.fct == "Exponential function")
273+
{
274+
this.computeData(
275+
this.exponential_function,
276+
this.grad_exponential_function,
277+
this.hess_exponential_function,
278+
2.0, data)
279+
}
280+
281+
if (this.fct == "Logarithmic function")
282+
{
283+
this.computeData(
284+
this.logarithmic_function,
285+
this.grad_logarithmic_function,
286+
this.hess_logarithmic_function,
287+
-2.5, data)
288+
}
289+
290+
var layout = {
291+
title: "Minimization with Newton's method",
292+
width: 1000,
293+
height: 600
294+
};
295+
296+
Plotly.newPlot('plotOutput', data, layout);
297+
}
298+
299+
}
300+
301+
plot = new Plot();
302+
plot.reset();
303+
</script>
304+
305+
</body>
306+
</html>

index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ I hope the examples and their documentation help you to learn something about th
1111
# General
1212

1313
* [Newton's method](examples/Newton_solver.html)
14+
* [Newton's method for minimization](examples/Newton_minimization.html)
1415
* [Heat equation](examples/heat_equation.html)
1516

1617
# Particles

0 commit comments

Comments
 (0)