Hello,
I am currently writin an algorithm in OCaml. Since its a learning algorithm, I would like to uses some existing code, which is mainly in C.
For the program to be usable by others, I write the main structure in C and make call to some functions in Ocaml when needed.
Well, I thought I had understood how this works. but obviously, there is omething wrong, for the program crashes, and it seems, according to my tests and sylvain le-gall, that it is due to problem concerning the garbage collector.
All I need is this:
- say I have an OCaml function psi : int -> float array -> float.
- say have a C matrix of data: double ** x_data, and a vector double * y_data.
Then, I just need to create, in C a matrix, double ** psi_mat, with values psi m x_i at position m,i, where w_i is the ith row of x_data.
One way to do that (not the most efficient) is to create the function psi_c corresponding to the OCaml psi function, and then use it in the code.
For instance, let consider this code:
--------------------------------------------------------------------
double psi_c(int m, int dim_x,double * x){
int d;
CAMLlocal2(val_M,val_x);
val_m = Val_int(m);
val_x = caml_alloc(dim_x * Double_wosize, Double_array_tag);
for(d=0;d<dim_x;d++){
printf("Stored %f",x[d]);
Store_double_field(val_x, d,x[d]);
}
return(Double_val(caml_callback2( *closure_psi, val_m, val_x)));
}
--------------------------------------------------------------------
where of course, the following variable is declared globally:
static value * closure_psi = NULL;
and somewhere in the main we have:
if (closure_psi == NULL) {
closure_psi = (value*) caml_named_value("psi_Ocaml");
}
Well, this code does not work, meaning that a call to this function may generate either segmentation fault, or infinite loop, or just the correct expected result. This impredictible behaviour seems to come from the Garbage collector that moves blocks it should not move here...
But generally, you can handle this when you write a function C from OCaml, since you have a function of the form:
value my_function(value x){
CAMLparam1(x)
...
CAMLreturn(...)
}
thus CAMLparam and CAMLreturn seem to do the job.
But how to do that when you are on the other side ??
I really do not understand hoxw to do that. I suspect moreover that there is something specific to be done due to the fact I use double values, which are handled in a specific way by OCaml (so may be the same code would work with int values (or not ??) ? anyway I need double).
Eventually, what I would prefer is to do only one allocation of the ith row x_i to call the corresponding OCaml, like the following code (which works when executed !?!) :
------------------------------------------------------------------------------------------------
void make_psi_matrix(int Mnumber_of_compressed_features,
int Knumber_of_training_data,
int Dspace_dimension,
double **x_train,
double ***psi_matrix) {
double * xk;
double ** psi_matrixm;
int m,d,k;
xk = malloc (Dspace_dimension * sizeof (double));
*psi_matrix = malloc (Mnumber_of_compressed_features * sizeof (double*));
for(m=0,psi_matrixm = *psi_matrix;
m<Mnumber_of_compressed_features;
m++,psi_matrixm++) {
*psi_matrixm = malloc (Knumber_of_training_data * sizeof (double));
}
CAMLlocal2(val_x,val_M);
val_x = caml_alloc(Dspace_dimension * Double_wosize, Double_array_tag);
for(k=0;k<Knumber_of_training_data;k++){
xk = x_train[k];
//printf("k :%d/%d\n",k,Knumber_of_training_data);
for(d=0;d<Dspace_dimension;d++){
//printf("Store %f at position %d,%d...",xk[d],k,d);
Store_double_field(val_x, d, xk[d]);
// printf("...ok\n");
}
for(m=0;m<Mnumber_of_compressed_features;m++){
val_M = Val_int(m);
((*psi_matrix)[m])[k] = Double_val(caml_callback2( *closure_psi, val_M, val_x));
}
}
}
------------------------------------------------------------------------------------------------
What is very suprisin is that its brother that outputs a vector y_predict of prediciton does not work at all (though the code is very similar for the Ocaml call).
Thus we have the same problem again : how to handle this more complicated case ? Suppose I can use CAMLparam in the following code : How can I realluy use it ?? I really do not know because of the loops.
------------------------------------------------------------------------------------------------
void predict(double * beta,
int Mnumber_of_compressed_features,
int Dspace_dimension,
int Knumber_of_data,
double **x_data,
double ** y_predict) {
int d,m,k;
double s,aux_val;
double *xk;
xk = malloc (Dspace_dimension * sizeof (double));
*y_predict = malloc (Knumber_of_data * sizeof (double));
CAMLlocal2(val_x,val_M);
val_x = caml_alloc(Dspace_dimension * Double_wosize, Double_array_tag);
for(k=0;k<Knumber_of_data;k++){
xk = x_data[k];
for(d=0;d<Dspace_dimension;d++){
Store_double_field(val_x, d, xk[d]);
}
s = 0;
for(m=0;m<Mnumber_of_compressed_features;m++){
val_M = Val_int(m);
s = s + beta[m]*Double_val(caml_callback2( *closure_psi, val_M, val_x));
}
(*y_predict)[k] = s;
}
}
------------------------------------------------------------------------------------------------
So, does anybody has a solution, idea, or even a good example (using vectors or matrix of double, I insist) that could help ?
Have a good day,
Odalric-Ambrym