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 | |
28 | const 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 | //======================================================================= |
38 | math_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 | //======================================================================= |
74 | void 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 | //======================================================================= |
102 | void 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 | //======================================================================= |
123 | math_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. |
132 | void 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 | //======================================================================= |
176 | Standard_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 | //======================================================================= |
238 | void 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 | //======================================================================= |
310 | Standard_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 | //======================================================================= |
326 | Standard_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 | //======================================================================= |
353 | Standard_Integer math_GlobOptMin::NbExtrema() |
354 | { |
355 | return mySolCount; |
356 | } |
357 | |
358 | //======================================================================= |
359 | //function : GetF |
360 | //purpose : |
361 | //======================================================================= |
362 | Standard_Real math_GlobOptMin::GetF() |
363 | { |
364 | return myF; |
365 | } |
366 | |
367 | //======================================================================= |
368 | //function : IsDone |
369 | //purpose : |
370 | //======================================================================= |
371 | Standard_Boolean math_GlobOptMin::isDone() |
372 | { |
373 | return myDone; |
374 | } |
375 | |
376 | //======================================================================= |
377 | //function : Points |
378 | //purpose : |
379 | //======================================================================= |
380 | void 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 | } |