Logo ROOT   6.10/09
Reference Guide
TPyFitFunction.cxx
Go to the documentation of this file.
1 // Author: Wim Lavrijsen November 2010
2 
3 // Bindings
4 #include "PyROOT.h"
5 #include "TPyFitFunction.h"
6 #include "ObjectProxy.h"
7 #include "MethodProxy.h"
8 #include "TPyBufferFactory.h"
9 
10 // Standard
11 #include <stdexcept>
12 
13 //______________________________________________________________________________
14 // Python wrapper for Fit functions
15 // ================================
16 //
17 
18 
19 //- data ---------------------------------------------------------------------
22 
23 
24 //- helper functions ---------------------------------------------------------
25 static PyObject* GetOverriddenPyMethod( PyObject* pyself, const char* method )
26 {
27 // Retrieve an overriden method on pyself
28  PyObject* pymethod = 0;
29 
30  if ( pyself && pyself != Py_None ) {
31  pymethod = PyObject_GetAttrString( (PyObject*)pyself, const_cast< char* >( method ) );
32  if ( ! PyROOT::MethodProxy_CheckExact( pymethod ) )
33  return pymethod;
34 
35  Py_XDECREF( pymethod );
36  pymethod = 0;
37  }
38 
39  return pymethod;
40 }
41 
42 static PyObject* DispatchCall( PyObject* pyself, const char* method, PyObject* pymethod = NULL,
43  PyObject* arg1 = NULL, PyObject* arg2 = NULL, PyObject* arg3 = NULL )
44 {
45 // Forward <method> to python (need to refactor this with TPySelector).
46  PyObject* result = 0;
47 
48 // get the named method and check for python side overload by not accepting the
49 // binding's methodproxy
50  if ( ! pymethod )
51  pymethod = GetOverriddenPyMethod( pyself, method );
52 
53  if ( pymethod ) {
54  result = PyObject_CallFunctionObjArgs( pymethod, arg1, arg2, arg3, NULL );
55  } else {
56  // means the method has not been overridden ... simply accept its not there
57  result = 0;
58  PyErr_Format( PyExc_AttributeError,
59  "method %s needs implementing in derived class", const_cast< char* >( method ) );
60  }
61 
62  Py_XDECREF( pymethod );
63 
64  return result;
65 }
66 
67 
68 //- constructors/destructor --------------------------------------------------
70 {
71 // Construct a TPyMultiGenFunction derived with <self> as the underlying
72  if ( self ) {
73  // steal reference as this is us, as seen from python
74  fPySelf = self;
75  } else {
76  Py_INCREF( Py_None ); // using None allows clearer diagnostics
77  fPySelf = Py_None;
78  }
79 }
80 
81 ////////////////////////////////////////////////////////////////////////////////
82 /// Destructor. Only deref if still holding on to Py_None (circular otherwise).
83 
85 {
86  if ( fPySelf == Py_None ) {
87  Py_DECREF( fPySelf );
88  }
89 }
90 
91 
92 //- public functions ---------------------------------------------------------
93 unsigned int TPyMultiGenFunction::NDim() const
94 {
95 // Simply forward the call to python self.
96  PyObject* pyresult = DispatchCall( fPySelf, "NDim" );
97 
98  if ( ! pyresult ) {
99  PyErr_Print();
100  throw std::runtime_error( "Failure in TPyMultiGenFunction::NDim" );
101  }
102 
103  unsigned int cppresult = (unsigned int)PyLong_AsLong( pyresult );
104  Py_XDECREF( pyresult );
105 
106  return cppresult;
107 }
108 
109 ////////////////////////////////////////////////////////////////////////////////
110 /// Simply forward the call to python self.
111 
112 double TPyMultiGenFunction::DoEval( const double* x ) const
113 {
115  PyObject* pyresult = DispatchCall( fPySelf, "DoEval", NULL, xbuf );
116  Py_DECREF( xbuf );
117 
118  if ( ! pyresult ) {
119  PyErr_Print();
120  throw std::runtime_error( "Failure in TPyMultiGenFunction::DoEval" );
121  }
122 
123  double cppresult = (double)PyFloat_AsDouble( pyresult );
124  Py_XDECREF( pyresult );
125 
126  return cppresult;
127 }
128 
129 
130 
131 //- constructors/destructor --------------------------------------------------
133 {
134 // Construct a TPyMultiGradFunction derived with <self> as the underlying
135  if ( self ) {
136  // steal reference as this is us, as seen from python
137  fPySelf = self;
138  } else {
139  Py_INCREF( Py_None ); // using None allows clearer diagnostics
140  fPySelf = Py_None;
141  }
142 }
143 
144 ////////////////////////////////////////////////////////////////////////////////
145 /// Destructor. Only deref if still holding on to Py_None (circular otherwise).
146 
148 {
149  if ( fPySelf == Py_None ) {
150  Py_DECREF( fPySelf );
151  }
152 }
153 
154 
155 //- public functions ---------------------------------------------------------
156 unsigned int TPyMultiGradFunction::NDim() const
157 {
158 // Simply forward the call to python self.
159  PyObject* pyresult = DispatchCall( fPySelf, "NDim" );
160 
161  if ( ! pyresult ) {
162  PyErr_Print();
163  throw std::runtime_error( "Failure in TPyMultiGradFunction::NDim" );
164  }
165 
166  unsigned int cppresult = (unsigned int)PyLong_AsLong( pyresult );
167  Py_XDECREF( pyresult );
168 
169  return cppresult;
170 }
171 
172 ////////////////////////////////////////////////////////////////////////////////
173 /// Simply forward the call to python self.
174 
175 double TPyMultiGradFunction::DoEval( const double* x ) const
176 {
178  PyObject* pyresult = DispatchCall( fPySelf, "DoEval", NULL, xbuf );
179  Py_DECREF( xbuf );
180 
181  if ( ! pyresult ) {
182  PyErr_Print();
183  throw std::runtime_error( "Failure in TPyMultiGradFunction::DoEval" );
184  }
185 
186  double cppresult = (double)PyFloat_AsDouble( pyresult );
187  Py_XDECREF( pyresult );
188 
189  return cppresult;
190 }
191 
192 ////////////////////////////////////////////////////////////////////////////////
193 /// Simply forward the call to python self.
194 
195 void TPyMultiGradFunction::Gradient( const double* x, double* grad ) const {
196  PyObject* pymethod = GetOverriddenPyMethod( fPySelf, "Gradient" );
197 
198  if ( pymethod ) {
201  PyObject* pyresult = DispatchCall( fPySelf, "Gradient", pymethod, xbuf, gbuf );
202  Py_DECREF( gbuf );
203  Py_DECREF( xbuf );
204 
205  if ( ! pyresult ) {
206  PyErr_Print();
207  throw std::runtime_error( "Failure in TPyMultiGradFunction::Gradient" );
208  }
209 
210  Py_DECREF( pyresult );
211 
212  } else
214 }
215 
216 ////////////////////////////////////////////////////////////////////////////////
217 /// Simply forward the call to python self.
218 
219 void TPyMultiGradFunction::FdF( const double* x, double& f, double* df ) const
220 {
221  PyObject* pymethod = GetOverriddenPyMethod( fPySelf, "FdF" );
222 
223  if ( pymethod ) {
225  PyObject* pyf = PyList_New( 1 );
226  PyList_SetItem( pyf, 0, PyFloat_FromDouble( f ) );
228 
229  PyObject* pyresult = DispatchCall( fPySelf, "FdF", pymethod, xbuf, pyf, dfbuf );
230  f = PyFloat_AsDouble( PyList_GetItem( pyf, 0 ) );
231 
232  Py_DECREF( dfbuf );
233  Py_DECREF( pyf );
234  Py_DECREF( xbuf );
235 
236  if ( ! pyresult ) {
237  PyErr_Print();
238  throw std::runtime_error( "Failure in TPyMultiGradFunction::FdF" );
239  }
240 
241  Py_DECREF( pyresult );
242 
243  } else
244  return ROOT::Math::IMultiGradFunction::FdF( x, f, df );
245 }
246 
247 ////////////////////////////////////////////////////////////////////////////////
248 /// Simply forward the call to python self.
249 
250 double TPyMultiGradFunction::DoDerivative( const double * x, unsigned int icoord ) const
251 {
253  PyObject* pycoord = PyLong_FromLong( icoord );
254 
255  PyObject* pyresult = DispatchCall( fPySelf, "DoDerivative", NULL, xbuf, pycoord );
256  Py_DECREF( pycoord );
257  Py_DECREF( xbuf );
258 
259  if ( ! pyresult ) {
260  PyErr_Print();
261  throw std::runtime_error( "Failure in TPyMultiGradFunction::DoDerivative" );
262  }
263 
264  double cppresult = (double)PyFloat_AsDouble( pyresult );
265  Py_XDECREF( pyresult );
266 
267  return cppresult;
268 }
269 
virtual unsigned int NDim() const
Retrieve the dimension of the function.
virtual double DoEval(const double *x) const
Simply forward the call to python self.
virtual void Gradient(const double *x, double *grad) const
Evaluate all the vector of function derivatives (gradient) at a point x.
Definition: IFunction.h:350
#define NULL
Definition: RtypesCore.h:88
virtual void Gradient(const double *x, double *grad) const
Simply forward the call to python self.
Double_t x[n]
Definition: legend1.C:17
virtual void FdF(const double *x, double &f, double *df) const
Simply forward the call to python self.
virtual double DoEval(const double *x) const
Simply forward the call to python self.
virtual unsigned int NDim() const
Retrieve the dimension of the function.
TPyMultiGenFunction(PyObject *self=0)
virtual ~TPyMultiGradFunction()
Destructor. Only deref if still holding on to Py_None (circular otherwise).
PyObject * PyBuffer_FromMemory(Bool_t *buf, Py_ssize_t size=-1)
#define ClassImp(name)
Definition: Rtypes.h:336
double f(double x)
double Double_t
Definition: RtypesCore.h:55
virtual void FdF(const double *x, double &f, double *df) const
Optimized method to evaluate at the same time the function value and derivative at a point x...
Definition: IFunction.h:367
static PyObject * DispatchCall(PyObject *pyself, const char *method, PyObject *pymethod=NULL, PyObject *arg1=NULL, PyObject *arg2=NULL, PyObject *arg3=NULL)
static PyObject * GetOverriddenPyMethod(PyObject *pyself, const char *method)
static TPyBufferFactory * Instance()
double result[121]
virtual ~TPyMultiGenFunction()
Destructor. Only deref if still holding on to Py_None (circular otherwise).
Bool_t MethodProxy_CheckExact(T *object)
Definition: MethodProxy.h:69
_object PyObject
Definition: TPyArg.h:20
TPyMultiGradFunction(PyObject *self=0)
virtual double DoDerivative(const double *x, unsigned int icoord) const
Simply forward the call to python self.