Version française
Home     About     Download     Resources     Contact us    
Browse thread
OCaml, C, Garbage Collector etc
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Odalric-Ambrym Maillard <odalricambrym.maillard@g...>
Subject: OCaml, C, Garbage Collector etc
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