Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
GSLMultiRootFinder.cxx
Go to the documentation of this file.
1// @(#)root/mathmore:$Id$
2// Authors: L. Moneta, A. Zsenei 08/2005
3
4 /**********************************************************************
5 * *
6 * Copyright (c) 2004 ROOT Foundation, CERN/PH-SFT *
7 * *
8 * This library is free software; you can redistribute it and/or *
9 * modify it under the terms of the GNU General Public License *
10 * as published by the Free Software Foundation; either version 2 *
11 * of the License, or (at your option) any later version. *
12 * *
13 * This library is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16 * General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this library (see file COPYING); if not, write *
20 * to the Free Software Foundation, Inc., 59 Temple Place, Suite *
21 * 330, Boston, MA 02111-1307 USA, or contact the author. *
22 * *
23 **********************************************************************/
24
25// Implementation file for class GSLMultiRootFinder
26//
27// Created by: moneta at Sun Nov 14 11:27:11 2004
28//
29// Last update: Sun Nov 14 11:27:11 2004
30//
31
32#include "Math/IFunction.h"
34#include "GSLMultiRootSolver.h"
35#include "Math/Error.h"
36
37#include "gsl/gsl_multiroots.h"
38#include "gsl/gsl_errno.h"
39#include <cmath>
40#include <iomanip>
41
42#include <algorithm>
43#include <functional>
44#include <cctype> // need to use c version of tolower defined here
45
46
47namespace ROOT {
48namespace Math {
49
50 // default values
51
52 int gDefaultMaxIter = 100;
53 double gDefaultAbsTolerance = 1.E-6;
54 double gDefaultRelTolerance = 1.E-10;
55
56// implementation of static methods
57void GSLMultiRootFinder::SetDefaultTolerance(double abstol, double reltol ) {
58 // set default tolerance
59 gDefaultAbsTolerance = abstol;
60 if (reltol > 0) gDefaultRelTolerance = reltol;
61}
63 // set default max iter
64 gDefaultMaxIter = maxiter;
65}
66
68 fIter(0), fStatus(-1), fPrintLevel(0),
69 fType(type), fUseDerivAlgo(false),
70 fSolver(nullptr)
71{
72 // constructor for non derivative type
73 fFunctions.reserve(2);
74}
75
77 fIter(0), fStatus(-1), fPrintLevel(0),
78 fType(type), fUseDerivAlgo(true),
79 fSolver(nullptr)
80{
81 // constructor for non derivative type
82 fFunctions.reserve(2);
83}
84
86 fIter(0), fStatus(-1), fPrintLevel(0),
87 fType(0), fUseDerivAlgo(false),
88 fSolver(nullptr)
89{
90 // constructor for a string
91 fFunctions.reserve(2);
93}
94
96{
97 // delete function wrapper
99 if (fSolver) delete fSolver;
100}
101
103 // set type using a string
104 std::pair<bool,int> type = GetType(name);
105 fUseDerivAlgo = type.first;
106 fType = type.second;
107}
108
109
111 // add a new function in the vector
113 if (!f) return 0;
114 fFunctions.push_back(f);
115 return fFunctions.size();
116}
117
119 // clear the function list
120 for (unsigned int i = 0; i < fFunctions.size(); ++i) {
121 if (fFunctions[i] != nullptr ) delete fFunctions[i];
122 fFunctions[i] = nullptr;
123 }
124 fFunctions.clear();
125}
126
128 // clear the function list and the solver
130 if (fSolver) Clear();
131 fSolver = nullptr;
132}
133
134
135const double * GSLMultiRootFinder::X() const {
136 // return x
137 return (fSolver != nullptr) ? fSolver->X() : nullptr;
138}
139const double * GSLMultiRootFinder::Dx() const {
140 // return x
141 return (fSolver != nullptr) ? fSolver->Dx() : nullptr;
142}
143const double * GSLMultiRootFinder::FVal() const {
144 // return x
145 return (fSolver != nullptr) ? fSolver->FVal() : nullptr;
146}
147const char * GSLMultiRootFinder::Name() const {
148 // get GSL name
149 return (fSolver != nullptr) ? fSolver->Name().c_str() : "";
150}
151
152// bool GSLMultiRootFinder::AddFunction( const ROOT::Math::IMultiGenFunction & func) {
153// // clone and add function to the list
154// // If using a derivative algorithm the function is checked if it implements
155// // the gradient interface. If this is not the case the type is set to non-derivatibe algo
156// ROOT::Math::IGenMultiFunction * f = func.Clone();
157// if (f != 0) return false;
158// if (fUseDerivAlgo) {
159// bool gradFunc = (dynamic_cast<ROOT::Math::IMultiGradFunction *> (f) != 0 );
160// if (!gradFunc) {
161// MATH_ERROR_MSG("GSLMultiRootFinder::AddFunction","Function does not provide gradient interface");
162// MATH_WARN_MSG("GSLMultiRootFinder::AddFunction","clear the function list");
163// ClearFunctions();
164// return false;
165// }
166// }
167// fFunctions.push_back(f);
168// return true;
169// }
170
171 const gsl_multiroot_fsolver_type * GetGSLType(GSLMultiRootFinder::EType type) {
172 //helper functions to find GSL type
173 switch(type)
174 {
176 return gsl_multiroot_fsolver_hybrids;
178 return gsl_multiroot_fsolver_hybrid;
180 return gsl_multiroot_fsolver_dnewton;
182 return gsl_multiroot_fsolver_broyden;
183 default:
184 return gsl_multiroot_fsolver_hybrids;
185 }
186 return nullptr;
187}
188
189const gsl_multiroot_fdfsolver_type * GetGSLDerivType(GSLMultiRootFinder::EDerivType type) {
190//helper functions to find GSL deriv type
191 switch(type)
192 {
194 return gsl_multiroot_fdfsolver_hybridsj;
196 return gsl_multiroot_fdfsolver_hybridj;
198 return gsl_multiroot_fdfsolver_newton;
200 return gsl_multiroot_fdfsolver_gnewton;
201 default:
202 return gsl_multiroot_fdfsolver_hybridsj;
203 }
204 return nullptr; // cannot happen
205}
206
207std::pair<bool,int> GSLMultiRootFinder::GetType(const char * name) {
208 if (name == nullptr) return std::make_pair<bool,int>(false, -1);
209 std::string aname = name;
210 std::transform(aname.begin(), aname.end(), aname.begin(), (int(*)(int)) tolower );
211
212 if (aname.find("hybridsj") != std::string::npos) return std::make_pair(true, kHybridSJ);
213 if (aname.find("hybridj") != std::string::npos) return std::make_pair(true, kHybridJ);
214 if (aname.find("hybrids") != std::string::npos) return std::make_pair(false, kHybridS);
215 if (aname.find("hybrid") != std::string::npos) return std::make_pair(false, kHybrid);
216 if (aname.find("gnewton") != std::string::npos) return std::make_pair(true, kGNewton);
217 if (aname.find("dnewton") != std::string::npos) return std::make_pair(false, kDNewton);
218 if (aname.find("newton") != std::string::npos) return std::make_pair(true, kNewton);
219 if (aname.find("broyden") != std::string::npos) return std::make_pair(false, kBroyden);
220 MATH_INFO_MSG("GSLMultiRootFinder::GetType","Unknow algorithm - use default one");
221 return std::make_pair(false, -1);
222}
223
224bool GSLMultiRootFinder::Solve (const double * x, int maxIter, double absTol, double relTol)
225{
226 fIter = 0;
227 // create the solvers - delete previous existing solver
228 if (fSolver) delete fSolver;
229 fSolver = nullptr;
230
231 if (fFunctions.empty()) {
232 MATH_ERROR_MSG("GSLMultiRootFinder::Solve","Function list is empty");
233 fStatus = -1;
234 return false;
235 }
236
237 if (fUseDerivAlgo) {
240 }
241 else {
242 EType type = (EType) fType;
244 }
245
246
247 // first set initial values and function
248 assert(fSolver != nullptr);
249 bool ret = fSolver->InitSolver( fFunctions, x);
250 if (!ret) {
251 MATH_ERROR_MSG("GSLMultiRootFinder::Solve","Error initializing the solver");
252 fStatus = -2;
253 return false;
254 }
255
256 if (maxIter == 0) maxIter = gDefaultMaxIter;
257 if (absTol <= 0) absTol = gDefaultAbsTolerance;
258 if (relTol <= 0) relTol = gDefaultRelTolerance;
259
260 if (fPrintLevel >= 1)
261 std::cout << "GSLMultiRootFinder::Solve:" << Name() << " max iterations " << maxIter << " and tolerance " << absTol << std::endl;
262
263 // find the roots by iterating
264 fStatus = 0;
265 int status = 0;
266 int iter = 0;
267 do {
268 iter++;
269 status = fSolver->Iterate();
270
271 if (fPrintLevel >= 2) {
272 std::cout << "GSLMultiRootFinder::Solve - iteration # " << iter << " status = " << status << std::endl;
273 PrintState();
274 }
275 // act in case of error
276 if (status == GSL_EBADFUNC) {
277 MATH_ERROR_MSG("GSLMultiRootFinder::Solve","The iteration encountered a singular point due to a bad function value");
278 fStatus = status;
279 break;
280 }
281 if (status == GSL_ENOPROG) {
282 MATH_ERROR_MSG("GSLMultiRootFinder::Solve","The iteration is not making any progress");
283 fStatus = status;
284 break;
285 }
286 if (status != GSL_SUCCESS) {
287 MATH_ERROR_MSG("GSLMultiRootFinder::Solve","Unknown iteration error - exit");
288 fStatus = status;
289 break;
290 }
291
292 // test also residual
293 status = fSolver->TestResidual(absTol);
294
295
296 // should test also the Delta ??
297 int status2 = fSolver->TestDelta(absTol, relTol);
298 if (status2 == GSL_SUCCESS) {
299 MATH_INFO_MSG("GSLMultiRootFinder::Solve","The iteration converged");
300 }
301 }
302 while (status == GSL_CONTINUE && iter < maxIter);
303 if (status == GSL_CONTINUE) {
304 MATH_INFO_MSGVAL("GSLMultiRootFinder::Solve","exceeded max iterations, reached tolerance is not sufficient",absTol);
305 }
306 if (status == GSL_SUCCESS) {
307 if (fPrintLevel>=1) { // print the result
308 MATH_INFO_MSG("GSLMultiRootFinder::Solve","The iteration converged");
309 std::cout << "GSL Algorithm used is : " << fSolver->Name() << std::endl;
310 std::cout << "Number of iterations = " << iter<< std::endl;
311
312 PrintState();
313 }
314 }
315 fIter = iter;
316 fStatus = status;
317 return (fStatus == GSL_SUCCESS);
318
319}
320
321void GSLMultiRootFinder::PrintState(std::ostream & os) {
322 // print current state
323 if (!fSolver) return;
324 double ndigits = std::log10( double( Dim() ) );
325 int wi = int(ndigits)+1;
326 const double * xtmp = fSolver->X();
327 const double * ftmp = fSolver->FVal();
328 os << "Root values = ";
329 for (unsigned int i = 0; i< Dim(); ++i)
330 os << "x[" << std::setw(wi) << i << "] = " << std::setw(12) << xtmp[i] << " ";
331 os << std::endl;
332 os << "Function values = ";
333 for (unsigned int i = 0; i< Dim(); ++i)
334 os << "f[" << std::setw(wi) << i << "] = " << std::setw(12) << ftmp[i] << " ";
335 os << std::endl;
336}
337
338
339
340} // namespace Math
341} // namespace ROOT
#define MATH_INFO_MSG(loc, str)
Pre-processor macro to report messages which can be configured to use ROOT error or simply an std::io...
Definition Error.h:77
#define MATH_INFO_MSGVAL(loc, txt, x)
Definition Error.h:101
#define MATH_ERROR_MSG(loc, str)
Definition Error.h:83
#define f(i)
Definition RSha256.hxx:104
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
char name[80]
Definition TGX11.cxx:110
int TestResidual(double absTol) const
test using abs tolerance Sum |f|_i < absTol
const double * FVal() const
return function values
const double * X() const
solution values at the current iteration
virtual const std::string & Name() const =0
return name
const double * Dx() const
return function steps
bool InitSolver(const std::vector< ROOT::Math::IMultiGenFunction * > &funcVec, const double *x)
init the solver with function list and initial values
virtual int Iterate()=0
perform an iteration
int TestDelta(double absTol, double relTol) const
test using abs and relative tolerance |dx| < absTol + relTol*|x| for every component
GSLMultiRootDerivSolver, internal class for implementing GSL multi-root finders using derivatives.
unsigned int Dim() const
return the number of sunctions set in the class.
const double * Dx() const
return the last step size
const double * FVal() const
return the function values f(X) solving the system i.e.
void SetType(EType type)
set the type for an algorithm without derivatives
std::vector< ROOT::Math::IMultiGenFunction * > fFunctions
bool Solve(const double *x, int maxIter=0, double absTol=0, double relTol=0)
Find the root starting from the point X; Use the number of iteration and tolerance if given otherwise...
EType
enumeration specifying the types of GSL multi root finders which do not require the derivatives
std::pair< bool, int > GetType(const char *name)
const char * Name() const
Return the algorithm name used for solving Note the name is available only after having called solved...
void PrintState(std::ostream &os=std::cout)
print iteration state
GSLMultiRootBaseSolver * fSolver
EDerivType
enumeration specifying the types of GSL multi root finders requiring the derivatives
GSLMultiRootFinder(EType type)
create a multi-root finder based on an algorithm not requiring function derivative
void Clear()
clear list of functions
static void SetDefaultTolerance(double abstol, double reltol=0)
set tolerance (absolute and relative) relative tolerance is only use to verify the convergence do it ...
int AddFunction(const ROOT::Math::IMultiGenFunction &func)
const double * X() const
return the root X values solving the system
static void SetDefaultMaxIterations(int maxiter)
set maximum number of iterations
GSLMultiRootSolver, internal class for implementing GSL multi-root finders not using derivatives.
Documentation for the abstract class IBaseFunctionMultiDim.
Definition IFunction.h:61
virtual IBaseFunctionMultiDimTempl< T > * Clone() const =0
Clone a function.
Double_t x[n]
Definition legend1.C:17
Namespace for new Math classes and functions.
const gsl_multiroot_fsolver_type * GetGSLType(GSLMultiRootFinder::EType type)
double gDefaultRelTolerance
const gsl_multiroot_fdfsolver_type * GetGSLDerivType(GSLMultiRootFinder::EDerivType type)
double gDefaultAbsTolerance
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...