Files
opti-non-lin/OptiNonLin2026 DAOUST Alexandre.ipynb.json
2026-01-20 14:46:11 +00:00

416 lines
11 KiB
JSON

{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "541f3ecd",
"metadata": {},
"outputs": [],
"source": [
"# DAOUST Alexandre 242015"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "c68d497b",
"metadata": {},
"outputs": [],
"source": [
"import numpy as np"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "018d8af6",
"metadata": {},
"outputs": [],
"source": [
"def fct(x, nargout=2):\n",
" x1, x2 = x\n",
" \n",
" f = 2*x1**3 + 3*x2**3 + 2*x1**2 + 4*x2**2 + x1*x2 - 3*x1 - 2*x2\n",
" g = np.array([6*x1**2 + 4*x1 + x2 - 3,\n",
" 6*x2**2 + 8*x2 + x1 - 2])\n",
" if nargout==3:\n",
" H = np.array([[12*x1 + 4, 1 ],\n",
" [ 1, 12*x2 + 8]])\n",
" return f, g, H\n",
" return f, g"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "4ab88c2f",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"f = 19.0000\n",
"g = |28.0000|\n",
" |-2.0000|\n",
"H = |28.0000 1.0000|\n",
" |1.0000 -4.0000|\n",
"\n",
"f = 0.0000\n",
"g = |-3.0000|\n",
" |-2.0000|\n",
"H = |4.0000 1.0000|\n",
" |1.0000 8.0000|\n"
]
}
],
"source": [
"# Test de f en 2,-1\n",
"x = np.array([2.0, -1.0])\n",
"f, g, H = fct(x, nargout=3)\n",
"print(f\"f = {f:.4f}\")\n",
"print(f\"g = |{g[0]:.4f}|\\n |{g[1]:.4f}|\")\n",
"print(f\"H = |{H[0][0]:.4f} {H[0][1]:.4f}|\\n |{H[1][0]:.4f} {H[1][1]:.4f}|\")\n",
"print()\n",
"\n",
"# Test de f en 0,0\n",
"x = np.array([0.0, 0.0])\n",
"f, g, H = fct(x, nargout=3)\n",
"print(f\"f = {f:.4f}\")\n",
"print(f\"g = |{g[0]:.4f}|\\n |{g[1]:.4f}|\")\n",
"print(f\"H = |{H[0][0]:.4f} {H[0][1]:.4f}|\\n |{H[1][0]:.4f} {H[1][1]:.4f}|\")\n",
"# On a bien le bon résultat"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "958a11f2",
"metadata": {},
"outputs": [],
"source": [
"def CoordinateDescent(x0, maxiter=10):\n",
" # Formules calculées à la main selon x1 et x2 respectivement\n",
" # Elles correspondent à f(xi) = Somme(coeff*xi^n) + C (C constante reprennant le(s) xj!=xi actuel(s) et\n",
" # les autres constantes) qu'on dérive et qu'on optimise.\n",
" x = x0.copy()\n",
" n = len(x)\n",
" \n",
" for i in range(maxiter):\n",
" # Mise à jour de x1\n",
" delta = 4**2-4*6*(x[1]-3)\n",
" x[0] = (-4 + np.sqrt(delta))/12\n",
" \n",
" #Mise à jour de x2\n",
" delta = 8**2 - 4*6*(x[0]-2)\n",
" x[1] = (-8 + np.sqrt(delta))/12\n",
" return x"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "0b6c0173",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"x* = |0.4297|\n",
" |0.1737|\n",
"f = -0.8975\n",
"g = |-0.0000|\n",
" |-0.0000|\n",
"H = |9.1560 1.0000|\n",
" |1.0000 10.0840|\n",
"Valeurs propres:\n",
" 8.5176\n",
" 10.7224\n"
]
}
],
"source": [
"# Test de CoordinateDescent\n",
"\n",
"# On trouve bien un minimum car la gradient est nul (à une tolérance près) et la matrice hessienne est définie positive\n",
"# (on augmente f si on se déplace du point)\n",
"\n",
"x = np.array([2.0, -1.0])\n",
"x_opt = CoordinateDescent(x)\n",
"print(f\"x* = |{x_opt[0]:.4f}|\\n |{x_opt[1]:.4f}|\")\n",
"f, g, H = fct(x_opt, nargout=3)\n",
"print(f\"f = {f:.4f}\")\n",
"print(f\"g = |{g[0]:.4f}|\\n |{g[1]:.4f}|\")\n",
"print(f\"H = |{H[0][0]:.4f} {H[0][1]:.4f}|\\n |{H[1][0]:.4f} {H[1][1]:.4f}|\")\n",
"eigval, eigvec = np.linalg.eig(H)\n",
"print(f\"Valeurs propres:\\n {eigval[0]:.4f}\\n {eigval[1]:.4f}\")"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "230d6b8b",
"metadata": {},
"outputs": [],
"source": [
"def w1(fct, x, d, alpha, beta1):\n",
" f0, g0 = fct(x)\n",
" f1, g1 = fct(x + alpha*d)\n",
" return f1 <= f0 + alpha*beta1*(g0@d)\n",
"\n",
"def w2(fct, x, d, alpha, beta2):\n",
" f0, g0 = fct(x)\n",
" f1, g1 = fct(x + alpha*d)\n",
" return g1@d >= beta2*(g0@d)\n",
"\n",
"def wolfebissection(fct, x, d, alpha=1, beta1=0.0001, beta2=0.9):\n",
" alphal = 0\n",
" alphar = np.inf\n",
" \n",
" wf1 = False\n",
" wf2 = False\n",
" \n",
" # k pour ne pas boucler à l'infini\n",
" k = 0\n",
" \n",
" while not (wf1 and wf2) and k < 1e4:\n",
" wf1 = w1(fct, x, d, alpha, beta1)\n",
" wf2 = w2(fct, x, d, alpha, beta2)\n",
" \n",
" if not wf1:\n",
" alphar = alpha\n",
" alpha = (alphal + alphar)/2\n",
" \n",
" elif not wf2:\n",
" alphal = alpha\n",
" if alphar < np.inf:\n",
" alpha = (alphal + alphar)/2\n",
" else:\n",
" alpha *= 2\n",
" \n",
" k += 1\n",
" \n",
" return alpha"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "14f1cafd",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"alpha = 0.1250\n"
]
}
],
"source": [
"# Test de wolfebissection\n",
"x = np.array([0.0, 0.0])\n",
"d = np.array([3.0, 2.0])\n",
"alpha = wolfebissection(fct, x, d)\n",
"print(f\"alpha = {alpha:.4f}\")"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "2e390c95",
"metadata": {},
"outputs": [],
"source": [
"def MethGradient(x0, maxiter=10):\n",
" x = x0.copy()\n",
" \n",
" for k in range(maxiter):\n",
" f, g = fct(x)\n",
" d = -g\n",
" alpha = wolfebissection(fct, x, d)\n",
" x = x + alpha*d\n",
" \n",
" if np.linalg.norm(x) < 1e-9:\n",
" break\n",
" \n",
" return x"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "07f82a85",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"x* = |0.4291|\n",
" |0.1674|\n",
"f = -0.8978\n",
"g = |-0.0116|\n",
" |-0.0640|\n",
"H = |9.1490 1.0000|\n",
" |1.0000 10.0083|\n",
"Valeurs propres:\n",
" 8.4903\n",
" 10.6671\n"
]
}
],
"source": [
"# Test de MethGradient\n",
"\n",
"# La méthode du Gradient se raproche de la solution (x1 est correct, x2 est légèrement différent) mais n'y converge pas à cause\n",
"# du calcul du pas alpha qui ne donne pas le pas exact pour arriver au minimum (autrement dit, on n'arrive pas à calculer\n",
"# le pas alpha permettant de converger vers le minimum). Au plus on est proche, au plus le calcul d'un alpha admissible prend\n",
"# du temps.\n",
"\n",
"x = np.array([0.0, 0.0])\n",
"x_opt = MethGradient(x)\n",
"print(f\"x* = |{x_opt[0]:.4f}|\\n |{x_opt[1]:.4f}|\")\n",
"f, g, H = fct(x_opt, nargout=3)\n",
"print(f\"f = {f:.4f}\")\n",
"print(f\"g = |{g[0]:.4f}|\\n |{g[1]:.4f}|\")\n",
"print(f\"H = |{H[0][0]:.4f} {H[0][1]:.4f}|\\n |{H[1][0]:.4f} {H[1][1]:.4f}|\")\n",
"eigval, eigvec = np.linalg.eig(H)\n",
"print(f\"Valeurs propres:\\n {eigval[0]:.4f}\\n {eigval[1]:.4f}\")"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "1efec1bb",
"metadata": {},
"outputs": [],
"source": [
"def MethNewton(x0, maxiter=10):\n",
" x = x0.copy()\n",
" \n",
" for k in range(maxiter):\n",
" f, g, H = fct(x, nargout=3)\n",
" z = np.linalg.solve(H,g)\n",
" \n",
" x = x - z\n",
" \n",
" if np.linalg.norm(x) < 1e-9:\n",
" break\n",
" \n",
" return x"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "f151f070",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"x* = |-1.2757|\n",
" |-1.6619|\n",
"f = 5.6516\n",
"g = |0.0000|\n",
" |-0.0000|\n",
"H = |-11.3086 1.0000|\n",
" |1.0000 -11.9422|\n",
"Valeurs propres:\n",
" -10.5764\n",
" -12.6744\n"
]
}
],
"source": [
"# Test de MethNewton\n",
"\n",
"# La méthode de Newton est très sensible au point de départ, cela peut conduire (comme c'est le cas ici) à trouver un point\n",
"# qui n'est pas un minimum mais un maximum.\n",
"\n",
"x = np.array([-1.0, -1.0])\n",
"x_opt = MethNewton(x)\n",
"print(f\"x* = |{x_opt[0]:.4f}|\\n |{x_opt[1]:.4f}|\")\n",
"f, g, H = fct(x_opt, nargout=3)\n",
"print(f\"f = {f:.4f}\")\n",
"print(f\"g = |{g[0]:.4f}|\\n |{g[1]:.4f}|\")\n",
"print(f\"H = |{H[0][0]:.4f} {H[0][1]:.4f}|\\n |{H[1][0]:.4f} {H[1][1]:.4f}|\")\n",
"eigval, eigvec = np.linalg.eig(H)\n",
"print(f\"Valeurs propres:\\n {eigval[0]:.4f}\\n {eigval[1]:.4f}\")"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "b023fe44",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"x* = |0.4297|\n",
" |0.1737|\n",
"f = -0.8975\n",
"g = |0.0000|\n",
" |0.0000|\n",
"H = |9.1560 1.0000|\n",
" |1.0000 10.0840|\n",
"Valeurs propres:\n",
" 8.5176\n",
" 10.7224\n"
]
}
],
"source": [
"# Validation du point calculé par la CoordinateDescent (et par la MethGradient aussi)\n",
"\n",
"# On trouve bien un minimum car la gradient est nul (à une tolérance près) et la matrice hessienne est définie positive\n",
"# (on augmente f si on se déplace du point)\n",
"\n",
"x = np.array([0.0, 0.0])\n",
"x_opt = MethNewton(x)\n",
"print(f\"x* = |{x_opt[0]:.4f}|\\n |{x_opt[1]:.4f}|\")\n",
"f, g, H = fct(x_opt, nargout=3)\n",
"print(f\"f = {f:.4f}\")\n",
"print(f\"g = |{g[0]:.4f}|\\n |{g[1]:.4f}|\")\n",
"print(f\"H = |{H[0][0]:.4f} {H[0][1]:.4f}|\\n |{H[1][0]:.4f} {H[1][1]:.4f}|\")\n",
"eigval, eigvec = np.linalg.eig(H)\n",
"print(f\"Valeurs propres:\\n {eigval[0]:.4f}\\n {eigval[1]:.4f}\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e3b81f36",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.13"
}
},
"nbformat": 4,
"nbformat_minor": 5
}