C Extension help

T

thomas.luce

Hi all,

I was wondering if I could get some people to take a look at some code.
I have narrowed down where the problem is, just not what the problem
is. I haven't coded in C in quite some time, so I'm re-learning a lot.
Basically, I get a seg fault on the Data_Get_Struct when net_update is
called. I figured it has something to do with the stuff in net_new.
Heres the code:

<code>
typedef struct NN
{
//Activations of each of those layers
float *ai;
float *ah;
float *ao;

// We are making pointers to arrays, not arrays of pointers.
//float *nodes;
float **wi;
float **wo;

//Change in weights used for momentum calculations
float **ci;
float **co;

//Number of nodes in each layer
int ni;
int nh;
int no;
} NN;

static VALUE
net_new(VALUE self, VALUE ni, VALUE nh, VALUE no)
{
//TODO: something about the way I am allocating net is causing it to
crap out on me in update.
NN *net;
VALUE obj = Data_Make_Struct(self,NN,NULL,net_free,net);

//Set layer sizes
net->ni = NUM2INT(ni) + 1;
net->nh = NUM2INT(nh);
net->no = NUM2INT(no);

//Set activations
net->ai = calloc(NUM2INT(ni)+1, sizeof(float));
net->ah = calloc(NUM2INT(nh), sizeof(float));
net->ao = calloc(NUM2INT(no), sizeof(float));
if(net->ai == NULL || net->ah == NULL || net->ao == NULL)
rb_raise(rb_eRuntimeError, "could not allocate activations");

//Build and randomize the link weights
net->wi = malloc((net->ni+ 1) * sizeof(float));
net->wo = malloc(net->nh * sizeof(float));
if(net->wi == NULL || net->wo == NULL)
rb_raise(rb_eRuntimeError, "could not allocate weight tables [1]");

int i;
int y;
for(i = 0; i < NUM2INT(nh); i++)
{
net->wi = malloc(NUM2INT(nh) * sizeof(float));
if(net->wi == NULL)
rb_raise(rb_eRuntimeError, "could not allocate weight
tables[2]");

for(y = 0; y < net->nh; y++)
{
net->wi[y] = -1.0 + (float)rand()/RAND_MAX;
}
}
for(i = 0; i < NUM2INT(no); i++)
{
net->wo = malloc(NUM2INT(no) * sizeof(float));
if(net->wo == NULL)
rb_raise(rb_eRuntimeError, "could not allocate weight
tables[3]");

for(y = 0; y < net->no; y++)
{
net->wo[y] = -1.0 + (float)rand()/RAND_MAX;
}
}

//Build our change in weight (momentum) arrays
net->ci = malloc(sizeof(float)*(NUM2INT(ni)+1));
net->co = malloc(sizeof(float)*NUM2INT(nh));
if(net->ci == NULL || net->co == NULL)
rb_raise(rb_eRuntimeError, "could not allocate change tables[1]");

for(i = 0; i < NUM2INT(nh); i++)
{
net->ci = calloc(NUM2INT(nh), sizeof(float));
if(net->ci == NULL || net->co == NULL)
rb_raise(rb_eRuntimeError, "could not allocate change
tables[2]");
}
for(i = 0; i < NUM2INT(no); i++)
{
net->co = calloc(NUM2INT(no), sizeof(float));
if(net->co == NULL || net->co == NULL)
rb_raise(rb_eRuntimeError, "could not allocate change
tables[3]");
}

return obj;
}
static VALUE
net_update(VALUE self, VALUE input)
{
NN *net;
Data_Get_Struct(self,NN,net);

int i;
int y;
//Inputs
for(i = 0; i < net->ni - 1; i++)
{
net->ai = (float)NUM2DBL(rb_ary_entry(input,i));
}

//Hidden
float sum = 0.0;
for(i = 0; i < net->nh; i++)
{
sum = 0.0;
for(y = 0; y < net->ni; y++)
{
sum = sum + net->ai[y] * net->wi[y];
}
net->ah = sigmoid(sum);
}

//Outputs
for(i = 0; i < net->no; i++)
{
sum = 0.0;
for(y = 0; y < net->nh; y++)
{
sum = sum + net->ah[y] * net->wo[y];
}
net->ao = sigmoid(sum);
}

//Now, stuff it all in an array, and throw it back.
VALUE ary = rb_ary_new();
for(i = 0; i < net->no; i++)
{
rb_ary_push(ary, rb_float_new(net->ao));
}
return ary;
}
</code>

Thanks to anyone that can offer any insight.

-Thomas
 
G

Gerald Murray

Hello Thomas,

There is still a learning curve ahead of you for the C.

There were parts of the code that were not posted, or missing:
net_free()
The function declarations (see Init_exx() following this part)
There was no call to initialize the class. In the following
example, look at rb_obj_call_init() which calls "initialize"

The code had malloc() and calloc() calls, but no corresponding calls
to free(). It would be a good improvement to use ruby's
allocation to avoid memory leaks. See how this was done in the
following example with the macro ALLOC(); this will be cleaned up
when exx_free() is called. Data_Wrap_Struct passes the address
of exx_free(). For just starting out, avoid using C allocation calls.
You might find the following example helpful. To keep the debugging
simple, start from a simple program that works; then add the more
complex stuff later. Other examples of wrapping can be found in
the ruby application archive at www.ruby-lang.org or www.rubyforge.net

Good luck,
Gerald

-- FILE exx.c--
/* exx.c */
#include <ruby.h>

typedef struct Udata{
int c;
}Udata;

VALUE cExx;

static VALUE
exx_init(VALUE self, VALUE unit){
return self;
}

static void
exx_free(Udata *pr)
{
free(pr);
}

static VALUE
exx_new(VALUE class)
{
VALUE argv[1],tt;
Udata *pr;
pr = ALLOC(Udata);
tt = Data_Wrap_Struct(class,0,exx_free,pr);
argv[0] = tt;
rb_obj_call_init(tt,1,argv); // call exx_init to initialize
pr->c = 0;

return tt;
}

static VALUE
exx_verify(VALUE self, VALUE num)
{
Udata *pr;
int c = FIX2INT(num);

Data_Get_Struct(self,Udata,pr);
printf("val was %d, changed to %d\n",pr->c,c);
pr->c = c;

return self;
}

void Init_exx(){
cExx = rb_define_class("Exx",rb_cObject);
rb_define_singleton_method(cExx,"new",exx_new,0);
rb_define_method(cExx,"initialize",exx_init,1);
rb_define_method(cExx,"verify",exx_verify,1);
}

// vim: sts=2 sw=2 ts=4 et ai tw=77

-- FILE extconf.rb --
#extconf.rb
require "mkmf"
create_makefile("exx")

-- FILE useexx.rb --
#!/usr/bin/ruby
#useexx.rb
require 'exx'

a = Exx.new()
a.verify(1)
a.verify(2)
puts "that's all"

-- PROGRAM --
% ./useexx.rb
val was 0, changed to 1
val was 1, changed to 2
that's all
 
T

thomas.luce

Yeah, I realize this. I didn't post some of the code because it wasn't
part of the issue I was having. I've been coding since I was 9, and
haven't done C in about 5 years, so it's starting to come back to me.

Anyway, I got it figured out already, but thank you for your input! It
is very appreciated!

-Thomas
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,777
Messages
2,569,604
Members
45,223
Latest member
Jurgen2087

Latest Threads

Top