33#include < Fit/ParameterSettings.h>
44#include < Math/IFunction.h>
55#include < Math/FitMethodFunction.h>
6+ #include " Math/GenAlgoOptions.h"
67#include < TString.h>
78#include < iostream>
89
@@ -15,9 +16,11 @@ using namespace ROOT::Math::Experimental;
1516using namespace ROOT ::Fit;
1617
1718// / function wrapper for the function to be minimized
18- const ROOT::Math::IMultiGenFunction *gFunction ;
19+ const ROOT::Math::IMultiGenFunction *gFunction = nullptr ;
1920// / function wrapper for the gradient of the function to be minimized
20- const ROOT::Math::IMultiGradFunction *gGradFunction ;
21+ const ROOT::Math::IMultiGradFunction *gGradFunction = nullptr ;
22+
23+ #define PyPrint (pyo ) PyObject_Print(pyo, stdout, Py_PRINT_RAW)
2124
2225PyObject *target_function (PyObject * /* self*/ , PyObject *args)
2326{
@@ -46,10 +49,12 @@ PyObject *jac_function(PyObject * /*self*/, PyObject *args)
4649ScipyMinimizer::ScipyMinimizer () : BasicMinimizer()
4750{
4851 fOptions .SetMinimizerType (" Scipy" );
49- fOptions .SetMinimizerAlgorithm (" lbfgsb " );
52+ fOptions .SetMinimizerAlgorithm (" L-BFGS-B " );
5053 if (!PyIsInitialized ()) {
5154 PyInitialize ();
5255 }
56+ // set extra options
57+ SetAlgoExtraOptions ();
5358}
5459
5560// _______________________________________________________________________
@@ -60,6 +65,19 @@ ScipyMinimizer::ScipyMinimizer(const char *type)
6065 if (!PyIsInitialized ()) {
6166 PyInitialize ();
6267 }
68+ // set extra options
69+ SetAlgoExtraOptions ();
70+ }
71+
72+ // _______________________________________________________________________
73+ void ScipyMinimizer::SetAlgoExtraOptions ()
74+ {
75+ std::string type = fOptions .MinimizerAlgorithm ();
76+ if (type == " L-BFGS-B" ) {
77+ fExtraOpts .SetValue (" gtol" , 1e-10 );
78+ fExtraOpts .SetValue (" eps" , 1.0 );
79+ }
80+ SetExtraOptions (fExtraOpts );
6381}
6482
6583// _______________________________________________________________________
@@ -144,7 +162,19 @@ bool ScipyMinimizer::Minimize()
144162{
145163 (gFunction ) = ObjFunction ();
146164 (gGradFunction ) = GradObjFunction ();
165+ if (gGradFunction == nullptr ) {
166+ fJacobian = Py_None;
167+ }
147168 auto method = fOptions .MinimizerAlgorithm ();
169+ PyObject *pyoptions = PyDict_New ();
170+ if (method == " L-BFGS-B" ) {
171+ for (std::string key : fExtraOpts .GetAllRealKeys ()) {
172+ double value = 0 ;
173+ fExtraOpts .GetRealValue (key.c_str (), value);
174+ PyDict_SetItemString (pyoptions, key.c_str (), PyFloat_FromDouble (value));
175+ }
176+ }
177+
148178 std::cout << " === Scipy Minimization" << std::endl;
149179 std::cout << " === Method: " << method << std::endl;
150180 std::cout << " === Initial value: (" ;
@@ -157,15 +187,20 @@ bool ScipyMinimizer::Minimize()
157187
158188 double *values = const_cast <double *>(X ());
159189 npy_intp dims[1 ] = {NDim ()};
160- PyObject *py_array = PyArray_SimpleNewFromData (1 , dims, NPY_DOUBLE, values);
161-
162- PyObject *pargs = PyTuple_New (0 );
163-
164- auto pyvalues = Py_BuildValue (" (OOOsO)" , fTarget , py_array, pargs, method.c_str (), fJacobian );
165-
166- PyObject *result = PyObject_CallObject (fMinimize , pyvalues);
167- Py_DECREF (pyvalues);
168- Py_DECREF (py_array);
190+ PyObject *x0 = PyArray_SimpleNewFromData (1 , dims, NPY_DOUBLE, values);
191+
192+ // minimize(fun, x0, args=(), method=None, jac=None, hess=None, hessp=None, bounds=None, constraints=(), tol=None,
193+ // callback=None, options=None)
194+ auto args = Py_BuildValue (" (OO)" , fTarget , x0);
195+ auto kw = Py_BuildValue (" {s:s,s:O,s:d,s:O}" , " method" , method.c_str (), " jac" , fJacobian , " tol" , Tolerance (),
196+ " options" , pyoptions);
197+
198+ // PyPrint(kw);
199+ PyObject *result = PyObject_Call (fMinimize , args, kw);
200+ // PyPrint(result);
201+ Py_DECREF (args);
202+ Py_DECREF (kw);
203+ Py_DECREF (x0);
169204
170205 // if the minimization works
171206 PyObject *pstatus = PyObject_GetAttrString (result, " status" );
0 commit comments