// Created on: 1996-05-03 // Created by: Philippe MANGIN // Copyright (c) 1996-1999 Matra Datavision // Copyright (c) 1999-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 OCCT_DEBUG #define No_Standard_RangeError #define No_Standard_OutOfRange #define No_Standard_DimensionError //#endif #include #include #include #include #include #include #include //======================================================================= //function : math_NewtonMinimum //purpose : Constructor //======================================================================= math_NewtonMinimum::math_NewtonMinimum( const math_MultipleVarFunctionWithHessian& theFunction, const Standard_Real theTolerance, const Standard_Integer theNbIterations, const Standard_Real theConvexity, const Standard_Boolean theWithSingularity ) : TheStatus (math_NotBracketed), TheLocation(1, theFunction.NbVariables()), TheGradient(1, theFunction.NbVariables()), TheStep (1, theFunction.NbVariables(), 10.0 * theTolerance), TheHessian (1, theFunction.NbVariables(), 1, theFunction.NbVariables()), PreviousMinimum (0.0), TheMinimum (0.0), MinEigenValue (0.0), XTol (theTolerance), CTol (theConvexity), nbiter (0), NoConvexTreatement(theWithSingularity), Convex (Standard_True), myIsBoundsDefined(Standard_False), myLeft(1, theFunction.NbVariables(), 0.0), myRight(1, theFunction.NbVariables(), 0.0), Done (Standard_False), Itermax (theNbIterations) { } //======================================================================= //function : ~math_NewtonMinimum //purpose : Destructor //======================================================================= math_NewtonMinimum::~math_NewtonMinimum() { } //======================================================================= //function : SetBoundary //purpose : Set boundaries for conditional optimization //======================================================================= void math_NewtonMinimum::SetBoundary(const math_Vector& theLeftBorder, const math_Vector& theRightBorder) { myLeft = theLeftBorder; myRight = theRightBorder; myIsBoundsDefined = Standard_True; } //======================================================================= //function : Perform //purpose : //======================================================================= void math_NewtonMinimum::Perform(math_MultipleVarFunctionWithHessian& F, const math_Vector& StartingPoint) { math_Vector Point1 (1, F.NbVariables()); Point1 = StartingPoint; math_Vector Point2(1, F.NbVariables()); math_Vector* precedent = &Point1; math_Vector* suivant = &Point2; math_Vector* auxiliaire = precedent; Standard_Boolean Ok = Standard_True; Standard_Integer NbConv = 0, ii, Nreduction; Standard_Real VPrecedent, VItere; Done = Standard_True; TheStatus = math_OK; nbiter = 0; while ( Ok && (NbConv < 2) ) { nbiter++; // Positionnement Ok = F.Values(*precedent, VPrecedent, TheGradient, TheHessian); if (!Ok) { Done = Standard_False; TheStatus = math_FunctionError; return; } if (nbiter==1) { PreviousMinimum = VPrecedent; TheMinimum = VPrecedent; } // Traitement de la non convexite math_Jacobi CalculVP(TheHessian); if ( !CalculVP.IsDone() ) { Done = Standard_False; TheStatus = math_FunctionError; return; } MinEigenValue = CalculVP.Values() ( CalculVP.Values().Min()); if ( MinEigenValue < CTol) { Convex = Standard_False; if (NoConvexTreatement && // Treatment is allowed. Abs (MinEigenValue) > CTol) // Treatment will have effect. { Standard_Real Delta = CTol + 0.1 * Abs(MinEigenValue) - MinEigenValue; for (ii=1; ii<=TheGradient.Length(); ii++) TheHessian(ii, ii) += Delta; } else { Done = Standard_False; TheStatus = math_FunctionError; return; } } // Schemas de Newton math_Gauss LU(TheHessian, CTol/100); if ( !LU.IsDone()) { Done = Standard_False; TheStatus = math_DirectionSearchError; return; } LU.Solve(TheGradient, TheStep); if (myIsBoundsDefined) { // Project point on bounds or nullify TheStep coords if point lies on boundary. *suivant = *precedent - TheStep; Standard_Real aMult = RealLast(); for(Standard_Integer anIdx = 1; anIdx <= myLeft.Upper(); anIdx++) { const Standard_Real anAbsStep = Abs(TheStep(anIdx)); if (anAbsStep < gp::Resolution()) continue; if (suivant->Value(anIdx) < myLeft(anIdx)) { Standard_Real aValue = Abs(precedent->Value(anIdx) - myLeft(anIdx)) / anAbsStep; aMult = Min (aValue, aMult); } if (suivant->Value(anIdx) > myRight(anIdx)) { Standard_Real aValue = Abs(precedent->Value(anIdx) - myRight(anIdx)) / anAbsStep; aMult = Min (aValue, aMult); } } if (aMult != RealLast()) { if (aMult > Precision::PConfusion()) { // Project point into param space. TheStep *= aMult; } else { // Old point on border and new point out of border: // Nullify corresponding TheStep indexes. for(Standard_Integer anIdx = 1; anIdx <= myLeft.Upper(); anIdx++) { if ((Abs(precedent->Value(anIdx) - myRight(anIdx)) < Precision::PConfusion() && TheStep(anIdx) < 0.0) || (Abs(precedent->Value(anIdx) - myLeft(anIdx) ) < Precision::PConfusion() && TheStep(anIdx) > 0.0) ) { TheStep(anIdx) = 0.0; } } } } } Standard_Boolean hasProblem = Standard_False; do { *suivant = *precedent - TheStep; // Gestion de la convergence hasProblem = !(F.Value(*suivant, TheMinimum)); if (hasProblem) { TheStep /= 2.0; } } while (hasProblem); if (IsConverged()) { NbConv++; } else { NbConv=0; } // Controle et corrections. VItere = TheMinimum; TheMinimum = PreviousMinimum; Nreduction =0; while (VItere > VPrecedent && Nreduction < 10) { TheStep *= 0.4; *suivant = *precedent - TheStep; F.Value(*suivant, VItere); Nreduction++; } if (VItere <= VPrecedent) { auxiliaire = precedent; precedent = suivant; suivant = auxiliaire; PreviousMinimum = VPrecedent; TheMinimum = VItere; Ok = (nbiter < Itermax); if (!Ok && NbConv < 2) TheStatus = math_TooManyIterations; } else { Ok = Standard_False; TheStatus = math_DirectionSearchError; } } TheLocation = *precedent; } //======================================================================= //function : Dump //purpose : //======================================================================= void math_NewtonMinimum::Dump(Standard_OStream& o) const { o<< "math_Newton Optimisation: "; o << " Done =" << Done << std::endl; o << " Status = " << (Standard_Integer)TheStatus << std::endl; o << " Location Vector = " << Location() << std::endl; o << " Minimum value = "<< Minimum()<< std::endl; o << " Previous value = "<< PreviousMinimum << std::endl; o << " Number of iterations = " <