1 // Copyright (c) 1997-1999 Matra Datavision
2 // Copyright (c) 1999-2014 OPEN CASCADE SAS
4 // This file is part of Open CASCADE Technology software library.
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.
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
15 // pmn 15/05/97 pas de Gauss avec des pivot trop petit. SVD fait mieux
16 // l'affaire + limitation de la longeur du pas + qq comentaire issus d'EUCLID3
17 // pmn 10/06/97 refonte totale du traitement des bords + ajustement des init
18 // et des tolerances pour brent...
21 #define No_Standard_RangeError
22 #define No_Standard_OutOfRange
23 #define No_Standard_DimensionError
26 //math_FunctionSetRoot.cxx
28 #include <math_BrentMinimum.hxx>
29 #include <math_Function.hxx>
30 #include <math_FunctionSetRoot.hxx>
31 #include <math_FunctionSetWithDerivatives.hxx>
32 #include <math_Gauss.hxx>
33 #include <math_GaussLeastSquare.hxx>
34 #include <math_IntegerVector.hxx>
35 #include <math_Matrix.hxx>
36 #include <math_SVD.hxx>
37 #include <Precision.hxx>
38 #include <Standard_DimensionError.hxx>
39 #include <StdFail_NotDone.hxx>
41 //===========================================================================
42 // - A partir d une solution de depart, recherche d une direction.( Newton la
43 // plupart du temps, gradient si Newton echoue.
44 // - Recadrage au niveau des bornes avec recalcul de la direction si une
45 // inconnue a une valeur imposee.
46 // -Si On ne sort pas des bornes
47 // Tant que (On ne progresse pas assez ou on ne change pas de direction)
48 // . Si (Progression encore possible)
49 // Si (On ne sort pas des bornes)
50 // On essaye de progresser dans cette meme direction.
52 // On diminue le pas d'avancement ou on change de direction.
54 // Si on depasse le minimum
55 // On fait une interpolation parabolique.
56 // - Si on a progresse sur F
57 // On fait les tests d'arret
59 // On change de direction
60 //============================================================================
61 #define FSR_DEBUG(arg)
62 // Uncomment the following code to have debug output to cout
63 //==========================================================
64 //static Standard_Boolean mydebug = Standard_True;
66 //#define FSR_DEBUG(arg) {if (mydebug) { std::cout << arg << std::endl; }}
67 //===========================================================
69 class MyDirFunction : public math_Function
76 math_FunctionSetWithDerivatives *F;
80 MyDirFunction(math_Vector& V1,
84 math_FunctionSetWithDerivatives& f) ;
86 void Initialize(const math_Vector& p0, const math_Vector& dir) const;
88 Standard_Boolean Value(const math_Vector& Sol, math_Vector& FF,
89 math_Matrix& DF, math_Vector& GH,
90 Standard_Real& F2, Standard_Real& Gnr1);
91 // Standard_Boolean MyDirFunction::Value(const math_Vector& Sol, math_Vector& FF,
92 // math_Matrix& DF, math_Vector& GH,
93 // Standard_Real& F2, Standard_Real& Gnr1);
94 Standard_Boolean Value(const Standard_Real x, Standard_Real& fval) ;
98 MyDirFunction::MyDirFunction(math_Vector& V1,
102 math_FunctionSetWithDerivatives& f) {
111 void MyDirFunction::Initialize(const math_Vector& p0,
112 const math_Vector& dir) const
119 Standard_Boolean MyDirFunction::Value(const Standard_Real x,
123 for(Standard_Integer i = P->Lower(); i <= P->Upper(); i++) {
125 P->Value(i) = p * x + P0->Value(i);
127 if( F->Value(*P, *FV) )
130 Standard_Real aVal = 0.0;
132 for(Standard_Integer i = FV->Lower(); i <= FV->Upper(); i++)
135 if(aVal <= -1.e+100) // Precision::HalfInfinite() later
136 return Standard_False;
137 else if(aVal >= 1.e+100) // Precision::HalfInfinite() later
138 return Standard_False;
141 fval = 0.5 * (FV->Norm2());
142 return Standard_True;
144 return Standard_False;
147 Standard_Boolean MyDirFunction::Value(const math_Vector& Sol,
154 if( F->Values(Sol, FF, DF) ) {
156 Standard_Real aVal = 0.;
158 for(Standard_Integer i = FF.Lower(); i <= FF.Upper(); i++) {
159 // modified by NIZHNY-MKK Mon Oct 3 17:56:50 2005.BEGIN
162 if(aVal <= -1.e+100) // Precision::HalfInfinite() later
163 // if(Precision::IsInfinite(Abs(FF.Value(i)))) {
164 // F2 = Precision::Infinite();
165 // Gnr1 = Precision::Infinite();
166 return Standard_False;
168 else if(aVal >= 1.e+100) // Precision::HalfInfinite() later
169 return Standard_False;
170 // modified by NIZHNY-MKK Mon Oct 3 17:57:05 2005.END
174 F2 = 0.5 * (FF.Norm2());
175 GH.TMultiply(DF, FF);
176 for(Standard_Integer i = GH.Lower(); i <= GH.Upper(); i++)
178 if(Precision::IsInfinite((GH.Value(i))))
180 return Standard_False;
184 return Standard_True;
186 return Standard_False;
190 //--------------------------------------------------------------
191 static Standard_Boolean MinimizeDirection(const math_Vector& P0,
192 const math_Vector& P1,
193 const math_Vector& P2,
194 const Standard_Real F1,
196 const math_Vector& Tol,
198 // Purpose : minimisation a partir de 3 points
199 //-------------------------------------------------------
201 // (1) Evaluation d'un tolerance parametrique 1D
202 Standard_Real tol1d = 2.1 , invnorme, tsol;
203 Standard_Real Eps = 1.e-16;
204 Standard_Real ax, bx, cx;
206 for (Standard_Integer ii =1; ii<=Tol.Length(); ii++) {
207 invnorme = Abs(Delta(ii));
208 if (invnorme>Eps) tol1d = Min(tol1d, Tol(ii) / invnorme);
210 if (tol1d > 1.9) return Standard_False; //Pas la peine de se fatiguer
214 const math_Vector& PP0 = P0 ;
215 const math_Vector& PP1 = P1 ;
218 invnorme = Delta.Norm();
219 if (invnorme <= Eps) return Standard_False;
220 invnorme = ((Standard_Real) 1) / invnorme;
222 F.Initialize(P1, Delta);
225 FSR_DEBUG (" minimisation dans la direction")
227 cx = (P2-P1).Norm()*invnorme;
229 return Standard_False;
231 math_BrentMinimum Sol(tol1d, 100, tol1d);
232 Sol.Perform(F, ax, bx, cx);
235 tsol = Sol.Location();
236 if (Sol.Minimum() < F1) {
237 Delta.Multiply(tsol);
238 return Standard_True;
241 return Standard_False;
244 //----------------------------------------------------------------------
245 static Standard_Boolean MinimizeDirection(const math_Vector& P,
247 const Standard_Real& PValue,
248 const Standard_Real& PDirValue,
249 const math_Vector& Gradient,
250 const math_Vector& DGradient,
251 const math_Vector& Tol,
253 // Purpose: minimisation a partir de 2 points et une derives
254 //----------------------------------------------------------------------
257 if(Precision::IsInfinite(PValue) || Precision::IsInfinite(PDirValue))
259 return Standard_False;
261 // (0) Evaluation d'un tolerance parametrique 1D
262 Standard_Boolean good = Standard_False;
263 Standard_Real Eps = 1.e-20;
264 Standard_Real tol1d = 1.1, Result = PValue, absdir;
266 for (Standard_Integer ii =1; ii<=Tol.Length(); ii++) {
267 absdir = Abs(Dir(ii));
268 if (absdir >Eps) tol1d = Min(tol1d, Tol(ii) / absdir);
270 if (tol1d > 0.9) return Standard_False;
272 // (1) On realise une premiere interpolation quadratique
273 Standard_Real ax, bx, cx, df1, df2, Delta, tsol, fsol, tsolbis;
274 FSR_DEBUG(" essai d interpolation");
279 if (df1<-Eps && df2>Eps) { // cuvette
280 tsol = - df1 / (df2 - df1);
285 ax = PDirValue - (bx+cx);
287 if (Abs(ax) <= Eps) { // cas lineaire
288 if ((Abs(bx) >= Eps)) tsol = - cx/bx;
291 else { // cas quadratique
292 Delta = bx*bx - 4*ax*cx;
294 // il y a des racines, on prend la plus proche de 0
296 tsol = -(bx + Delta);
297 tsolbis = (Delta - bx);
298 if (Abs(tsolbis) < Abs(tsol)) tsol = tsolbis;
302 // pas ou peu de racine : on "extremise"
308 if (Abs(tsol) >= 1) return Standard_False; //resultat sans interet
310 F.Initialize(P, Dir);
314 good = Standard_True;
316 FSR_DEBUG("t= "<<tsol<<" F = " << fsol << " OldF = "<<PValue);
319 // (2) Si l'on a pas assez progresser on realise une recherche
320 // en bonne et due forme, a partir des inits precedents
321 if ((fsol > 0.2*PValue) && (tol1d < 0.5))
325 ax = tsol; bx = 0.0; cx = 1.0;
328 ax = 0.0; bx = tsol; cx = 1.0;
330 FSR_DEBUG(" minimisation dans la direction");
332 math_BrentMinimum Sol(tol1d, 100, tol1d);
335 Sol.Perform(F, ax, bx, cx);
338 if (Sol.Minimum() <= Result)
340 tsol = Sol.Location();
341 good = Standard_True;
342 Result = Sol.Minimum();
344 // Objective function changes too fast ->
345 // perform additional computations.
346 if (Gradient.Norm2() > 1.0 / Precision::SquareConfusion() &&
348 tsol < cx) // Solution inside of (ax, cx) interval.
350 // First and second part invocation.
351 Sol.Perform(F, ax, (ax + tsol) / 2.0, tsol);
354 if (Sol.Minimum() <= Result)
356 tsol = Sol.Location();
357 good = Standard_True;
358 Result = Sol.Minimum();
362 Sol.Perform(F, tsol, (cx + tsol) / 2.0, cx);
365 if (Sol.Minimum() <= Result)
367 tsol = Sol.Location();
368 good = Standard_True;
369 Result = Sol.Minimum();
373 } // if (Sol.Minimum() <= Result)
374 } // if(Sol.IsDone())
379 // mise a jour du Delta
385 //------------------------------------------------------
386 static void SearchDirection(const math_Matrix& DF,
387 const math_Vector& GH,
388 const math_Vector& FF,
389 Standard_Boolean ChangeDirection,
390 const math_Vector& InvLengthMax,
391 math_Vector& Direction,
395 Standard_Integer Ninc = DF.ColNumber(), Neq = DF.RowNumber();
396 Standard_Real Eps = 1.e-32;
397 if (!ChangeDirection) {
399 for (Standard_Integer i = FF.Lower(); i <= FF.Upper(); i++) {
400 Direction(i) = -FF(i);
402 math_Gauss Solut(DF, 1.e-9);
403 if (Solut.IsDone()) Solut.Solve(Direction);
404 else { // we have to "forget" singular directions.
405 FSR_DEBUG(" Matrice singuliere : On prend SVD");
406 math_SVD SolvebySVD(DF);
407 if (SolvebySVD.IsDone()) SolvebySVD.Solve(-1*FF, Direction);
408 else ChangeDirection = Standard_True;
411 else if (Ninc > Neq) {
413 if (Solut.IsDone()) Solut.Solve(-1*FF, Direction);
414 else ChangeDirection = Standard_True;
416 else if (Ninc < Neq) { // Calcul par GaussLeastSquare
417 math_GaussLeastSquare Solut(DF);
418 if (Solut.IsDone()) Solut.Solve(-1*FF, Direction);
419 else ChangeDirection = Standard_True;
422 // Il vaut mieux interdire des directions trops longue
423 // Afin de blinder les cas trop mal conditionne
424 // PMN 12/05/97 Traitement des singularite dans les conges
425 // Sur des surfaces periodiques
427 Standard_Real ratio = Abs( Direction(Direction.Lower())
428 *InvLengthMax(Direction.Lower()) );
430 for (i = Direction.Lower()+1; i<=Direction.Upper(); i++) {
431 ratio = Max(ratio, Abs( Direction(i)*InvLengthMax(i)) );
438 if (Dy >= -Eps) { // newton "ne descend pas" on prend le gradient
439 ChangeDirection = Standard_True;
441 if (ChangeDirection) { // On va faire un gradient !
442 for (i = Direction.Lower(); i <= Direction.Upper(); i++) {
443 Direction(i) = - GH(i);
450 //=====================================================================
451 static void SearchDirection(const math_Matrix& DF,
452 const math_Vector& GH,
453 const math_Vector& FF,
454 const math_IntegerVector& Constraints,
455 // const math_Vector& X, // Le point d'init
456 const math_Vector& , // Le point d'init
457 Standard_Boolean ChangeDirection,
458 const math_Vector& InvLengthMax,
459 math_Vector& Direction,
461 //Purpose : Recherche une direction (et un pas si Newton Fonctionne) le long
463 //=====================================================================
465 Standard_Integer Ninc = DF.ColNumber(), Neq = DF.RowNumber();
466 Standard_Integer i, j, k, Cons = 0;
468 // verification sur les bornes imposees:
470 for (i = 1; i <= Ninc; i++) {
471 if (Constraints(i) != 0) Cons++;
472 // sinon le systeme a resoudre ne change pas.
476 SearchDirection(DF, GH, FF, ChangeDirection, InvLengthMax,
479 else if (Cons == Ninc) { // il n'y a plus rien a faire...
480 for(i = Direction.Lower(); i <= Direction.Upper(); i++) {
485 else { //(1) Cas general : On definit un sous probleme
486 math_Matrix DF2(1, Neq, 1, Ninc-Cons);
487 math_Vector MyGH(1, Ninc-Cons);
488 math_Vector MyDirection(1, Ninc-Cons);
489 math_Vector MyInvLengthMax(1, Ninc);
491 for (k=1, i = 1; i <= Ninc; i++) {
492 if (Constraints(i) == 0) {
494 MyInvLengthMax(k) = InvLengthMax(i);
495 MyDirection(k) = Direction(i);
496 for (j = 1; j <= Neq; j++) {
497 DF2(j, k) = DF(j, i);
499 k++; //on passe a l'inconnue suivante
503 SearchDirection(DF2, MyGH, FF, ChangeDirection, MyInvLengthMax,
506 // (3) On l'interprete...
507 // Reconstruction de Direction:
508 for (i = 1, k = 1; i <= Ninc; i++) {
509 if (Constraints(i) == 0) {
510 if (!ChangeDirection) {
511 Direction(i) = MyDirection(k);
513 else Direction(i) = - GH(i);
525 //====================================================
526 Standard_Boolean Bounds(const math_Vector& InfBound,
527 const math_Vector& SupBound,
528 const math_Vector& Tol,
530 const math_Vector& SolSave,
531 math_IntegerVector& Constraints,
533 Standard_Boolean& theIsNewSol)
535 // Purpose: Trims an initial solution Sol to be within a domain defined by
536 // InfBound and SupBound. Delta will contain a distance between final Sol and
538 // IsNewSol returns False, if final Sol fully coincides with SolSave, i.e.
539 // if SolSave already lied on a boundary and initial Sol was fully beyond it
540 //======================================================
542 Standard_Boolean Out = Standard_False;
543 Standard_Integer i, Ninc = Sol.Length();
544 Standard_Real monratio = 1;
546 theIsNewSol = Standard_True;
548 // Calcul du ratio de recadrage
549 for (i = 1; i <= Ninc; i++) {
551 Delta(i) = Sol(i) - SolSave(i);
552 if (InfBound(i) == SupBound(i)) {
554 Out = Standard_True; // Ok mais, cela devrait etre eviter
556 else if(Sol(i) < InfBound(i)) {
559 // Delta(i) is negative
560 if (-Delta(i) > Tol(i)) // Afin d'eviter des ratio nulles pour rien
561 monratio = Min(monratio, (InfBound(i) - SolSave(i))/Delta(i) );
563 else if (Sol(i) > SupBound(i)) {
566 // Delta(i) is positive
567 if (Delta(i) > Tol(i))
568 monratio = Min(monratio, (SupBound(i) - SolSave(i))/Delta(i) );
572 if (Out){ // Troncature et derniers recadrage pour blinder (pb numeriques)
573 if (monratio == 0.0) {
574 theIsNewSol = Standard_False;
580 for (i = 1; i <= Ninc; i++) {
581 if(Sol(i) < InfBound(i)) {
582 Sol(i) = InfBound(i);
583 Delta(i) = Sol(i) - SolSave(i);
585 else if (Sol(i) > SupBound(i)) {
586 Sol(i) = SupBound(i);
587 Delta(i) = Sol(i) - SolSave(i);
598 //=======================================================================
599 //function : math_FunctionSetRoot
600 //purpose : Constructor
601 //=======================================================================
602 math_FunctionSetRoot::math_FunctionSetRoot(
603 math_FunctionSetWithDerivatives& theFunction,
604 const math_Vector& theTolerance,
605 const Standard_Integer theNbIterations)
607 : Delta(1, theFunction.NbVariables()),
608 Sol (1, theFunction.NbVariables()),
609 DF (1, theFunction.NbEquations() , 1, theFunction.NbVariables()),
610 Tol (1, theFunction.NbVariables()),
611 Done (Standard_False),
614 Itermax (theNbIterations),
615 InfBound(1, theFunction.NbVariables(), RealFirst()),
616 SupBound(1, theFunction.NbVariables(), RealLast ()),
617 SolSave (1, theFunction.NbVariables()),
618 GH (1, theFunction.NbVariables()),
619 DH (1, theFunction.NbVariables()),
620 DHSave (1, theFunction.NbVariables()),
621 FF (1, theFunction.NbEquations()),
622 PreviousSolution(1, theFunction.NbVariables()),
623 Save (0, theNbIterations),
624 Constraints(1, theFunction.NbVariables()),
625 Temp1 (1, theFunction.NbVariables()),
626 Temp2 (1, theFunction.NbVariables()),
627 Temp3 (1, theFunction.NbVariables()),
628 Temp4 (1, theFunction.NbEquations()),
629 myIsDivergent(Standard_False)
631 SetTolerance(theTolerance);
634 //=======================================================================
635 //function : math_FunctionSetRoot
636 //purpose : Constructor
637 //=======================================================================
638 math_FunctionSetRoot::math_FunctionSetRoot(math_FunctionSetWithDerivatives& theFunction,
639 const Standard_Integer theNbIterations)
641 : Delta(1, theFunction.NbVariables()),
642 Sol (1, theFunction.NbVariables()),
643 DF (1, theFunction.NbEquations() , 1, theFunction.NbVariables()),
644 Tol (1, theFunction.NbVariables()),
645 Done (Standard_False),
648 Itermax (theNbIterations),
649 InfBound(1, theFunction.NbVariables(), RealFirst()),
650 SupBound(1, theFunction.NbVariables(), RealLast ()),
651 SolSave (1, theFunction.NbVariables()),
652 GH (1, theFunction.NbVariables()),
653 DH (1, theFunction.NbVariables()),
654 DHSave (1, theFunction.NbVariables()),
655 FF (1, theFunction.NbEquations()),
656 PreviousSolution(1, theFunction.NbVariables()),
657 Save (0, theNbIterations),
658 Constraints(1, theFunction.NbVariables()),
659 Temp1 (1, theFunction.NbVariables()),
660 Temp2 (1, theFunction.NbVariables()),
661 Temp3 (1, theFunction.NbVariables()),
662 Temp4 (1, theFunction.NbEquations()),
663 myIsDivergent(Standard_False)
667 //=======================================================================
668 //function : ~math_FunctionSetRoot
669 //purpose : Destructor
670 //=======================================================================
671 math_FunctionSetRoot::~math_FunctionSetRoot()
675 //=======================================================================
676 //function : SetTolerance
678 //=======================================================================
679 void math_FunctionSetRoot::SetTolerance(const math_Vector& theTolerance)
681 for (Standard_Integer i = 1; i <= Tol.Length(); ++i)
682 Tol(i) = theTolerance(i);
685 //=======================================================================
688 //=======================================================================
689 void math_FunctionSetRoot::Perform(math_FunctionSetWithDerivatives& theFunction,
690 const math_Vector& theStartingPoint,
691 const Standard_Boolean theStopOnDivergent)
693 Perform(theFunction, theStartingPoint, InfBound, SupBound, theStopOnDivergent);
696 //=======================================================================
699 //=======================================================================
700 void math_FunctionSetRoot::Perform(math_FunctionSetWithDerivatives& F,
701 const math_Vector& StartingPoint,
702 const math_Vector& theInfBound,
703 const math_Vector& theSupBound,
704 Standard_Boolean theStopOnDivergent)
706 Standard_Integer Ninc = F.NbVariables(), Neq = F.NbEquations();
709 (StartingPoint.Length()!= Ninc) ||
710 (theInfBound.Length() != Ninc) ||
711 (theSupBound.Length() != Ninc)) { throw Standard_DimensionError(); }
714 Standard_Boolean ChangeDirection = Standard_False, Sort = Standard_False, isNewSol = Standard_False;
715 Standard_Boolean Good, Verif;
716 Standard_Boolean Stop;
717 const Standard_Real EpsSqrt = 1.e-16, Eps = 1.e-32, Eps2 = 1.e-64, Progres = 0.005;
718 Standard_Real F2, PreviousMinimum, Dy, OldF;
719 Standard_Real Ambda, Ambda2, Gnr1, Oldgr;
720 math_Vector InvLengthMax(1, Ninc); // Pour bloquer les pas a 1/4 du domaine
721 math_IntegerVector aConstraints(1, Ninc); // Pour savoir sur quels bord on se trouve
722 for (i = 1; i <= Ninc ; i++) {
723 const Standard_Real aSupBound = Min (theSupBound(i), Precision::Infinite());
724 const Standard_Real anInfBound = Max (theInfBound(i), -Precision::Infinite());
725 InvLengthMax(i) = 1. / Max((aSupBound - anInfBound)/4, 1.e-9);
728 MyDirFunction F_Dir(Temp1, Temp2, Temp3, Temp4, F);
729 Standard_Integer DescenteIter;
731 Done = Standard_False;
736 myIsDivergent = Standard_False;
737 for (i = 1; i <= Ninc; i++)
739 myIsDivergent = myIsDivergent
740 || Sol(i) < theInfBound(i)
741 || Sol(i) > theSupBound(i);
743 if (theStopOnDivergent && myIsDivergent)
748 // Verification de la validite des inconnues par rapport aux bornes.
749 // Recentrage sur les bornes si pas valide.
750 for ( i = 1; i <= Ninc; i++) {
751 if (Sol(i) <= theInfBound(i)) Sol(i) = theInfBound(i);
752 else if (Sol(i) > theSupBound(i)) Sol(i) = theSupBound(i);
755 // Calcul de la premiere valeur de F et de son gradient
756 if(!F_Dir.Value(Sol, FF, DF, GH, F2, Gnr1)) {
757 Done = Standard_False;
758 if (!theStopOnDivergent || !myIsDivergent)
760 State = F.GetStateNumber();
765 // Le rang 0 de Save ne doit servir q'au test accelarteur en fin de boucle
766 // s'il on est dejas sur la solution, il faut leurer ce test pour eviter
767 // de faire une seconde iteration...
768 Save(0) = Max (F2, EpsSqrt);
769 Standard_Real aTol_Func = Epsilon(F2);
770 FSR_DEBUG("=== Mode Debug de Function Set Root" << std::endl);
771 FSR_DEBUG(" F2 Initial = " << F2);
773 if ((F2 <= Eps) || (Gnr1 <= Eps2)) {
774 Done = Standard_False;
775 if (!theStopOnDivergent || !myIsDivergent)
777 Done = Standard_True;
778 State = F.GetStateNumber();
783 for (Kount = 1; Kount <= Itermax; Kount++) {
784 PreviousMinimum = F2;
786 PreviousSolution = Sol;
789 SearchDirection(DF, GH, FF, ChangeDirection, InvLengthMax, DH, Dy);
790 if (Abs(Dy) <= Eps) {
791 Done = Standard_False;
792 if (!theStopOnDivergent || !myIsDivergent)
794 Done = Standard_True;
795 ////modified by jgv, 31.08.2011////
796 F.Value(Sol, FF); //update F before GetStateNumber
797 ///////////////////////////////////
798 State = F.GetStateNumber();
802 if (ChangeDirection) {
803 Ambda = Ambda2 / Sqrt(Abs(Dy));
804 if (Ambda > 1.0) Ambda = 1.0;
808 Ambda2 = 0.5*Ambda/DH.Norm();
811 for( i = Sol.Lower(); i <= Sol.Upper(); i++) {
812 Sol(i) = Sol(i) + Ambda * DH(i);
815 for (i = 1; i <= Ninc; i++)
817 myIsDivergent = myIsDivergent
818 || Sol(i) < theInfBound(i)
819 || Sol(i) > theSupBound(i);
821 if (theStopOnDivergent && myIsDivergent)
826 Sort = Bounds(theInfBound, theSupBound, Tol, Sol, SolSave,
827 aConstraints, Delta, isNewSol);
832 // F_Dir.Value(Sol, FF, DF, GH, F2, Gnr1);
833 if(!F_Dir.Value(Sol, FF, DF, GH, F2, Gnr1)) {
834 Done = Standard_False;
835 if (!theStopOnDivergent || !myIsDivergent)
837 State = F.GetStateNumber();
843 FSR_DEBUG("Kount = " << Kount);
844 FSR_DEBUG("Le premier F2 = " << F2);
845 FSR_DEBUG("Direction = " << ChangeDirection);
847 if ((F2 <= Eps) || (Gnr1 <= Eps2)) {
848 Done = Standard_False;
849 if (!theStopOnDivergent || !myIsDivergent)
851 Done = Standard_True;
852 ////modified by jgv, 31.08.2011////
853 F.Value(Sol, FF); //update F before GetStateNumber
854 ///////////////////////////////////
855 State = F.GetStateNumber();
860 if (Sort || (F2/PreviousMinimum > Progres)) {
862 OldF = PreviousMinimum;
863 Stop = Standard_False;
864 Good = Standard_False;
866 Standard_Boolean Sortbis;
868 // -------------------------------------------------
869 // Traitement standard sans traitement des bords
870 // -------------------------------------------------
871 if (!Sort) { // si l'on est pas sortie on essaye de progresser en avant
872 while((F2/PreviousMinimum > Progres) && !Stop) {
873 if (F2 < OldF && (Dy < 0.0)) {
874 // On essaye de progresser dans cette direction.
875 FSR_DEBUG(" iteration de descente = " << DescenteIter);
879 for( i = Sol.Lower(); i <= Sol.Upper(); i++) {
880 Sol(i) = Sol(i) + Ambda * DH(i);
883 for (i = 1; i <= Ninc; i++)
885 myIsDivergent = myIsDivergent
886 || Sol(i) < theInfBound(i)
887 || Sol(i) > theSupBound(i);
889 if (theStopOnDivergent && myIsDivergent)
894 Stop = Bounds(theInfBound, theSupBound, Tol, Sol, SolSave,
895 aConstraints, Delta, isNewSol);
896 FSR_DEBUG(" Augmentation de lambda");
900 if ((F2 >= OldF)||(F2 >= PreviousMinimum)) {
901 Good = Standard_False;
902 if (DescenteIter == 0) {
903 // C'est le premier pas qui flanche, on fait une interpolation.
904 // et on minimise si necessaire.
906 Good = MinimizeDirection(SolSave, Delta, OldF, F2, DHSave, GH,
909 else if (ChangeDirection || (DescenteIter>1)
910 || (OldF>PreviousMinimum) ) {
911 // La progression a ete utile, on minimise...
913 Good = MinimizeDirection(PreviousSolution, SolSave, Sol,
914 OldF, Delta, Tol, F_Dir);
923 for (i = 1; i <= Ninc; i++)
925 myIsDivergent = myIsDivergent
926 || Sol(i) < theInfBound(i)
927 || Sol(i) > theSupBound(i);
929 if (theStopOnDivergent && myIsDivergent)
934 Sort = Bounds(theInfBound, theSupBound, Tol, Sol, SolSave,
935 aConstraints, Delta, isNewSol);
937 Sort = Standard_False; // On a rejete le point sur la frontiere
939 Stop = Standard_True; // et on sort dans tous les cas...
943 // F_Dir.Value(Sol, FF, DF, GH, F2, Gnr1);
944 if(!F_Dir.Value(Sol, FF, DF, GH, F2, Gnr1)) {
945 Done = Standard_False;
946 if (!theStopOnDivergent || !myIsDivergent)
948 State = F.GetStateNumber();
954 if (Abs(Dy) <= Eps) {
957 Done = Standard_False;
958 if (!theStopOnDivergent || !myIsDivergent)
960 Done = Standard_True;
961 ////modified by jgv, 31.08.2011////
962 F.Value(Sol, FF); //update F before GetStateNumber
963 ///////////////////////////////////
964 State = F.GetStateNumber();
968 if (DescenteIter >= 100) {
969 Stop = Standard_True;
972 FSR_DEBUG("--- Sortie du Traitement Standard");
973 FSR_DEBUG(" DescenteIter = "<<DescenteIter << " F2 = " << F2);
975 // ------------------------------------
976 // on passe au traitement des bords
977 // ------------------------------------
979 Stop = (F2 > 1.001*OldF); // Pour ne pas progresser sur le bord
982 while (Sortbis && ((F2<OldF)|| (DescenteIter == 0))
985 // On essaye de progresser sur le bord
988 SearchDirection(DF, GH, FF, aConstraints, Sol,
989 ChangeDirection, InvLengthMax, DH, Dy);
990 FSR_DEBUG(" Conditional Direction = " << ChangeDirection);
991 if (Dy<-Eps) { //Pour eviter des calculs inutiles et des /0...
992 if (ChangeDirection) {
994 // Ambda = Ambda2 / Sqrt(Abs(Dy));
995 Ambda = Ambda2 / Sqrt(-Dy);
996 if (Ambda > 1.0) Ambda = 1.0;
1000 Ambda2 = 0.5*Ambda/DH.Norm();
1003 for( i = Sol.Lower(); i <= Sol.Upper(); i++) {
1004 Sol(i) = Sol(i) + Ambda * DH(i);
1007 for (i = 1; i <= Ninc; i++)
1009 myIsDivergent = myIsDivergent
1010 || Sol(i) < theInfBound(i)
1011 || Sol(i) > theSupBound(i);
1013 if (theStopOnDivergent && myIsDivergent)
1018 Sortbis = Bounds(theInfBound, theSupBound, Tol, Sol, SolSave,
1019 aConstraints, Delta, isNewSol);
1023 // F_Dir.Value(Sol, FF, DF, GH, F2, Gnr1);
1024 if(!F_Dir.Value(Sol, FF, DF, GH, F2, Gnr1)) {
1025 Done = Standard_False;
1026 if (!theStopOnDivergent || !myIsDivergent)
1028 State = F.GetStateNumber();
1034 FSR_DEBUG("--- Iteration au bords : " << DescenteIter);
1035 FSR_DEBUG("--- F2 = " << F2);
1038 Stop = Standard_True;
1041 while((F2/PreviousMinimum > Progres) && (F2<OldF) && (!Stop) ) {
1043 FSR_DEBUG("--- Iteration de descente conditionnel = " << DescenteIter);
1044 if (F2 < OldF && Dy < 0.0) {
1045 // On essaye de progresser dans cette direction.
1048 for( i = Sol.Lower(); i <= Sol.Upper(); i++) {
1049 Sol(i) = Sol(i) + Ambda * DH(i);
1052 for (i = 1; i <= Ninc; i++)
1054 myIsDivergent = myIsDivergent
1055 || Sol(i) < theInfBound(i)
1056 || Sol(i) > theSupBound(i);
1058 if (theStopOnDivergent && myIsDivergent)
1063 Sortbis = Bounds(theInfBound, theSupBound, Tol, Sol, SolSave,
1064 aConstraints, Delta, isNewSol);
1068 // F_Dir.Value(Sol, FF, DF, GH, F2, Gnr1);
1069 if(!F_Dir.Value(Sol, FF, DF, GH, F2, Gnr1)) {
1070 Done = Standard_False;
1071 if (!theStopOnDivergent || !myIsDivergent)
1073 State = F.GetStateNumber();
1080 Stop = ((Dy >=0) || (DescenteIter >= 10) || Sortbis);
1082 Stop = ((Dy >=0) || (DescenteIter >= 10));
1084 if (((F2/PreviousMinimum > Progres) &&
1085 (F2>=OldF))||(F2>=PreviousMinimum)) {
1086 // On minimise par Brent
1088 Good = MinimizeDirection(SolSave, Delta, OldF, F2,
1089 DHSave, GH, Tol, F_Dir);
1092 Sort = Standard_False;
1095 Sol = SolSave + Delta;
1097 for (i = 1; i <= Ninc; i++)
1099 myIsDivergent = myIsDivergent
1100 || Sol(i) < theInfBound(i)
1101 || Sol(i) > theSupBound(i);
1103 if (theStopOnDivergent && myIsDivergent)
1108 Sort = Bounds(theInfBound, theSupBound, Tol, Sol, SolSave,
1109 aConstraints, Delta, isNewSol);
1111 // F_Dir.Value(Sol, FF, DF, GH, F2, Gnr1);
1112 if(!F_Dir.Value(Sol, FF, DF, GH, F2, Gnr1)) {
1113 Done = Standard_False;
1114 if (!theStopOnDivergent || !myIsDivergent)
1116 State = F.GetStateNumber();
1124 FSR_DEBUG("--- Sortie du Traitement des Bords");
1125 FSR_DEBUG("--- DescenteIter = "<<DescenteIter << " F2 = " << F2);
1129 // ---------------------------------------------
1130 // on passe aux tests d'ARRET
1131 // ---------------------------------------------
1133 // Est ce la solution ?
1134 if (ChangeDirection) Verif = Standard_True;
1135 // Gradient : Il faut eviter de boucler
1137 Verif = Standard_False;
1138 if (Kount > 1) { // Pour accelerer les cas quasi-quadratique
1139 if (Save(Kount-1)<1.e-4*Save(Kount-2)) Verif = Standard_True;
1141 else Verif = (F2 < 1.e-6*Save(0)); //Pour les cas dejas solutions
1144 for(i = Delta.Lower(); i <= Delta.Upper(); i++) {
1145 Delta(i) = PreviousSolution(i) - Sol(i);
1148 if (IsSolutionReached(F)) {
1149 if (PreviousMinimum < F2) {
1152 Done = Standard_False;
1153 if (!theStopOnDivergent || !myIsDivergent)
1155 Done = Standard_True;
1156 ////modified by jgv, 31.08.2011////
1157 F.Value(Sol, FF); //update F before GetStateNumber
1158 ///////////////////////////////////
1159 State = F.GetStateNumber();
1164 //fin du test solution
1166 // Analyse de la progression...
1167 //comparison of current minimum and previous minimum
1168 if ((F2 - PreviousMinimum) <= aTol_Func){
1170 // L'historique est il bon ?
1171 if (F2 >= 0.95*Save(Kount - 5)) {
1172 if (!ChangeDirection) ChangeDirection = Standard_True;
1175 Done = Standard_False;
1176 if (!theStopOnDivergent || !myIsDivergent)
1178 Done = Standard_True;
1179 State = F.GetStateNumber();
1181 return; // si un gain inf a 5% on sort
1184 else ChangeDirection = Standard_False; //Si oui on recommence
1186 else ChangeDirection = Standard_False; //Pas d'historique on continue
1187 // Si le gradient ne diminue pas suffisemment par newton on essaie
1188 // le gradient sauf si f diminue (aussi bizarre que cela puisse
1189 // paraitre avec NEWTON le gradient de f peut augmenter alors que f
1190 // diminue: dans ce cas il faut garder NEWTON)
1191 if ((Gnr1 > 0.9*Oldgr) &&
1192 (F2 > 0.5*PreviousMinimum)) {
1193 ChangeDirection = Standard_True;
1196 // Si l'on ne decide pas de changer de strategie, on verifie,
1197 // si ce n'est dejas fait
1198 if ((!ChangeDirection) && (!Verif)) {
1199 for(i = Delta.Lower(); i <= Delta.Upper(); i++) {
1200 Delta(i) = PreviousSolution(i) - Sol(i);
1202 if (IsSolutionReached(F)) {
1203 Done = Standard_False;
1204 if (!theStopOnDivergent || !myIsDivergent)
1206 Done = Standard_True;
1207 ////modified by jgv, 31.08.2011////
1208 F.Value(Sol, FF); //update F before GetStateNumber
1209 ///////////////////////////////////
1210 State = F.GetStateNumber();
1216 else { // Cas de regression
1217 if (!ChangeDirection) { // On passe au gradient
1218 ChangeDirection = Standard_True;
1219 Sol = PreviousSolution;
1220 // F_Dir.Value(Sol, FF, DF, GH, F2, Gnr1);
1221 if(!F_Dir.Value(Sol, FF, DF, GH, F2, Gnr1)) {
1222 Done = Standard_False;
1223 if (!theStopOnDivergent || !myIsDivergent)
1225 State = F.GetStateNumber();
1233 if (!theStopOnDivergent || !myIsDivergent)
1235 State = F.GetStateNumber();
1237 return; // y a plus d'issues
1241 if (!theStopOnDivergent || !myIsDivergent)
1243 State = F.GetStateNumber();
1247 //=======================================================================
1250 //=======================================================================
1251 void math_FunctionSetRoot::Dump(Standard_OStream& o) const
1253 o << " math_FunctionSetRoot";
1255 o << " Status = Done\n";
1256 o << " Location value = " << Sol << "\n";
1257 o << " Number of iterations = " << Kount << "\n";
1260 o << "Status = Not Done\n";
1264 //=======================================================================
1267 //=======================================================================
1268 void math_FunctionSetRoot::Root(math_Vector& Root) const
1270 StdFail_NotDone_Raise_if(!Done, " ");
1271 Standard_DimensionError_Raise_if(Root.Length() != Sol.Length(), " ");
1275 //=======================================================================
1276 //function : FunctionSetErrors
1278 //=======================================================================
1279 void math_FunctionSetRoot::FunctionSetErrors(math_Vector& Err) const
1281 StdFail_NotDone_Raise_if(!Done, " ");
1282 Standard_DimensionError_Raise_if(Err.Length() != Sol.Length(), " ");