Numerical Recipes: Member functions of a class as arguments - function-pointers

My question concerns Numerical Recipes. I'm trying to use the conjugate gradient solver “frprmn.cpp” to minimize the negative log-likelihood function of a problem that depends on data and a bunch of other parameters. In order to have all pertinent parameters and data available to evaluate the log-likelihood, I have written a class, and both the log-likelihood function and the gradient function are member functions of that class. When I call frprmn with these functions as arguments, I get the error message
argument of type 'DP (kalman_yield_only::)(Vec_I_DP&) {aka double (kalman_yield_only::)(const NRVec&)}' does not match 'DP (*)(Vec_I_DP&){aka double (*)(const NRVec&)}'
The objective log-likelihood function and the gradient function are defined as below in a file called kalman_yield_only.cpp, which also defines the class of the name kalman_yield_only.
DP kalman_yield_only::llh(Vec_I_DP& theta)
{
...code...;
DP L_num=...;
return L_num;
}
The gradient function is:
void kalman_yield_only::llh_grad(Vec_I_DP& theta, Vec_O_DP& grad)
{
...code...;
}
The same file also has a member function that calls the solver:
void kalman_yield_only::optimizer(Vec_IO_DP& theta)
{
const double ftol = 1e-6;
double fret;
int iter;
NR::frprmn(theta,ftol,iter,fret,kalman_yield_only::llh,kalman_yield_only::llh_grad);
}
The whole thing is then called in main by
int main(int arg, char* pszArgs[])
{
...code for data and parameters...;
kalman_yield_only ks(...data and parameters...);
...code for theta...;
ks.optimizer(theta);
...code for doing stuff with theta...;
return 0;
}
In kalman_yield_only.h, I have the lines
class kalman_yield_only
{
public:
kalman_yield_only(Mat_IO_DP& , Mat_IO_DP& , Vec_IO_DP& , Vec_IO_DP& , Mat_IO_DP& , Mat_IO_DP& , DP& , DP& , DP& , DP& , DP&, Vec_IO_DP& );
// All sorts of data and parameter object declarations...
// Member functions
DP llh(Vec_I_DP &);
void llh_grad(Vec_I_DP & , Vec_O_DP & );
void optimizer(Vec_IO_DP& );
};
The corresponding constructor in kalman_yield_only.cpp reads:
kalman_yield_only::kalman_yield_only(Mat_IO_DP& Y_in, Mat_IO_DP& Z_in, Vec_IO_DP& vH_in, Vec_IO_DP& c_in, Mat_IO_DP& mT_in, Mat_IO_DP& Q_in, DP& maxZ_in, DP& maxT_in, DP& maxQ_in, DP& maxc_in, DP& tol_in, Vec_IO_DP& Maturities_in )
{
… code...;
}
I think I tried all permutations of adding and deleting the NR:: and kalman_yield_only:: prefixes in the function call, to no avail.
When I compile the example file “xfrprmn.cpp” from the numerical recipes using the same compiler and make-file infrastructure, it compiles and runs without problems. I cannot see much difference to my own code, except that my objective and gradient routines are member functions of a class, so I wonder if this is what trips me up. Any help is thoroughly appreciated.

I found a workaround whereby I adapt the Numerical Recipes routines so as to take as arguments pointers to my class object instead of pointers to objective and gradient functions. Inside the routines, I changed the code such that they call the member functions of the class object they were handed. Would still be interested if there's a more elegant solution.

argument of type 'DP (kalman_yield_only::)(Vec_I_DP&) {aka double
(kalman_yield_only::)(const NRVec&)}' does not match 'DP
(*)(Vec_I_DP&){aka double (*)(const NRVec&)}'
This means you're trying to use a method (which needs a hidden this pointer) where a function is expected.
Numerical Recipes in C++ is not really C++, as it expects you to use global/static variables!!!!
I think I would edit Numerical recipes so that the function you're passing is a template argument
-- means at the place of usage it is not defined, other than it needs a vector argument and returns a double:
template<typename FUNCTION>
frprmn(..., const FUNCTION &_rF, ....)
{
...
}
Writing frprmn like that still lets you pass a normal function pointer.
Then define the function as the operator() of your class containing all the information:
struct YourClass
{
double operator()(const NRVec&) const;
};

Related

System Verilog: ref class member

It should be possible to have a reference as a class member, like in C++. However...
covergroup smurf_car_covergroup(ref smurf_transaction tx)
;
covpt_tx_direction_TURN_LEFT :
coverpoint tx.tx_direction {
bins left[] = {[ENUM_C_LEFT_TURN:ENUM_C_LEFT_TURN]
}
;
}
endgroup
class smurf_coverage_container extends
smurf_coverage_object;
ref smurf_transaction m_ref_smurf_transaction ;
function new(string name, ref smurf_transaction) ;
m_ref_smurf_transaction=smurf_transaction ;
super.new(smurf_transaction) ;
// does the following:
// // m_smurf_bicycle_covergroup
//= new(smurf_transaction) ;
// etc
endfunction : new
function void smurf_sample() ;
// important
if (m_ref_smurf_transaction.is_bicycle() )
m_smurf_bicycle_covergroup.sample () ;
if (m_ref_smurf_transaction . is_car () )
m_smurf_car_covergroup .sample () ;
endfunction : smurf_sample
endclass : smurf_coverage_container
This doesn't work because ref isn't allowed to apply to class fields - the compiler complains "Following verilog source has a syntax problem : NNN: token is smurf_transaction."
Clearly holding a reference (so that when another class assigns its handle to a new object, the sampled object is updated automatically) is technically possible, so what syntax would acheive this effect?
Note I can't add arguments to the sample method owing to coding guidelines and common sense.
The ref keyword only applies as connection type to arguments like in a task or function. It is not needed(allowed) in a class variable declaration because a class variable is always a reference to a class object. See my short class on classes.
A ref argument is a variable passed by reference. This type of argument are not a copy but a reference to the original variable(in this case the object of the class).
Arguments passed by reference are not copied into the subroutine area, rather, a reference to the original argument is passed to the subroutine. The subroutine can then access the argument data via the reference.
From section 13.5.2 in [IEEE Std 1800-2012].
Thus using ref for a class variable is not needed .You can directly pass the object of the class .

Error: passing 'const xxx' as 'this' argument discards qualifiers

I am trying to implement bigint class in c++, it's not completed yet, i have encountered some errors that i am unable understand.
I have erased all other functions (as they are unnecessary in this case)
and karatsuba is not yet completed (but that should't pose a problem in this case).
In the multiply function (overloaded * ) my compiler gives an error:
passing 'const BigInt' as 'this' argument discards qualifiers [-fpermissive]
at line
ans.a = karatsuba(n,m);
I understand that this would occur when i am trying to change a constant object or object passed to a constant function, in my case i am merely creating a new vector and passing it to karatsuba function.
Removing const from overloded * gets rid of this error.
So,does this mean that a constant function can't change anything at all? (including local variables?)
class BigInt {
typedef long long int ll;
typedef vector<int> vi;
#define p10 1000000000;
#define range 9
vi a;
bool sign;
public:
BigInt operator * (const BigInt &num) const
{
vi n(a.begin(),a.end()),m(num.a.begin(),num.a.end());
BigInt ans;
ans.sign = !(sign ^ num.sign);
while(n.size()<m.size()) n.push_back(0);
while(n.size()>m.size()) m.push_back(0);
ans.a = karatsuba(n,m);
return ans;
}
vi karatsuba(vi a,vi b)
{
int n = a.size();
if(n <= 16)
{
// some code
}
// some code
return a;
}
};
Ok so after googling a bit more, i realized that this pointer is implicitly passed to the oveloaded * and then on to karatsuba (as it is a member function of the class), and as karatsuba is not a constant function, there is no guarantee that it won't change the object contents, hence this error is triggered.
One solution is to declare karatsuba as static, as static member functions don't receive this pointer (they can even be called with out a class object simply using :: operator) , read more about them from here Static data members and member functions.
All that is needed to be changed is :-
static vi karatsuba(vi a,vi b)
{
int n = a.size();
if(n <= 16)
{
// some code
}
// some code
return a;
}

MATLAB Mex C API Check if mxarray is base class

We are using classes in MATLAB which are passed into some C Mex functions. Previously the class objects we have been passing were all the same type, so we have been able to use mxIsClass to verify that the objects are the correct type.
We have however changed the architecture such that the objects are now derived from the original base class to allow customisation. Effectively we have something like:
handle & mixin.Heterogeneous>
BaseClass >
Class1
Class2
Because the base class uses mixin.Heterogeneous, if I pass an array like [Class1_obj Class2_obj], the mex function works as expected - MATLAB treats the array as an array of type BaseClass, and mxIsClass(obj, 'BaseClass') returns true.
The problem arises that when we pass a single object or an array of the same derived class, say [Class1_obj1 Class1_obj2], into the mex function. Because they are the same type, MATLAB treats the array as type Class1, and so mxIsClass(obj, 'BaseClass') returns false because it only considers the class of the object and not the classes it derives from.
I'm trying to figure out if there is a way to get around this problem and make sure that the mxArray* object in the mex function is either a BaseClass directly, or derives from it.
I've considered simply adding checks for every known derived class name, but this seems an ugly way of doing this, not least because if we add more derived classes we need to change the mex function every time.
I suppose I could use the mexCallMATLAB function to call isa in MATLAB which should correctly identify that it is a base class.
I wonder also if there is a way to get MATLAB to pass the object through to the Mex function treating it as a BaseClass object rather than the derived class.
Is there a standard way of acheiving this?
MATLAB's built in isa function can be used to find out if the object or object array is the correct type. The MATLAB function does look at base clases, so doing isa(Class1_obj,'BaseClass') does return true.
I've implemented a function in the mex file that simply calls MATLAB's own isa function to check the type. As a reference for anyone with similar issues, the following is the C function I've written for this task.
//Check the type of class object or object array using MATLAB
static bool isa(mxArray* obj, const char* type) {
//Create LHS/RHS arrays for calling MATLAB
mxArray *lhs[1];
mxArray *rhs[2];
//Return value
bool retVal;
//Populate Inputs to MATLAB isa
rhs[0] = obj;
rhs[1] = mxCreateString(type);
//Call the MATLAB isa function
mexCallMATLAB(1, lhs, 2, rhs, "isa");
//Extract result
retVal = mxIsLogicalScalarTrue(lhs[0]);
//Cleanup
mxDestroyArray(rhs[1]);
mxDestroyArray(lhs[0]);
//Done
return retVal;
}

Invalid initialization of reference type 'Class&' from expression of type 'Class'

Ok guys , so I have a list of objects and I want to sort my list by a boolean function I created .
Function ->
bool funct(Student &s1,Student &s2)
{
return s1.calculMedie()<s2.calculMedie();
}
I got this list:
list<Student*> list;
list.push_back(sx[0]);
list.push_back(sx[1]);
list.push_back(sx[2]);
sx is comming from this declaration-> Student **sx=new Student*[3];
I created 3 objects of the type class Student.
I want to sort them by 'calculMedie()' which is a function that returns their average grade.
double Student::calculMedie()
{
int nr=0;
double s=0;
for(auto i : note)
{
nr++;
s=s+i;
}
return s/nr;}
^ thats how it looks.
And when I tried to do a list.sort(list.begin(),list.end(),funct) it gets me this error : " Invalid initialization of reference type 'Class&' from expression of type 'Class'"
It looks like you mixed std::sort algorithm with list<T>::sort method. List can be sorted only by using its sort method.
There are two overloads of list::sort:
void sort();
template< class Compare >
void sort( Compare comp ); // [2]
if you want to sort by comparator, write as follows:
list<Student*> list;
list.sort (funct);
because list stores pointers to Student, you need to modify signature of funct function, it must takes pointers not references:
bool funct(Student* s1,Student* s2)
{
return s1->calculMedie()<s2->calculMedie();
}
good practice is to pass s1,s2 as pointers to const object, when you change s1,s2 to be const Student* s1, const Student* s2 you need also to make calculMedie as const member function.

Errors with a movieClip class

I have defined a class as
package telmate.com.audioB.volume {
import flash.display.MovieClip;
public class Volume_Bar extends MovieClip {
public static const BAR_WIDTH = 20;
public function Volume_Bar(op: Number, vol: Number) {
alpha = Util.clamp(op);
volume = vol;
}
private _volume:Number;// do we even need to store this?
public function set volume(v: Number){
_volume = v;
var f:uint = Util.clamp(v * totalFrames, 0, totalFrames - 1) + 1;
gotoAndStop(f);
}
}
}
and I am getting two errors: I am calling the constant BAR_WIDTH and instantiating it with parameters - new Volume_Bar(op, vol) -- and getting
/Users/dave/Documents/Audio/telmate/com/audioB/Audio_Bars.as, Line 152
1136: Incorrect number of arguments. Expected 0.
and
/Users/dave/Documents/Audio/telmate/com/audioB/Audio_Bars.as, Line 156
1119: Access of possibly undefined property BAR_WIDTH through a
reference with static type Class.
Why would this be?
Unfortunately, I don't know how specific I can be here, but...
That first error message indicates that when you're calling a function, you're passing arguments, but the function is not set up to handle arguments. Have you adjusted either the function itself, or the line of code that is calling it? (If you're calling through an event listener, be sure to include an argument in the function to hold the referring event. See documentation.)
What specifically is on Audio_bars.as, Line 152? That's where the error is occurring.
The second error seems to indicate that you haven't declared a function/variable by the name of "BAR_WIDTH". In reading your code, there doesn't appear to be an error in the declaration. Thus, you may be having a weird issue I've had before.
Hope that helps!