Mailing list for all users of the OCaml language and system.
 help / color / mirror / Atom feed
From: Odalric-Ambrym Maillard <odalricambrym.maillard@gmail.com>
To: caml-list@yquem.inria.fr
Subject: OCaml, C, Garbage Collector etc
Date: Fri, 15 Jan 2010 18:43:15 +0100	[thread overview]
Message-ID: <406c33611001150943o2aeb2429qefa22f1102699730@mail.gmail.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 5585 bytes --]

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

[-- Attachment #2: Type: text/html, Size: 6326 bytes --]

             reply	other threads:[~2010-01-15 17:43 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-01-15 17:43 Odalric-Ambrym Maillard [this message]
2010-01-18  9:06 ` Odalric-Ambrym Maillard

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=406c33611001150943o2aeb2429qefa22f1102699730@mail.gmail.com \
    --to=odalricambrym.maillard@gmail.com \
    --cc=caml-list@yquem.inria.fr \
    --cc=odalric.maillard@inria.fr \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox