• No se han encontrado resultados

Algoritmos Numéricos

N/A
N/A
Protected

Academic year: 2022

Share "Algoritmos Numéricos"

Copied!
41
0
0

Texto completo

(1)

Algoritmos y Programación Paralela 1

Algoritmos Numéricos

Algoritmos matriciales básicos

Almacenamiento de matrices

Operaciones básicas con vectores

Operaciones básicas con matrices

Multiplicación de matrices

Factorización LU

Operaciones con matrices dispersas

Trabajo por bloques

(2)

Almacenamiento de matrices densas

En array bidimensional: double a[n][m]

En array unidimensional: double *b[n*m]

Fila i columna j:

a[n][m] , b[i*m+j] 

Cuando es submatriz de otra

“ Leading dimension” : posiciones de memoria entre dos elementos consecutivos de la misma columna

c m

nn ld

(3)

Almacenamiento de matrices dispersas

Muchas maneras distintas

Tres arrays:

datos[0,..,d-1], filas[0,..,d-1], columnas[0,..,d-1]

datos (1,3,2,4), filas (0,1,2,2), columnas (2,0,1,3)

Tres arrays:

datos[0,..,d-1], columnas[0,..,d-1], comienzo fila[0,..,n-1]

datos (1,3,2,4), columnas (2,0,1,3), com. filas (0,1,2,-1)

    0    1    2    3 0      1 1  3   

2        2      4 3

(4)

Operaciones básicas con vectores

void escalar_vector(double d,double *v,int n) {

int i;

for(i=0;i<n;i++) v[i]*=d;

}

n flops (operaciones en coma flotante)

En algoritmos numéricos se estudia el número de flops.

En el estudio experimental los flops (Mflops, Gflops) por segundo.

(5)

Operaciones básicas con vectores

double sumar_vector(double *v,int n) {

int i;

double s=0.;

for(i=0;i<n;i++) s+=v[i];

return s;

}

n flops

(6)

Operaciones básicas con vectores

void sumar_vectores(double *v1,double *v2, double *vr,int n)

{

int i;

for(i=0;i<n;i++) vr[i]=v1[i]+v2[i];

}

n flops

(7)

Operaciones básicas con vectores

double producto_escalar(double *v1,double *v2,int n) {

int i;

double p=0.;

for(i=0;i<n;i++) p+=v1[i]*v2[i];

return p;

}

2n flops

(8)

Operaciones básicas con matrices

void escalar_matriz(double d,double **a,int n,int m) {

int i,j;

for(i=0;i<n;i++) for(j=0;j<m;j++) (a[i][j])*=d;

}

nm ,  n2 flops

(9)

Operaciones básicas con matrices

Uso de “ stride” de un vector

void producto_escalar_stride(double *v1,int str1,

double *v2,int str2,int n) {

int i;

double p=0.;

for(i=0;i<n;i++)

p+=v1[i*str1]*v2[i*str2];

return p;

}

2n flops

(10)

Operaciones básicas con matrices

void sumar_matrices(double *a,int fa,int ca,int lda, double *b,int fb,int cb,int ldb, double *c,int fc,int cc,int ldc) {

int i,j;

for(i=0;i<fa;i++) for(j=0;j<ca;j++)

c[i*ldc+j]=a[i*lda+j]+b[i*ldb+j];

n2 flops

(11)

Operaciones básicas con matrices

void matriz_vector(double *m,int fm,int cm,int ldm,

double *v,int fv,int strv,double *r,int fr,int strr) { int i,j;

double s;

for(i=0;i<fm;i++) { s=0.;

for(j=0;j<cm;j++)

s+=m[i*ldm+j]*v[j*strv];

r[i*strr]=s;

} }

2n flops 2n2 flops

(12)

Operaciones básicas con matrices

void matriz_vector_pe(double *m,int fm,int cm,int ldm,double *v,int fv,int strv,double *r,int fr,int strr) {

int i,j;

double s;

for(i=0;i<fm;i++)

r[i*strr]=producto_escalar_stride(&m[i*ldm],1,v,1,cm);

}

2n flops 2n2 flops

(13)

Operaciones básicas con matrices

void trasponer_matriz(double *m,int n,int ld) {

int i,j;

double t;

for(i=0;i<n;i++)

for(j=i+1;j<n;j++) { t=m[i*ld+j];

m[i*ld+j]=m[j*ld+i];

m[j*ld+i]=t;

} }

3(n­i) asignaciones 3n(n+1)/2 asignaciones

(14)

Multiplicación de matrices

i i

j j

k k

(15)

Multiplicación de matrices

void matriz_matriz(double **a,int fa,int ca,double **b, int fb,int cb,double **c,int fc,int cc)

{ int i,j,k; double s;

for(i=0;i<fa;i++) { for(j=0;j<cb;j++) { s=0.;

for(k=0;k<ca;k++) { s+=a[i][k]*b[k][j];

}

c[i][j]=s;

} } }

2n flops 2n2 flops

2n3 flops

(16)

Multiplicación de matrices

void matriz_matriz_ld(double *a,int fa,int ca,int lda,

double *b,int fb,int cb,int ldb,double *c,int fc,int cc,int ldc) { int i,j,k;

double s;

for(i=0;i<fa;i++) { for(j=0;j<cb;j++) { s=0.;

for(k=0;k<ca;k++)

s+=a[i*lda+k]*b[k*ldb+j];

c[i*ldc+j]=s;

2n flops 2n2 flops

2n3 flops

(17)

Multiplicación de matrices

void matriz_matriz_tras(double *a,int fa,int ca,int lda,

double *b,int fb,int cb,int ldb,double *c,int fc,int cc,int ldc) { int i,j,k; double s; double *bt,*da,*db;

bt=(double *) malloc(sizeof(double)*cb*fb);

trasponer_matriz_esp(b,fb,cb,ldb,bt,cb,fb,fb);

for(i=0;i<fa;i++) { for(j=0;j<cb;j++) {

s=0.; da=&a[i*lda]; db=&bt[j*fb];

for(k=0;k<ca;k++,da++,db++) s+=da[0]*db[0];

c[i*ldc+j]=s;

} } free(bt); }

2n flops 2n2 flops

2n3 flops

(18)

Multiplicación de matrices

void matriz_matriz_pe(double *a,int fa,int ca,int lda,

double *b,int fb,int cb,int ldb,double *c,int fc,int cc,int ldc) {

int i,j;

for(i=0;i<fa;i++) for(j=0;j<cb;j++)

c[i*ldc+j]=producto_escalar_stride(&a[i*lda],1,

&b[j],ldb,ca);

2n flops 2n2 flops

2n3 flops

(19)

Multiplicación de matrices

void matriz_matriz_mv(double *a,int fa,int ca,int lda,double

*b,int fb,int cb,int ldb,double *c,int fc,int cc,int ldc) {

int i;

for(i=0;i<cb;i++)

matriz_vector_pe(a,fa,ca,lda,&b[i],fb,ldb,&c[i],fc,ldc);

}

2n2 flops 2n3 flops

(20)

Multiplicación de matrices

en mi portátil

:

Método\tamaño 1000 1200 1400

bidimensional 12.26 20.15 32.37

leading dimension12.70 21.95 36.41

leading+punteros 12.29 22.84 34.90

traspuesta 12.71 20.88 36.29

producto escalar 12.92 21.75 35.17

matriz-vector 12.19 21.47 36.92

(21)

Multiplicación de matrices

en SUN Ultra 1

:

Método\tamaño 200 400 800

Normal 0.2179 13.4601 217.5464

Traspuesta 0.2013 3.3653 27.9945

Bloques 10 0.2880 2.5901 21.9029

25 0.2192 1.8347 14.9642

50 0.2161 1.7709 14.2502

Bloq tras 10 0.2937 2.5026 20.4405

25 0.2195 1.8009 14.6415

50 0.2152 1.7628 14.1806

Almac blo 10 0.2949 2.5122 20.3762

25 0.2277 1.8490 14.8625

50 0.2296 1.8429 14.7314

Bl tr al bl 10 0.2925 2.4985 20.1975

25 0.2244 1.8082 14.5282

50 0.2231 1.7147 13.6553

Bloq dob 20 5 0.6105 4.9363 39.9594

20 10 0.3206 2.6669 19.7044

50 10 0.3039 2.4542 19.7044

50 25 0.2370 1.9221 15.5190

(22)

Multiplicación de matrices

en kefren, pentium 4

:

Método\tamaño 200 400 800

Normal 0.0463 0.7854 7.9686

Traspuesta 0.0231 0.2875 2.3190

Bloques 10 0.0255 0.2493 2.0327

25 0.0265 0.2033 1.6928

50 0.0219 0.1785 1.6594

Bloq dob 20 5 0.0393 0.3669 3.4955

20 10 0.0269 0.3090 2.4424

50 10 0.0316 0.2232 2.2768

50 25 0.0215 0.1755 1.4726

Blas 1 0.0536 0.8190 8.2311

Blas 2 0.0501 0.5861 5.9997

(23)

Factorización LU

Uii=1

Paso 1: L00 U00=A00  L00 =A00 Paso 2: L00 U0i=A0i  U0i =A0i/L00 Li0 =Ai0

Paso 3: Aij =Li0 U0j +...  A’ ij =Aij -Li0 U0j

(24)

Factorización LU

Uii=1

Paso 1: Lii Uii=Aii  Lii =Aii Paso 2: Lii Uij=Aij  Uij =Aij/Lii Lji =Aji

Paso 3: A =L U +...  A’ =A -L U

i

i

L

U

(25)

Factorización LU

void lu(double *a,int fa,int ca,int lda) { int i,j,k;

for(i=0;i<fa;i++) {

for(j=i+1;j<ca;j++) //Paso 2 a[i*lda+j]/=a[i*lda+i];

for(j=i+1;j<fa;j++) //Paso 3 for(k=i+1;k<ca;k++)

a[j*lda+k]-=a[j*lda+i]*a[i*lda+k];

} }

(26)

Factorización LU

Para resolver sistema Ax=b

   En la forma: LUx=b

   Resolver: Ly=b (Sistema triangular  inferior: sustitución progresiva)

Seguido de: Ux=y (Sistema triangular 

superior: sustitución regresiva)

(27)

Operaciones con matrices dispersas

Producto matriz-vector

Por cada elemento de la matriz

Buscamos si hay elemento de la misma columna en el vector y acumulamos sobre la suma

correspondiente a su fila

datos       3 1 2 4 fila      0 1 2 2 columna  2 0 2 3

datos 1 3 fila    0 2

resultado datos 9 1 6 fila    0 1 2

(28)

Operaciones con matrices dispersas

void matriz_vector_disperso(double *dm,int *fm,int *cm, int ndm,double *dv,int *fv,int ndv,double *dr,int *fr,int ndr) { int i,j,fact; double s;

for(i=0;i<ndr;i++) fr[i]=i;

i=0;

while(i<ndm) { fact=fm[i]; j=0; s=0.;

while(i<ndm && fm[i]==fact) { while(j<ndv && fv[j]<cm[i]) j++;

if(j<ndv && fv[j]==cm[i]) s+=dm[i]*dv[j];

dr[fact]=s; i++;

(29)

Trabajo por bloques

En las operaciones anteriores los costes son:

Vector­vector

Matriz­vector

Matriz­matriz 

Desarrollando algoritmos con operaciones matriz­matriz,  para el mismo número de operaciones aritméticas menos  accesos a memoria ⇒ menor tiempo de ejecución

Especialmente adecuado para jerarquías de memoria  amplias (Memoria Compartida)

Usado en el desarrollo de librerías desde los 80 (LAPACK)

Computacional Memoria

n n

n

2

n

2

n

3

n

2

(30)

Multiplicación de matrices

en mi portátil

:

Método\tamaño 1000 1200 1400

normal 12.70 21.95 36.41

bloques  25 3.69 6.30 9.25

50 3.56 5.90 8.71

100 4.25 6.33 8.95

bloques 25 5  4.67 7.87 10.89

dobles 50 10  5.03 8.08 12.93

50 25 4.53 7.16 11.11

100 20 4.87 7.33 10.97

100 25 4.78 7.06 9.92

Reducción 76%

(31)

Trabajo por bloques

Multiplicación de matrices, en SUN Ultra 1

:

Método\tamaño 200 400 800

Normal 0.2179 13.4601 217.5464

Traspuesta 0.2013 3.3653 27.9945

Bloques  10 0.2880 2.5901 21.9029

25 0.2192 1.8347 14.9642

50 0.2161 1.7709 14.2502

Bloq tras 10 0.2937 2.5026 20.4405

25 0.2195 1.8009 14.6415

50 0.2152 1.7628 14.1806

Almac blo 10 0.2949 2.5122 20.3762

25 0.2277 1.8490 14.8625

50 0.2296 1.8429 14.7314

Bl tr al bl 10 0.2925 2.4985 20.1975

25 0.2244 1.8082 14.5282

50 0.2231 1.7147 13.6553

Bloq dob 20  5 0.6105 4.9363 39.9594

20 10 0.3206 2.6669 19.7044

50 10 0.3039 2.4542 19.7044

50 25 0.2370 1.9221 15.5190

Reducción 93%

(32)

Trabajo por bloques

Multiplicación de matrices, en kefren, pentium 4

:

Método\tamaño 200 400 800

Normal 0.0463 0.7854 7.9686

Traspuesta 0.0231 0.2875 2.3190

Bloques  10 0.0255 0.2493 2.0327

25 0.0265 0.2033 1.6928

50 0.0219 0.1785 1.6594

Bloq dob 20  5  0.0393 0.3669 3.4955

20 10 0.0269 0.3090 2.4424

50 10 0.0316 0.2232 2.2768

50 25 0.0215 0.1755 1.4726

Reducción 79%

(33)

Trabajo por bloques

La reducción varía de un sistema a otro 

¿Cómo se sabe el tamaño de bloque óptimo? Varía con:

Sistema

Tamaño del problema

Con lo que el método preferido también varía con el tamaño y  el sistema

Se pueden hacer otras combinaciones que en algunos casos 

dan mejores resultados. Pero difícil determinar mejor método 

y parámetros

(34)

Multiplicación de matrices

A

i k

tb B

k

tb j C

i

tb j

s

(35)

Multiplicación de matrices

void matriz_matriz_ld(double *a,int fa,int ca,int lda,

double *b,int fb,int cb,int ldb,double *c,int fc,int cc,int ldc) { int i,j,k;

  double s;

  for(i=0;i<fa;i++) {     for(j=0;j<cb;j++) {       s=0.;

      for(k=0;k<ca;k++)

        s+=a[i*lda+k]*b[k*ldb+j];

      c[i*ldc+j]=s;

    }  }  }

Algoritmo sin bloques (normal).

Acceso elemento a elemento.

Problemas pequeños buenas prestaciones pues caben en memoria de niveles bajos de la jerarquía.

Problemas grandes peores prestaciones.

(36)

Multiplicación de matrices

void matriz_matriz_bloques(double *a,int fa,int ca,int lda,double *b,int fb, int cb,int ldb,double *c,int fc,int cc,int ldc,int tb)

{    int i,j,k;  double *s;

   s=(double *) malloc(sizeof(double)* tb * tb); 

   for(i=0;i<fa;i=i+ tb)       for(j=0;j<cb;j=j+ tb) {        ceros(s, tb, tb, tb);

       for(k=0;k<ca;k=k+ tb)

  multsumar(&a[i*lda+k], tb, tb,lda,&b[k*ldb+j], tb, tb,ldb,s, tb, tb, tb);

       copiar(s, tb, tb, tb,&c[i*ldc+j], tb, tb,ldc);

   }   free(s);

Algoritmo por bloques.

Acceso y operaciones por bloques.

Buenas prestaciones

independiente del tamaño.

El tamaño de bloque es parámetro a determinar.

(37)

Algoritmos y Programación Paralela 37

Multiplicación de matrices

void matriz_matriz_bloquesdobles(double *a,int fa,int ca,int lda,double *b, int fb,int cb,int ldb,double *c,int fc,int cc,int ldc,int tb,int tbp)

{    int i,j,k; double *s;

   s=(double *) malloc(sizeof(double)* tb * tb);

   for(i=0;i<fa;i=i+ tb)       for(j=0;j<cb;j=j+ tb) {        ceros(s, tb, tb, tb);

       for(k=0;k<ca;k=k+ tb) 

multsumarbloques(&a[i*lda+k], tb, tb,lda,&b[k*ldb+j], tb, tb,ldb, s, tb, tb, tb, tbp);

       copiar(s, tb, tb, tb,&c[i*ldc+j], tb, tb,ldc);

     }

   free(s);

Algoritmo por bloques dobles.

La operación sobre bloques no es la multiplicación

directa, sino por bloques.

Tenemos dos tamaños de bloque.

(38)

Multiplicación de matrices

Almacenamiento por bloques:

matriz

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

almacenamiento 0 1 4 5 2 3 6 7 8 9 12 13 10 11 14 15

posible acceso más rápido a los datos dentro de las operaciones por bloques

(39)

Factorización LU

      

Cada Aij, Lij, Uij  de tamaño b×b

Paso 1: L00 U00=A00  Factorización sin bloques

Paso 2: L00 U01=A01  Sistema múltiple triangular inferior (¿bloques?) Paso 3: L10 U00=A10  Sistema múltiple triangular superior (¿bloques?) Paso 4: A11 =L10 U01 + L11 U11  A’ 11 =A11 ­ L10 U01 , por bloques

y seguir trabajando con el nuevo valor de A11

(40)

Factorización LU

void lu_bloques(double *a,int fa,int ca,int lda,int tb) {int i,j,k,f,c;

  for(i=0;i<fa;i=i+tb)  {

    f=(tb<fa­i ? tb : fa­i);    c=(tb<ca­i ? tb : ca­i);

    lu(&a[i*lda+i],f,c,lda);

    if(i+tb<fa)    {

      sistema_triangular_inferior(&a[i*lda+i],f,c,lda,&a[i*lda+i+c],f,ca­i­c,lda);    

 sistema_triangular_superior(&a[i*lda+i],f,c,lda,&a[(i+f)*lda+i],fa­i­f,c,lda);

      multiplicar_restar_matrices(&a[(i+f)*lda+i],fa­i­f,c,lda,

        &a[i*lda+i+f],f,ca­i­c,lda,&a[(i+f)*lda+i+c],fa­i­f,ca­i­c,lda);

    } } }

(41)

Factorización LU

en mi portátil

:

tamaño bloque\matriz 800 1000

1 2.10 4.01

12 1.42 2.78

25 1.29 2.27

37 1.24 2.37

44 1.20 2.00

50 1.22 2.32

100 1.47 2.24

200 2.29 3.47

400 2.17 3.67

sin bloques  1.73 3.43

Referencias

Documento similar

La primera opción como algoritmo de compresión para secuencias biológicas que sugirió la directora del proyecto fue la adaptación de los algoritmos de Lempel-Ziv al alfabeto formado

En esta sección se tratan las características que debe tener un compresor de secuencias biológicas para poder ser usado como herramienta en la construcción de los árboles de

En [3], Cáceres- Duque da un procedimiento efectivo para encontrar la base mínima de un ideal de Z[x], el cual es el procedimiento efectivo al que nos referimos en el Teorema 2,

Con el objeto de describir la forma general de los cambios estructurales que tienen lugar en un sistema reactivo es necesario resolver la ecuación de Schrodinger independiente

En la vida cotidiana, se emplean algoritmos frecuentemente para resolver problemas. En términos de programación, un algoritmo es una secuencia de pasos lógicos que permiten

En la tabla 6.4 se muestran los valores correspondientes a las tensiones de Von Mises máxima, media y mínima, el desplazamiento máximo, la fracción de volumen, la compliance,

Por lo anterior se considera que el desarrollo de un Sistema de Gestión de la Calidad es de vital importancia para MEDDEX, el cual tiene como finalidad

41 Esta función inicializa las variables necesarias para resolver el problema de estimación mediante algoritmos genéticos, crea los ficheros vacios donde se almacenarán todos