320 likes | 537 Views
Las matemáticas como medio para medir la eficiencia de los Algoritmos Computacionales. ¿Qué es un algoritmo?. “(del árabe al-Khowârizmî, sobrenombre del célebre matemático árabe Mohámed ben Musa). Conjunto ordenado y finito de operaciones que permite encontrar la solución a un problema…”
E N D
Las matemáticas como medio para medir la eficiencia de los Algoritmos Computacionales
¿Qué es un algoritmo? • “(del árabe al-Khowârizmî, sobrenombre del célebre matemático árabe Mohámed ben Musa). Conjunto ordenado y finito de operaciones que permite encontrar la solución a un problema…” • Un algoritmo, puede expresarse en términos de un lenguaje de programación, para obtener un programa que resuelve el problema por medio de la computadora.
Cita... • “No hay un incremento concebible en el poder de las computadoras que pueda saturar la demanda científica: aún pensando que una computadora posea un ciclo de tiempo subnuclear (10-23 seg.) y densidades de almacenamiento subnucleares (1039 bits/cm3), ésta no podría manejar la mayoría de los problemas que son importantes en la investigación científica básica y aplicada. Por lo tanto, existirá siempre una fuerte presión para incrementar la eficiencia de los programas, para poder incrementar también la cantidad de información últil generada por un programa.” Ken Wilson, Nóbel de Física 1982
Áreas de estudio • ¿Cómo construir algoritmos? • Técnicas de diseño • ¿Cómo expresar algoritmos? • Enfoques de los lenguajes de programación • ¿Cómo validar algoritmos? • Verificación formal • ¿Cómo analizar algoritmos? • Complejidad computacional, eficiencia, legibilidad, usabilidad, etc...
Análisis de algoritmos • Si se tuvieran 2 programas que hacen lo mismo, ¿cómo se podrían comparar? 1. Eficiencia: • Tiempo de ejecución • Uso de espacios de memoria 2. Facilidad de lectura, mantenimiento, rapidez para codificarlo.
Medición del tiempo de ejecución • El tiempo de ejecución depende de: 1. La entrada al programa: Su tamaño Sus características 2. La calidad del código generado para el programa por el compilador . 3. La rapidez de las instrucciones de máquina. 4. La complejidad de tiempo del algoritmo.
¿Cómo medir? • Cantidad de instrucciones básicas (o elementales) que se ejecutan. • Ejemplos de instrucciones básicas: • asignación de escalares • lectura o escritura de escalares • saltos (goto’s) implícitos o explícitos. • evaluación de condiciones • llamada a funciones • etc.
Ejemplo cont = 1; while (cont <= n) do { x = x + a[cont]; x = x + b[cont]; cont = cont + 1; } • 1 • n+1 • n • n • n • n (goto implícito) • 1 goto en falso. TOTAL: 5n + 3
Ejemplo • 1 • 1 asignación + (n+1) comparaciones • (n+2)*n = n2 +2n • n*n = n2 • 2n2 (incremento+ goto implícito) • n (goto en falso for y) • 2n (incremento+ goto implícito) • 1 (goto en falso for x) • TOTAL: 4n2 + 6n + 4 z = 0; for (int x=1; x<=n; x++) for (int y=1; y<=n; y++) z = z + a[x,y];
Consecuencia… • Se requiere contar con una notación que permita comparar la eficiencia entre los algoritmos… • La NOTACIÓN ASINTÓTICA es la propuesta de notación aceptada por la comunidad científica para describir el comportamiento en eficiencia (o complejidad) de un algoritmo. • Describe en forma sintética el comportamiento de la función que con la variable de entrada, determina el número de operaciones que realiza el algoritmo.
NOTACIÓN ASINTÓTICA • COMPLEJIDAD TEMPORAL (y ESPACIAL). Tiempo (o espacio) requerido por un algoritmo, expresado en base a una función que depende del tamaño del problema. • COMPLEJIDAD TEMPORAL ASINTÓTICA (y ESPACIAL). Comportamiento límite conforme el tamaño del problema se incrementa. Determina el tamaño del problema que puede ser resuelto por un algoritmo.
Definición • Se dice que la función f(n) “es de orden g(n)” [O(g(n))], si existen constantes positivas c y n0tales que f(n) <= c g(n) cuando n >= n0 • Ejemplos: • n+5 es O(n) pues n+5 <= 2n para toda n >= 5 • (n+1)2 es O(n2) pues (n+1)2 <= 4n2 para n>= 1 • (n+1)2NO es O(n) pues para cualquier c > 1 no se cumple que (n+1)2 <= c*n
Ordenes más comunes de los algoritmos • O(1) Constante • O(n) Lineal • O(n2 ) Cuadrático • O(n3 ) Cúbico • O (nm ) Polinomial • O(log(n)) Logarítmico • O(nlog(n)) nlog (n) • O(mn ) exponencial • O(n!) factorial
Comportamiento de las funciones n2 n sqrt(n) n log n n log n
Otro método para calcular el orden de un problema • Consiste en aplicar reglas a los estatutos estructurados: • Secuencia de instrucciones • Decisiones (ejemplo: if) • Ciclos (ejemplo: while) • Recursividad
Regla 1: Secuencia de instrucciones Ejemplo: • Una secuencia de 3 ciclos: • Ciclo 1 = O(n) • Ciclo 2 = O(log n) • Ciclo 3 = O(n2) • Tendrá como orden total… • O(n2). O(g1(n)) ≈ O( mayor(g1(n), g2(n), …, gm(n) ) O(g2(n)) O(g3(n)) O(gm(n))
Regla 2: Decisiones Ejemplo: • Una decisión con: • Rama then = O(n log n) • Rama else = O(log n) • Tendrá como orden total… • O(n log n). ≈ O( mayor(g1(n), g2(n)) ) O(g1(n)) O(g2(n))
Regla 3: Ciclos Ejemplo: • Un ciclo cuya instrucción: • Tiene un O(log n) • Se repite n/2 veces • Tendrá como orden total… • O(½ n log n) = O(n log n). ≈ O( m * g(n) ) O(g(n)) Se repite m veces
Consideraciones especiales • En decisiones y ciclos anidados: • Analizar el código desde la instrucción más interna hacia el más externa. • Tip para los ciclos: • ¿“Normalmente” cuál es el orden de la instrucción interna? • Si la variable de control se incrementa o decrementa con un valor constante: Orden LINEAL. • Si la variable de control se multiplica o divide por un valor constante: Orden LOGARÍTIMICO.
Ejemplo: Sort por intercambio for (int i=1; i<n; i++) for (int j=i+1; j<=n;j++) if (a[ j ] < a[ i ]) intercambia(a[ i ], a[ j ]); → O( ) 1 → O( ) 1 Regla 2: Decisiones = mayor de las 2 ramas
Ejemplo: Sort por intercambio for (int i=1; i<n; i++) for (int j=i+1; j<=n;j++) if (a[ j ] < a[ i ]) intercambia(a[ i ], a[ j ]); Peor caso: se repite n-1 veces → O( ) n → O( ) 1 Regla 3: Ciclos = # veces * orden de la instrucción interna
Ejemplo: Sort por intercambio for (int i=1; i<n; i++) for (int j=i+1; j<=n;j++) if (a[ j ] < a[ i ]) intercambia(a[ i ], a[ j ]); Se repite n-1 veces → O( ) n2 → O( ) n Regla 3: Ciclos = # veces * orden de la instrucción interna
Ejemplo: Multiplicación de matrices a11 a12 … a1n a21 a22 … a2n … … … … am1 am2 … amn b11 b12 … b1m b21 b22 … b2m … … … … bn1 bn2 … bnm X = c11 c12 … c1m c21 c22 … c2m … … … … cm1 cm2 … cmm c11 = a11*b11+a12 *b21 +…+ a1n *bn1 c12 = a11*b12+a12 *b22 +…+ a1n *bn2 … c21 = a21*b11+a22 *b21 +…+ a2n *bn1 … cmm = am1*b1m+am2 *b2m +…+ amn *bnm n cij = aikbkj k=1
Ejemplo: Multiplicación de matrices for i = 1 to n do for j = 1 to n do C[i,j] = 0; for k = 1 to n do C[i,j] = C[i,j] + A[i,k]*B[k,j]; O( n3 ) ← O( n2 ) ← O( 1 ) ← O( n ) ← O( 1 ) ←
Regla 4: Recursividad • La complejidad de tiempo se obtiene contando la cantidad de veces que se hace la llamada recursiva. • Casos que “normalmente” se dan: • Orden LINEAL si sólo se tiene una llamada recursiva, con incrementos o decrementos en el parámetro de control. • Orden LOGARITMICO si sólo se tiene una llamada recursiva, con multiplicaciones o divisiones en el parámetro de control. • Si hay más de una llamada recursiva, el orden puede tender a ser EXPONENCIAL.
Ejemplo: Fibonacci (Iterativo) ant = 1; --> 1 act = 1; --> 1 while (n>2){--> n-2 + 1 aux = ant + act; --> n-2 ant = act; --> n-2 act = aux; --> n-2 n = n - 1; --> n-2 } --> n-2+1 write (act); --> 1 T(n) = 6n-7 Por lo tanto el orden del algoritmo esO(n)
Ejemplo: Fibonacci (recursivo) Function fibonacci (n:int): int; if (n < 3) return 1; else return fibonacci(n-1) + fibonacci(n-2); • ¿Cómo obtener la complejidad de tiempo del algoritmo? • Cantidad de llamadas recursivas: 2 en cada llamada. • Algoritmo de orden: O(2n/2)
f(5) f(3) f(4) f(1) f(2) f(2) f(3) f(1) f(2) Análisis de Fibonacci (recursivo) ¿Cuántos términos se requieren para calcular: f(5)? f(4)? f(3)? f(2)? f(6)? --> 9 --> 5 --> 3 --> 1 --> 15 Relación: El término T(n) requiere T(n-1)+T(n-2)+1 términos para calcularse.
n/2 veces Análisis de Fibonacci • Si el término T(n) requiere T(n-1)+T(n-2)+1 términos para calcularse… • se puede decir que T(n) > 2 * T(n-2)… • y por lo tanto: T(n) > 2 * 2 * T(n-4) … • y T(n) > 2 * 2 * 2 * T(n-6)… • y así sucesivamente hasta: T(n) > 2 * 2 * 2 * …. * 2 * T(1) Por lo tanto: T(n) > 2n/2 y podemos decir que el orden del algoritmo es O(2n/2)