Re: minuit fcn

From: Rutger van der Eijk (r36@nikhef.nl)
Date: Wed Feb 02 2000 - 19:06:44 MET


Hi Gilles,

I ran into the same problem. ROOT has a solution for this, which I think
isn't very elegant (read Object Oriented). This is I think due to
historical reasons (As a relative young HEPer I'm impressed to read in the 
minuit manual that the program is older than I am!). To my opinion the
things is now:


TVirtualFitter (basically a wrapper around TMinuit) wants to have a
pointer to a function to minimize, i.e. the FCN function. Technically
this is inplemented in TMinuit by having a datamember:

void (*)(Int_t&npar, Double_t*gin, Double_t&f, Double_t*u, Int_t flag)* fFCN    

i.e. a pointer to a function which has as arguments
(Int_t&npar, Double_t*gin, Double_t&f, Double_t*u, Int_t flag)

So with the member function 

::SetFCN(void (*)(Int_t&, Double_t*, Double_t&f, Double_t*, Int_t) fcn))

you give a function as argument  to set the datamamber fFCN, such that
TMinuit can use it. An technical complication is that CINT (as far as I
understand) doesn't allow pointers to functions. This is circumvented by
having a second SetFCN which takes a pointer to void, i.e. which can be
anything. This all works fine if your function is also a interpreted
function. (It seems not to if from the interpreter you call a compiled
version (see my mail earlier this week). I think this is a bug, but it
isn't directly important here.).


There is a more serious problem, which is partly a limitation by C++ (but
which can't be avoided). You can have pointers to member functions (see
B. Stroustrup par 15.5) but they have to be invoked on an object. So in
your case you have the pointer to member function:

void (DPrecAlign::*)(int,double *,double,double *,int)

You can even set a variable which is a pointer to this member function:

void (DPrecAlign::*)(int,double *,double,double *,int) pntrToMem = 
&DPrecAlign::fcn;

but you have to use it on a DPrecAlign object, i.e.,

DPrecAlign* tDPAObj = <something>;
(tDPAObj->*pntrToMem)(npar, gin, f, par, flag);


The syntax is horrible but this is what it boils down to. The upshot is
that a pointer to a member function is not the same thing as a pointer to
a normal function. This means you can not use it as a pointer to a member
function.

This together with the fact that ROOT in interactive mode uses
TMinuit::SetFCN(void *); explains your error message (I think.)

"Argument of type 'void (DPrecAlign::*)(int,double *,double,double *,int)'
could not be converted to 'void *'"

The solution to not being able to have a pointer to a member function
suggested by ROOT is to instead have a normal (i.e. global) fcn function
which is called. In this fcn you have to find out for which original
object (i.e. the object which is an instance of the class DPrecAlign) it
was called. And than retrieve the information you need to implement fcn.
To help you with this TMinuit has the members  

void SetObjectFit(TObject* obj);

and 

TObject* GetObjectFit();

So before you start you call SetObjectFit(...) with your object and in
your global FCN you call GetObjectFit() to retrieve it.


Concrete in your case I think the solution is:

making a global function:

GFForwardDPrecAlignFCN(Int_t& npar, Double_t*gin,
                       Double_t&f, Double_t* par, Int_t flag)
{

  DPrecAlign* tDPAObj = dynamic_cast<DPrecAlign*>(gMinuit->GetObjectFit());
  tDPAObj->fcn(npar, gin, f, par, flag);
}


and make sure you do gMinuit->SetObjectFit(tDPAObj); 
before you call the fit.

This should think work with the (current) ROOT.


However, to come back to my first line of this email, I don't think this
whole approach is very OO. It is also risky e.g. if you would like to
fit 2 objects at the same time. I think a better solution to this problem
is to use a functor (i.e. function object) in an analogue way STL
algorithms work with predicates (see Chapter 18 Stroustrup). In order for
this to work we need a templatized member function. If people are
interested I could present the idea (not tested yet) Friday on the
ROOT workshop.

Ciao,

Rutger van der Eijk



This archive was generated by hypermail 2b29 : Tue Jan 02 2001 - 11:50:18 MET