Académique Documents
Professionnel Documents
Culture Documents
Ncleo de Sucre
Escuela de Ciencias
Departamento de Matemticas
Programa de la Licenciatura En Informtica
Tutor:
Prof. Ana Fuentes
Bachiller:
Jess Alejandro Machado Ortiz
C.I: 24877491
Planteamiento
de insercin y eliminacin.
Como se puede observar los comunes son los que se encuentran en ambas
cadenas, esto no es al azar, hay un mtodo mediante el cual se obtiene la LCS.
Para el llenado de esta tabla, nos basamos en las siguientes premisas:
E
M
A
C
H
A
D
O
E
0
0
0
0
0
0
0
0
M
0
1
1
1
1
1
1
1
A
0
1
2
2
2
2
2
2
N
0
1
2
2
2
2
2
2
C
0
1
2
3
3
3
3
3
H
0
1
2
3
4
4
4
4
A
0
1
2
3
4
5
5
5
ALGORITMO SECUENCIAL
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
/*
* Definimos dos funciones para buscar el maximo de dos numero
* y el minimo de dos numeros tambien.
*/
#define MAX(x,y) (((x) >= (y)) ? (x) : (y))
#define MIN(x,y) (((x) <= (y)) ? (x) : (y))
/*
* @parametro char * x, primer string recibido por archivos.
* @parametro char * y, segundo string recibido por archivos.
* @parametro unsigned short int **c, matriz LCS.
*/
void LCS_procesar(char *x, char *y,unsigned short int **c);
/*
* @parametro unsigned shor int **c, la matriz LCS.
* @parametro char *x, primer string recibido por archivos.
* @parametro int i, indice de las filas de la matriz.
* @parametro int j, indice de las columnas de la matriz.
*/
void LCS_mostrar(unsigned short int **c,char *x, int i, int j);
/*
* @parametro char *infile, nombre del archivo al cual leera el string
*/
char* LCS_leer(char *infile);
//Se tiene argc, argv como puntos de entrada de datos externos al
main,
//Que en este codigo, se usan para pasar el nombre de los
archivos(flujos,
//de entrada).
int main(int argc, char** argv){
//si argc es diferente de 3, esto quiere decir que no se coloco
//el flujo de entrada tanto para string 1 y string 2.
//una validacion previa a la ejecucion.
if(argc != 3){
printf("Porfavor, use 2 archivos de lectura");
exit(0);
}
//1 - leemos los archivos, creamos los string y se lo asignamos a
//nuestras variables.
char *X = LCS_leer(argv[1]);
char *Y = LCS_leer(argv[2]);
//Tomando el tamao de X y Y, para porteriormente crear la
matriz
int len_X = (int) strlen(X);
int len_Y = (int) strlen(Y);
//En esta validacion, hacemos un posible estimado de que tan
grande
//podria ser nuestra entrada, y segun los requisitos de nuestra
maquina
//restringir un tamao en especifico.
if(len_X + len_Y +len_X*8 + (len_X*len_Y)*2 > 2147483648){
printf("Ocurrio un error de desbordamiento de datos");
return 0;
}
//Declaramos la matriz de la forma **c, para que sea dinmica.
//Permitiendo manejadar filas y columnas de tamao variable.
unsigned short int **c;
//definimos la fila
int fila;
//Asignamos memoria dinamicamente, que sera igual a [tam(x)
+1]
c = malloc(sizeof(unsigned short int*)*(len_X+1));
for(fila = 0; fila < len_X+1; fila++){
//Aqui por asignamos [tam(x) + 1][tam(y) +1] -> por
eso el ciclo,
//a cada [tam(x) + 1][0...tam(y)+1]
c[fila] = malloc(sizeof(unsigned short
int)*(len_Y+1));
}
LCS_procesar(X,Y,c);
LCS_mostrar(c,X,len_X,len_Y);
printf("\n\n");
printf("El tamano de la subsecuencia comun mas larga es:
%d\n",c[len_X][len_Y]);
for(fila = 0; fila < len_X+1; fila++){
free(c[fila]);
}
free(c);
free(X);
free(Y);
return 0;
}
//Leer un archivo que contiene cadena de caracteres,
//se ignoraran nuevas lineas y espacios.
char* LCS_leer(char *infile){
FILE *FIN;
char c = 'n';
char *S = NULL;
char *T;
int count = 0;
if((FIN = fopen(infile,"r"))==NULL){
printf("Ocurrio un problema abriendo el archivo: %s\n",infile);
exit(0);
}
while(( c = fgetc(FIN))!= EOF){
if ( c != '\n'){
count++;
//se ensancha, una forma de decirlo la cadena de caracteres
dinamicamente.
T = (char *) realloc((void *) S, (count+1)*sizeof(char));
if(T != NULL){
S = T;
S[count-1] = c;
S[count]='\0';
}
else{
free(S);
printf("Error de (re) asignacion de memoria para guardar la
cadena en %s\n",infile);
exit(1);
}
}
}
fclose(FIN);
return S;
}
void LCS_procesar(char *x, char *y, unsigned short int **c){
int fila, columna;
int len_X = (int) strlen(x);
int len_Y = (int) strlen(y);
//Hacemos 0's la primera columna y la primera fila
for(fila = 0; fila <= len_X; fila++){
c[fila][0] = 0;
}
for(columna = 1; columna <= len_Y; columna++){
c[0][columna] = 0;
}
for(fila = 1; fila <= len_X; fila++){
for(columna = 1; columna <= len_Y; columna++){
//Rellenar c[fila][columna] con el valor apropiado
if(x[fila-1] == y[columna-1]){
c[fila][columna] = c[fila-1][columna-1]+1;
}
else{
c[fila][columna] = MAX(c[fila-1][columna],c[fila][columna1]);
}
}
}
return;
}
void LCS_mostrar(unsigned short int **c,char *x,int i, int j){
if(i == 0 || j == 0)
return;
if((c[i][j] - 1 == c[i-1][j - 1]) &&
(c[i][j] - 1 == c[i-1][j ]) &&
(c[i][j] - 1 == c[i ][j - 1])){
LCS_mostrar(c,x,i-1,j-1);
printf("%c",x[i-1]);
}
else
if(c[i][j] == c[i-1][j])
LCS_mostrar(c,x,i-1,j);
else
LCS_mostrar(c,x,i,j-1);
return;
}
Este cdigo fue escrito y probado en un entorno Linux Ubuntu
14.04, teniendo como compilador base GCC. Con el IDE CODEBLOCKS,
y se deber usar la siguientes lneas para su ejecucin.
-
Acumulad
o
Segundos Se
g
Llamad
as
100
2.49
Llamada
s
por
segundo
2.49
0.00
2.49
0.00
Llamada Nombre
s
por
segundo
2.49
LCS_proce
sar
0.00
LCS_leer
0.00
2.49
0.00
0.00
2.4
9
0.0
0
0.0
0
Total
LCS_mostr
ar
Leyenda:
-
Grafo de Llamadas:
Granularidad: Para cada muestra abarca 2 byte(s) para 0.40% de 2.49
segundos.
ndice
[1]
100.0
[2]
100.0
Tiempo
2.49
2.49
Hijos(propagacin)
0.00
0.00
Llamadas
1/1
1
0.00
2.49
2.49
0.00
1/1
Nombre
Main [2]
LCS_procesar [1]
<espontaneo>
Main [2]
LCS_procesar [1]
0.00
0.00
0.00
0.00
2/2
1/1
LCS_leer [3]
LCS_mostrar [4]
0.00
0.00
0.00
0.00
0.00
0.00
0.00
0.00
2/2
2
13537
1/1
1 + 13537
13537
Main [2]
LCS_leer [3]
LCS_mostrar [4]
Main [2]
LCS_mostrar [4]
LCS_mostrar
[1]
[4]
[3]
0.0
[4]
[4]
Para los padres de las funciones, los campos tienen los siguientes
significados:
-
ALGORITMO SECUENCIAL
Procesamiento Diagonal.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define MAX(x, y) (((x) >= (y)) ? (x) : (y))
#define MIN(x, y) (((x) <= (y)) ? (x) : (y))
void LCS_procesar(char *x, char *y, unsigned short int **c);
void LCS_mostrar(unsigned short int **c, char *x, int i, int j);
char* LCS_leer(char *infile);
int main(int argc, char** argv)
{
if( argc != 3 )
{
printf("Porfavor use 2 archivos de lectura ");
exit(0);
}
char *X = LCS_leer(argv[1]);
char *Y = LCS_leer(argv[2]);
int len_X = (int) strlen(X);
int len_Y = (int) strlen(Y);
if( len_X+len_Y + len_X*8 + (len_X*len_Y)*2 > 4294967296 /* 4*2^30
*/ )
{
printf("Problema de apertura con el archivo %s.\n", infile);
exit(0);
}
fclose(FIN);
return S;
}
Acumulad
o
Seg
Seg
Tiemp
o
100
13.75
0.00
0.00
13.75
13.75
13.7
5
0.00
0.00
Total
Llama
das
1
Llamadas
por
segundo
13.75
Llamadas
por
segundo
13.75
2
1
0.00
0.00
0.00
0.00
Nombr
e
LCS_pro
cesar
LCS_leer
LCS_mo
strar
Grafo de Llamadas:
Granularidad: Para cada muestra abarca 2 byte(s) para 0.07% de
13.75 segundos.
ndice
[1]
100.0
[2]
100.0
Tiempo
13.75
13.75
Hijos(propagacin)
0.00
0.00
Llamadas
1/1
1
0.00
13.75
13.75
0.00
1/1
Nombre
Main [2]
LCS_procesar [1]
<espontaneo>
Main [2]
LCS_procesar [1]
0.00
0.00
0.00
0.00
2/2
1/1
LCS_leer [3]
LCS_mostrar [4]
0.00
0.00
0.00
0.00
0.00
0.00
0.00
0.00
2/2
2
13537
1/1
1 + 13537
13537
Main [2]
LCS_leer [3]
LCS_mostrar [4]
Main [2]
LCS_mostrar [4]
LCS_mostrar
[1]
[4]
[3]
0.0
[4]
[4]
Para los padres de las funciones, los campos tienen los siguientes
significados:
-
GRAFO DE DEPENDENCIAS
Grafo de dependencias del MAIN
void LCS_mostrar(unsigned short int **c, char *x, int i, int j){
c1: if( i == 0 || j == 0 )
I1: return;
&&
C5: return;
])
ALGORITMO PARALELO
#include <mpi.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define MAX(x, y) (((x) >= (y)) ? (x) : (y))
#define MIN(x, y) (((x) <= (y)) ? (x) : (y))
//Estructura que contendr la informacin y argumentos para el LCS
typedef struct LCS
{
char *x; //string x
char *y; //string y
short int **c; //Matriz
int
m; // tamao de filas
int
n; //tamao de columnas
}LCS_T;
MPI_Status status; //el status, sirve para comunicacin directas e
indirectas.
void LCS_procesar(LCS_T *, int, int); //Arma la matriz del LCS
char* LCS_leer(char *);//Lee de un archivo el flujo de datos
void distribuir_datos(LCS_T *, char *, int, int);//Se aplica la
distribucin de datos a los procesadores.
void LCS_mostrar(short int **c,char *x, int i, int j); // Se
muestra el LCS.
int main(int argc, char** argv)
{
//Cuando se trabaja con MPI,
//es necesario tener identificadores por proceso.
int totalprocesos, miproc;
LCS_T LCS_info; //Meta Contenedor Global.
char* string1;
MPI_Init(&argc, &argv); //Iniciamos el entorno MPI
MPI_Comm_size(MPI_COMM_WORLD, &totalprocesos); //obtenemos el
numero de procesos
MPI_Comm_rank(MPI_COMM_WORLD, &miproc); //obtenemos el
identificador nico de ese proceso
if( miproc == 0 ) { //Se tomara al proceso 0, como al proceso
raz.
if( argc != 3 )
{
printf("Utilizar archivos externos para cargar los
datos.\n");
printf("Ejemplo: %s file1 file2\n", argv[0]);
MPI_Abort(MPI_COMM_WORLD,0); //Se aborta el entorno MPI;
}
//se lee desde el archivo
string1
= LCS_leer(argv[1]);
LCS_info.y = LCS_leer(argv[2]);
//se obtiene el tamano de filas y columnas
LCS_info.m = (int) strlen(string1);
LCS_info.n = (int) strlen(LCS_info.y);
}
//Se usara Broadcast para y & Scatter para x
distribuir_datos(&LCS_info, string1, miproc, totalprocesos);
//Crear e inicializar las matrices.
int i;
LCS_info.c = malloc(sizeof(int*)*LCS_info.m+1);
for(i = 0; i <= LCS_info.m; i++) {
LCS_info.c[i] = malloc(sizeof(int)*LCS_info.n+1);
LCS_info.c[i][0] = 0; // La primera columna es 0
}
if (miproc == 0) {
for (i = 0; i <= LCS_info.n; i++)
LCS_info.c[0][i] = 0; // La primera fila es 0
}
LCS_procesar( &LCS_info, miproc, totalprocesos );
if( miproc == totalprocesos - 1 )
printf("Length of LCS: %d\n", LCS_info.c[LCS_info.m]
[LCS_info.n]);
if( miproc == 0 ) {
LCS_mostrar(LCS_info.c, LCS_info.x, LCS_info.m, LCS_info.n);
printf("\n\n");
printf("Numero de Procesos: %d\n", totalprocesos);
}
MPI_Finalize();
return 0;
}
/******************************************************************
* Distribuir los datos necesarios a los procesos
*
******************************************************************/
void distribuir_datos(LCS_T *LCS_info, char* string1, int miproc, int
totalprocesos ) {
//Se envia el tamao de columnas a todos los procesadores.
MPI_Bcast( &LCS_info->n, 1, MPI_INT, 0, MPI_COMM_WORLD);
//si es el procesador principal, asignamos dinamicamente el tamano
de y igual al tamano de filas.
if( miproc!= 0 )
LCS_info->y = malloc(LCS_info->n*sizeof(char));
//Pasamos y a todos los procesadores
MPI_Bcast( LCS_info->y, LCS_info->n, MPI_CHAR, 0, MPI_COMM_WORLD
);
//Pasamos las filas a los procesadores.
MPI_Bcast( &LCS_info->m, 1, MPI_INT, 0, MPI_COMM_WORLD);
//Hacemos el balanceo de carga
int intervalo = (totalprocesos + LCS_info->m - LCS_info->m %
totalprocesos) / totalprocesos;
LCS_info->x = malloc((intervalo+1)*sizeof(char));
bzero(LCS_info->x, intervalo+1); //establece los primeros n bytes
del area a patir de de s a 0.
//Distribuir el mismo numero de elementos a cada procesador, se
requiere que sea intervalo divisible por el total de procesos.
MPI_Scatter( string1, intervalo, MPI_CHAR, LCS_info->x, intervalo,
MPI_CHAR, 0, MPI_COMM_WORLD);
//Se toma el nuevo tamao de filas.
LCS_info->m = (int) strlen(LCS_info->x);
return;
}
void LCS_diagonal(int k, LCS_T *LCS_info)
{
//El core bastante igual al secuencial, solo que aqui el trabajo
se realizara a traves de diagonales.
//Para trabajar mejor los bloques.
int i,j;
int start = MAX(1,k-LCS_info->n);
int finish = MIN(LCS_info->m,k-1);
for( i = start; i <= finish; i++ )
{
j = k - i;
if(LCS_info->x[i-1] == LCS_info->y[j-1])
LCS_info->c[i][j] = LCS_info->c[i-1][j-1] + 1;
else
{
if( LCS_info->c[i-1][j] >= LCS_info->c[i][j-1] )
LCS_info->c[i][j] = LCS_info->c[i-1][j];
else
LCS_info->c[i][j] = LCS_info->c[i][j-1];
}
}
}
void LCS_procesar(LCS_T *LCS_info, int miproc, int totalprocesos )
{
int diag, col;
//
printf("N: %d\n", LCS_info->n);
/* For each diagonal */
for(diag = 2; diag <= LCS_info->m+LCS_info->n; diag++)
{
/* Receive value of first row to myid+1 */
CONCLUSIONES
Durante la ejecucin de este proyecto, se observo con gran
agrado las potencialidades que tiene este nuevo paradigma de la
multiprogramacin. En donde una gran responsabilidad de las cosas
recae en los programadores, como lo es gestionar los datos,
analizando sus dependencias, observar su congruencia, estudiar las
distintas topologas fsicas que permiten la comunicacin de los
procesos. Esto con el fin de optimizar el cdigo y aprovechar en su
totalidad las nuevas caractersticas hardware.
El LCS Longest Common Substring Subsecuencia comn
ms larga es de los problemas en donde se necesita un gran estudio
de sus dependencias y del comportamiento secuencial del mismo. Ya
que como se observo en el cdigo descrito con anterioridad, el
procesamiento era complicado resolverlo a travs de sus filas, puesto
que la dependencia imposibilitaba en gran medida la reparticin
equitativa de las tareas. Por esto se opto a una nueva forma,
procesando sus diagonales. Aqu se minimiz en gran parte esta
dependencia, a sacrificio de un poco de tiempo. De 2.47 segundos
aproximadamente en el secuencial por filas, llegamos a 13s
aproximadamente en el secuencial por diagonales.
A la hora de paralelizarlo, basndome en el grafo de
dependencias. Concluimos que era factible y se llevo a cabo dicha
labor. Se escogi la funcin LCS_procesar para la realizacin de la
paralizacin, ya que LCS_mostrar se dificultaba su paralelizacin. Se
obtuvo un tiempo relativo de 9.30 seg. Un mejoramiento del 28% de
rendimiento respecto al diagonal secuencial. Y un desmejoramiento
de 256% respecto a algoritmo secuencial. Tambin cabe resaltar que
las pruebas realizadas fueron en un entorno muy simple y de bajos
recursos.
En un entorno con 8 ncleos y 16gb de ram, podra encontrarse
con un mejor rendimiento del algoritmo aqu desarrollado.
BIBLIOGRAFIA
George Em Kardiadakis y Robert M. Kirby II. University
Cambridge. Parallel Scientific Computing in C++ and MPI,
Francisco Hidrobo y Herbert
(Message Passing Interface).
Hoeger.
Introduccin
MPI
Approximate
String
ACM