1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-04 13:13:25 +03:00

0024608: Development of methods of global optimization of multivariable function

math_GlobOptMin - new global optimization minimization algorithm
Extrema_GlobOptFuncCC, Extrema_ExtCC, Extrema_ExtCC2d - implementation of GlobOptMin algorithm to extrema curve / curve
Extrema_CurveCache - deleted as obsolete code
ChFi3d_Builder.cxx  - fixed processing of extrema
math_NewtonMinimum.cxx - fixed step to avoid incorrect behavior
Test cases modification to meet new behavior.
This commit is contained in:
aml
2014-04-15 10:36:52 +04:00
committed by apn
parent 97385d6142
commit 4bbaf12b67
32 changed files with 1319 additions and 1064 deletions

View File

@@ -8,4 +8,6 @@ math_Vector.hxx
math_Vector.cxx
math_IntegerVector.hxx
math_IntegerVector.cxx
math_SingleTab.hxx
math_SingleTab.hxx
math_GlobOptMin.hxx
math_GlobOptMin.cxx

View File

@@ -51,6 +51,7 @@ is
deferred class MultipleVarFunctionWithHessian;
deferred class FunctionSet;
deferred class FunctionSetWithDerivatives;
imported GlobOptMin;
class IntegerRandom;
class Gauss;
class GaussLeastSquare;

View File

@@ -0,0 +1,386 @@
// Created on: 2014-01-20
// Created by: Alexaner Malyshev
// Copyright (c) 2014-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement
#include <math_GlobOptMin.hxx>
#include <math_BFGS.hxx>
#include <math_Matrix.hxx>
#include <math_MultipleVarFunctionWithGradient.hxx>
#include <math_MultipleVarFunctionWithHessian.hxx>
#include <math_NewtonMinimum.hxx>
#include <math_Powell.hxx>
#include <Precision.hxx>
#include <Standard_Integer.hxx>
#include <Standard_Real.hxx>
const Handle(Standard_Type)& STANDARD_TYPE(math_GlobOptMin)
{
static Handle(Standard_Type) _atype = new Standard_Type ("math_GlobOptMin", sizeof (math_GlobOptMin));
return _atype;
}
//=======================================================================
//function : math_GlobOptMin
//purpose : Constructor
//=======================================================================
math_GlobOptMin::math_GlobOptMin(math_MultipleVarFunction* theFunc,
const math_Vector& theA,
const math_Vector& theB,
Standard_Real theC)
: myN(theFunc->NbVariables()),
myA(1, myN),
myB(1, myN),
myGlobA(1, myN),
myGlobB(1, myN),
myX(1, myN),
myTmp(1, myN),
myV(1, myN)
{
Standard_Integer i;
myFunc = theFunc;
myC = theC;
myZ = -1;
mySolCount = 0;
for(i = 1; i <= myN; i++)
{
myGlobA(i) = theA(i);
myGlobB(i) = theB(i);
myA(i) = theA(i);
myB(i) = theB(i);
}
myDone = Standard_False;
}
//=======================================================================
//function : SetGlobalParams
//purpose : Set params without memory allocation.
//=======================================================================
void math_GlobOptMin::SetGlobalParams(math_MultipleVarFunction* theFunc,
const math_Vector& theA,
const math_Vector& theB,
Standard_Real theC)
{
Standard_Integer i;
myFunc = theFunc;
myC = theC;
myZ = -1;
mySolCount = 0;
for(i = 1; i <= myN; i++)
{
myGlobA(i) = theA(i);
myGlobB(i) = theB(i);
myA(i) = theA(i);
myB(i) = theB(i);
}
myDone = Standard_False;
}
//=======================================================================
//function : SetLocalParams
//purpose : Set params without memory allocation.
//=======================================================================
void math_GlobOptMin::SetLocalParams(const math_Vector& theLocalA,
const math_Vector& theLocalB)
{
Standard_Integer i;
myZ = -1;
mySolCount = 0;
for(i = 1; i <= myN; i++)
{
myA(i) = theLocalA(i);
myB(i) = theLocalB(i);
}
myDone = Standard_False;
}
//=======================================================================
//function : ~math_GlobOptMin
//purpose :
//=======================================================================
math_GlobOptMin::~math_GlobOptMin()
{
}
//=======================================================================
//function : Perform
//purpose : Compute Global extremum point
//=======================================================================
// In this algo indexes started from 1, not from 0.
void math_GlobOptMin::Perform()
{
Standard_Integer i;
// Compute parameters range
Standard_Real minLength = RealLast();
Standard_Real maxLength = RealFirst();
for(i = 1; i <= myN; i++)
{
Standard_Real currentLength = myB(i) - myA(i);
if (currentLength < minLength)
minLength = currentLength;
if (currentLength > maxLength)
maxLength = currentLength;
}
Standard_Real myTol = 1e-2;
myE1 = minLength * myTol / myC;
myE2 = 2.0 * myTol / myC * maxLength;
myE3 = - maxLength * myTol / 4;
// Compure start point.
math_Vector aPnt(1,2);
for(i = 1; i <= myN; i++)
{
Standard_Real currCentral = (myA(i) + myB(i)) / 2.0;
aPnt(i) = currCentral;
myY.Append(currCentral);
}
myFunc->Value(aPnt, myF);
mySolCount++;
computeGlobalExtremum(myN);
myDone = Standard_True;
}
//=======================================================================
//function : computeLocalExtremum
//purpose :
//=======================================================================
Standard_Boolean math_GlobOptMin::computeLocalExtremum(const math_Vector& thePnt,
Standard_Real& theVal,
math_Vector& theOutPnt)
{
Standard_Integer i;
//Newton method
if (dynamic_cast<math_MultipleVarFunctionWithHessian*>(myFunc))
{
math_MultipleVarFunctionWithHessian* myTmp =
dynamic_cast<math_MultipleVarFunctionWithHessian*> (myFunc);
math_NewtonMinimum newtonMinimum(*myTmp, thePnt);
if (newtonMinimum.IsDone())
{
newtonMinimum.Location(theOutPnt);
theVal = newtonMinimum.Minimum();
}
else return Standard_False;
} else
// BFGS method used.
if (dynamic_cast<math_MultipleVarFunctionWithGradient*>(myFunc))
{
math_MultipleVarFunctionWithGradient* myTmp =
dynamic_cast<math_MultipleVarFunctionWithGradient*> (myFunc);
math_BFGS bfgs(*myTmp, thePnt);
if (bfgs.IsDone())
{
bfgs.Location(theOutPnt);
theVal = bfgs.Minimum();
}
else return Standard_False;
} else
// Powell method used.
if (dynamic_cast<math_MultipleVarFunction*>(myFunc))
{
math_Matrix m(1, myN, 1, myN, 0.0);
for(i = 1; i <= myN; i++)
m(1, 1) = 1.0;
math_Powell powell(*myFunc, thePnt, m, 1e-10);
if (powell.IsDone())
{
powell.Location(theOutPnt);
theVal = powell.Minimum();
}
else return Standard_False;
}
if (isInside(theOutPnt))
return Standard_True;
else
return Standard_False;
}
//=======================================================================
//function : ComputeGlobalExtremum
//purpose :
//=======================================================================
void math_GlobOptMin::computeGlobalExtremum(Standard_Integer j)
{
Standard_Integer i;
Standard_Real d; // Functional in moved point.
Standard_Real val = RealLast(); // Local extrema computed in moved point.
Standard_Real stepBestValue = RealLast();
math_Vector stepBestPoint(1,2);
Standard_Boolean isInside = Standard_False;
Standard_Real r;
for(myX(j) = myA(j) + myE1; myX(j) < myB(j) + myE1; myX(j) += myV(j))
{
if (myX(j) > myB(j))
myX(j) = myB(j);
if (j == 1)
{
isInside = Standard_False;
myFunc->Value(myX, d);
r = (d - myF) * myZ;
if(r > myE3)
{
isInside = computeLocalExtremum(myX, val, myTmp);
}
stepBestValue = (isInside && (val < d))? val : d;
stepBestPoint = (isInside && (val < d))? myTmp : myX;
// Solutions are close to each other.
if (Abs(stepBestValue - myF) < Precision::Confusion() * 0.01)
{
if (!isStored(stepBestPoint))
{
if ((stepBestValue - myF) * myZ > 0.0)
myF = stepBestValue;
for(i = 1; i <= myN; i++)
myY.Append(stepBestPoint(i));
mySolCount++;
}
}
// New best solution.
if ((stepBestValue - myF) * myZ > Precision::Confusion() * 0.01)
{
mySolCount = 0;
myF = stepBestValue;
myY.Clear();
for(i = 1; i <= myN; i++)
myY.Append(stepBestPoint(i));
mySolCount++;
}
myV(1) = myE2 + Abs(myF - d) / myC;
}
else
{
myV(j) = RealLast() / 2.0;
computeGlobalExtremum(j - 1);
}
if ((j < myN) && (myV(j + 1) > myV(j)))
{
if (myV(j) > (myB(j + 1) - myA(j + 1)) / 3.0) // Case of too big step.
myV(j + 1) = (myB(j + 1) - myA(j + 1)) / 3.0;
else
myV(j + 1) = myV(j);
}
}
}
//=======================================================================
//function : IsInside
//purpose :
//=======================================================================
Standard_Boolean math_GlobOptMin::isInside(const math_Vector& thePnt)
{
Standard_Integer i;
for(i = 1; i <= myN; i++)
{
if (thePnt(i) < myGlobA(i) || thePnt(i) > myGlobB(i))
return Standard_False;
}
return Standard_True;
}
//=======================================================================
//function : IsStored
//purpose :
//=======================================================================
Standard_Boolean math_GlobOptMin::isStored(const math_Vector& thePnt)
{
Standard_Integer i,j;
Standard_Boolean isSame = Standard_True;
for(i = 0; i < mySolCount; i++)
{
isSame = Standard_True;
for(j = 1; j <= myN; j++)
{
if ((Abs(thePnt(j) - myY(i * myN + j))) > (myB(j) - myA(j)) * Precision::Confusion())
{
isSame = Standard_False;
break;
}
}
if (isSame == Standard_True)
return Standard_True;
}
return Standard_False;
}
//=======================================================================
//function : NbExtrema
//purpose :
//=======================================================================
Standard_Integer math_GlobOptMin::NbExtrema()
{
return mySolCount;
}
//=======================================================================
//function : GetF
//purpose :
//=======================================================================
Standard_Real math_GlobOptMin::GetF()
{
return myF;
}
//=======================================================================
//function : IsDone
//purpose :
//=======================================================================
Standard_Boolean math_GlobOptMin::isDone()
{
return myDone;
}
//=======================================================================
//function : Points
//purpose :
//=======================================================================
void math_GlobOptMin::Points(const Standard_Integer theIndex, math_Vector& theSol)
{
Standard_Integer j;
for(j = 1; j <= myN; j++)
theSol(j) = myY((theIndex - 1) * myN + j);
}

View File

@@ -0,0 +1,101 @@
// Created on: 2014-01-20
// Created by: Alexaner Malyshev
// Copyright (c) 2014-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _math_GlobOptMin_HeaderFile
#define _math_GlobOptMin_HeaderFile
#include <math_MultipleVarFunction.hxx>
#include <NCollection_Sequence.hxx>
#include <Standard_Type.hxx>
//! This class represents Evtushenko's algorithm of global optimization based on nonuniform mesh.<br>
//! Article: Yu. Evtushenko. Numerical methods for finding global extreme (case of a non-uniform mesh). <br>
//! U.S.S.R. Comput. Maths. Math. Phys., Vol. 11, N 6, pp. 38-54.
class math_GlobOptMin
{
public:
Standard_EXPORT math_GlobOptMin(math_MultipleVarFunction* theFunc,
const math_Vector& theA,
const math_Vector& theB,
Standard_Real theC = 9);
Standard_EXPORT void SetGlobalParams(math_MultipleVarFunction* theFunc,
const math_Vector& theA,
const math_Vector& theB,
Standard_Real theC = 9);
Standard_EXPORT void SetLocalParams(const math_Vector& theLocalA,
const math_Vector& theLocalB);
Standard_EXPORT ~math_GlobOptMin();
Standard_EXPORT void Perform();
//! Get best functional value.
Standard_EXPORT Standard_Real GetF();
//! Return count of global extremas. NbExtrema <= MAX_SOLUTIONS.
Standard_EXPORT Standard_Integer NbExtrema();
//! Return solution i, 1 <= i <= NbExtrema.
Standard_EXPORT void Points(const Standard_Integer theIndex, math_Vector& theSol);
private:
math_GlobOptMin & operator = (const math_GlobOptMin & theOther);
Standard_Boolean computeLocalExtremum(const math_Vector& thePnt, Standard_Real& theVal, math_Vector& theOutPnt);
void computeGlobalExtremum(Standard_Integer theIndex);
//! Check that myA <= pnt <= myB
Standard_Boolean isInside(const math_Vector& thePnt);
Standard_Boolean isStored(const math_Vector &thePnt);
Standard_Boolean isDone();
// Input.
math_MultipleVarFunction* myFunc;
Standard_Integer myN;
math_Vector myA; // Left border on current C2 interval.
math_Vector myB; // Right border on current C2 interval.
math_Vector myGlobA; // Global left border.
math_Vector myGlobB; // Global right border.
// Output.
Standard_Boolean myDone;
NCollection_Sequence<Standard_Real> myY;// Current solutions.
Standard_Integer mySolCount; // Count of solutions.
// Algorithm data.
Standard_Real myZ;
Standard_Real myC; //Lipschitz constant
Standard_Real myE1; // Border coeff.
Standard_Real myE2; // Minimum step size.
Standard_Real myE3; // Local extrema starting parameter.
math_Vector myX; // Current modified solution
math_Vector myTmp; // Current modified solution
math_Vector myV; // Steps array.
Standard_Real myF; // Current value of Global optimum.
};
const Handle(Standard_Type)& TYPE(math_GlobOptMin);
#endif

View File

@@ -143,12 +143,19 @@ void math_NewtonMinimum::Perform(math_MultipleVarFunctionWithHessian& F,
}
LU.Solve(TheGradient, TheStep);
*suivant = *precedent - TheStep;
Standard_Boolean hasProblem = Standard_False;
do
{
*suivant = *precedent - TheStep;
// Gestion de la convergence
hasProblem = !(F.Value(*suivant, TheMinimum));
// Gestion de la convergence
F.Value(*suivant, TheMinimum);
if (hasProblem)
{
TheStep /= 2.0;
}
} while (hasProblem);
if (IsConverged()) { NbConv++; }
else { NbConv=0; }