0027371: Regression: BRepExtrema works too much slower in 691 (from 670)
[occt.git] / src / math / math_GlobOptMin.cxx
CommitLineData
4bbaf12b 1// Created on: 2014-01-20
2// Created by: Alexaner Malyshev
4b65fc77 3// Copyright (c) 2014-2015 OPEN CASCADE SAS
4bbaf12b 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>
4bbaf12b 24#include <Standard_Integer.hxx>
25#include <Standard_Real.hxx>
e8746a26 26#include <Precision.hxx>
4bbaf12b 27
246c7a75 28//=======================================================================
29//function : DistanceToBorder
30//purpose :
31//=======================================================================
32static Standard_Real DistanceToBorder(const math_Vector & theX,
33 const math_Vector & theMin,
34 const math_Vector & theMax)
35{
36 Standard_Real aDist = RealLast();
37
38 for (Standard_Integer anIdx = theMin.Lower(); anIdx <= theMin.Upper(); ++anIdx)
39 {
40 const Standard_Real aDist1 = Abs (theX(anIdx) - theMin(anIdx));
41 const Standard_Real aDist2 = Abs (theX(anIdx) - theMax(anIdx));
42
43 aDist = Min (aDist, Min (aDist1, aDist2));
44 }
45
46 return aDist;
47}
48
4bbaf12b 49
50//=======================================================================
51//function : math_GlobOptMin
52//purpose : Constructor
53//=======================================================================
54math_GlobOptMin::math_GlobOptMin(math_MultipleVarFunction* theFunc,
55 const math_Vector& theA,
56 const math_Vector& theB,
5493d334 57 const Standard_Real theC,
58 const Standard_Real theDiscretizationTol,
59 const Standard_Real theSameTol)
4bbaf12b 60: myN(theFunc->NbVariables()),
61 myA(1, myN),
62 myB(1, myN),
63 myGlobA(1, myN),
64 myGlobB(1, myN),
1907fb9a 65 myIsConstLocked(Standard_False),
4bbaf12b 66 myX(1, myN),
67 myTmp(1, myN),
5493d334 68 myV(1, myN),
3f733bb1 69 myMaxV(1, myN),
4b65fc77 70 myCellSize(0, myN - 1),
5333268d 71 myFilter(theFunc->NbVariables()),
72 myCont(2)
4bbaf12b 73{
74 Standard_Integer i;
75
76 myFunc = theFunc;
77 myC = theC;
1907fb9a 78 myInitC = theC;
78e7cada 79 myIsFindSingleSolution = Standard_False;
836d7b64 80 myFunctionalMinimalValue = -Precision::Infinite();
4bbaf12b 81 myZ = -1;
82 mySolCount = 0;
83
84 for(i = 1; i <= myN; i++)
85 {
86 myGlobA(i) = theA(i);
87 myGlobB(i) = theB(i);
88
89 myA(i) = theA(i);
90 myB(i) = theB(i);
91 }
92
5493d334 93 for(i = 1; i <= myN; i++)
94 {
95 myMaxV(i) = (myB(i) - myA(i)) / 3.0;
96 }
97
98 myTol = theDiscretizationTol;
99 mySameTol = theSameTol;
100
4b65fc77 101 const Standard_Integer aMaxSquareSearchSol = 200;
102 Standard_Integer aSolNb = Standard_Integer(Pow(3.0, Standard_Real(myN)));
103 myMinCellFilterSol = Max(2 * aSolNb, aMaxSquareSearchSol);
104 initCellSize();
1907fb9a 105 ComputeInitSol();
4b65fc77 106
4bbaf12b 107 myDone = Standard_False;
108}
109
110//=======================================================================
111//function : SetGlobalParams
1907fb9a 112//purpose : Set parameters without memory allocation.
4bbaf12b 113//=======================================================================
114void math_GlobOptMin::SetGlobalParams(math_MultipleVarFunction* theFunc,
115 const math_Vector& theA,
116 const math_Vector& theB,
5493d334 117 const Standard_Real theC,
118 const Standard_Real theDiscretizationTol,
119 const Standard_Real theSameTol)
4bbaf12b 120{
121 Standard_Integer i;
122
123 myFunc = theFunc;
124 myC = theC;
1907fb9a 125 myInitC = theC;
4bbaf12b 126 myZ = -1;
127 mySolCount = 0;
128
129 for(i = 1; i <= myN; i++)
130 {
131 myGlobA(i) = theA(i);
132 myGlobB(i) = theB(i);
133
134 myA(i) = theA(i);
135 myB(i) = theB(i);
136 }
137
3f733bb1 138 for(i = 1; i <= myN; i++)
139 {
140 myMaxV(i) = (myB(i) - myA(i)) / 3.0;
141 }
142
5493d334 143 myTol = theDiscretizationTol;
144 mySameTol = theSameTol;
145
4b65fc77 146 initCellSize();
1907fb9a 147 ComputeInitSol();
4b65fc77 148
4bbaf12b 149 myDone = Standard_False;
150}
151
152//=======================================================================
153//function : SetLocalParams
1907fb9a 154//purpose : Set parameters without memory allocation.
4bbaf12b 155//=======================================================================
156void math_GlobOptMin::SetLocalParams(const math_Vector& theLocalA,
157 const math_Vector& theLocalB)
158{
159 Standard_Integer i;
160
161 myZ = -1;
4bbaf12b 162 for(i = 1; i <= myN; i++)
163 {
164 myA(i) = theLocalA(i);
165 myB(i) = theLocalB(i);
166 }
167
5493d334 168 for(i = 1; i <= myN; i++)
169 {
170 myMaxV(i) = (myB(i) - myA(i)) / 3.0;
171 }
172
4bbaf12b 173 myDone = Standard_False;
174}
175
5493d334 176//=======================================================================
177//function : SetTol
178//purpose : Set algorithm tolerances.
179//=======================================================================
180void math_GlobOptMin::SetTol(const Standard_Real theDiscretizationTol,
181 const Standard_Real theSameTol)
182{
183 myTol = theDiscretizationTol;
184 mySameTol = theSameTol;
185}
186
187//=======================================================================
188//function : GetTol
189//purpose : Get algorithm tolerances.
190//=======================================================================
191void math_GlobOptMin::GetTol(Standard_Real& theDiscretizationTol,
192 Standard_Real& theSameTol)
193{
194 theDiscretizationTol = myTol;
195 theSameTol = mySameTol;
196}
197
4bbaf12b 198//=======================================================================
199//function : Perform
200//purpose : Compute Global extremum point
201//=======================================================================
202// In this algo indexes started from 1, not from 0.
78e7cada 203void math_GlobOptMin::Perform(const Standard_Boolean isFindSingleSolution)
4bbaf12b 204{
246c7a75 205 myDone = Standard_False;
4bbaf12b 206
207 // Compute parameters range
208 Standard_Real minLength = RealLast();
209 Standard_Real maxLength = RealFirst();
246c7a75 210 for(Standard_Integer i = 1; i <= myN; i++)
4bbaf12b 211 {
212 Standard_Real currentLength = myB(i) - myA(i);
213 if (currentLength < minLength)
214 minLength = currentLength;
215 if (currentLength > maxLength)
216 maxLength = currentLength;
246c7a75 217
218 myV(i) = 0.0;
4bbaf12b 219 }
220
e8746a26 221 if (minLength < Precision::PConfusion())
222 {
223 #ifdef OCCT_DEBUG
224 cout << "math_GlobOptMin::Perform(): Degenerated parameters space" << endl;
225 #endif
226
227 return;
228 }
229
1907fb9a 230 if (!myIsConstLocked)
231 {
232 // Compute initial value for myC.
233 computeInitialValues();
234 }
e8746a26 235
797d11c6 236 myE1 = minLength * myTol;
237 myE2 = maxLength * myTol;
78e7cada 238
239 myIsFindSingleSolution = isFindSingleSolution;
240 if (isFindSingleSolution)
241 {
1907fb9a 242 // Run local optimization if current value better than optimal.
78e7cada 243 myE3 = 0.0;
244 }
797d11c6 245 else
78e7cada 246 {
247 if (myC > 1.0)
248 myE3 = - maxLength * myTol / 4.0;
249 else
250 myE3 = - maxLength * myTol * myC / 4.0;
251 }
4bbaf12b 252
1907fb9a 253 // Search single solution and current solution in its neighborhood.
836d7b64 254 if (CheckFunctionalStopCriteria())
255 {
256 myDone = Standard_True;
257 return;
258 }
259
1907fb9a 260 myLastStep = 0.0;
4b65fc77 261 isFirstCellFilterInvoke = Standard_True;
4bbaf12b 262 computeGlobalExtremum(myN);
263
264 myDone = Standard_True;
4bbaf12b 265}
266
267//=======================================================================
268//function : computeLocalExtremum
269//purpose :
270//=======================================================================
271Standard_Boolean math_GlobOptMin::computeLocalExtremum(const math_Vector& thePnt,
272 Standard_Real& theVal,
273 math_Vector& theOutPnt)
274{
275 Standard_Integer i;
276
277 //Newton method
5333268d 278 if (myCont >= 2 &&
279 dynamic_cast<math_MultipleVarFunctionWithHessian*>(myFunc))
4bbaf12b 280 {
747f90db 281 math_MultipleVarFunctionWithHessian* aTmp =
4bbaf12b 282 dynamic_cast<math_MultipleVarFunctionWithHessian*> (myFunc);
747f90db 283 math_NewtonMinimum newtonMinimum(*aTmp);
91806b90 284 newtonMinimum.SetBoundary(myGlobA, myGlobB);
747f90db 285 newtonMinimum.Perform(*aTmp, thePnt);
859a47c3 286
4bbaf12b 287 if (newtonMinimum.IsDone())
288 {
289 newtonMinimum.Location(theOutPnt);
290 theVal = newtonMinimum.Minimum();
291 }
292 else return Standard_False;
293 } else
294
295 // BFGS method used.
5333268d 296 if (myCont >= 1 &&
297 dynamic_cast<math_MultipleVarFunctionWithGradient*>(myFunc))
4bbaf12b 298 {
747f90db 299 math_MultipleVarFunctionWithGradient* aTmp =
4bbaf12b 300 dynamic_cast<math_MultipleVarFunctionWithGradient*> (myFunc);
747f90db 301 math_BFGS bfgs(aTmp->NbVariables());
302 bfgs.Perform(*aTmp, thePnt);
4bbaf12b 303 if (bfgs.IsDone())
304 {
305 bfgs.Location(theOutPnt);
306 theVal = bfgs.Minimum();
307 }
308 else return Standard_False;
309 } else
310
311 // Powell method used.
312 if (dynamic_cast<math_MultipleVarFunction*>(myFunc))
313 {
314 math_Matrix m(1, myN, 1, myN, 0.0);
315 for(i = 1; i <= myN; i++)
316 m(1, 1) = 1.0;
317
859a47c3 318 math_Powell powell(*myFunc, 1e-10);
319 powell.Perform(*myFunc, thePnt, m);
4bbaf12b 320
321 if (powell.IsDone())
322 {
323 powell.Location(theOutPnt);
324 theVal = powell.Minimum();
325 }
326 else return Standard_False;
327 }
328
329 if (isInside(theOutPnt))
330 return Standard_True;
331 else
332 return Standard_False;
333}
334
797d11c6 335//=======================================================================
336//function : computeInitialValues
337//purpose :
338//=======================================================================
339void math_GlobOptMin::computeInitialValues()
340{
341 Standard_Integer i;
342 math_Vector aCurrPnt(1, myN);
343 math_Vector aBestPnt(1, myN);
e8746a26 344 math_Vector aParamStep(1, myN);
797d11c6 345 Standard_Real aCurrVal = RealLast();
797d11c6 346
1907fb9a 347 // Lipchitz const approximation.
e8746a26 348 Standard_Real aLipConst = 0.0, aPrevValDiag, aPrevValProj;
797d11c6 349 Standard_Integer aPntNb = 13;
e8746a26 350 myFunc->Value(myA, aPrevValDiag);
351 aPrevValProj = aPrevValDiag;
797d11c6 352 Standard_Real aStep = (myB - myA).Norm() / aPntNb;
e8746a26 353 aParamStep = (myB - myA) / aPntNb;
797d11c6 354 for(i = 1; i <= aPntNb; i++)
355 {
e8746a26 356 aCurrPnt = myA + aParamStep * i;
797d11c6 357
e8746a26 358 // Walk over diagonal.
359 myFunc->Value(aCurrPnt, aCurrVal);
360 aLipConst = Max (Abs(aCurrVal - aPrevValDiag), aLipConst);
361 aPrevValDiag = aCurrVal;
797d11c6 362
e8746a26 363 // Walk over diag in projected space aPnt(1) = myA(1) = const.
364 aCurrPnt(1) = myA(1);
365 myFunc->Value(aCurrPnt, aCurrVal);
366 aLipConst = Max (Abs(aCurrVal - aPrevValProj), aLipConst);
367 aPrevValProj = aCurrVal;
797d11c6 368 }
e8746a26 369
1907fb9a 370 myC = myInitC;
e8746a26 371 aLipConst *= Sqrt(myN) / aStep;
797d11c6 372 if (aLipConst < myC * 0.1)
797d11c6 373 myC = Max(aLipConst * 0.1, 0.01);
1907fb9a 374 else if (aLipConst > myC * 5)
375 myC = Min(myC * 5, 50.0);
376
377 // Clear all solutions except one.
378 if (myY.Size() != myN)
797d11c6 379 {
1907fb9a 380 for(i = 1; i <= myN; i++)
381 aBestPnt(i) = myY(i);
382 myY.Clear();
383 for(i = 1; i <= myN; i++)
384 myY.Append(aBestPnt(i));
797d11c6 385 }
1907fb9a 386 mySolCount = 1;
797d11c6 387}
388
4bbaf12b 389//=======================================================================
390//function : ComputeGlobalExtremum
391//purpose :
392//=======================================================================
393void math_GlobOptMin::computeGlobalExtremum(Standard_Integer j)
394{
395 Standard_Integer i;
246c7a75 396 Standard_Real d = RealLast(), aPrevVal; // Functional in original and moved points.
4bbaf12b 397 Standard_Real val = RealLast(); // Local extrema computed in moved point.
3f733bb1 398 Standard_Real aStepBestValue = RealLast();
3f733bb1 399 math_Vector aStepBestPoint(1, myN);
246c7a75 400 Standard_Boolean isInside = Standard_False,
401 isReached = Standard_False;
4bbaf12b 402
246c7a75 403 Standard_Real r1, r2, r;
1907fb9a 404
246c7a75 405 for(myX(j) = myA(j) + myE1; !isReached; myX(j) += myV(j))
4bbaf12b 406 {
407 if (myX(j) > myB(j))
debc95ee 408 {
4bbaf12b 409 myX(j) = myB(j);
debc95ee 410 isReached = Standard_True;
411 }
4bbaf12b 412
836d7b64 413 if (CheckFunctionalStopCriteria())
414 return; // Best possible value is obtained.
415
4bbaf12b 416 if (j == 1)
417 {
418 isInside = Standard_False;
246c7a75 419 aPrevVal = d;
4bbaf12b 420 myFunc->Value(myX, d);
246c7a75 421 r1 = (d + myZ * myC * myLastStep - myF) * myZ; // Evtushenko estimation.
422 r2 = ((d + aPrevVal - myC * myLastStep) * 0.5 - myF) * myZ; // Shubert / Piyavsky estimation.
423 r = Min(r1, r2);
4bbaf12b 424 if(r > myE3)
425 {
246c7a75 426 Standard_Real aSaveParam = myX(1);
427
428 // Piyavsky midpoint estimation.
429 Standard_Real aParam = (2 * myX(1) - myV(1) ) * 0.5 + (aPrevVal - d) * 0.5 / myC;
430 if (Precision::IsInfinite(aPrevVal))
431 aParam = myX(1) - myV(1) * 0.5; // Protection from upper dimension step.
432
433 myX(1) = aParam;
434 Standard_Real aVal = 0;
435 myFunc->Value(myX, aVal);
436 myX(1) = aSaveParam;
437
438 if ( (aVal < d && aVal < aPrevVal) ||
439 DistanceToBorder(myX, myA, myB) < myE1 ) // Condition optimization case near the border.
440 {
441 isInside = computeLocalExtremum(myX, val, myTmp);
442 }
4bbaf12b 443 }
3f733bb1 444 aStepBestValue = (isInside && (val < d))? val : d;
445 aStepBestPoint = (isInside && (val < d))? myTmp : myX;
4bbaf12b 446
78e7cada 447 // Solutions are close to each other
448 // and it is allowed to have more than one solution.
449 if (Abs(aStepBestValue - myF) < mySameTol * 0.01 &&
450 !myIsFindSingleSolution)
4bbaf12b 451 {
3f733bb1 452 if (!isStored(aStepBestPoint))
4bbaf12b 453 {
3f733bb1 454 if ((aStepBestValue - myF) * myZ > 0.0)
455 myF = aStepBestValue;
4bbaf12b 456 for(i = 1; i <= myN; i++)
3f733bb1 457 myY.Append(aStepBestPoint(i));
4bbaf12b 458 mySolCount++;
459 }
460 }
461
78e7cada 462 // New best solution:
463 // new point is out of (mySameTol * 0.01) surrounding or
464 // new point is better than old + single point search.
465 Standard_Real aFunctionalDelta = (aStepBestValue - myF) * myZ;
466 if (aFunctionalDelta > mySameTol * 0.01 ||
467 (aFunctionalDelta > 0.0 && myIsFindSingleSolution))
4bbaf12b 468 {
469 mySolCount = 0;
3f733bb1 470 myF = aStepBestValue;
4bbaf12b 471 myY.Clear();
472 for(i = 1; i <= myN; i++)
3f733bb1 473 myY.Append(aStepBestPoint(i));
4bbaf12b 474 mySolCount++;
4b65fc77 475
476 isFirstCellFilterInvoke = Standard_True;
4bbaf12b 477 }
478
836d7b64 479 if (CheckFunctionalStopCriteria())
480 return; // Best possible value is obtained.
481
1907fb9a 482 myV(1) = Min(myE2 + Abs(myF - d) / myC, myMaxV(1));
483 myLastStep = myV(1);
4bbaf12b 484 }
485 else
486 {
487 myV(j) = RealLast() / 2.0;
488 computeGlobalExtremum(j - 1);
3f733bb1 489
490 // Nullify steps on lower dimensions.
491 for(i = 1; i < j; i++)
492 myV(i) = 0.0;
4bbaf12b 493 }
3f733bb1 494 if (j < myN)
4bbaf12b 495 {
246c7a75 496 Standard_Real aUpperDimStep = Max(myV(j), myE2);
3f733bb1 497 if (myV(j + 1) > aUpperDimStep)
498 {
499 if (aUpperDimStep > myMaxV(j + 1)) // Case of too big step.
500 myV(j + 1) = myMaxV(j + 1);
501 else
502 myV(j + 1) = aUpperDimStep;
503 }
4bbaf12b 504 }
505 }
506}
507
508//=======================================================================
509//function : IsInside
510//purpose :
511//=======================================================================
512Standard_Boolean math_GlobOptMin::isInside(const math_Vector& thePnt)
513{
514 Standard_Integer i;
515
516 for(i = 1; i <= myN; i++)
517 {
518 if (thePnt(i) < myGlobA(i) || thePnt(i) > myGlobB(i))
519 return Standard_False;
520 }
521
522 return Standard_True;
523}
524//=======================================================================
525//function : IsStored
526//purpose :
527//=======================================================================
528Standard_Boolean math_GlobOptMin::isStored(const math_Vector& thePnt)
529{
530 Standard_Integer i,j;
531 Standard_Boolean isSame = Standard_True;
20a216fe 532 math_Vector aTol(1, myN);
533 aTol = (myB - myA) * mySameTol;
4bbaf12b 534
4b65fc77 535 // C1 * n^2 = C2 * 3^dim * n
536 if (mySolCount < myMinCellFilterSol)
4bbaf12b 537 {
4b65fc77 538 for(i = 0; i < mySolCount; i++)
4bbaf12b 539 {
4b65fc77 540 isSame = Standard_True;
541 for(j = 1; j <= myN; j++)
4bbaf12b 542 {
4b65fc77 543 if ((Abs(thePnt(j) - myY(i * myN + j))) > aTol(j))
544 {
545 isSame = Standard_False;
546 break;
547 }
4bbaf12b 548 }
4b65fc77 549 if (isSame == Standard_True)
550 return Standard_True;
4bbaf12b 551 }
4b65fc77 552 }
553 else
554 {
50bc8f96 555 NCollection_CellFilter_Inspector anInspector(myN, Precision::PConfusion());
4b65fc77 556 if (isFirstCellFilterInvoke)
557 {
558 myFilter.Reset(myCellSize);
4bbaf12b 559
4b65fc77 560 // Copy initial data into cell filter.
561 for(Standard_Integer aSolIdx = 0; aSolIdx < mySolCount; aSolIdx++)
562 {
563 math_Vector aVec(1, myN);
564 for(Standard_Integer aSolDim = 1; aSolDim <= myN; aSolDim++)
565 aVec(aSolDim) = myY(aSolIdx * myN + aSolDim);
566
567 myFilter.Add(aVec, aVec);
568 }
569 }
570
571 isFirstCellFilterInvoke = Standard_False;
572
573 math_Vector aLow(1, myN), anUp(1, myN);
574 anInspector.Shift(thePnt, myCellSize, aLow, anUp);
575
576 anInspector.ClearFind();
577 anInspector.SetCurrent(thePnt);
578 myFilter.Inspect(aLow, anUp, anInspector);
579 if (!anInspector.isFind())
580 {
581 // Point is out of close cells, add new one.
582 myFilter.Add(thePnt, thePnt);
583 }
4bbaf12b 584 }
585 return Standard_False;
586}
587
4bbaf12b 588//=======================================================================
589//function : Points
590//purpose :
591//=======================================================================
592void math_GlobOptMin::Points(const Standard_Integer theIndex, math_Vector& theSol)
593{
594 Standard_Integer j;
595
596 for(j = 1; j <= myN; j++)
597 theSol(j) = myY((theIndex - 1) * myN + j);
598}
4b65fc77 599
600//=======================================================================
601//function : initCellSize
602//purpose :
603//=======================================================================
604void math_GlobOptMin::initCellSize()
605{
606 for(Standard_Integer anIdx = 1; anIdx <= myN; anIdx++)
607 {
608 myCellSize(anIdx - 1) = (myGlobB(anIdx) - myGlobA(anIdx))
609 * Precision::PConfusion() / (2.0 * Sqrt(2.0));
610 }
611}
836d7b64 612
613//=======================================================================
614//function : CheckFunctionalStopCriteria
615//purpose :
616//=======================================================================
617Standard_Boolean math_GlobOptMin::CheckFunctionalStopCriteria()
618{
1907fb9a 619 // Search single solution and current solution in its neighborhood.
836d7b64 620 if (myIsFindSingleSolution &&
621 Abs (myF - myFunctionalMinimalValue) < mySameTol * 0.01)
622 return Standard_True;
623
624 return Standard_False;
625}
1907fb9a 626
627//=======================================================================
628//function : ComputeInitSol
629//purpose :
630//=======================================================================
631void math_GlobOptMin::ComputeInitSol()
632{
633 Standard_Real aCurrVal, aBestVal;
634 math_Vector aCurrPnt(1, myN);
635 math_Vector aBestPnt(1, myN);
636 math_Vector aParamStep(1, myN);
637 // Check functional value in midpoint, lower and upper border points and
638 // in each point try to perform local optimization.
639 aBestPnt = (myGlobA + myGlobB) * 0.5;
640 myFunc->Value(aBestPnt, aBestVal);
641
642 Standard_Integer i;
643 for(i = 1; i <= 3; i++)
644 {
645 aCurrPnt = myA + (myB - myA) * (i - 1) / 2.0;
646
647 if(computeLocalExtremum(aCurrPnt, aCurrVal, aCurrPnt))
648 {
649 // Local search tries to find better solution than current point.
650 if (aCurrVal < aBestVal)
651 {
652 aBestVal = aCurrVal;
653 aBestPnt = aCurrPnt;
654 }
655 }
656 }
657
658 myF = aBestVal;
659 myY.Clear();
660 for(i = 1; i <= myN; i++)
661 myY.Append(aBestPnt(i));
662 mySolCount = 1;
1907fb9a 663}