PDS Random Variable Biblioteca para la generación de variables aleatorias. Ing. Fernando Pujaico Rivera Desarrollador Principal Investigador Universidad Nacional de Ingeniería PDS Random Variable Biblioteca para la generación de variables aleatorias. por Ing. Fernando Pujaico Rivera "PDS Random Variable" (PdsRv) es una biblioteca escrita en C, para trabajar con variables aleatorias (o RV por sus siglas en ingles). Usando PdsRv es posible generar RV’s de tipo: • Secuencia congruencial • Uniformemente distribuida • Gaussiana • Rayleigh • Exponencial • Poisson <fernando.pujaico.rivera en gmail.com> Licencia GPL V3 Historial de revisiones Revisión 0.0.1 16-03-2011 Revisado por: fpr Documento inicial Revisión 0.01.0 21-04-2011 Revisado por: fpr Inclusión de autotools Tabla de contenidos 1. Variables Aleatorias...............................................................................................................................1 1.1. Variable aleatoria Uniforme ........................................................................................................1 1.2. Variable aleatoria Gaussiana .......................................................................................................2 1.3. Variable aleatoria Rayleighiana ..................................................................................................3 1.4. Variable aleatoria Exponencial....................................................................................................4 1.5. Variable aleatoria Poissoniana ....................................................................................................5 2. Modo de uso............................................................................................................................................7 2.1. Creando las variables aleatorias. .................................................................................................7 2.2. Usando las variables aleatorias. ..................................................................................................7 2.3. Destruyendo las variables aleatorias. ..........................................................................................8 3. Compilación con PDSRV y ejemplos de uso........................................................................................9 3.1. Compilación con PDSRV............................................................................................................9 3.1.1. Compilación por linea de comandos ............................................................................10 3.1.2. Compilación usando autotools .....................................................................................10 3.2. Ejemplos de uso de la biblioteca...............................................................................................11 4. Referencias ...........................................................................................................................................16 A. Preguntas Frecuentes..........................................................................................................................17 iii Lista de tablas 1-1. Estadística de la variable aleatoria Uniforme.......................................................................................2 1-2. Estadística de la variable aleatoria Gaussiana ......................................................................................3 1-3. Estadística de la variable aleatoria Rayleighiana .................................................................................4 1-4. Estadística de la variable aleatoria Exponencial ..................................................................................5 1-5. Estadística de la variable aleatoria Poissoniana ...................................................................................6 2-1. Tipos de datos de las variables aleatorias.............................................................................................7 iv Capítulo 1. Variables Aleatorias Para generar todas las variables aleatorias se uso un generador secuencial pseudoaleatorio usando el método congruencial. Esta secuencia puede ser generada usando la variable PdsCongruential. Esta secuencia genera números enteros aleatoriamente desde el valor 0 hasta el valor PDS_RAND_MAX-1. Cada vez que se crea una variable de tipo PdsCongruential, esta es estadísticamente independiente a las anteriores. En un generador congruencial, el parámetro aditivo "c" debe ser primo relativo con PDS_RAND_MAX y menor que este. Siguiendo la premisa anterior se puede ver que solo se pueden crear 7830 secuencias aleatorias distintas. Si se crean mas de 7830 secuencias, las secuencias aleatorias comenzarán a repetirse. Dado que todas las variables aleatorias de esta biblioteca usan como base este generador congruencial, entonces solo se pueden crear 7830 variables aleatorias distintas. 1.1. Variable aleatoria Uniforme Una variable aleatoria uniformemente distribuida (PdsUniform) tiene la función de densidad de la Figura 1-1. Para generar una nueva variable aleatoria uniformemente distribuida X, se crea primero una nueva secuencia aleatoria X1. Luego se aplica la siguiente ecuación. 1 Capítulo 1. Variables Aleatorias Figura 1-1. Función densidad de probabilidad uniforme. fx(x)=Uniform(A,B) Tabla 1-1. Estadística de la variable aleatoria Uniforme PdsTipova PdsUniform (B+A)/2 (B-A)2/12 1.2. Variable aleatoria Gaussiana Una variable aleatoria Gaussiana (PdsGaussian) tiene la función de densidad de la Figura 1-2. Para generar una nueva variable aleatoria Gaussiana X, se crea primero dos nuevas variables aleatorias uniformemente distribuidas X1 y X2. Luego se aplica la siguiente ecuación. 2 Capítulo 1. Variables Aleatorias Figura 1-2. Función densidad de probabilidad Gaussiana. fx(x)=N(U,Sigma2) Tabla 1-2. Estadística de la variable aleatoria Gaussiana PdsTipova PdsGaussian U Sigma2 1.3. Variable aleatoria Rayleighiana Una variable aleatoria Rayleighiana (PdsRayleigh) tiene la función de densidad de la Figura 1-3. Para generar una nueva variable aleatoria Rayleighiana X, se crea primero una nueva variable aleatoria uniformemente distribuida X1. Luego se aplica la siguiente ecuación. 3 Capítulo 1. Variables Aleatorias Figura 1-3. Función densidad de probabilidad Rayleighiana. fx(x)=Rayleigh(Sigma) Tabla 1-3. Estadística de la variable aleatoria Rayleighiana PdsTipova PdsRayleigh Sigma * sqrt(PI/2) ((4-PI)/2)*Sigma2 1.4. Variable aleatoria Exponencial Una variable aleatoria Exponencial (PdsExponential) tiene la función de densidad de la Figura 1-4. Para generar una nueva variable aleatoria Exponential X, se crea primero una nueva variable aleatoria uniformemente distribuida X1. Luego se aplica la siguiente ecuación. 4 Capítulo 1. Variables Aleatorias Figura 1-4. Función densidad de probabilidad Exponencial. fx(x)=Exponential(Lambda) Tabla 1-4. Estadística de la variable aleatoria Exponencial PdsTipova PdsExponential Lambda-1 Lambda-2 1.5. Variable aleatoria Poissoniana Una variable aleatoria Poissoniana (PdsPoisson) tiene la función de densidad de la Figura 1-5. Para generar una nueva variable aleatoria Poisson K, se crea primero una nueva variable aleatoria uniformemente distribuida X1. Luego se aplica el siguiente algoritmo. Algoritmo para la generación de variables aleatorias poissonianas (Knuth): Inicia: Genera una variable aleatoria uniforme X, x in [0,1). 5 Capítulo 1. Variables Aleatorias L = e^{-Lambda}, k = 0 y p = 1.0. do: k = k + 1. p = p * x. while p > L. return k - 1 Figura 1-5. Función densidad de probabilidad Poissoniana. fk(k)=Poisson(Lambda) Tabla 1-5. Estadística de la variable aleatoria Poissoniana PdsTipova PdsPoisson Lambda Lambda 6 Capítulo 2. Modo de uso Para la fácil reutilización del código se han definido algunos tipos de variables. Por ejemplo: typedef float PdsRvReal; typedef int PdsRvInteger; typedef unsigned long PdsRvNaturalD; La Tabla 2-1 muestra todos los tipos de variable aleatorias (RV), los tipos de estructuras correspondientes y el tipo de variable entregado por cada RV. Tabla 2-1. Tipos de datos de las variables aleatorias. tipova PdsTipova Variable devuelta congruential PdsCongruential PdsRvNaturalD uniform PdsUniform PdsRvReal gaussian PdsGaussian PdsRvReal rayleigh PdsRayleigh PdsRvReal exponential PdsExponential PdsRvReal poisson PdsPoisson PdsRvInteger 2.1. Creando las variables aleatorias. Todas las funciones para crear una variable aleatoria de tipo "tipova" siguen el siguiente formato. La función de creación de variable se llamará: PdsTipova *pds_tipova_new(....); Los parámetros de esta función dependerá del tipo de RV, nótese que devuelve un puntero al tipo PdsRvTipo. PdsCongruential *pds_congruential_new(void); PdsUniform *pds_uniform_new(PdsRvReal A,PdsRvReal B); PdsGaussian *pds_gaussian_new(PdsRvReal U,PdsRvReal Sigma); PdsRayleigh *pds_rayleigh_new(PdsRvReal Sigma); PdsExponential *pds_exponential_new(PdsRvReal Lambda); PdsPoisson *pds_poisson_new(PdsRvReal Lambda); 7 Capítulo 2. Modo de uso 2.2. Usando las variables aleatorias. La función para la petición de un elemento de la RV X es: PdsRvReal PdsRvInteger pds_tipova_get_value(PdsTipova *X); PdsRvNaturalD Como se ve, esta función recibe un puntero a la RV X, y luego extrae un elemento de X en cada llamada a esta función. Los valores devueltos por esta función pueden ser variables de tipo PdsRvInteger, PdsRvNaturalD o PdsRvReal, según el tipo de variable aleatoria X. También es posible pedir a la RV X el último valor generado, para conseguir esto, se usan las siguientes funciones segun sea el tipo de variable de X. PdsRvReal PdsRvInteger pds_tipova_get_last_value(PdsTipova *X); PdsRvNaturalD 2.3. Destruyendo las variables aleatorias. La función para liberar la RV X es: void pds_tipova_free(PdsTipova *X); Si además de liberar la memoria, se desea cargar a la RV X con un NULL, se debe usar: void pds_tipova_destroy (PdsTipova **X); 8 Capítulo 3. Compilación con PDSRV y ejemplos de uso La biblioteca PDSRV puede ser encontrada con los nombres libpdsrv.so y libpdsrv.a. La biblioteca libpdsrv.so es una biblioteca compartida, el uso de esta biblioteca indica que el programa que la invoque no incluirá el código de la biblioteca en el código del programa, sino que incluirá en el programa una referencia a la función contenida en la biblioteca. Para que esto funcione la biblioteca tiene que estar en la carpeta estándar en donde el sistema operativo busca las bibliotecas o en la misma carpeta del programa que lo invoca. La biblioteca libpdsrv.a es una biblioteca estática, el uso de esta biblioteca indica que el programa incluirá dentro de su propio código todo el código correspondiente a las funciones de la biblioteca usadas en el programa, esto se hace durante la compilación del programa. La biblioteca tiene que estar en la carpeta estándar en donde el compilador busca las bibliotecas o en la misma carpeta del código fuente del programa que lo invoca. 3.1. Compilación con PDSRV Para compilar un programa con gcc usando la biblioteca PDSRV se deben de conocer los siguientes parámetros. El parámetro -lpdsrv se usa para indicar al compilador que debe incluirse la biblioteca libpdsrv.a o libpdsrv.so • Si existe libpdsrv.a y libpdsrv.so. Se coge por defecto libpdsrv.a • Si sólo existe una de ellas. Se coge la que existe. • Si no existe ninguna de ellas. da Error. La opción -Bdynamic cambia el primer caso, haciendo que se coja libpdsrv.so en vez de libpdsrv.a. La opción -Bdynamic afecta a todas las librerías que van detrás en la línea de compilación. Para volver a cambiar, podemos poner -Bstatic en cualquier momento. También es posible indicarle al compilador que biblioteca usar, indicando el nombre completo de la biblioteca, en este caso libpdsrv.a. Si el código fuente que se desea compilar usa las bibliotecas libnombre1.a y libnombre2.a, y la biblioteca libnombre1.a usa funciones de la biblioteca libnombre2.a, el comando de compilación deberá seguir el siguiente orden. gcc ejemplo1.c -o ejemplo1 -lnombre1 -lnombre2 El parámetro -Ldirectory agrega un directorio a la lista de directorios que contienen a las bibliotecas *.a y *.so. Por defecto los directorios son /lib , /usr/lib y el directorio de trabajo. gcc ejemplo1.c -o ejemplo1 -L/home/myname/mylibs libnombre.a gcc ejemplo1.c -o ejemplo1 -L/home/myname/mylibs -lnombre 9 Capítulo 3. Compilación con PDSRV y ejemplos de uso El parámetro -Ipathname agrega un directorio a la lista de directorios que contienen los archivos invocados con #include . Por defecto el compilador busca los archivos en el directorio que contiene el código fuente, después los directorios nombrados con la opción -I (si existe), y finalmente, en /usr/include. Si se tienen los archivos de cabecera en /home/myname/myheaders se debería de usar de la siguiente manera: gcc ejemplo1.c -o ejemplo1 -I/home/myname/myheaders 3.1.1. Compilación por linea de comandos Para compilar un programa que usa la biblioteca PDSRV se debe de incluir la siguiente linea en el código fuente (ejemplo.c). #include <pds/pdsrv.h> Si la biblioteca ha sido instalada correctamente en el sistema, se procede entonces a compilar el código ejemplo.c mediante el siguiente comando. gcc ejemplo.c -o ejemplo -lpdsrv Si la biblioteca no se ha instalado y el archivo libpdsrv.* se encuentra en /home/name/mylibs, y los archivos de cabecera *.h se encuentran en /home/name/include entonces la compilación se realizará de la siguiente manera. gcc ejemplo.c -o ejemplo -lpdsrv -L/home/name/mylibs -I/home/name/include Si se desea compilar el archivo ejemplo.c de tal manera de que use una biblioteca compartida preferencial-mente, entonces se usará el siguiente comando. gcc ejemplo.c -o ejemplo -Bdynamic -lpdsrv -L/home/name/mylibs -I/home/name/include 3.1.2. Compilación usando autotools Para compilar un programa que usa la biblioteca PDSRV haciendo uso de las AUTOTOOLS, se debe de escribir en el archivo Makefile.am correspondiente los siguiente. # Adicionales archivos include para compilar el ejemplo1.c . INCLUDES = -I/home/name/header 10 Capítulo 3. Compilación con PDSRV y ejemplos de uso # El programa a construir. bin_PROGRAMS = ejemplo1 # Lista de códigos fuente para crear ejemplo1. ejemplo1_SOURCES = ejemplo1.c # Adicionales bibliotecas para compilar el programa ejemplo1. ejemplo1_LDADD = -lpdsrv libnombre1.a /home/name/mylibs/libnombre2.a Para compilar un biblioteca estatica (*.a) que usa la biblioteca PDSRV haciendo uso de las AUTOTOOLS con RANLIB, se debe de escribir en el archivo Makefile.am correspondiente los siguiente. # Adicionales archivos include para compilar la biblioteca libejemplo1.a. INCLUDES = -I/home/name/header # La biblioteca a construir. lib_LIBRARIES = libejemplo1.a # Lista de códigos fuente para crear la biblioteca libejemplo1.a . libejemplo1_a_SOURCES = ejemplo1.c # Adicionales bibliotecas para compilar la biblioteca libejemplo1.* . libejemplo1_a_LIBADD = -lpdsrv libnombre1.a /home/name/mylibs/libnombre2.a Para compilar un biblioteca que usa la biblioteca PDSRV haciendo uso de las AUTOTOOLS con LIBTOOL, se debe de escribir en el archivo Makefile.am correspondiente los siguiente. # Adicionales archivos include para compilar la biblioteca libejemplo1.a # y libejemplo1.so. INCLUDES = -I/home/name/header # La biblioteca a construir. lib_LTLIBRARIES = libejemplo1.la # Lista de códigos fuente para crear la biblioteca libejemplo1.* . libejemplo1_la_SOURCES = ejemplo1.c # Adicionales bibliotecas para compilar la biblioteca libejemplo1.* . libejemplo1_la_LIBADD = -lpdsrv libnombre1.a \ /home/name/mylibs/libnombre2.a carpeta/libotra.la 3.2. Ejemplos de uso de la biblioteca Los siguientes ejemplos darán un idea del uso de la biblioteca PDSRV. 11 Capítulo 3. Compilación con PDSRV y ejemplos de uso Ejemplo 3-1. Test de la variable aleatoria gaussiana. N(1.0,3.02) Este programa crea una variable aleatoria gaussiana X, luego obtiene NUMELEMENTOS de esa variable aleatoria y los guarda en una columna en el archivo "DataGauss.txt". #include <stdlib.h> #include <pds/pdsrv.h> #define NUMELEMENTOS 1000 int main(int argc, char** argv) { PdsRvReal x; unsigned long int i; PdsGaussian *X=NULL; FILE *fd=NULL; X=pds_gaussian_new(1.0,3.0); if(X==NULL) return EXIT_FAILURE; fd=fopen("DataGauss.txt","w"); if(fd==NULL) {printf("ERROR:Ejecutando fopen.\n");return EXIT_FAILURE;} for(i=0;i<NUMELEMENTOS;i++) { x=pds_gaussian_get_value(X); fprintf(fd,"%f\n",x); } fclose(fd); pds_gaussian_destroy(&X); return EXIT_SUCCESS; } Ejemplo 3-2. Test de la función de densidad de probabilidad de todas las RV de la biblioteca. El programa realiza un test de la función de densidad de probabilidad de todas las variables aleatorias de la biblioteca, para lograr esto crea el archivo "prueba.txt" con los datos de las RV en columnas y el archivo "plot_octave_pds.m", que será usado por OCTAVE para graficar las funciones de densidad de probabilidad. #include <stdlib.h> #include <pds/pdsrv.h> #define NUMELEMENTOS PDS_RAND_MAX/1000 int pds_octave_plot_pdf(char NombreOctaveFile[],char NombreOctaveDataFile[]); 12 Capítulo 3. Compilación con PDSRV y ejemplos de uso int main(int argc, char** argv) { PdsRvReal xc,x1,x2,x3,x4,x5,x6; unsigned long int i; PdsCongruential *Xc=NULL; PdsUniform *X1=NULL; PdsUniform *X2=NULL; PdsGaussian *X3=NULL; PdsRayleigh *X4=NULL; PdsExponential *X5=NULL; PdsPoisson *X6=NULL; FILE *fd=NULL; Xc=pds_congruential_new(); if(Xc==NULL) return EXIT_FAILURE; X1=pds_uniform_new(1.5,3.5); if(X1==NULL) return EXIT_FAILURE; X2=pds_uniform_new(1.5,3.5); if(X2==NULL) return EXIT_FAILURE; X3=pds_gaussian_new(0.0,1.0); if(X3==NULL) return EXIT_FAILURE; X4=pds_rayleigh_new(1.0); if(X4==NULL) return EXIT_FAILURE; X5=pds_exponential_new(1.0); if(X5==NULL) return EXIT_FAILURE; X6=pds_poisson_new(4.0); if(X6==NULL) return EXIT_FAILURE; pds_octave_plot_pdf("plot_octave_pds.m","prueba.txt"); fd=fopen("prueba.txt","w"); if(fd==NULL) {printf("ERROR:fopen de datos.\n");return EXIT_FAILURE;} for(i=0;i<NUMELEMENTOS;i++) { xc=(PdsRvReal)pds_congruential_get_value(Xc); x1=pds_uniform_get_value(X1); x2=pds_uniform_get_value(X2); x3=pds_gaussian_get_value(X3); x4=pds_rayleigh_get_value(X4); x5=pds_exponential_get_value(X5); x6=(PdsRvReal)pds_poisson_get_value(X6); fprintf(fd,"%f\t%f\t%f\t%f\t%f\t%f\t%f\n",x1,x2,x3,x4,x5,x6,xc); } fclose(fd); pds_congruential_destroy(&Xc); pds_uniform_destroy(&X1); pds_uniform_destroy(&X2); pds_gaussian_destroy(&X3); pds_rayleigh_destroy(&X4); pds_exponential_destroy(&X5); pds_poisson_destroy(&X6); return EXIT_SUCCESS; } 13 Capítulo 3. Compilación con PDSRV y ejemplos de uso int pds_octave_plot_pdf(char NombreOctaveFile[],char NombreOctaveDataFile[]) { FILE *fd; fd=fopen(NombreOctaveFile,"w"); if(fd==NULL) {printf("ERROR:fopen de octave.\n");return EXIT_FAILURE;} fprintf(fd,"X=load(\’%s\’)\’;\n",NombreOctaveDataFile); fprintf(fd,"intervalos=100;\n"); fprintf(fd,"\n"); fprintf(fd,"[Nj1 abscisax1]=hist(X(1,:),intervalos);\n"); fprintf(fd,"Rango1=max(X(1,:))-min(X(1,:));\n"); fprintf(fd,"figure(1);bar(abscisax1,Nj1*intervalos/(Rango1*%lu));\n",NUMELEMENTOS); fprintf(fd,"\n"); fprintf(fd,"[Nj2 abscisax2]=hist(X(2,:),intervalos);\n"); fprintf(fd,"Rango2=max(X(2,:))-min(X(2,:));\n"); fprintf(fd,"figure(2);bar(abscisax2,Nj2*intervalos/(Rango2*%lu));\n",NUMELEMENTOS); fprintf(fd,"\n"); fprintf(fd,"Ex1=mean(X(1,:))\n"); fprintf(fd,"Ex2=mean(X(2,:))\n"); fprintf(fd,"cov_xy=mean(cov((X(1,:)-Ex1),(X(2,:)-Ex1)))\n"); fprintf(fd,"\n"); fprintf(fd,"[Nj3 abscisax3]=hist(X(3,:),intervalos);\n"); fprintf(fd,"Rango3=max(X(3,:))-min(X(3,:));\n"); fprintf(fd,"figure(3);bar(abscisax3,Nj3*intervalos/(Rango3*%lu));\n",NUMELEMENTOS); fprintf(fd,"Ex3=mean(X(3,:))\n"); fprintf(fd,"E2x3=mean((X(3,:)-Ex3).*(X(3,:)-Ex3))\n"); fprintf(fd,"\n"); fprintf(fd,"[Nj4 abscisax4]=hist(X(4,:),intervalos);\n"); fprintf(fd,"Rango4=max(X(4,:))-min(X(4,:));\n"); fprintf(fd,"figure(4);bar(abscisax4,Nj4*intervalos/(Rango4*%lu));\n",NUMELEMENTOS); fprintf(fd,"Ex4=mean(X(4,:))\n"); fprintf(fd,"E2x4=mean((X(4,:)-Ex4).*(X(4,:)-Ex4))\n"); fprintf(fd,"\n"); fprintf(fd,"[Nj5 abscisax5]=hist(X(5,:),intervalos);\n"); fprintf(fd,"Rango5=max(X(5,:))-min(X(5,:));\n"); fprintf(fd,"figure(5);bar(abscisax5,Nj5*intervalos/(Rango5*%lu));\n",NUMELEMENTOS); fprintf(fd,"Ex5=mean(X(5,:))\n"); fprintf(fd,"E2x5=mean((X(5,:)-Ex5).*(X(5,:)-Ex5))\n"); fprintf(fd,"\n"); fprintf(fd,"[Nj6 abscisax6]=hist(X(6,:),intervalos);\n"); fprintf(fd,"Rango6=max(X(6,:))-min(X(6,:));\n"); fprintf(fd,"figure(6);bar(abscisax6,Nj6*1.0/(%lu));\n",NUMELEMENTOS); fprintf(fd,"Ex6=mean(X(6,:))\n"); fprintf(fd,"E2x6=mean((X(6,:)-Ex6).*(X(6,:)-Ex6))\n"); fprintf(fd,"\n"); fprintf(fd,"\n"); fprintf(fd,"C=min(size(X))\n"); fprintf(fd,"[NjC abscisaxC]=hist(X(C,:),intervalos);\n"); fprintf(fd,"RangoC=max(X(C,:))-min(X(C,:));\n"); fprintf(fd,"figure(C);bar(abscisaxC,NjC*intervalos/(RangoC*%lu));\n",NUMELEMENTOS); fprintf(fd,"\n"); 14 Capítulo 3. Compilación con PDSRV y ejemplos de uso fclose(fd); return EXIT_SUCCESS; } 15 Capítulo 4. Referencias • http://zsoluciones.com (http://zsoluciones.com) Blog personal. • http://identi.ca/trucomanx (http://identi.ca/trucomanx) Microblogging del proyecto. • http://en.wikipedia.org/wiki/Probability_distribution (http://en.wikipedia.org/wiki/Probability_distribution) Wikipedia. 16 Apéndice A. Preguntas Frecuentes 1. Puedo participar en el proyecto ? Si, entra en contacto con: fernando.pujaico.rivera en gmail.com 2. Que tipo de licencia usa la biblioteca? Usa la licencia GPL V.3. 3. La variable aleatoria que busco no está, que hago? Si tienes la ecuación para generar la RV a partir de una RV uniformemente distribuida, mándame un email a fernando.pujaico.rivera en gmail.com con esa ecuación, y la incorporaré en la siguiente versión de la biblioteca. También puedes crearla tu haciendo uso de la secuencia aleatoria generada congruencialmente (PdsRvCongruential). 17