0024608: Development of methods of global optimization of multivariable function
[occt.git] / src / math / math_GlobOptMin.cxx
CommitLineData
4bbaf12b 1// Created on: 2014-01-20
2// Created by: Alexaner Malyshev
3// Copyright (c) 2014-2014 OPEN CASCADE SAS
4//
5// This file is part of Open CASCADE Technology software library.
6//
7// This library is free software; you can redistribute it and/or modify it under
8// the terms of the GNU Lesser General Public License version 2.1 as published
9// by the Free Software Foundation, with special exception defined in the file
10// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11// distribution for complete text of the license and disclaimer of any warranty.
12//
13// Alternatively, this file may be used under the terms of Open CASCADE
14// commercial license or contractual agreement
15
16#include <math_GlobOptMin.hxx>
17
18#include <math_BFGS.hxx>
19#include <math_Matrix.hxx>
20#include <math_MultipleVarFunctionWithGradient.hxx>
21#include <math_MultipleVarFunctionWithHessian.hxx>
22#include <math_NewtonMinimum.hxx>
23#include <math_Powell.hxx>
24#include <Precision.hxx>
25#include <Standard_Integer.hxx>
26#include <Standard_Real.hxx>
27
28const Handle(Standard_Type)& STANDARD_TYPE(math_GlobOptMin)
29{
30 static Handle(Standard_Type) _atype = new Standard_Type ("math_GlobOptMin", sizeof (math_GlobOptMin));
31 return _atype;
32}
33
34//=======================================================================
35//function : math_GlobOptMin
36//purpose : Constructor
37//=======================================================================
38math_GlobOptMin::math_GlobOptMin(math_MultipleVarFunction* theFunc,
39 const math_Vector& theA,
40 const math_Vector& theB,
41 Standard_Real theC)
42: myN(theFunc->NbVariables()),
43 myA(1, myN),
44 myB(1, myN),
45 myGlobA(1, myN),
46 myGlobB(1, myN),
47 myX(1, myN),
48 myTmp(1, myN),
49 myV(1, myN)
50{
51 Standard_Integer i;
52
53 myFunc = theFunc;
54 myC = theC;
55 myZ = -1;
56 mySolCount = 0;
57
58 for(i = 1; i <= myN; i++)
59 {
60 myGlobA(i) = theA(i);
61 myGlobB(i) = theB(i);
62
63 myA(i) = theA(i);
64 myB(i) = theB(i);
65 }
66
67 myDone = Standard_False;
68}
69
70//=======================================================================
71//function : SetGlobalParams
72//purpose : Set params without memory allocation.
73//=======================================================================
74void math_GlobOptMin::SetGlobalParams(math_MultipleVarFunction* theFunc,
75 const math_Vector& theA,
76 const math_Vector& theB,
77 Standard_Real theC)
78{
79 Standard_Integer i;
80
81 myFunc = theFunc;
82 myC = theC;
83 myZ = -1;
84 mySolCount = 0;
85
86 for(i = 1; i <= myN; i++)
87 {
88 myGlobA(i) = theA(i);
89 myGlobB(i) = theB(i);
90
91 myA(i) = theA(i);
92 myB(i) = theB(i);
93 }
94
95 myDone = Standard_False;
96}
97
98//=======================================================================
99//function : SetLocalParams
100//purpose : Set params without memory allocation.
101//=======================================================================
102void math_GlobOptMin::SetLocalParams(const math_Vector& theLocalA,
103 const math_Vector& theLocalB)
104{
105 Standard_Integer i;
106
107 myZ = -1;
108 mySolCount = 0;
109
110 for(i = 1; i <= myN; i++)
111 {
112 myA(i) = theLocalA(i);
113 myB(i) = theLocalB(i);
114 }
115
116 myDone = Standard_False;
117}
118
119//=======================================================================
120//function : ~math_GlobOptMin
121//purpose :
122//=======================================================================
123math_GlobOptMin::~math_GlobOptMin()
124{
125}
126
127//=======================================================================
128//function : Perform
129//purpose : Compute Global extremum point
130//=======================================================================
131// In this algo indexes started from 1, not from 0.
132void math_GlobOptMin::Perform()
133{
134 Standard_Integer i;
135
136 // Compute parameters range
137 Standard_Real minLength = RealLast();
138 Standard_Real maxLength = RealFirst();
139 for(i = 1; i <= myN; i++)
140 {
141 Standard_Real currentLength = myB(i) - myA(i);
142 if (currentLength < minLength)
143 minLength = currentLength;
144 if (currentLength > maxLength)
145 maxLength = currentLength;
146 }
147
148 Standard_Real myTol = 1e-2;
149
150 myE1 = minLength * myTol / myC;
151 myE2 = 2.0 * myTol / myC * maxLength;
152 myE3 = - maxLength * myTol / 4;
153
154 // Compure start point.
155 math_Vector aPnt(1,2);
156 for(i = 1; i <= myN; i++)
157 {
158 Standard_Real currCentral = (myA(i) + myB(i)) / 2.0;
159 aPnt(i) = currCentral;
160 myY.Append(currCentral);
161 }
162
163 myFunc->Value(aPnt, myF);
164 mySolCount++;
165
166 computeGlobalExtremum(myN);
167
168 myDone = Standard_True;
169
170}
171
172//=======================================================================
173//function : computeLocalExtremum
174//purpose :
175//=======================================================================
176Standard_Boolean math_GlobOptMin::computeLocalExtremum(const math_Vector& thePnt,
177 Standard_Real& theVal,
178 math_Vector& theOutPnt)
179{
180 Standard_Integer i;
181
182 //Newton method
183 if (dynamic_cast<math_MultipleVarFunctionWithHessian*>(myFunc))
184 {
185 math_MultipleVarFunctionWithHessian* myTmp =
186 dynamic_cast<math_MultipleVarFunctionWithHessian*> (myFunc);
187
188 math_NewtonMinimum newtonMinimum(*myTmp, thePnt);
189 if (newtonMinimum.IsDone())
190 {
191 newtonMinimum.Location(theOutPnt);
192 theVal = newtonMinimum.Minimum();
193 }
194 else return Standard_False;
195 } else
196
197 // BFGS method used.
198 if (dynamic_cast<math_MultipleVarFunctionWithGradient*>(myFunc))
199 {
200 math_MultipleVarFunctionWithGradient* myTmp =
201 dynamic_cast<math_MultipleVarFunctionWithGradient*> (myFunc);
202 math_BFGS bfgs(*myTmp, thePnt);
203 if (bfgs.IsDone())
204 {
205 bfgs.Location(theOutPnt);
206 theVal = bfgs.Minimum();
207 }
208 else return Standard_False;
209 } else
210
211 // Powell method used.
212 if (dynamic_cast<math_MultipleVarFunction*>(myFunc))
213 {
214 math_Matrix m(1, myN, 1, myN, 0.0);
215 for(i = 1; i <= myN; i++)
216 m(1, 1) = 1.0;
217
218 math_Powell powell(*myFunc, thePnt, m, 1e-10);
219
220 if (powell.IsDone())
221 {
222 powell.Location(theOutPnt);
223 theVal = powell.Minimum();
224 }
225 else return Standard_False;
226 }
227
228 if (isInside(theOutPnt))
229 return Standard_True;
230 else
231 return Standard_False;
232}
233
234//=======================================================================
235//function : ComputeGlobalExtremum
236//purpose :
237//=======================================================================
238void math_GlobOptMin::computeGlobalExtremum(Standard_Integer j)
239{
240 Standard_Integer i;
241 Standard_Real d; // Functional in moved point.
242 Standard_Real val = RealLast(); // Local extrema computed in moved point.
243 Standard_Real stepBestValue = RealLast();
244 math_Vector stepBestPoint(1,2);
245 Standard_Boolean isInside = Standard_False;
246 Standard_Real r;
247
248 for(myX(j) = myA(j) + myE1; myX(j) < myB(j) + myE1; myX(j) += myV(j))
249 {
250 if (myX(j) > myB(j))
251 myX(j) = myB(j);
252
253 if (j == 1)
254 {
255 isInside = Standard_False;
256 myFunc->Value(myX, d);
257 r = (d - myF) * myZ;
258 if(r > myE3)
259 {
260 isInside = computeLocalExtremum(myX, val, myTmp);
261 }
262 stepBestValue = (isInside && (val < d))? val : d;
263 stepBestPoint = (isInside && (val < d))? myTmp : myX;
264
265 // Solutions are close to each other.
266 if (Abs(stepBestValue - myF) < Precision::Confusion() * 0.01)
267 {
268 if (!isStored(stepBestPoint))
269 {
270 if ((stepBestValue - myF) * myZ > 0.0)
271 myF = stepBestValue;
272 for(i = 1; i <= myN; i++)
273 myY.Append(stepBestPoint(i));
274 mySolCount++;
275 }
276 }
277
278 // New best solution.
279 if ((stepBestValue - myF) * myZ > Precision::Confusion() * 0.01)
280 {
281 mySolCount = 0;
282 myF = stepBestValue;
283 myY.Clear();
284 for(i = 1; i <= myN; i++)
285 myY.Append(stepBestPoint(i));
286 mySolCount++;
287 }
288
289 myV(1) = myE2 + Abs(myF - d) / myC;
290 }
291 else
292 {
293 myV(j) = RealLast() / 2.0;
294 computeGlobalExtremum(j - 1);
295 }
296 if ((j < myN) && (myV(j + 1) > myV(j)))
297 {
298 if (myV(j) > (myB(j + 1) - myA(j + 1)) / 3.0) // Case of too big step.
299 myV(j + 1) = (myB(j + 1) - myA(j + 1)) / 3.0;
300 else
301 myV(j + 1) = myV(j);
302 }
303 }
304}
305
306//=======================================================================
307//function : IsInside
308//purpose :
309//=======================================================================
310Standard_Boolean math_GlobOptMin::isInside(const math_Vector& thePnt)
311{
312 Standard_Integer i;
313
314 for(i = 1; i <= myN; i++)
315 {
316 if (thePnt(i) < myGlobA(i) || thePnt(i) > myGlobB(i))
317 return Standard_False;
318 }
319
320 return Standard_True;
321}
322//=======================================================================
323//function : IsStored
324//purpose :
325//=======================================================================
326Standard_Boolean math_GlobOptMin::isStored(const math_Vector& thePnt)
327{
328 Standard_Integer i,j;
329 Standard_Boolean isSame = Standard_True;
330
331 for(i = 0; i < mySolCount; i++)
332 {
333 isSame = Standard_True;
334 for(j = 1; j <= myN; j++)
335 {
336 if ((Abs(thePnt(j) - myY(i * myN + j))) > (myB(j) - myA(j)) * Precision::Confusion())
337 {
338 isSame = Standard_False;
339 break;
340 }
341 }
342 if (isSame == Standard_True)
343 return Standard_True;
344
345 }
346 return Standard_False;
347}
348
349//=======================================================================
350//function : NbExtrema
351//purpose :
352//=======================================================================
353Standard_Integer math_GlobOptMin::NbExtrema()
354{
355 return mySolCount;
356}
357
358//=======================================================================
359//function : GetF
360//purpose :
361//=======================================================================
362Standard_Real math_GlobOptMin::GetF()
363{
364 return myF;
365}
366
367//=======================================================================
368//function : IsDone
369//purpose :
370//=======================================================================
371Standard_Boolean math_GlobOptMin::isDone()
372{
373 return myDone;
374}
375
376//=======================================================================
377//function : Points
378//purpose :
379//=======================================================================
380void math_GlobOptMin::Points(const Standard_Integer theIndex, math_Vector& theSol)
381{
382 Standard_Integer j;
383
384 for(j = 1; j <= myN; j++)
385 theSol(j) = myY((theIndex - 1) * myN + j);
386}