]> OCCT Git - occt.git/commitdiff
0030492: Foundation Classes - math_BFGS fails if starting point is exactly the minimum
authoraml <aml@opencascade.com>
Fri, 3 Jun 2022 09:30:22 +0000 (12:30 +0300)
committerafokin <afokin@opencascade.com>
Thu, 9 Jun 2022 17:34:57 +0000 (20:34 +0300)
Fix affects BFGS optimization methods by checking convergence as the first step on each iteration. FRPR works well, but it is updated as well since its logic potentially dangerous.

src/QABugs/QABugs_19.cxx
src/math/math_BFGS.cxx
src/math/math_FRPR.cxx
tests/bugs/fclasses/bug30492 [new file with mode: 0644]

index 46df73de956f63a0a4403160fb3dc2105bf7638a..8dc0e69aaa99e1f40f6ba6750d7b505635e876eb 100644 (file)
@@ -5267,6 +5267,79 @@ static Standard_Integer OCC29412 (Draw_Interpretor& /*theDI*/, Standard_Integer
   return 0;
 }
 
+#include <math_FRPR.hxx>
+#include <math_BFGS.hxx>
+//=======================================================================
+//function : OCC30492
+//purpose  : BFGS and FRPR fail if starting point is exactly the minimum.
+//=======================================================================
+// Function is:
+// f(x) = x^2
+class SquareFunction : public math_MultipleVarFunctionWithGradient
+{
+public:
+  SquareFunction()
+  {}
+
+  virtual Standard_Integer NbVariables() const
+  {
+    return 1;
+  }
+  virtual Standard_Boolean Value(const math_Vector& X,
+                                 Standard_Real&     F)
+  {
+    const Standard_Real x = X(1);
+    F = x * x;
+
+    return Standard_True;
+  }
+  virtual Standard_Boolean Gradient(const math_Vector& X,
+                                    math_Vector&       G)
+  {
+    const Standard_Real x = X(1);
+    G(1) = 2 * x;
+
+    return Standard_True;
+  }
+  virtual Standard_Boolean Values(const math_Vector& X,
+                                  Standard_Real&     F,
+                                  math_Vector&       G)
+  {
+    Value(X, F);
+    Gradient(X, G);
+
+    return Standard_True;
+  }
+
+private:
+};
+
+static Standard_Integer OCC30492(Draw_Interpretor& /*theDI*/,
+                                 Standard_Integer  /*theNArg*/,
+                                 const char**      /*theArgs*/)
+{
+  SquareFunction aFunc;
+  math_Vector aStartPnt(1, 1);
+  aStartPnt(1) = 0.0;
+
+  // BFGS and FRPR fail when if starting point is exactly the minimum.
+  math_FRPR aFRPR(aFunc, Precision::Confusion());
+  aFRPR.Perform(aFunc, aStartPnt);
+  if (!aFRPR.IsDone())
+    std::cout << "OCC30492: Error: FRPR optimization is not done." << std::endl;
+  else
+    std::cout << "OCC30492: OK: FRPR optimization is done." << std::endl;
+
+  math_BFGS aBFGS(1, Precision::Confusion());
+  aBFGS.Perform(aFunc, aStartPnt);
+  if (!aBFGS.IsDone())
+    std::cout << "OCC30492: Error: BFGS optimization is not done." << std::endl;
+  else
+    std::cout << "OCC30492: OK: BFGS optimization is done." << std::endl;
+
+  return 0;
+}
+
 //========================================================================
 //function : Commands_19
 //purpose  :
@@ -5390,5 +5463,8 @@ void QABugs::Commands_19(Draw_Interpretor& theCommands) {
                   "OCC28310: Tests validness of iterator in AIS_InteractiveContext after an removing object from it",
                   __FILE__, OCC28310, group);
   theCommands.Add("OCC29412", "OCC29412 [nb cycles]: test display / remove of many small objects", __FILE__, OCC29412, group);
+  theCommands.Add ("OCC30492",
+                   "OCC30492: Checks whether BFGS and FRPR fail when starting point is exact minimum.",
+                   __FILE__, OCC30492, group);
   return;
 }
index 60a0644b30a748f69211579ada68773862257f2a..6073c8b8015d59c60390ba8406fa6599d0c2b954 100644 (file)
 #include <math_MultipleVarFunctionWithGradient.hxx>
 #include <Precision.hxx>
 
-#define R 0.61803399
-#define C (1.0-R)
-#define SHFT(a,b,c,d) (a)=(b);(b)=(c);(c)=(d);
-#define SIGN(a, b) ((b) > 0.0 ? fabs(a) : -fabs(a))
-#define MOV3(a,b,c, d, e, f) (a)=(d); (b)= (e); (c)=(f);
-
-
 // l'utilisation de math_BrentMinumim pur trouver un minimum dans une direction
 // donnee n'est pas du tout optimale. voir peut etre interpolation cubique
 // classique et aussi essayer "recherche unidimensionnelle economique"
 // PROGRAMMATION MATHEMATIQUE (theorie et algorithmes) tome1 page 82.
 
-class DirFunction : public math_FunctionWithDerivative {
+// Target function for 1D problem, point and direction are known.
+class DirFunction : public math_FunctionWithDerivative
+{
 
-     math_Vector *P0;
-     math_Vector *Dir;
-     math_Vector *P;
-     math_Vector *G;
-     math_MultipleVarFunctionWithGradient *F;
+  math_Vector *P0;
+  math_Vector *Dir;
+  math_Vector *P;
+  math_Vector *G;
+  math_MultipleVarFunctionWithGradient *F;
+
+public:
+
+  //! Ctor.
+  DirFunction(math_Vector& V1,
+              math_Vector& V2,
+              math_Vector& V3,
+              math_Vector& V4,
+              math_MultipleVarFunctionWithGradient& f)
+  : P0(&V1),
+    Dir(&V2),
+    P(&V3),
+    G(&V4),
+    F(&f)
+  {}
+
+  //! Sets point and direction.
+  void Initialize(const math_Vector& p0,
+                  const math_Vector& dir) const
+  {
+    *P0 = p0;
+    *Dir = dir;
+  }
 
-public :
+  void TheGradient(math_Vector& Grad)
+  {
+    Grad = *G;
+  }
 
-     DirFunction(math_Vector& V1, 
-                 math_Vector& V2,
-                 math_Vector& V3,
-                math_Vector& V4,
-                 math_MultipleVarFunctionWithGradient& f) ;
+  virtual Standard_Boolean Value(const Standard_Real x,
+                                 Standard_Real&      fval)
+  {
+    *P = *Dir;
+    P->Multiply(x);
+    P->Add(*P0);
+    fval = 0.;
+    return F->Value(*P, fval);
+  }
 
-     void Initialize(const math_Vector& p0, const math_Vector& dir) const;
-     void TheGradient(math_Vector& Grad);
-     virtual Standard_Boolean Value(const Standard_Real x, Standard_Real& fval) ;
-     virtual Standard_Boolean Values(const Standard_Real x, Standard_Real& fval, Standard_Real& D) ;
-     virtual Standard_Boolean Derivative(const Standard_Real x, Standard_Real& D) ;
+  virtual Standard_Boolean Values(const Standard_Real x,
+                                  Standard_Real&      fval,
+                                  Standard_Real&      D)
+  {
+    *P = *Dir;
+    P->Multiply(x);
+    P->Add(*P0);
+    fval = D = 0.;
+    if (F->Values(*P, fval, *G))
+    {
+      D = (*G).Multiplied(*Dir);
+      return Standard_True;
+    }
 
-     
-};
+    return Standard_False;
+  }
+  virtual Standard_Boolean Derivative(const Standard_Real x,
+                                      Standard_Real&      D)
+  {
+    *P = *Dir;
+    P->Multiply(x);
+    P->Add(*P0);
+    Standard_Real fval;
+    D = 0.;
+    if (F->Values(*P, fval, *G))
+    {
+      D = (*G).Multiplied(*Dir);
+      return Standard_True;
+    }
 
-     DirFunction::DirFunction(math_Vector& V1, 
-                              math_Vector& V2,
-                              math_Vector& V3,
-                             math_Vector& V4,
-                              math_MultipleVarFunctionWithGradient& f) {
-        
-        P0  = &V1;
-        Dir = &V2;
-        P   = &V3;
-        F   = &f;
-       G =   &V4;
-     }
-
-     void DirFunction::Initialize(const math_Vector& p0, 
-                                  const math_Vector& dir)  const{
-
-        *P0 = p0;
-        *Dir = dir;
-     }
-
-     void DirFunction::TheGradient(math_Vector& Grad) {
-       Grad = *G;
-     }
-
-
-     Standard_Boolean DirFunction::Value(const Standard_Real x, 
-                                        Standard_Real& fval) 
-     {
-        *P = *Dir;
-        P->Multiply(x);
-        P->Add(*P0); 
-        fval = 0.;
-        return F->Value(*P, fval);
-     }
-
-     Standard_Boolean DirFunction::Values(const Standard_Real x, 
-                                         Standard_Real& fval, 
-                                         Standard_Real& D) 
-     {
-        *P = *Dir;
-        P->Multiply(x);
-        P->Add(*P0);
-        fval = D = 0.;
-        if (F->Values(*P, fval, *G))
-        {
-          D = (*G).Multiplied(*Dir);
-          return Standard_True;
-        }
-        return Standard_False;
-     }
-     Standard_Boolean DirFunction::Derivative(const Standard_Real x, 
-                                             Standard_Real& D) 
-     {
-        *P = *Dir;
-        P->Multiply(x);
-        P->Add(*P0);        
-       Standard_Real fval;
-        D = 0.;
-        if (F->Values(*P, fval, *G))
-        {
-          D = (*G).Multiplied(*Dir);
-          return Standard_True;
-        }
-        return Standard_False;
-     }
+    return Standard_False;
+  }
 
-//=======================================================================
+
+};
+
+//=============================================================================
 //function : ComputeInitScale
 //purpose  : Compute the appropriate initial value of scale factor to apply
 //           to the direction to approach to the minimum of the function
-//=======================================================================
+//=============================================================================
 static Standard_Boolean ComputeInitScale(const Standard_Real theF0,
-                                         const math_Vector& theDir,
-                                         const math_Vector& theGr,
-                                         Standard_Real& theScale)
+                                         const math_Vector&  theDir,
+                                         const math_Vector&  theGr,
+                                         Standard_Real&      theScale)
 {
-  Standard_Real dy1 = theGr * theDir;
+  const Standard_Real dy1 = theGr * theDir;
   if (Abs(dy1) < RealSmall())
     return Standard_False;
-  Standard_Real aHnr1 = theDir.Norm2();
-  Standard_Real alfa = 0.7*(-theF0) / dy1;
+
+  const Standard_Real aHnr1 = theDir.Norm2();
+  const Standard_Real alfa = 0.7*(-theF0) / dy1;
   theScale = 0.015 / Sqrt(aHnr1);
   if (theScale > alfa)
     theScale = alfa;
+
   return Standard_True;
 }
 
-//=======================================================================
+//=============================================================================
 //function : ComputeMinMaxScale
 //purpose  : For a given point and direction, and bounding box,
 //           find min and max scale factors with which the point reaches borders
 //           if we apply translation Point+Dir*Scale.
 //return   : True if found, False if point is out of bounds.
-//=======================================================================
+//=============================================================================
 static Standard_Boolean ComputeMinMaxScale(const math_Vector& thePoint,
                                            const math_Vector& theDir,
                                            const math_Vector& theLeft,
                                            const math_Vector& theRight,
-                                           Standard_Real& theMinScale,
-                                           Standard_Real& theMaxScale)
+                                           Standard_Real&     theMinScale,
+                                           Standard_Real&     theMaxScale)
 {
-  Standard_Integer anIdx;
-  for (anIdx = 1; anIdx <= theLeft.Upper(); anIdx++)
+  for (Standard_Integer anIdx = 1; anIdx <= theLeft.Upper(); anIdx++)
   {
-    Standard_Real aLeft = theLeft(anIdx) - thePoint(anIdx);
-    Standard_Real aRight = theRight(anIdx) - thePoint(anIdx);
+    const Standard_Real aLeft = theLeft(anIdx) - thePoint(anIdx);
+    const Standard_Real aRight = theRight(anIdx) - thePoint(anIdx);
     if (Abs(theDir(anIdx)) > RealSmall())
     {
-      // use PConfusion to get off a little from the bounds to prevent
+      // Use PConfusion to get off a little from the bounds to prevent
       // possible refuse in Value function.
-      Standard_Real aLScale = (aLeft + Precision::PConfusion()) / theDir(anIdx);
-      Standard_Real aRScale = (aRight - Precision::PConfusion()) / theDir(anIdx);
+      const Standard_Real aLScale = (aLeft + Precision::PConfusion()) / theDir(anIdx);
+      const Standard_Real aRScale = (aRight - Precision::PConfusion()) / theDir(anIdx);
       if (Abs(aLeft) < Precision::PConfusion())
       {
-        // point is on the left border
+        // Point is on the left border.
         theMaxScale = Min(theMaxScale, Max(0., aRScale));
         theMinScale = Max(theMinScale, Min(0., aRScale));
       }
       else if (Abs(aRight) < Precision::PConfusion())
       {
-        // point is on the right border
+        // Point is on the right border.
         theMaxScale = Min(theMaxScale, Max(0., aLScale));
         theMinScale = Max(theMinScale, Min(0., aLScale));
       }
       else if (aLeft * aRight < 0)
       {
-        // point is inside allowed range
+        // Point is inside allowed range.
         theMaxScale = Min(theMaxScale, Max(aLScale, aRScale));
         theMinScale = Max(theMinScale, Min(aLScale, aRScale));
       }
@@ -202,8 +189,8 @@ static Standard_Boolean ComputeMinMaxScale(const math_Vector& thePoint,
     {
       // Direction is parallel to the border.
       // Check that the point is not out of bounds
-      if (aLeft > Precision::PConfusion() ||
-        aRight < -Precision::PConfusion())
+      if (aLeft  >  Precision::PConfusion() ||
+          aRight < -Precision::PConfusion())
       {
         return Standard_False;
       }
@@ -212,13 +199,18 @@ static Standard_Boolean ComputeMinMaxScale(const math_Vector& thePoint,
   return Standard_True;
 }
 
-static Standard_Boolean MinimizeDirection(math_Vector&   P,
-                                          Standard_Real  F0,
-                                          math_Vector&   Gr,
-                                          math_Vector&   Dir,
-                                          Standard_Real& Result,
-                                          DirFunction&   F,
-                                          Standard_Boolean isBounds,
+//=============================================================================
+//function : MinimizeDirection
+//purpose  : Solves 1D minimization problem when point and directions
+//           are known.
+//=============================================================================
+static Standard_Boolean MinimizeDirection(math_Vector&       P,
+                                          Standard_Real      F0,
+                                          math_Vector&       Gr,
+                                          math_Vector&       Dir,
+                                          Standard_Real&     Result,
+                                          DirFunction&       F,
+                                          Standard_Boolean   isBounds,
                                           const math_Vector& theLeft,
                                           const math_Vector& theRight)
 {
@@ -262,13 +254,15 @@ static Standard_Boolean MinimizeDirection(math_Vector&   P,
   Standard_Real F1;
   if (!F.Value(lambda, F1))
     return Standard_False;
+
   math_BracketMinimum Bracket(0.0, lambda);
   if (isBounds)
     Bracket.SetLimits(aMinLambda, aMaxLambda);
   Bracket.SetFA(F0);
   Bracket.SetFB(F1);
   Bracket.Perform(F);
-  if (Bracket.IsDone()) {
+  if (Bracket.IsDone())
+  {
     // find minimum inside the bracket
     Standard_Real ax, xx, bx, Fax, Fxx, Fbx;
     Bracket.Values(ax, xx, bx);
@@ -278,7 +272,8 @@ static Standard_Boolean MinimizeDirection(math_Vector&   P,
     Standard_Real tol = 1.e-03;
     math_BrentMinimum Sol(tol, Fxx, niter, 1.e-08);
     Sol.Perform(F, ax, xx, bx);
-    if (Sol.IsDone()) {
+    if (Sol.IsDone())
+    {
       Standard_Real Scale = Sol.Location();
       Result = Sol.Minimum();
       Dir.Multiply(Scale);
@@ -313,154 +308,181 @@ static Standard_Boolean MinimizeDirection(math_Vector&   P,
   return Standard_False;
 }
 
-
+//=============================================================================
+//function : Perform
+//purpose  : Performs minimization problem using BFGS method.
+//=============================================================================
 void  math_BFGS::Perform(math_MultipleVarFunctionWithGradient& F,
-                         const math_Vector& StartingPoint) {
-  
-       Standard_Boolean Good;
-       Standard_Integer n = TheLocation.Length();
-       Standard_Integer j, i;
-       Standard_Real fae, fad, fac;
-
-       math_Vector xi(1, n), dg(1, n), hdg(1, n);
-       math_Matrix hessin(1, n, 1, n);
-       hessin.Init(0.0);
-
-       math_Vector Temp1(1, n);
-       math_Vector Temp2(1, n);
-       math_Vector Temp3(1, n);
-       math_Vector Temp4(1, n);
-       DirFunction F_Dir(Temp1, Temp2, Temp3, Temp4, F);
-
-       TheLocation = StartingPoint;
-       Good = F.Values(TheLocation, PreviousMinimum, TheGradient);
-       if(!Good) { 
-         Done = Standard_False;
-         TheStatus = math_FunctionError;
-         return;
-       }
-       for(i = 1; i <= n; i++) {
-         hessin(i, i) = 1.0;
-        xi(i) = -TheGradient(i);
-       }
-
-
-       for(nbiter = 1; nbiter <= Itermax; nbiter++) {
-        TheMinimum = PreviousMinimum;
-         Standard_Boolean IsGood = MinimizeDirection(TheLocation, TheMinimum,
-                                                     TheGradient,
-                                                     xi, TheMinimum, F_Dir,
-                                                     myIsBoundsDefined, myLeft, myRight);
-         if(!IsGood) {
-           Done = Standard_False;
-           TheStatus = math_DirectionSearchError;
-           return;
-         }
-         if(IsSolutionReached(F)) {
-           Done = Standard_True;
-           TheStatus = math_OK;
-           return;
-         }
-        if (nbiter == Itermax) {
-          Done = Standard_False;
-          TheStatus = math_TooManyIterations;
-          return;
-        }
-         PreviousMinimum = TheMinimum;
-
-        dg = TheGradient;
-
-         Good = F.Values(TheLocation, TheMinimum, TheGradient);
-         if(!Good) { 
-           Done = Standard_False;
-           TheStatus = math_FunctionError;
-           return;
-         }
-
-         for(i = 1; i <= n; i++) {
-          dg(i) = TheGradient(i) - dg(i);
-        }
-        for(i = 1; i <= n; i++) {
-          hdg(i) = 0.0;
-          for (j = 1; j <= n; j++) 
-            hdg(i) += hessin(i, j) * dg(j);
-        }
-        fac = fae = 0.0;
-        for(i = 1; i <= n; i++) {
-          fac += dg(i) * xi(i);
-          fae += dg(i) * hdg(i);
-        }
-         fac = 1.0 / fac;
-         fad = 1.0 / fae;
-
-        for(i = 1; i <= n; i++) 
-          dg(i) = fac * xi(i) - fad * hdg(i);
-        
-         for(i = 1; i <= n; i++) 
-           for(j = 1; j <= n; j++)
-             hessin(i, j) += fac * xi(i) * xi(j)
-               - fad * hdg(i) * hdg(j) + fae * dg(i) * dg(j);
-
-        for(i = 1; i <= n; i++) {
-          xi(i) = 0.0;
-          for (j = 1; j <= n; j++) xi(i) -= hessin(i, j) * TheGradient(j);
-        }  
-       }
-       Done = Standard_False;
-       TheStatus = math_TooManyIterations;
-       return;
-   }
-
-    Standard_Boolean math_BFGS::IsSolutionReached(
-                           math_MultipleVarFunctionWithGradient&) const {
-
-       return 2.0 * fabs(TheMinimum - PreviousMinimum) <= 
-              XTol * (fabs(TheMinimum) + fabs(PreviousMinimum) + EPSZ);
+                         const math_Vector&                    StartingPoint)
+{
+  const Standard_Integer n = TheLocation.Length();
+  Standard_Boolean Good = Standard_True;
+  Standard_Integer j, i;
+  Standard_Real fae, fad, fac;
+
+  math_Vector xi(1, n), dg(1, n), hdg(1, n);
+  math_Matrix hessin(1, n, 1, n);
+  hessin.Init(0.0);
+
+  math_Vector Temp1(1, n);
+  math_Vector Temp2(1, n);
+  math_Vector Temp3(1, n);
+  math_Vector Temp4(1, n);
+  DirFunction F_Dir(Temp1, Temp2, Temp3, Temp4, F);
+
+  TheLocation = StartingPoint;
+  Good = F.Values(TheLocation, PreviousMinimum, TheGradient);
+  if (!Good)
+  {
+    Done = Standard_False;
+    TheStatus = math_FunctionError;
+    return;
+  }
+  for (i = 1; i <= n; i++)
+  {
+    hessin(i, i) = 1.0;
+    xi(i) = -TheGradient(i);
+  }
+
+
+  for (nbiter = 1; nbiter <= Itermax; nbiter++)
+  {
+    TheMinimum = PreviousMinimum;
+    const Standard_Boolean IsGood = MinimizeDirection(TheLocation, TheMinimum, TheGradient,
+                                                      xi, TheMinimum, F_Dir, myIsBoundsDefined,
+                                                      myLeft, myRight);
+
+    if (IsSolutionReached(F))
+    {
+      Done = Standard_True;
+      TheStatus = math_OK;
+      return;
+    }
+
+    if (!IsGood)
+    {
+      Done = Standard_False;
+      TheStatus = math_DirectionSearchError;
+      return;
     }
-                             
-    math_BFGS::math_BFGS(const Standard_Integer     NbVariables,
-                         const Standard_Real        Tolerance,
-                         const Standard_Integer     NbIterations,
-                         const Standard_Real        ZEPS) 
-    : TheStatus(math_OK),
-      TheLocation(1, NbVariables),
-      TheGradient(1, NbVariables),
-      PreviousMinimum(0.),
-      TheMinimum(0.),
-      XTol(Tolerance),
-      EPSZ(ZEPS),
-      nbiter(0),
-      myIsBoundsDefined(Standard_False),
-      myLeft(1, NbVariables, 0.0),
-      myRight(1, NbVariables, 0.0),
-      Done(Standard_False),
-      Itermax(NbIterations)
+    PreviousMinimum = TheMinimum;
+
+    dg = TheGradient;
+
+    Good = F.Values(TheLocation, TheMinimum, TheGradient);
+    if (!Good)
     {
+      Done = Standard_False;
+      TheStatus = math_FunctionError;
+      return;
     }
 
+    for (i = 1; i <= n; i++)
+      dg(i) = TheGradient(i) - dg(i);
+
+    for (i = 1; i <= n; i++)
+    {
+      hdg(i) = 0.0;
+      for (j = 1; j <= n; j++)
+        hdg(i) += hessin(i, j) * dg(j);
+    }
 
-    math_BFGS::~math_BFGS()
+    fac = fae = 0.0;
+    for (i = 1; i <= n; i++)
     {
+      fac += dg(i) * xi(i);
+      fae += dg(i) * hdg(i);
     }
+    fac = 1.0 / fac;
+    fad = 1.0 / fae;
+
+    for (i = 1; i <= n; i++)
+      dg(i) = fac * xi(i) - fad * hdg(i);
 
-    void math_BFGS::Dump(Standard_OStream& o) const {
-
-       o<< "math_BFGS resolution: ";
-       if(Done) {
-         o << " Status = Done \n";
-        o <<" Location Vector = " << Location() << "\n";
-        o <<" Minimum value = "<< Minimum()<<"\n";
-        o <<" Number of iterations = "<<NbIterations() <<"\n";
-       }
-       else {
-         o<< " Status = not Done because " << (Standard_Integer)TheStatus << "\n";
-       }
+    for (i = 1; i <= n; i++)
+    {
+      for (j = 1; j <= n; j++)
+        hessin(i, j) += fac * xi(i) * xi(j) - fad * hdg(i) * hdg(j) + fae * dg(i) * dg(j);
     }
 
-//=======================================================================
+    for (i = 1; i <= n; i++)
+    {
+      xi(i) = 0.0;
+      for (j = 1; j <= n; j++)
+        xi(i) -= hessin(i, j) * TheGradient(j);
+    }
+  }
+  Done = Standard_False;
+  TheStatus = math_TooManyIterations;
+  return;
+}
+
+//=============================================================================
+//function : IsSolutionReached
+//purpose  : Checks whether solution reached or not.
+//=============================================================================
+Standard_Boolean math_BFGS::IsSolutionReached(math_MultipleVarFunctionWithGradient&) const
+{
+
+  return 2.0 * fabs(TheMinimum - PreviousMinimum) <=
+    XTol * (fabs(TheMinimum) + fabs(PreviousMinimum) + EPSZ);
+}
+
+//=============================================================================
+//function : math_BFGS
+//purpose  : Constructor.
+//=============================================================================
+math_BFGS::math_BFGS(const Standard_Integer     NbVariables,
+                     const Standard_Real        Tolerance,
+                     const Standard_Integer     NbIterations,
+                     const Standard_Real        ZEPS)
+: TheStatus(math_OK),
+  TheLocation(1, NbVariables),
+  TheGradient(1, NbVariables),
+  PreviousMinimum(0.),
+  TheMinimum(0.),
+  XTol(Tolerance),
+  EPSZ(ZEPS),
+  nbiter(0),
+  myIsBoundsDefined(Standard_False),
+  myLeft(1, NbVariables, 0.0),
+  myRight(1, NbVariables, 0.0),
+  Done(Standard_False),
+  Itermax(NbIterations)
+{
+}
+
+//=============================================================================
+//function : ~math_BFGS
+//purpose  : Destructor.
+//=============================================================================
+math_BFGS::~math_BFGS()
+{
+}
+
+//=============================================================================
+//function : Dump
+//purpose  : Prints dump.
+//=============================================================================
+void math_BFGS::Dump(Standard_OStream& o) const
+{
+
+  o << "math_BFGS resolution: ";
+  if (Done)
+  {
+    o << " Status = Done \n";
+    o << " Location Vector = " << Location() << "\n";
+    o << " Minimum value = " << Minimum() << "\n";
+    o << " Number of iterations = " << NbIterations() << "\n";
+  }
+  else
+    o << " Status = not Done because " << (Standard_Integer)TheStatus << "\n";
+}
+
+//=============================================================================
 //function : SetBoundary
 //purpose  : Set boundaries for conditional optimization
-//=======================================================================
+//=============================================================================
 void math_BFGS::SetBoundary(const math_Vector& theLeftBorder,
                             const math_Vector& theRightBorder)
 {
index dd3498a9530c3df446af74c8b7ad4853639f4f94..3adad8464380e5179874db95f9e99ace0073c183 100644 (file)
@@ -167,17 +167,17 @@ void  math_FRPR::Perform(math_MultipleVarFunctionWithGradient& F,
         
          Standard_Boolean IsGood = MinimizeDirection(TheLocation,
                                             TheGradient, TheMinimum, F_Dir);
-         if(!IsGood) {
-           Done = Standard_False;
-           TheStatus = math_DirectionSearchError;
-           return;
-         }
-         if(IsSolutionReached(F)) {
+         if (IsSolutionReached(F)) {
            Done = Standard_True;
            State = F.GetStateNumber();
            TheStatus = math_OK;
            return;
          }
+         if(!IsGood) {
+           Done = Standard_False;
+           TheStatus = math_DirectionSearchError;
+           return;
+         }
          Good = F.Values(TheLocation, PreviousMinimum, TheGradient);
          if(!Good) { 
            Done = Standard_False;
diff --git a/tests/bugs/fclasses/bug30492 b/tests/bugs/fclasses/bug30492
new file mode 100644 (file)
index 0000000..9ae5346
--- /dev/null
@@ -0,0 +1,8 @@
+puts "============"
+puts "0030492: Foundation Classes - math_BFGS fails if starting point is exactly the minimum"
+puts "============"
+puts ""
+
+pload QAcommands
+
+OCC30492