Aller au contenu
  • Pas encore inscrit ?

    Pourquoi ne pas vous inscrire ? C'est simple, rapide et gratuit.
    Pour en savoir plus, lisez Les avantages de l'inscription... et la Charte de Zébulon.
    De plus, les messages que vous postez en tant qu'invité restent invisibles tant qu'un modérateur ne les a pas validés. Inscrivez-vous, ce sera un gain de temps pour tout le monde, vous, les helpeurs et les modérateurs ! :wink:

[Résolu] Du C dans R (=S-plus)


Messages recommandés

Posté(e)

Bonjour,

 

au boulot, j'utilise beaucoup R ( http://www.r-project.org ) pour réaliser du traitement statistique de data et réaliser des graphiques.

 

Seulement, ce langage étant non compilé, j'ai certaines boucles qui mettent un temps fou à s'éxécuter sous R. R permet d'appeller des objets compilés (.so ou dll) réalisés en Fortran ou en C.

dyn.load("le nom de la dll")
.Fortran("la fonction",arg1,arg2,.....)

 

J'ai déjà réalisé ce type de chose pour faire de la tranformée de fourier appliquées à mes data dans R (aucun mérite, on m'a filé le code source et il m'a suffit de le compiler en so), c'est donc possible.

 

Là je pars de zéro et ai voulu réaliser une dll en langage C pour "apprendre" :P.

Problématique: j'ai 2 vecteurs (tableau 1D) d'entiers signés dans R de longueur identique mais variable d'une traitement de lot à un autre. Ces 2 vecteurs, ainsi que la longueur du vecteur, doivent être passés à la fonction C pour réaliser une bête boucle de calcul pour sortir un nouveau tableau 1D que j'écris dans un fichier (j'ai essayé un return du tableau mais apparemment la fonction ne renvoie que le pointeur vers le tableau :-/) qu'il sera possible de relire dans R.

 

Mon problème vient, je pense, de l'allocation dynamique de la mémoire en fonction des 2 vecteurs envoyés à la fonction C => segfault.

 

Pour commencer, j'ai compilé un exécutable stand-alone avec des vecteurs prédéfinis et une taille définie, ça marche:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define SIZE 5 /* taille des tableaux pour allocation mémoire */

main()

{
/* Déclaration des variables */
FILE *f;   /* pointeur vers le fichier résultat */
int *p_Fa; /* pointeur vers futur tableau de résultat Fa */

int signed vecteur1[5] = {-12,6,4,0,-10};
int signed vecteur2[5] = {1,1,1,1,1};
int signed Fa[SIZE];  /* tableau de résultat */

int i;

/* allocation mémoire pour le tableau de résultat */

p_Fa = malloc(SIZE * sizeof(int));

/* calcul de la fonctionA pour chaque battement */
f=fopen("resultats.txt","w");
for ( i = 0; i < SIZE; i++ ) {
	p_Fa[i]= (fabs(vecteur1[i]) + fabs(vecteur2[i])) * vecteur2[i];
	Fa[i] = *(p_Fa+i);
	printf("%d\n", Fa[i]);
	fprintf(f,"%d\n", Fa[i]);
	}
fclose(f);
}

 

pas d'erreur à la compilation, l'éxécution est OK.

C'est maintenant que ça se gâte :-/ : modification du code pour que main() attende des arguments passés par R : .C("main", as.integer(m), as.integer(n), as.integer(s))

 

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

void main(int* m, int* n, int s)

{
/* Déclaration des variables */

FILE *f;  /* pointeur vers le fichier de résultat */
int *p_Fa; /* pointeur vers futur tableau de résultat Fa */

int *p_m; /*pointeur vers le vecteur1 = m */	
int *p_n; /*pointeur vers le vecteur2 = n */

int signed Fa[s]; /* tableau de résultat de taille s passé en argument*/

int i;

/* allocation mémoire pour les tableaux */

p_Fa = malloc(s * sizeof(int));
p_m = malloc(s * sizeof(int));
p_n = malloc(s * sizeof(int));

p_m = &m[0]; /* les pointeurs correspondent aux vecteurs passés en argument */
p_n = &n[0];


/* calcul de la fonctionA pour chaque battement */
f=fopen("resultats.txt","w");
for ( i = 0; i < s; i++ ) {
	p_Fa[i]= (fabs(p_m[i]) + fabs(p_n[i])) * p_n[i];
	Fa[i] = *(p_Fa+i);
	printf("%d\n", Fa[i]);
	fprintf(f,"%d\n", Fa[i]);
	}
fclose(f);
}

 

le code se compile avec un warning:

fonctionR2.c: In function 'main':
fonctionR2.c:7: warning: return type of 'main' is not 'int'

 

j'arrive à charger la dll dans R, vérifier que main est accessible mais erreur de segmentation:

*** caught segfault ***
address 0x9db40e00, cause 'memory not mapped'

 

 

Voilà désolé pour la longueur. Si vous avez une petite idée :P

Posté(e)

ne serait-il pas plus simple de sauver mes vecteurs 1 et 2 dans des fichiers txt sous R et de les faire relire dans le programme C?

 

je lis et je stocke le contenu du fichier dans un tableau jusqu'à EOF? comme ça plus de problème de malloc?

 

et pour le malloc du tableau de résultat, déterminer le nombre de lignes d'un des 2 fichiers lus?

Posté(e)

Erreurs :

- main() ne doit pas être présent dans une librairie (c'est le point d'entrée d'un exécutable)

- main() a un prototype fixe qui est : int main (int argc, char **argv, char **arge). On ignore très souvent un ou plusieurs paramètre(s).

Tu ne peux / dois donc pas utiliser main pour faire ta librairie. Au pire tu peux laisser main() dedans pour en faire un exécutable qui teste la librairie, mais la fonction que tu appelleras depuis R devra s'appeler autrement.

 

Conseils :

- si tu sais comment fonctionnent les fonctions à nombre d'argument variable (va_list) c'est peut-être ce qu'il faut utiliser pour passer des vecteurs.

- s'il est possible de récupérer la structure de données de tes vecteurs en C (par le biais d'un struct qu'on trouverait par exemple dans une API entre C et R) ça serait mieux

- si tu trouves que l'interprétation du code est lente, crois-tu vraiment que faire des accès disque pour faire transiter de données soit optimal ?

Posté(e)

Erreurs :

- main() ne doit pas être présent dans une librairie (c'est le point d'entrée d'un exécutable)

- main() a un prototype fixe qui est : int main (int argc, char **argv, char **arge). On ignore très souvent un ou plusieurs paramètre(s).

Tu ne peux / dois donc pas utiliser main pour faire ta librairie. Au pire tu peux laisser main() dedans pour en faire un exécutable qui teste la librairie, mais la fonction que tu appelleras depuis R devra s'appeler autrement.

 

OK je modifie pour faire une sous_fonction à appeler dans R

 

Conseils :

- si tu sais comment fonctionnent les fonctions à nombre d'argument variable (va_list) c'est peut-être ce qu'il faut utiliser pour passer des vecteurs.

 

je vais regarder dans le Kernighan & Ritchie :-P

 

- s'il est possible de récupérer la structure de données de tes vecteurs en C (par le biais d'un struct qu'on trouverait par exemple dans une API entre C et R) ça serait mieux

aucune idée, je vais creuser cette piste

 

- si tu trouves que l'interprétation du code est lente, crois-tu vraiment que faire des accès disque pour faire transiter de données soit optimal ?

là tu marques un point mais faute de grives ... :P

 

Merci des tuyaux :P

Posté(e)

bon, j'ai modifié pour faire une sous-fonction; compilation OK mais toujours le problème de mapping mémoire sous R. Je vais éplucher la doc du site

 

#include <stdio.h>
#include <stdlib.h>
#include <math.h>


main()
{
int signed m[5] = {-12,6,4,0,-10};
int signed n[5] = {1,1,1,1,1};
int s = 5;

fonctionR(m,n,s);
}

fonctionR (int* m,int* n,int s)
{
/* Déclaration des variables */

FILE *f;  /* pointeur vers le fichier de résultat */
int *p_Fa; /* pointeur vers futur tableau de résultat Fa */

int *p_m; /*pointeur vers le vecteur1 = m */	
int *p_n; /*pointeur vers le vecteur2 = n */

int signed Fa[s]; /* tableau de résultat de taille s passé en argument*/

int i;

/* allocation mémoire pour les tableaux */

p_Fa = malloc(s * sizeof(int));
p_m = malloc(s * sizeof(int));
p_n = malloc(s * sizeof(int));

p_m = &m[0]; /* les pointeurs correspondent aux vecteurs passés en argument */
p_n = &n[0];


/* calcul de la fonctionA pour chaque battement */
f=fopen("resultats.txt","w");
for ( i = 0; i < s; i++ ) {
	p_Fa[i]= (fabs(p_m[i]) + fabs(p_n[i])) * p_n[i];
	Fa[i] = *(p_Fa+i);
	printf("%d\n", Fa[i]);
	fprintf(f,"%d\n", Fa[i]);
	}
fclose(f);
}

Posté(e)
fonctionR (int* m,int* n,int s)
C'est bizarre que tu appelles avec C("fonctionR", as.integer(), as.integer(), as.integer()) que tu utilises int* et int ...

Soit il manque un * soit il y en a deux en trop ;-) (et à la limite le cast peut intervenir après)

Cherche ce que passe as.integer(uneVariableR) au code C qui est appelé... Si ça passe une adresse mémoire (pointeur) ou une valeur...

Posté(e)

j'ai commencé à bouquiner cette doc : http://cran.r-project.org/doc/manuals/R-exts.pdf

 

notamment 5.2 Interface functions .C and .Fortran (page 52 & 53)

 

The following table gives the mapping between the modes of R vectors and the types of

arguments to a C function or FORTRAN subroutine.

R storage mode C type FORTRAN type
logical int * INTEGER
integer int * INTEGER
double double * DOUBLE PRECISION
complex Rcomplex * DOUBLE COMPLEX
character char ** CHARACTER*255
raw char * none

 

et

 

It is possible to pass numeric vectors of storage mode double to C as float * or FORTRAN

as REAL by setting the attribute Csingle, most conveniently by using the R functions as.single,

single or storage.mode. This is intended only to be used to aid interfacing to existing C or

FORTRAN code.

 

il faut que je mette mes vecteurs en double float si je comprends bien pour pouvoir les passer à la dll avec as.single()

 

structure d'un vecteur dans R:

vector (mode, length)

 

avec mode : The atomic modes are '"logical"', '"integer"', '"numeric"','"complex"', '"character"' and '"raw"'.

Posté(e)

Ouais.....

En clair, quand tu faisais ton as.integer il te filait un int*.

Maintenant, pour tes vecteurs...

Il faut mettre leur "storage mode" à "double" en "mettant l'attribut Csingle" ou en utilisant "as.single" et "storage.mode"...

 

Ca a l'air rigolo comme langage...

 

Une fois qu'on a les float * correspondant aux vecteurs, comment on chope leur taille ?

 

-- edit --

Ouais, en matant les exemples de code page 53... Ils ne s'emmerdent pas : ils passent la taille en paramètre après le float * :-D

Posté(e)

résolu :P

 

la fonction en C

int FctA(double *vector1,double *vector2,double *resultats,int *l) /* *l est la taille du vecteur 1 */
{
 int i;
 for (i=0;i<*l;i++)
{
  resultats[i]=(fabs(vector1[i])+fabs(vector2[i])) * vector2[i];
}

 return(0);
}

 

compilation en so, chargement sour R via dyn.load("nom de la bibliothèque .so")

 

fonction d'appel sous R:

calcul_FctA <- function(V1,V2)
 {
res <- .C("FctA",
		  as.double(V1),
		  as.double(V2),
		  res=double(length(V1)), ### cela revient à faire une malloc directement dans R afin de pouvoir récupéré les bonnes valeurs
		  as.integer(length(V1)))

return(res$res)
 }

 

y'a plus qu'à appeller avec calcul_FctA(vecteur1,vecteur2)

 

merci à Philippe du service bioinformatique de l'Institut Curie :P

 

Il ne me reste plus qu'à réécrire d'autres fonctions un poil plus compliquées en C:

une sous-fonction peut-elle renvoyer un pointeur?

 

la déclaration

 

double *f(char[] , &a);

 

désigne-t-elle bien une fonction f qui prend comme argument un tableau de caractères plus un pointeur vers un objet a et qui retourne un pointeur vers un double ?

Rejoindre la conversation

Vous pouvez publier maintenant et vous inscrire plus tard. Si vous avez un compte, connectez-vous maintenant pour publier avec votre compte.
Remarque : votre message nécessitera l’approbation d’un modérateur avant de pouvoir être visible.

Invité
Répondre à ce sujet…

×   Collé en tant que texte enrichi.   Coller en tant que texte brut à la place

  Seulement 75 émoticônes maximum sont autorisées.

×   Votre lien a été automatiquement intégré.   Afficher plutôt comme un lien

×   Votre contenu précédent a été rétabli.   Vider l’éditeur

×   Vous ne pouvez pas directement coller des images. Envoyez-les depuis votre ordinateur ou insérez-les depuis une URL.

  • En ligne récemment   0 membre est en ligne

    • Aucun utilisateur enregistré regarde cette page.
×
×
  • Créer...