Vous êtes sur la page 1sur 20

1

4. Minimisation/maximisation dune fonction


4.1. Introduction
A nouveau il sagit l dun problme frquemment rencontr en traitement numrique. En
guise de premire remarque, maximiser une fonction f revient minimiser la fonction f. On
ne considrera donc que le problme de minimisation dune fonction une ou plusieurs
variables.
La premire ide intuitive que lon peut avoir sur ce problme consiste remarquer que si la
fonction est minimale, alors sa drive (ou son gradient) est nulle (nul). On pourrait ainsi se
ramener au cas de la recherche des zros dune fonction ou dun systme non linaire.
Cependant, ce genre dapproche prsente quelques inconvnients :
annuler la drive ou le gradient ne permet pas de distinguer un maximum dun minimum,
cette approche ncessite la connaissance de la drive ou du gradient, ce qui nest pas
toujours possible,
dautre part, on na pas quivalence entre minimum local et zro de la drive ! ainsi, la
fonction f(x)=x
3
a une drive nulle en x=0, mais ne prsente pas pour autant de minimum
ou maximum local.
En outre, il est gnralement plus facile de recherche un minimum que dannuler un gradient.
En effet, les diffrentes composantes dun gradient ne sont pas indpendantes, elles satisfont
des critres dintgrabilit trs restrictifs. Or ce type de proprit ne peut pas tre prise en
compte dans un algorithme tel que celui de Newton-Raphson gnralis aux systmes non
linaires.
De faon gnrale, on peut distinguer deux situations diffrentes :
1. le premier cas de figure correspond une fonction dont la drive ou le gradient est
difficilement calculable,
2. le second cas de figure, gnralement plus favorable, correspond une fonction dont on
sait calculer efficacement (avec bonne prcision) la drive ou le gradient.
Les algorithmes seront gnralement plus efficaces sils disposent de la drive ou du gradient
de la fonction traite ; en effet, la possibilit de calculer la drive implique une meilleure
connaissance de la fonction et de ses proprits (par rapport au cas de figure o seule la
fonction est accessible numriquement). En revanche, il peut tre utile de se demander si le
gain est suffisant pour compenser le surcot en calcul.
Une chose viter : considrer que le gradient de la fonction est calculable, moyennant une
formule du type
( ) ( )
h
x h x x f x h x x f
x
f
n i n i
i
2
, , , , , , , ,
1 1
L L L L +

En effet, cette approximation est souvent dune prcision assez mdiocre ; le calcul du
gradient complet ncessite n+1 valuations de la fonction f, ce qui peut tre relativement long
en temps de calcul. Enfin, une formule de ce type est dlicate car elle doit choisir un pas h
adquat : ni trop grand (mathmatiquement, lestimation de la drive est alors plutt
mdiocre), ni trop petit (le problme dans ce cas est plutt numrique, le calcul de la fonction
2
f faisant mal voire pas du tout la diffrente entre x
i
+h et x
i
-h). Les critres de validit du
pas h dpendent beaucoup de la fonction, et du point en lequel on calcule la drive. Par
consquent, il est dlicat de dfinir un algorithme un peu gnral mettant en uvre ce genre
de technique.
4.2. Cas dune fonction une variable
Le cas de figure le plus simple est naturellement celui des fonctions une seule variable. Le
principe gnral de recherche dun minimum consiste en une mthode itrative par
encadrements successifs du minimum recherch.
Cette mthode sinspire de la dichotomie : partant dun encadrement initial du minimum, on
cherche rduire lintervalle dencadrement jusqu ce que lon puisse considrer que lon a
atteint le seuil de convergence.
Pour encadrer un zro, deux valeurs suffisent, sous rserve que la fonction change de signe.
Dans le cas dun minimum local, trois valeurs a, b et c sont ncessaires, satisfaisant les
conditions suivantes :
( ) ( ) ( ) ( ) c f b f a f b f c b a < < < < , ,
Par continuit de la fonction f, on a alors un minimum entre a et c. On choisit alors un point
intermdiaire x entre a et b, ou entre b et c.
Suivant la position de b par rapport x, et en fonction de ( ) b f par rapport ( ) x f , on doit
distinguer quatre cas de figures diffrents illustrs par les diagrammes ci-dessous.
On poursuit ainsi litration jusqu ce que lon ait atteint le seuil de convergence souhait,
savoir que la longueur de lintervalle dencadrement a c est suffisamment petite.
Le problme qui se pose ici est "Quentend-on par suffisamment petit ?". La premire rponse
que lon peut apporter cette question est < a c , o est la prcision de lordinateur
(10
-8
ou 10
-15
en simple ou double prcision). De manire gnrale, il est prfrable de faire
une comparaison en valeurs relatives plutt quen valeurs absolues : ( ) c a a c , max < .
Au voisinage de son minimum b, on peut crire par dveloppement de Taylor au second ordre
la fonction sous la forme
( ) ( ) ( )( )
2

2
1
b x b f b f x f +
Si lon veut que la fonction atteigne son minimum la prcision machine prs, on a :
( )( ) ( ) ( )
( )( ) ( )

'

<
<
0 si
2
1
0 si
2
1
2
2
b f b x b f
b f b f b x b f

soit encore
3
( ) ( ) b f x f >
a b c x
Intervalle courant :
c b a , ,
Nouvel intervalle :
x b a , ,
b x >
( ) ( ) b f x f <
a b c x
Intervalle courant :
c b a , ,
Nouvel intervalle :
c x b , ,
( ) ( ) b f x f >
a x c b
Intervalle courant :
c b a , ,
Nouvel intervalle :
c b x , ,
b x <
( ) ( ) b f x f <
a x c b
Intervalle courant :
c b a , ,
Nouvel intervalle :
b x a , ,
( )
( )
( )
( )
( )

'

<
<
0 si

2
0 si

2
b f
b f
b x
b f
b f
b f
b x

Plus gnralement, si k est le premier ordre de drive non nulle de la fonction, alors la
condition de convergence scrit :
4
( ) ( )
( )
( )
( )
( ) f b x
b x
k
b f
b f x f
k
k
k
fonction la de dpendant terme
!
<
+

On constate donc que le critre de convergence


par rapport aux valeurs de la fonction : varie en
par rapport aux valeurs de x : varie en
k

Autrement dit, il est inutile de chercher une prcision sur x meilleure que 10
-4
(simple
prcision) ou 10
-8
(double prcision) correspondant k=2.
Le problme qui subsiste maintenant est le choix du point intermdiaire x dans lintervalle
entre a et c. Parmi les diverses mthodes que lon peut trouver dans la litrature, on peut citer
la mthode de Brent, utilisant une interpolation parabolique.
Linterpolation parabolique consiste calculer les paramtres dune parabole passant par les
points (a,f(a)), (b,f(b)) et (c,f(c)), le point intermdiaire x correspondant au minimum de cette
parabole. On obtient par quelques calculs simples non dtaills ici la formulation suivante :
( ) ( ) ( ) ( ) ( ) ( ) ( ) ( )
( ) ( ) ( ) ( ) ( ) ( ) ( ) ( ) a f b f c b c f b f a b
a f b f c b c f b f a b
b x



2 2
2
1
Linconvnient de cette mthode est quelle doit garantir que le dnominateur reste
suffisamment grand afin de limiter les risques derreurs numriques (le dnominateur nul
correspond trois points aligns).
Dans le cadre de cette mthode, on peut galement considrer que b est une valuation
approche du minimum, et que le second terme de lexpression ci-dessus correspond un
terme correctif. On peut donc ajouter aux critres de convergences prcdents un test portant
sur la valeur de ce terme correctif : sil est assez faible, alors b ou x est la solution cherche.
Le programme ci-dessous donne un exemple d'implmentation de cette mthode.
#include <stdio.h>
#include <math.h>
#define EPS 1.0E-8
#define ZERO 1.0E-20
//-------------------------------------------------------------
// Calcul de x*x
//-------------------------------------------------------------
double sqr (double x)
{
return x*x;
}
//-------------------------------------------------------------
// Cette fonction modifie les 3 points courants a, b et c
// par rapport au nouveau point x
// La fonction modifie galement les valeurs des fonctions aux
// points courants
// ATTENTION : les interversions doivent se faire dans le bon
// ordre !
//-------------------------------------------------------------
void change_intervalle (double *a, double *b, double *c,
double *fa, double *fb, double *fc,
double x, double fx)
{
5
if (x>*b) {
if (fx>*fb) { *c=x; *fc=fx; }
else { *a=*b; *fa=*fb; *b=x; *fb=fx; }
}
else {
if (fx>*fb) { *a=x; *fa=fx; }
else { *c=*b; *fc=*fb; *b=x; *fb=fx; }
}
}
//-------------------------------------------------------------
// Cette fonction calcule le minimum encadr par les 3 points
// de rfrence a, b et c
// Elle retourne la valeur du minimum trouv, ainsi que la
// valeur de la fonction en ce point
//-------------------------------------------------------------
int brent (double a, double b, double c,
double (*f)(double),
double *xmin, double *fmin)
{
double n,d,fa,fb,fc,x,fx;
int ok=1,it=0;
// On vrifie que les points a, b et c satisfont les hypothses de base
if (b<=a || b>=c) return 0;
fa=f(a); fb=f(b); fc=f(c);
if (fb>=fa || fb>=fc) return 0;
// Boucle d'itration de la mthode de Brent
do {
it++;
n=sqr(b-a)*(fb-fc)-sqr(b-c)*(fb-fa);
d=(b-a)*(fc-fb)-(b-c)*(fa-fb);
if (fabs(d)<ZERO) {
if (fabs(n)<ZERO) x=b;
else ok=0;
break;
}
// x rsulte de l'interpolation parabolique
x=b+n/(2.0*d);
fx=f(x);
// x serait la solution cherche ?
if (fabs(b-x)<EPS*(fabs(b)+fabs(x))) break;
// nombre excessif d'itrations
if (it>100) {
ok=0;
break;
}
change_intervalle(&a,&b,&c,&fa,&fb,&fc,x,fx);
printf("iteration %d, x=%le\n",it,x);
} while (fabs(c-a)>EPS*(fabs(a)+fabs(c)));
// Si tout s'est bien pass, on doit avoir ok=1 !
if (ok) {
*xmin=x; *fmin=fx;
printf("brent : minimum x=%le, f(x)=%le\n",x,fx);
return 1;
}
else return 0;
}
//-------------------------------------------------------------
// f est la fonction minimiser
//-------------------------------------------------------------
double f (double x)
{
return x*(x*(x*(x-3)+10)-5)-5;
}
//-------------------------------------------------------------
// Programme principal
//-------------------------------------------------------------
main ()
{
6
double x,fx;
brent(-1.0,-0.5,2.0,f,&x,&fx);
return 0;
}
L'excution de ce programme fournit alors les affichages suivants :
iteration 1, x=4.555556e-01
iteration 2, x=3.496591e-01
iteration 3, x=3.043965e-01
iteration 4, x=2.903762e-01
iteration 5, x=2.844560e-01
iteration 6, x=2.824188e-01
iteration 7, x=2.815988e-01
iteration 8, x=2.813035e-01
iteration 9, x=2.811881e-01
iteration 10, x=2.811456e-01
iteration 11, x=2.811292e-01
iteration 12, x=2.811231e-01
iteration 13, x=2.811208e-01
iteration 14, x=2.811199e-01
iteration 15, x=2.811196e-01
iteration 16, x=2.811195e-01
iteration 17, x=2.811194e-01
iteration 18, x=2.811194e-01
iteration 19, x=2.811194e-01
brent : minimum x=2.811194e-01, f(x)=-5.675719e+00
4.3. Cas dune fonction plusieurs variables - la mthode de Powell
D'aprs ce qui prcde, on est en thorie capable de minimiser une fonction d'une variable. A
n dimensions, connaissant
la fonction
n
f : ,
un point
n
P donn,
une direction
n
u donne,
on peut dfinir une fonction g une variable unique par ( ) ( ) u P f g + . Dans ce cas, la
fonction g reprsente une coupe de la fonction f, suivant la direction u et passant par le point
P. On peut alors minimiser cette fonction en utilisant une mthode telle que celle dcrite
prcdemment.
L'ide de base de la mthode de Powell repose alors sur l'itration suivante :
on part d'un point P
0
et d'une direction donne u
0
,
par minimisation 1D suivant la direction u
0
, on obtient un point P
1
,
on change de direction pour regarder ce qui se passe suivant u
1
,
par itration, on cre ainsi P
2
, u
2
, jusqu' convergence de l'itration.
Dans l'implmentation de base de la mthode de Powell, les directions de base utilises sont
les vecteurs unitaires du repre ( )
n
e e e , , ,
2 1
L , d'o les tapes suivantes :
partant d'un point initial P
1
, on minimise la fonction ( ) ( )
1 1 1
e P f g + pour obtenir P
2
,
partant du point P
2
, on minimise la fonction ( ) ( )
2 2 2
e P f g + pour obtenir P
3
,
jusqu' convergence.
Au-del de n itrations (on a minimis suivant toutes les directions), on recommence le
processus avec e
1
, et ce autant de fois que ncessaire.
7
Le programme ci-dessous donne un exemple d'implmentation de la mthode de Powell pour
minimiser des fonctions deux variables. En pratique, il serait ncessaire d'adapter le
programme afin qu'il puisse tre utilisable avec n dimensions.
On notera une adaptation de la fonction brent prcdente : la fonction 1D utilise 2
paramtres, l'un correspondant au point de calcul et le second rfrenant (par le biais d'un
pointeur) une zone mmoire ou sont stockes des informations complmentaires (en
l'occurrence, fonction 2D minimiser, direction et point de dpart de minimisation) ; cela
vite l'utilisation de variables globales qui nuisent la lisibilit du programme.
D'autre part, cette implmentation utilise deux fonctions particulires, gaussiennes, la seconde
fonction tant identique la premire, mais tourne de 45 degrs. Cela permet alors de
comparer l'efficacit de la mthode entre diverses situations caractristiques.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define EPS 1.0E-8
#define ZERO 1.0E-20
//-------------------------------------------------------------
// Calcul de x*x
//-------------------------------------------------------------
double sqr (double x)
{
return x*x;
}
//-------------------------------------------------------------
// Cette fonction modifie les 3 points courants a, b et c
// par rapport au nouveau point x
// La fonction modifie galement les valeurs des fonctions aux
// points courants
// ATTENTION : les interversions doivent se faire dans le bon
// ordre !
//-------------------------------------------------------------
void change_intervalle (double *a, double *b, double *c,
double *fa, double *fb, double *fc,
double x, double fx)
{
if (x>*b) {
if (fx>*fb) { *c=x; *fc=fx; }
else { *a=*b; *fa=*fb; *b=x; *fb=fx; }
}
else {
if (fx>*fb) { *a=x; *fa=fx; }
else { *c=*b; *fc=*fb; *b=x; *fb=fx; }
}
}
//-------------------------------------------------------------
// Cette fonction calcule le minimum encadr par les 3 points
// de rfrence a, b et c
// Elle retourne la valeur du minimum trouv, ainsi que la
// valeur de la fonction en ce point
// On utilise ici une version un peu modifie de la mthode de
// Brent : la fonction reoit 2 paramtres (le point de calcul
// et un pointeur rfrenant des donnes utilises par la
// fonction ; cela vite d'utiliser des variables globales !
//-------------------------------------------------------------
int brent2 (double a, double b, double c,
double (*f)(double, void *),
void *fbuffer,
double *xmin, double *fmin)
{
8
double n,d,fa,fb,fc,x,fx;
int ok=1,it=0;
if (b<=a || b>=c) return 0;
fa=f(a,fbuffer); fb=f(b,fbuffer); fc=f(c,fbuffer);
if (fb>=fa || fb>=fc) return 0;
do {
it++;
n=sqr(b-a)*(fb-fc)-sqr(b-c)*(fb-fa);
d=(b-a)*(fc-fb)-(b-c)*(fa-fb);
if (fabs(d)<ZERO) {
if (fabs(n)<ZERO) x=b;
else ok=0;
break;
}
x=b+n/(2.0*d);
fx=f(x,fbuffer);
if (fabs(b-x)<EPS*(fabs(b)+fabs(x))) break;
if (it>100) {
ok=0;
break;
}
change_intervalle(&a,&b,&c,&fa,&fb,&fc,x,fx);
} while (fabs(c-a)>EPS*(fabs(c)+fabs(a)));
if (ok) {
*xmin=x;
*fmin=fx;
return 1;
}
else return 0;
}
//-------------------------------------------------------------
// Dfinition d'une structure permettant de passer des
// paramtres la fonction 1D transmise l'algorithme Brent
//-------------------------------------------------------------
typedef struct {
double x0,y0;
double nx,ny;
double (*f2d)(double,double);
} FBUFFER;
//-------------------------------------------------------------
// La fonction 1D utilise la structure prcdente ; elle
// calcule f2d(x0+l*nx,y0+l*ny).
// Les diffrents champs de la structure FBUFFER permettent de
// dfinir :
// - le point de dpart (x0,y0)
// - la direction de minimisation (nx,ny)
// - la fonction f2d(x,y) minimiser
//-------------------------------------------------------------
double f1d (double l, void *fbuffer)
{
FBUFFER *buf=(FBUFFER *)fbuffer;
return buf->f2d(buf->x0+l*buf->nx,
buf->y0+l*buf->ny);
}
//-------------------------------------------------------------
// Minimisation 1D de la fonction f(x0+l*nx,y0+l*ny).
//-------------------------------------------------------------
void min1d (double x0, double y0,
double nx, double ny,
double (*f)(double,double),
double *x, double *y)
{
FBUFFER fbuffer;
double a,b,c,fa,fb,fc,l,fl;
// On construit la structure FBUFFER adapte
fbuffer.x0=x0; fbuffer.nx=nx;
fbuffer.y0=y0; fbuffer.ny=ny;
9
fbuffer.f2d=f;
// On recherche les points a, b et c encadrant le minimum
// Veiller viter des boucles infinies !
a=-1.0; b=0.0; c=1.0;
fa=f1d(a,(void *)&fbuffer);
fb=f1d(b,(void *)&fbuffer);
fc=f1d(c,(void *)&fbuffer);
while (fa<=fb) {
a-=1.0;
fa=f1d(a,(void *)&fbuffer);
}
while (fc<=fb) {
c+=1.0;
fc=f1d(c,(void *)&fbuffer);
}
// Minimisation par la mthode de Brent
brent2(a,b,c,f1d,(void *)&fbuffer,&l,&fl);
*x=x0+l*nx;
*y=y0+l*ny;
}
//-------------------------------------------------------------
// X0 et Y0 correspondent au premier point de l'itration
//-------------------------------------------------------------
#define X0 1.0
#define Y0 1.0
//-------------------------------------------------------------
// Minimisation 2D de la fonction f(x,y) - mthode de Powell
// Le paramtre 'rot' permet de contrler les directions de
// base utilises dans l'algorithme :
// rot=0 : on utilise les vecteurs de base standard
// rot=1 : on tourne ces 2 vecteurs de 45 degrs
//-------------------------------------------------------------
void min2d (double (*f)(double,double), int rot=0)
{
double x0=X0,y0=Y0,x1,y1,d;
double nx[]={1.0,0.0};
double ny[]={0.0,1.0};
int it=0,c=0;
// Calcul ventuel de la rotation de 45 degrs
if (rot) {
double sqrt2=1.0/sqrt(2.0);
nx[0]=sqrt2; nx[1]=sqrt2;
ny[0]=sqrt2; ny[1]=-sqrt2;
}
// Itration de Powell - c vaut alternativement 0 et 1, ce qui permet de
// passer d'un vecteur de base l'autre !
// Le paramtre 'd' quantifie l'volution due l'itration en cours
do {
printf("iteration %d, x=%lf y=%lf\n",++it,x0,y0);
min1d(x0,y0,nx[c],ny[c],f,&x1,&y1);
d=sqrt(sqr(x1-x0)+sqr(y1-y0));
c=1-c;
x0=x1; y0=y1;
} while (d>EPS || it<2);
}
//-------------------------------------------------------------
// Premire fonction minimiser
//-------------------------------------------------------------
double f1 (double x, double y)
{
x-=0.4321; y+=0.1234;
return 1.0-exp(-sqr(x))*exp(-10.0*sqr(y));
}
//-------------------------------------------------------------
// Deuxime fonction minimiser (c'est la mme fonction, mais
// tourne de 45 degrs)
//-------------------------------------------------------------
10
double f2 (double x, double y)
{
x-=0.4321; y+=0.1234;
return 1.0-exp(-sqr(x+y)/2.0)*exp(-5.0*sqr(x-y));
}
//-------------------------------------------------------------
// Programme principal
// On teste la mthode de Powell avec les fonctions f1 et f2
// avec ou sans rotation de 45 degrs.
//-------------------------------------------------------------
int main ()
{
printf("Minimisation de f1 :\n");
min2d(f1,0);
printf("\nMinimisation de f2 (sans rotation) :\n");
min2d(f2,0);
printf("\nMinimisation de f2 (avec rotation) :\n");
min2d(f2,1);
return 0;
}
Excutant ce programme, on obtient les affichages suivants :
Minimisation de f1 :
iteration 1, x=1.000000 y=1.000000
iteration 2, x=0.432100 y=1.000000
iteration 3, x=0.432100 y=-0.123400
iteration 4, x=0.432100 y=-0.123400
Minimisation de f2 (sans rotation) :
iteration 1, x=1.000000 y=1.000000
iteration 2, x=1.351245 y=1.000000
iteration 3, x=1.351245 y=0.628628
iteration 4, x=1.047396 y=0.628628
iteration 5, x=1.047396 y=0.380024
iteration 6, x=0.843992 y=0.380024
iteration 7, x=0.843992 y=0.213603
iteration 8, x=0.707829 y=0.213603
iteration 9, x=0.707829 y=0.102197
iteration 10, x=0.616679 y=0.102197
...
iteration 70, x=0.432101 y=-0.123399
iteration 71, x=0.432101 y=-0.123399
iteration 72, x=0.432101 y=-0.123399
iteration 73, x=0.432101 y=-0.123399
iteration 74, x=0.432100 y=-0.123399
iteration 75, x=0.432100 y=-0.123400
iteration 76, x=0.432100 y=-0.123400
Minimisation de f2 (avec rotation) :
iteration 1, x=1.000000 y=1.000000
iteration 2, x=0.154350 y=0.154350
iteration 3, x=0.432100 y=-0.123400
On constate ainsi que la minimisation de la premire fonction est trs rapide, ainsi que le
traitement de la seconde fonction avec des directions de base tournes de 45 degrs (les
directions de base sont alors adaptes la structure de base de la fonction).
En revanche, la minimisation de la seconde fonction avec les vecteurs unitaires de base sans
rotation converge trs lentement (76 itrations sont ici ncessaires !) ; ces directions ne sont
en fait pas ada ptes aux directions caractristiques de la fonction, de sorte que les
minimisations 1D successives progressent par petites tapes.
Cet exemple montre l'importance du choix des directions utilises dans une mthode
numrique telle que l'algorithme de Powell. Cependant, il n'est gnralement pas facile de
11
dterminer l'avance les directions devant assurer une convergence optimale. Pour cela, il est
indispensable d'tudier pralablement le comportement de la fonction minimiser.
Naturellement, le problme devient plus complexe encore avec des fonctions plus de 2
variables.
Le programme ci-dessous fournit un exemple d'extension de la mthode de Powell permettant
de prendre ce cas en considration.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <malloc.h>
#define EPS 1.0E-8
#define ZERO 1.0E-20
//-------------------------------------------------------------
// Calcul de x*x
//-------------------------------------------------------------
double sqr (double x)
{
return x*x;
}
//-------------------------------------------------------------
// Cette fonction modifie les 3 points courants a, b et c
// par rapport au nouveau point x
// La fonction modifie galement les valeurs des fonctions aux
// points courants
// ATTENTION : les interversions doivent se faire dans le bon
// ordre !
//-------------------------------------------------------------
void change_intervalle (double *a, double *b, double *c,
double *fa, double *fb, double *fc,
double x, double fx)
{
if (x>*b) {
if (fx>*fb) { *c=x; *fc=fx; }
else { *a=*b; *fa=*fb; *b=x; *fb=fx; }
}
else {
if (fx>*fb) { *a=x; *fa=fx; }
else { *c=*b; *fc=*fb; *b=x; *fb=fx; }
}
}
//-------------------------------------------------------------
// Cette fonction calcule le minimum encadr par les 3 points
// de rfrence a, b et c
// Elle retourne la valeur du minimum trouv, ainsi que la
// valeur de la fonction en ce point
// On utilise ici une version un peu modifie de la mthode de
// Brent : la fonction reoit 2 paramtres (le point de calcul
// et un pointeur rfrenant des donnes utilises par la
// fonction ; cela vite d'utiliser des variables globales !
//-------------------------------------------------------------
int brent2 (double a, double b, double c,
double (*f)(double, void *),
void *fbuffer,
double *xmin, double *fmin)
{
double n,d,fa,fb,fc,x,fx;
int ok=1,it=0;
if (b<=a || b>=c) return 0;
fa=f(a,fbuffer); fb=f(b,fbuffer); fc=f(c,fbuffer);
if (fb>=fa || fb>=fc) return 0;
do {
it++;
n=sqr(b-a)*(fb-fc)-sqr(b-c)*(fb-fa);
12
d=(b-a)*(fc-fb)-(b-c)*(fa-fb);
if (fabs(d)<ZERO) {
if (fabs(n)<ZERO) x=b;
else ok=0;
break;
}
x=b+n/(2.0*d);
fx=f(x,fbuffer);
if (fabs(b-x)<EPS*(fabs(b)+fabs(x))) break;
if (it>100) {
ok=0;
break;
}
change_intervalle(&a,&b,&c,&fa,&fb,&fc,x,fx);
} while (fabs(c-a)>EPS*(fabs(c)+fabs(a)));
if (ok) {
*xmin=x;
*fmin=fx;
return 1;
}
else return 0;
}
//-------------------------------------------------------------
// Dfinition d'une structure permettant de passer des
// paramtres la fonction 1D transmise l'algorithme Brent
//-------------------------------------------------------------
typedef struct {
double *p; // point initial
double *u; // direction de minimisation
double *x; // zone mmoire temporaire
double (*fnd)(double *, int N); // fonction minimiser
int N; // nombre de variables
} FBUFFER;
//-------------------------------------------------------------
// La fonction 1D utilise la structure prcdente ; elle
// calcule fnd(p+l*u,N).
// Les diffrents champs de la structure FBUFFER permettent de
// dfinir :
// - le point de dpart (p : tableau de N valeurs)
// - la direction de minimisation (u : tableau de N valeurs)
// - une zone temporaire (x : tableau de N valeurs)
// - la fonction fnd(...) minimiser
// - le nombre de variables
//-------------------------------------------------------------
double f1d (double l, void *fbuffer)
{
FBUFFER *buf=(FBUFFER *)fbuffer;
for (int i=0; i<buf->N; i++) buf->x[i]=buf->p[i]+l*buf->u[i];
return buf->fnd(buf->x,buf->N);
}
//-------------------------------------------------------------
// Minimisation 1D de la fonction f(p0+l*u0,N), rsultat
// renvoy dans le tableau x
//-------------------------------------------------------------
void min1d (double *p0, double *u0,
double (*f)(double *,int), int N,
double *x)
{
FBUFFER fbuffer;
double a,b,c,fa,fb,fc,l,fl;
int i;
fbuffer.p=(double *)malloc(N*3*sizeof(double));
fbuffer.u=fbuffer.p+N;
fbuffer.x=fbuffer.u+N;
for (i=0; i<N; i++) {
fbuffer.p[i]=p0[i];
fbuffer.u[i]=u0[i];
}
fbuffer.fnd=f;
13
fbuffer.N=N;
a=-1.0; b=0.0; c=1.0;
fa=f1d(a,(void *)&fbuffer);
fb=f1d(b,(void *)&fbuffer);
fc=f1d(c,(void *)&fbuffer);
while (fa<=fb) {
a-=1.0;
fa=f1d(a,(void *)&fbuffer);
}
while (fc<=fb) {
c+=1.0;
fc=f1d(c,(void *)&fbuffer);
}
brent2(a,b,c,f1d,(void *)&fbuffer,&l,&fl);
for (i=0; i<N; i++) x[i]=p0[i]+l*u0[i];
free((void *)fbuffer.p);
}
//-------------------------------------------------------------
// Fonction de calcul de la distance (norme euclidienne)
// sparant deux vecteurs d'un espace N dimensions
//-------------------------------------------------------------
double dist (double *x, double *y, int N)
{
double d=0.0;
for (int i=0; i<N; i++) d+=sqr(x[i]-y[i]);
return sqrt(d);
}
//-------------------------------------------------------------
// Minimisation nD de la fonction f(...) - mthode de Powell
// Ici, on utilise les directions de base du repre
// Le paramtre X0 correspond la solution approche initiale
//-------------------------------------------------------------
void powell (double *X0,
double (*f)(double *,int), int N)
{
double *x0,*x1,*n,d;
int i,it=0,c=0;
x0=(double *)malloc(N*3*sizeof(double));
x1=x0+N;
n=x1+N;
for (i=0; i<N; i++) x0[i]=X0[i];
do {
for (i=0; i<N; i++) n[i]=(double)(i==c);
if (++c==N) c=0;
min1d(x0,n,f,N,x1);
d=dist(x1,x0,N);
printf("iteration %d :\n",++it);
for (i=0; i<N; i++) {
printf(" %le\n",x1[i]);
x0[i]=x1[i];
}
} while (d>EPS || it<N);
free((void *)x0);
}
//-------------------------------------------------------------
// Fonction minimiser
//-------------------------------------------------------------
double f (double *X, int N)
{
double res=1.0;
for (int i=0; i<N; i++) res*=exp(-(i+1)*sqr(X[i]-1.0/(i+1))/10.0);
return 1.0-res;
}
14
//-------------------------------------------------------------
// Programme principal
//-------------------------------------------------------------
int main ()
{
int i,N;
double *X0;
printf("Nombre de variables : ");
scanf("%d",&N);
X0=(double *)malloc(N*sizeof(double));
for (i=0; i<N; i++) X0[i]=0.0;
powell(X0,f,N);
free((void *)X0);
return 0;
}
4.4. La mthode de la plus grande pente
Dans certains cas, il est possible de calculer la fonction ainsi que son gradient ; cette
information complmentaire peut alors utilement tre utilise pour amliorer la recherche de
minimum.
La premire approche consiste rechercher chaque tape de l'itration la direction de
descente maximale (ou plus grande pente).
Au voisinage d'un point X
r
, on peut crire au premier ordre
( ) ( ) ( ) X X X X X
r r r r r r
f f f + +
La direction X
r
est dite direction de descente si ( ) 0 < X X
r r r
f .
A module X
r
constant (assez petit pour rester dans l'approximation de Taylor du
premier ordre) on peut crire ( n
r
tant de norme 1)
( ) ( ) ( ) X n X X X
r r
r
r r r
f f f + +
La direction de la plus grande pente est alors donne par ( ) X n
r r
r
f .
La mthode de minimisation par la plus grande pente repose sur cette remarque et utilise
l'itration suivante :
on part d'un point initial
0
P
r
,
par minimisation 1D suivant la direction ( )
0
P
r r
f , on obtient un point
1
P
r
,
et ainsi de suite jusqu' convergence de l'itration.
Le programme est identique au prcdent implmentant la mthode de Powell ; la fonction
powell est remplace par la fonction steepest_descent, recevant un paramtre
supplmentaire permettant de spcifier la fonction de calcul du gradient.
15
//-------------------------------------------------------------
// Minimisation nD de la fonction f(...) - mthode de la plus
// grande pente. La fonction de calcul du gradient est df.
// Le paramtre X0 correspond la solution approche initiale
//-------------------------------------------------------------
void steepest_descent (double *X0,
double (*f)(double *, int),
void (*df)(double *, double *, int),
int N)
{
double *x0,*x1,*n,d;
int i,it=0;
x0=(double *)malloc(N*3*sizeof(double));
x1=x0+N;
n=x1+N;
for (i=0; i<N; i++) x0[i]=X0[i];
do {
df(x0,n,N);
min1d(x0,n,f,N,x1);
d=dist(x1,x0,N);
printf("iteration %d :\n",++it);
for (i=0; i<N; i++) {
printf(" %le\n",x1[i]);
x0[i]=x1[i];
}
} while (d>EPS || it<N);
free((void *)x0);
}
//-------------------------------------------------------------
// Fonction minimiser
//-------------------------------------------------------------
double f (double *X, int N)
{
double res=1.0;
for (int i=0; i<N; i++) res*=exp(-(i+1)*sqr(X[i]-1.0/(i+1))/10.0);
return 1.0-res;
}
//-------------------------------------------------------------
// Gradient de la fonction minimiser
//-------------------------------------------------------------
void df (double *X, double *DX, int N)
{
double r=(1.0-f(X,N))/5.0;
for (int i=0; i<N; i++) DX[i]=(X[i]*(i+1)-1.0)*r;
}
Si on excute ce programme avec une fonction 5 variables, on constate que la convergence
est assure avec 43 itrations.
4.5. La mthode du gradient conjugu
La mthde du gradient conjugu utilise un critre diffrent pour changer de direction
d'exploration, ce qui permet d'acclrer la convergence.
4.5.1. Dfinition de la direction conjugue
16
Par minimisation 1D suivant une direction donne u
r
, on suppose avoir obtenu un point P
r
.
Au point minimum, le gradient de la fonction est orthogonal la direction de minimisation :
( ) 0 P u
r r
r
f
Au voisinage du point P
r
, on peut crire par un dveloppement de Taylor au deuxime ordre
( ) ( ) ( ) ( ) P X X P X P X P
r r r r r r r r r
j i
ij
x x
f
A A f f f

+ + +
2

2
1
o A est la matrice des drives secondes. Par diffrentiation de cette relation, partant du point
P
r
suivant une direction v
r
, on verra un gradient de la forme ( ) v P
r
r r
A f + . Le choix optimal de
la direction v
r
(au sens o l'on ne pnalisera pas les calculs prcdents suivant la direction u
r
)
consiste assurer la relation
( ) ( ) 0 0 + u v v u v P u
r r r r r
r r
r
A A A f
Les directions u
r
et v
r
sont dites conjugues.
4.5.2. Application au calcul de minimum
Le calcul de minimum se fait toujours par itrations et de minimisations 1D, mais on va
veiller maintenir en permanence la condition de directions conjugues (les directions de
minimisation aux itrations i et i+1 sont conjugues).
On part d'un vecteur
0
g
r
arbitraire,
0 0
g h
r
r
. On cre ensuite deux squences de vecteurs
dfinis par
i i i i i i i i
A h g h h g g
r
r
r r
r r
+
+ + + 1 1 1

satisfaisant les conditions suivantes :

'


+
+
+
i i
i i
i i i
i i
i i
i i i
A
A
A
A
h h
h g
h h
h g
g g
g g
r r
r
r
r r
r
r
r r
r r
1
1
1
0
0

Cette squence permet ainsi de crer les vecteurs


i
g
r
dont chacun est orthogonal son
prcdesseur, ainsi que les vecteur
i
h
r
dont chacun est conjugu de son prdcesseur.
itration 0 : on a
0
g
r
et
0 0
g h
r
r

itration 1 : on a
1
g
r
et
1
h
r
tels que 0
0 1
g g
r r
et 0
0 1
h h
r r
A
Hypothse de rcurrence : j i A
i j i j
, 0 h h g g
r r
r r
.
17
On suppose cette rcurrence satisfaite n j i , . A l'itration n+1, on a alors

'



+
+
+
+ + +
0
0

1
1
1 1 1
n n
n n
n n n n n n n n
A
A
h h
g g
h g h h g g
r r
r r
r
r
r r
r r

Pour i<n :
( )
( ) 0
0
1 1
0
1 1
0
1
+


+
43 42 1
r r
43 42 1
r r r r r
r
r
r
r
8 7 6
r r r
r
r r r
n i i n n i n n i i i n
n i n n i n i n i n n n i n
A A A
A A A
h h h h h h h
h g h g g g g h g g g


( )
0
1
0
1
0
1 1
1
1
1
0
1 1 1

,
_

,
_


+ +
+ + +
+
+
+ + + +
3 2 1
r r
43 42 1
r r
r r
r
r
r
48 47 6
r r r
r
r r
r
r r
i n i n
i i
i i
n
i n i n n i n i n n n i n
A A A A A
g g g g
g g
g
h g h h h g h h g h h


Cela prouve en fait par rcurrence que les vecteurs
i
g
r
et
i
h
r
satisfont en ralit les conditions
suivantes :
i j i A
i j i ij
, , 0 h h g g
r r
r r
Le squence permet qinsi de gnrer une famille de vecteurs
i
g
r
deux deux orthogonaux, et
une famille de vecteurs
i
h
r
deux deux conjugus.
La condition de vecteurs conjugus nous a donn prcdemment
i i
i i
i
A
A
h h
h g
r r
r
r


+1

Or on peut galement crire


1 1
0
1 1 1
1
1 1
1 1
+ + + + +
+
+ +

,
_

,
_


i i
i
i i i i
i i
i i
i i i
A g g g g g g
g g
g h g
r r
3 2 1
r r r r
r r
r
r
r

et
( )
i i
i
i i i i
i i
i i
i
i i i i i i i i i i i i i
A A A A A
g g g g g g
g g
g
h g h h h g h h g h h
r r r r
3 2 1
r r
r r
r
r
r
48 47 6
r r r
r
r r
r
r r

,
_

,
_


+ +
+
+



1 1
0
1
1
0
1 1 1 1
18
de sorte que
i i
i i
i
g g
g g
r r
r r

+ + 1 1

De mme, on a
i i
i i
i
Ah g
g g
r
r
r r


avec
( )
i i i i i i i i i i i i i
A A A A A h h h h h h h h h h g
r r
43 42 1
r r r r r r r r
r


0
1 1 1 1

En outre, on a
( )
1 1 1 1
+ +
i i i i i i i i i i i
h g g g h g g h g
r
r r r
r
r r
r
r

et
( )
( ) ( ) 0
0
0 0 3 2 0 0 3 2
2 2 2 2
0
1 2 2 1 1

+ +


3 2 1
r r
L
r
r
L
r
r
r
r
8 7 6
r r
r
r r
r
r
g g h g
h g h g g g h g g h g
i i i i i i
i i i i i i i i i i i i i i


Il en rsulte que l'on a
i i i i
g g h g
r r
r
r
, soit encore
i i
i i
i i
i i
i
A A h h
h g
h h
g g
r r
r
r
r r
r r


Sous rserve de connatre la matrice A, on peut donc gnrer compltement la squence
i
,
i
,
i
g
r
et
i
h
r
. Aprs N (nombre de variables) minimisations successives suivant chaque
direction
i
h
r
, on doit parvenir au minimum recherch. En pratique, des itrations
supplmentaires seront gnralement requises, la fonction n'tant pas simplement quadratique.
La question qui se pose maintenant est la suivante : comment procder si l'on ne connat pas
la matrice des drives secondes A ? On utilise le principe suivant :
en un point
i
P
r
, on dfinit ( )
i i
f P g
r r
r

partant de
i
P
r
suivant la direction
i
h
r
, on recherche le minimum
1 + i
P
r
en
1 + i
P
r
, on dfinit ( )
1 1 + +

i i
f P g
r r
r
19
Compte tenu de la forme suppose quadratique de la fonction f, on peut montrer que cette
squence est la mme que celle prcdemment introduite et calcule partir de la matrice A. Il
n'est donc plus ncessaire de connatre la matrice des drives secondes.
Cette mthode numrique correspond l'algorithme du gradient conjugu (FRPR - Fletcher,
Reeves, Polak et Ribiere).
Le programme est identique ceux implmentant les mthodes de Powell et de la plus grande
pente ; la fonction steepest_descent est ici remplace par la fonction frprmn.
//-------------------------------------------------------------
// Fonction de calcul du produit scalaire de 2 vecteurs
// d'un espace N dimensions
//-------------------------------------------------------------
double ProduitScalaire (double *x, double *y, int N)
{
double p=0.0;
for (int i=0; i<N; i++) p+=x[i]*y[i];
return p;
}
//-------------------------------------------------------------
// Minimisation nD de la fonction f(...) - mthode FRPR
// Le paramtre X0 correspond la solution approche initiale
//-------------------------------------------------------------
void frprmn (double *X0,
double (*f)(double *, int),
void (*df)(double *, double *, int),
int N)
{
double gamma,*x0,*x1,*g1,*g2,*h1,*h2,d;
int i,it=0;
x0=(double *)malloc(N*6*sizeof(double));
x1=x0+N;
g1=x1+N;
g2=g1+N;
h1=g2+N;
h2=h1+N;
for (i=0; i<N; i++) x0[i]=X0[i];
df(x0,g1,N);
for (i=0; i<N; i++) h1[i]=g1[i];
do {
min1d(x0,h1,f,N,x1);
d=dist(x1,x0,N);
printf("iteration %d :\n",++it);
for (i=0; i<N; i++) {
printf(" %le\n",x1[i]);
x0[i]=x1[i];
}
df(x1,g2,N);
gamma=ProduitScalaire(g2,g2,N)/ProduitScalaire(g1,g1,N);
for (i=0; i<N; i++) h2[i]=g2[i]+gamma*h1[i];
for (i=0; i<N; i++) {
g1[i]=g2[i];
h1[i]=h2[i];
}
} while (d>EPS || it<N);
free((void *)x0);
}
20
Si on excute ce programme avec une fonction 5 variables, on constate que la convergence
est assure avec 20 itrations, l o 43 itrations taient requises avec la mthode de la plus
grande pente.