0025720: Incorrect code of math classes can lead to unpredicted behavior of algorithms
[occt.git] / src / math / math_Powell.cxx
1 // Copyright (c) 1997-1999 Matra Datavision
2 // Copyright (c) 1999-2014 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14
15 //#ifndef OCCT_DEBUG
16 #define No_Standard_RangeError
17 #define No_Standard_OutOfRange
18 #define No_Standard_DimensionError
19 //#endif
20
21 #include <math_Powell.ixx>
22 #include <math_BracketMinimum.hxx>
23 #include <math_BrentMinimum.hxx>
24 #include <math_Function.hxx>
25 #include <math_MultipleVarFunction.hxx>
26
27
28 namespace {
29 static inline Standard_Real SQR (const Standard_Real a)
30 {
31     return a * a;
32 }
33 }
34
35 class DirFunctionBis : public math_Function {
36
37   math_Vector *P0;
38   math_Vector *Dir;
39   math_Vector *P;
40   math_MultipleVarFunction *F;
41
42   public :
43     DirFunctionBis(math_Vector& V1,
44                 math_Vector& V2,
45                 math_Vector& V3,
46                 math_MultipleVarFunction& f);
47
48     void Initialize(const math_Vector& p0, const math_Vector& dir);
49
50     virtual Standard_Boolean Value(const Standard_Real x, Standard_Real& fval);
51 };
52
53  DirFunctionBis::DirFunctionBis(math_Vector& V1,
54                           math_Vector& V2,
55                           math_Vector& V3,
56                           math_MultipleVarFunction& f) {
57    P0 = &V1;
58    Dir = &V2;
59    P = &V3;
60    F = &f;
61  }
62
63
64 void DirFunctionBis::Initialize(const math_Vector& p0,
65                              const math_Vector& dir) {
66
67   *P0 = p0;
68   *Dir = dir;
69 }
70
71 Standard_Boolean DirFunctionBis::Value(const Standard_Real x, Standard_Real& fval) {
72   *P = *Dir;
73   P->Multiply(x);
74   P->Add(*P0);
75   F->Value(*P, fval);
76   return Standard_True;
77 }
78
79
80 static Standard_Boolean MinimizeDirection(math_Vector& P,
81                                  math_Vector& Dir,
82                                  Standard_Real& Result,
83                                  DirFunctionBis& F) {
84
85   Standard_Real ax;
86   Standard_Real xx;
87   Standard_Real bx;
88
89
90   F.Initialize(P, Dir);
91
92   math_BracketMinimum Bracket(F, 0.0, 1.0);
93   if (Bracket.IsDone()) {
94     Bracket.Values(ax, xx, bx);
95     math_BrentMinimum Sol(1.0e-10);
96     Sol.Perform(F, ax, xx, bx);
97     if (Sol.IsDone()) {
98       Standard_Real Scale = Sol.Location();
99       Result = Sol.Minimum();
100       Dir.Multiply(Scale);
101       P.Add(Dir);
102       return Standard_True;
103     }
104   }
105   return Standard_False;
106 }
107
108 //=======================================================================
109 //function : math_Powell
110 //purpose  : Constructor
111 //=======================================================================
112 math_Powell::math_Powell(const math_MultipleVarFunction& theFunction,
113                          const Standard_Real             theTolerance,
114                          const Standard_Integer          theNbIterations,
115                          const Standard_Real             theZEPS)
116 : TheLocation     (1, theFunction.NbVariables()),
117   TheMinimum      (RealLast()),
118   TheLocationError(RealLast()),
119   PreviousMinimum (RealLast()),
120   XTol            (theTolerance),
121   EPSZ            (theZEPS),
122   Done            (Standard_False),
123   Iter            (0),
124   TheStatus       (math_NotBracketed),
125   TheDirections   (1, theFunction.NbVariables(), 1, theFunction.NbVariables()),
126   State           (0),
127   Itermax         (theNbIterations)
128 {
129 }
130
131 //=======================================================================
132 //function : ~math_Powell
133 //purpose  : Destructor
134 //=======================================================================
135 math_Powell::~math_Powell()
136 {
137 }
138
139 //=======================================================================
140 //function : Perform
141 //purpose  : 
142 //=======================================================================
143 void math_Powell::Perform(math_MultipleVarFunction& F,
144                           const math_Vector& StartingPoint,
145                           const math_Matrix& StartingDirections)
146 {
147   Done = Standard_False;
148   Standard_Integer i, ibig, j;
149   Standard_Real t, fptt, del;
150   Standard_Integer n = TheLocation.Length();
151   math_Vector pt(1,n);
152   math_Vector ptt(1,n);
153   math_Vector xit(1,n);
154   math_Vector Temp1(1, n);
155   math_Vector Temp2(1, n);
156   math_Vector Temp3(1, n);
157   DirFunctionBis F_Dir(Temp1, Temp2, Temp3, F);
158
159   TheLocation = StartingPoint;
160   TheDirections = StartingDirections;
161   pt = TheLocation;  //sauvegarde du point initial
162
163
164   for(Iter = 1; Iter<= Itermax; Iter++) {
165     F.Value(TheLocation, PreviousMinimum);
166     ibig = 0;
167     del = 0.0;
168     for (i = 1; i <= n; i++){
169       for(j =1; j<= n; j++) xit(j) = TheDirections(j,i);
170       F.Value(TheLocation, fptt); 
171       Standard_Boolean IsGood = MinimizeDirection(TheLocation, xit, 
172                                          TheMinimum, F_Dir);
173
174       if (!IsGood) {
175         Done = Standard_False;
176         TheStatus = math_DirectionSearchError;
177         return;
178       }
179
180       if (fabs(fptt - TheMinimum)> del) {
181         del = fabs(fptt- TheMinimum);
182         ibig = i;
183       }
184     }
185
186     if (IsSolutionReached(F)) {
187       //Termination criterion
188       State = F.GetStateNumber();
189       Done = Standard_True;
190       TheStatus = math_OK;
191       return;
192     }
193
194     if (Iter == Itermax) {
195       Done = Standard_False;
196       TheStatus = math_TooManyIterations;
197       return;
198     }
199
200       ptt = 2.0 * TheLocation - pt;
201       xit = TheLocation - pt;
202       pt = TheLocation;
203     
204     // Valeur de la fonction au point extrapole:
205
206     F.Value(ptt, fptt);
207
208     if (fptt < PreviousMinimum) {
209       t = 2.0 *(PreviousMinimum -2.0*TheMinimum +fptt)*
210         SQR(PreviousMinimum-TheMinimum -del)-del*
211           SQR(PreviousMinimum-fptt);
212       if (t <0.0) {
213         //Minimisation along the direction
214         Standard_Boolean IsGood = MinimizeDirection(TheLocation, xit,
215                                            TheMinimum, F_Dir);
216         if(!IsGood) {
217           Done = Standard_False;
218           TheStatus = math_FunctionError;
219           return;
220         }
221         
222         for(j =1; j <= n; j++) {
223           TheDirections(j, ibig)=xit(j);
224         }
225       }
226     }
227   }
228 }
229
230 //=======================================================================
231 //function : Dump
232 //purpose  : 
233 //=======================================================================
234 void math_Powell::Dump(Standard_OStream& o) const
235 {
236   o << "math_Powell resolution:";
237   if(Done) {
238     o << " Status = Done \n";
239     o << " Location Vector = "<< TheLocation << "\n";
240     o << " Minimum value = " << TheMinimum <<"\n";
241     o << " Number of iterations = " << Iter <<"\n";
242   }
243   else {
244     o << " Status = not Done because " << (Standard_Integer)TheStatus << "\n";
245   }
246 }