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