Вы находитесь на странице: 1из 133

Curso de C alculo Numerico

Juan Jose Gomez Cadenas


Jordi Burguet Castell
Departamento de Fsica At omica Molecular y Nuclear
Facultat de F

sicas
Universidad de Valencia
Curso 2004-2005

Indice general
1. Introduccion al Curso de C alculo Numerico 5
1.1. Objetivos del curso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2. Python no es el nombre de un reptil . . . . . . . . . . . . . . . . . . . . . . . 6
1.3. Organizaci on del curso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.4. Materiales asociados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2. El lenguaje de programaci on Python 9
2.1. El interprete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.2. Programas en Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.2.1. Desde el punto de vista del programador . . . . . . . . . . . . . . . . . 10
2.2.2. Desdel el punto de vista del programa . . . . . . . . . . . . . . . . . . 10
2.3. Velocidad de ejecuci on . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.4. Pero, por que no programar directamente en FORTRAN C o C++? . . . . 11
3. Datos, variables, operadores y sentencias 13
3.1. Python como calculadora . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.2. Datos y variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.3. Nombres de variables y nombres reservados . . . . . . . . . . . . . . . . . . . 16
3.4. Operadores y expresiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.5. Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
4. Principales tipos en Python 19
4.1. Introducci on . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
4.2. N umeros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
4.3. Cadenas literales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.4. Listas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
4.5. Tuplas y Secuencias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
4.6. Diccionarios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
4.7. Ficheros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
4.8. Resumen: Tipos en Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
3
4

INDICE GENERAL
5. Control del ujo en Python 33
5.1. Control del ujo en un programa Python . . . . . . . . . . . . . . . . . . . . 33
5.2. Bucle while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
5.3. La sentencia if . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
5.4. La sentencia for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
5.5. La funci on range() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
5.6. Sentencias break y continue . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
5.7. Cla usula else en bucles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
5.8. Sentencia pass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
5.9. Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
6. Rudimentos de programacion en Python 39
6.1. Ficheros ejecutables en Python . . . . . . . . . . . . . . . . . . . . . . . . . . 39
6.2. La serie de Fibonacci . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
6.3. N umeros primos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
6.4. Algoritmo de Newton para el calculo de races cuadradas . . . . . . . . . . . . 42
6.5. Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
7. Funciones y modulos 45
7.1. Funciones en Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
7.2. Resumen: Codicaci on de funciones . . . . . . . . . . . . . . . . . . . . . . . . 52
7.3. Funciones de tipo lambda . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
7.4. Mapas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
7.5. Programaci on funcional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
7.6. Operaciones de comprensi on en listas . . . . . . . . . . . . . . . . . . . . . 54
7.7. M odulos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
7.7.1. Localizacion de m odulos en Python . . . . . . . . . . . . . . . . . . . . 55
7.8. M odulos Est andar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
7.9. La funci on dir() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
8. Vectores, matrices y arreglos numericos en Python 57
8.1. Numerical Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
8.2. Objetos de tipo array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
8.3. Manejo de arreglos numericos . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
8.3.1. Creacion de un arreglo . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
8.3.2. Arreglos multidimensionales . . . . . . . . . . . . . . . . . . . . . . . . 59
8.3.3. Creacion de arreglos cuyos elementos se especican al vuelo . . . . . . 60
8.3.4. Acceso a los elementos de un arreglo . . . . . . . . . . . . . . . . . . . 61
8.3.5. Cortes sobre un arreglo . . . . . . . . . . . . . . . . . . . . . . . . . . 63

INDICE GENERAL 5
8.3.6. Operaciones sobre un arreglo . . . . . . . . . . . . . . . . . . . . . . . 63
8.3.7. Funciones que operan sobre arreglos numericos . . . . . . . . . . . . . 65
8.3.8. Funciones que manipulan arreglos . . . . . . . . . . . . . . . . . . . . 66
8.3.9. El modulo de

Algebra Lineal . . . . . . . . . . . . . . . . . . . . . . . 68
9. Representacion gr aca de funciones 71
9.1. Representacion gr aca de funciones . . . . . . . . . . . . . . . . . . . . . . . . 71
9.2. El programa gr aco gnuplot . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
9.2.1. Expresiones en gnuplot . . . . . . . . . . . . . . . . . . . . . . . . . . 73
9.2.2. Funciones en gnuplot . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
9.2.3. Operadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
9.2.4. Representacion gr aca de funciones . . . . . . . . . . . . . . . . . . . . 75
9.2.5. El comando plot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
9.2.6. El comando splot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
9.3. Uso del m odulo Gnuplot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
9.4. Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
10.Series de Taylor 89
10.1. Expansi on de Taylor de una funci on entorno a un punto . . . . . . . . . . . . 89
10.2. Teorema del valor medio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
10.3. Teorema de Taylor en terminos de h . . . . . . . . . . . . . . . . . . . . . . . 91
10.4. Teorema de las series alternas . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
11.Solucion de ecuaciones no lineales 95
11.1. Introducci on . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
11.2. Metodo de Biseccion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
11.3. Regula falsi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
11.4. Newton-Raphson . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
11.5. Programaci on de algoritmos de b usqueda de races . . . . . . . . . . . . . . . 101
11.5.1. Metodo de Biseccion . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
11.5.2. Metodo de Regula Falsi . . . . . . . . . . . . . . . . . . . . . . . . . . 108
11.5.3. Metodo de Newton Rapson . . . . . . . . . . . . . . . . . . . . . . . . 109
11.5.4. El modulo raices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
11.6. Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
12.Sistemas de ecuaciones lineales 113
12.1. Introducci on . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
12.2. Sistemas lineales faciles de resolver . . . . . . . . . . . . . . . . . . . . . . . . 114
12.3. Factorizaci on LU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
6

INDICE GENERAL
12.4. Factorizaci on de Doolittle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
12.5. Permutaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
12.6. Calculo de la matriz inversa . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
12.7. Determinante de una matriz . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
12.8. Programaci on del algoritmo de descomposicion LU . . . . . . . . . . . . . . . 121
12.8.1. El modulo lu.py . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
12.8.2. Matrices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
12.8.3. Descomposicion LU sin permutaciones . . . . . . . . . . . . . . . . . . 123
12.8.4. Descomposicion LU al estilo GSL . . . . . . . . . . . . . . . . . . . . . 124
12.8.5. Ejemplo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
12.9. Soluci on de sistemas lineales de ecuaciones . . . . . . . . . . . . . . . . . . . . 129
12.9.1. Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
Captulo 1
Introducci on al Curso de Calculo
Numerico
1.1. Objetivos del curso
Los objetivos de este curso de calculo numerico son los siguientes:
1. El estudio de una serie de algoritmos numericos basicos, de gran importancia a la
hora de resolver problemas aplicados en ciencia e ingeniera. Entre ellos, la resoluci on
de ecuaciones no lineales, sistemas de ecuaciones lineales, aproximaci on de funciones,
derivaci on e integracion numerica, tratamiento de datos experimentales y solucion de
ecuaciones diferenciales.
2. La implementacion de dichos algoritmos en un lenguaje de programaci on moderno,
potente y generico que permite una implementacion natural e intuitiva de los algoritmos
matematicos bajo estudio.
3. El estudio de aplicaciones pr acticas de los algoritmos numericos. En este caso, el alumno
se enfrenta al problema desde el punto de vista del usuario el cientco o ingeniero que
debe aprender a usar una determinada biblioteca matem atica para resolver un problema
especco.
En resumen. Se pretende ense nar a pensar en esta particular rama de las matem aticas
aplicadas que es el calculo numerico y al mismo tiempo proporcionar los rudimentos de
programaci on sucientes para que el alumno sea capaz por una parte de codicar sus propios
algoritmos y por otra de utilizar la biblioteca que acompa na al curso para la resoluci on
pr actica de problemas.
La herramienta de programaci on que hemos escogido es uno de los lenguajes mas modernos
y versatiles de la actualidad, llamado Python.
7
1.2. Python no es el nombre de un reptil
Python [1] es un moderno lenguaje de programaci on (fue inventado en 1989 por Guido
Van Rossum) entre cuyas cualidades se cuentan las siguientes:
Sintaxis elegante y muy escueta.
Tipos de alto nivel (incluye contenedores de objetos heterogeneos).
Asignacion din amica de tipos.
Amplia biblioteca de herramientas matem aticas y de manejo del sistema operativo.
Modelo sencillo pero muy potente de programaci on orientada a objeto.
Un robusto sistema de control de errores.
Es f acilmente extensible (es decir pueden denirse nuevos tipos y ampliar su funcional-
idad) utilizando lenguajes compilados como C o C++.
Estas caractersticas, junto a su naturaleza interpretada, portabilidad y excelente docu-
mentacion, lo convierten en un lenguaje muy apropiado para numerosas aplicaciones,entre
ellas: desarrollo de herramientas de internet, test de dispositivos y adquisici on de datos, ani-
macion, gr acos,juegos y un largo etc.
M as recientemente, Python ha comenzado a utilizarse en aplicaciones cientcas [2, 3].
En lo que se reere a la ense nanza de los metodos numericos, es corriente, en textos
introductorios, recurrir al pseudocodigo es decir una abstraccion m as o menos formal de
los elementos esenciales de todo lenguaje de programacion de alto nivel para expresar los
fundamentos de los algoritmos que se exponen. A menudo, dichos algoritmos se programan
posteriormente en un lenguaje de prop osito general, tal como FORTRAN, C, C++, etc, o bien
utilizando alguna de las numerosas herramientas matematicas disponibles en la actualidad,
tales como Mathematica, Matlab, Mapple, Octave, etc.
Python nos permite expresar los algoritmos numericos de manera tan concisa y sintetica
como si escribieramos pseudocodigo y a la vez tan pr actica como en cualquier lenguaje de
programaci on de alto nivel. De hecho, sus tipos din amicos, contenedores heterogeneos y nat-
uraleza interpretada lo hacen competitivo con los m as avanzados pseudolenguajes asociados
a entornos matematicos especializados tales como Mathematica.
Python es f acil de aprender, muy agradable de usar, funciona en cualquier plataforma y
es gratuito. Pocas herramientas de programaci on pueden competir hoy en da con una oferta
tan extensa y completa.
Python debe su nombre al grupo de c omicos ingleses Monthy Python, autores de pelcu-
las tan conocidas como La vida de Brian o Los caballeros de la Tabla Cuadrada.
1.3. Organizaci on del curso
El curso consta de dos partes bien diferenciadas. La primera introduce el lenguaje de
programaci on. La aproximaci on a la hora de preparar esta introducci on ha sido la de escribir
8
una tutora util para ilustrar los aspectos de Python necesarios para la enes nanza de los
metodos numericos, sin pretender en absoluto cubrir toda su potencialidad.
En la segunda parte del texto se exponen una selecci on de los problemas de c alculo m as
relevantes en aplicaciones cientcas. Soluci on de ecuaciones no lineales, soluci on de sistemas
de ecuaciones, problemas de vectores y valores propios, aproximacion de funciones, derivaci on
e integracion numerica, problemas de maximos y mnimos, tratamiento experimental de datos
y soluci on de ecuaciones diferenciales. En cada tema se aborda en primer lugar la descripci on
de los conceptos matematicos inherentes a los metodos que se describen y a continuaci on se
ilustra la programaci on de dichos metodos. Cada tema se complementa con una coleccion de
ejercicios tanto conceptuales como de programacion.
1.4. Materiales asociados
Tanto el texto de este curso como el codigo fuente de los algoritmos y otros materiales
utiles pueden encontrarse en el sito Web http://evalu29.ic.uv.es/docencia/pynum/index.html.
9
10
Captulo 2
El lenguaje de programaci on
Python
2.1. El interprete
Una de las caractersticas de toda implementacion actual de Python que lo hacen ex-
tremadamente atractivo como herramienta de programaci on es la implementacion asociada
al lenguaje de un paquete de software denominado interprete. Un interprete no es mas que un
programa que ejecuta otros programas. Cuando escribimos un programa Python, el interprete
lo lee y ejecuta las instrucciones que contiene. Estas instrucciones se han traducido previa-
mente a un tipo de c odigo binario denominado bytecode del que hablaremos m as adelante.
Cuando Python se instala en un ordenador, genera una serie de compomentes. Como
mnimo, el interprete y una biblioteca b asica. La manera mas sencilla de utilizar el interprete
es como un programa ejecutable. Dicho programa puede estar escrito, a priori en cualquier
lenguaje de programaci on. En la implementaci on m as extendida de Python en la actualidad
el interprete esta escrito en C.
La instalaci on de Python depende de la plataforma. En este curso asumiremos que la
plataforma de trabajo es un sistema Unix, pero todo el software que utilizaremos funciona
igualmente bien en Windows. Para la instalaci on en Windows de Python y las bibliotecas
matematicas utiles para el curso (Numeric, matplotlib, etc.) recomendamos la instalaci on de
Enthought (http://www.enthought.com). Python viene normalmente instalado en Linux, MacOS
X, etc. Numeric puede bajarse del sitio Web http://numeric.scipy.org/. Gnuplot viene normal-
mente instalado en Linux o puede obtenerse en http://www.gnuplot.info/. Gnuplot.py puede
bajarse del sitio web http://gnuplot-py.sourceforge.net/. Recomendamos tambien el paquete gr a-
co Matplotlib (http://matplotlib.sourceforge.net/installing.html). Finalmente, en el sitio ocial de
Python www.python.org puede encontrarse documentaci on, enlaces y distribuciones para todas
las plataformas del lenguaje propiamente dicho.
11
2.2. Programas en Python
2.2.1. Desde el punto de vista del programador
En su forma m as sencilla un programa Python no es mas que un chero de texto que
contiene una serie de sentencias en Python. Por ejemplo, el siguiente chero brian.py contiene
un sencillo programa en Python:
#
# Primer programa en Python. Imprime un mensaje por la pantalla.
print "Mira siempre el lado bueno de la vida" #famosa frase de la vida de Brian
Aparte de una serie de lneas de comentarios (el smbolo # indica a Python que el resto de
la lnea hasta el caracter de salto de carro es un comentario y puede ser ignorado) el programa
no hace mas que imprimir por la pantalla la celebre frase de la pelcula la vida de Brian,
una de las m as famosas de los Monthy Python.
Para escribir un programa Python, podemos utilizar cualquier editor de texto
1
para
escribir sentencias en un chero, cuya extension es por convenci on .py.
Una vez que el programa ha sido escrito es necesario que el interprete ejecute las sentencias
contenidas en este. En sistemas Unixel interprete suele estar instalado en /usr/bin o en
/usr/local/bin/. Si el correspondiente directorio est a incluido en la lista de ejecutables del
sistema (como suele ser el caso) basta con teclear:
python brian.py
Mira siempre el lado bueno de la vida
Admitdamente, este primer ejemplo no es demasiado complejo, pero al menos el resultado
es optimista.
2.2.2. Desdel el punto de vista del programa
Internamente, cuando invocamos a Python, este comienza por compilar nuestro c odigo
fuente (en este caso las sentencias en el chero brian.py) a un formato denominado bytecode
o codigo byte. La compilacion no es otra cosa que una traducci on desde el lenguaje de alto
nivel que el programador utiliza a una representacion de bajo nivel pero independiente de la
plataforma en la que el programa ejecuta del c odigo fuente. Cada sentencia del programa se
traduce a un grupo de instrucciones en c odigo byte, que se ejecutan mucho m as rapidamente
que el codigo original.
Esta traducci on se escribe en cheros con la extensi on .pyc (python compilado), aunque
estrictamente hablando esto solo ocurre cuando importamos el codigo fuente (hablaremos de
esta operacion m as adelante). En todo caso, el programador no necesita preocuparse por estos
cheros. La siguiente vez que se ejecuta el programa Python comprueba (comparado la rma
temporal de los cheros) si el codigo fuente original se modic o desde la ultima compilaci on
1
recomenadmos sin embargo emacs, algo mas que un editor.http://www.gnu.org/software/emacs/emacs.html
12
o no. En caso negativo, ejecuta el chero .pyc, ganando mucho en velocidad. En otro caso,
recompila el codigo fuente original.
Una vez que el programa ha sido traducido a c odigo byte, es ejecutado por la PVM (Python
Virtual Machine, o maquina virtual de Python) que no es m as que un bucle capaz de iterar
sobre las instrucciones en codigo byte y ejecutar las operaciones especicadas por estas.
Generalmente y por simplicidad, nos referimos simplemente al interprete como el genio
de la l ampara que ejecuta en tiempo real nuestro programa. Como hemos visto, el proceso
completo implica una compilaci on previa seguido por una ejecuci on en la PVM.
2.3. Velocidad de ejecuci on
La diferencia entre Python y otros lenguajes tradicionales como FORTRAN, C o C++
es que, mientras que estos ultimos traducen el codigo fuente a codigo m aquina en el proceso
de compilacion, Python lo traduce a c odigo byte. La ventaja de traducir a c odigo byte es
que este ejecuta igual en cualquier sistema. La desventaje es que el codigo maquina es m as
eciente para el hardware concreto para el que est a dise nado.
En consecuencia, a igualdad de optimizaci on, un programa Python ejecuta m as lento
que un programa escrito en FORTRAN o C, aunque m as rapido que programas escritos en
lenguajes puramente interpretados (como Basic) que no compilan nunca el codigo.
La forma de circunvalar este problema cuando la velocidad de ejecuci on es importante es
escribir una extensi on a Python. En la implementaci on CPython (que es la que usaremos en
este curso) el lenguaje ha sido implementado en C y es posible utilizar su API (Aplication
Interface) para escribir nuevos tipos y funciones en C que puede importarse a Python. Este
es el caso de la extension Numeric que utilizaremos en este curso para manejar vectores y
matrices. Desde el punto de vista del programador de Python, los vectores y matrices de
Numeric aparecen como tipos intrnsecos del lenguaje que no se diferencian en nada de otros
tipos (tales como n umeros enteros, reales, complejos, cadenas literales, etc.). Sin embargo,
estos objetos han sido escritos en C y compilados a codigo maquina. En consecuencia, cuando
el programa Python los utiliza, ejecuta a la velocidad de un lenguaje compilado.
2.4. Pero, por que no programar directamente en FORTRAN
C o C++?
FORTRAN se ha utilizado tradicionalmente para la ense nanza de los metodos numericos
(por ejemplo en [10]). Se trata de un lenguaje sencillo de aprender y muy r apido. Tiene
el inconveniente, sin embargo, de carecer de tipos de alto nivel y de manejo din amico de
memoria.
El lenguaje m as extendido en la actualidad, C++ ofrece, por su parte la ventaja de tipos
de mas alto nivel, manejo din amico de memoria y soporte a la programacion orientada a
objeto. Sin embargo se trata de un lenguaje complejo, difcil de aprender y que requiere una
considerable experiencia en programaci on para sacar buen provecho de sus posibles ventajas.
Python es el m as extendido hoy en da de los lenguajes de nueva generaci on capaces de
conjugar simplicidad y poder expresivo como veremos repetidamente a lo largo del curso. Es
13
f acil programar en Python y los algoritmos numericos pueden desarrollarse r apidamente y de
manera mas placentera. En consecuencia, el alumno puede dedicar su tiempo a entender los
algoritmos que esta estudiando en lugar de invertirlo en aprender un lenguaje de programaci on
difcil o insuciente. De ah nuestro primer algoritmo en Python. Mira siempre el lado bueno
de la vida.
14
Captulo 3
Datos, variables, operadores y
sentencias
3.1. Python como calculadora
Una de las peculiaridades m as atractivas de Python es que puede utilizarse de modo
interactivo, invocando directamente al interprete. En Unix, basta con invocarlo directamente:
python
Python 2.4 (#1, Dec 18 2004, 13:29:18)
[GCC 3.3 20030304 (Apple Computer, Inc. build 1495)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>
El smbolo de atenci on o prompt nos indica que el interprete esta listo para recibir comandos.
Si queremos salir, sin hace nada, basta con teclear en Unix Control-D.
Veamos un ejemplo elemental de uso del interprete. Para sumar dos n umeros:
>>> 5+3
8
o bien, una multiplicaci on y una divisi on:
>>> 5*6/3
10
Por otra parte, la operaci on 5/3 arroja un resultado que puede parece sorprendente a primera
vista:
>>> 5/3
1
La explicaci on es sencilla. El interprete ha realizado una divisi on entera, es decir ha dividido
dos n umeros enteros, proporcionando a su vez un resultado entero (mediante truncaci on).
15
Para indicarle que los n umeros que queremos dividir son reales basta con a nadir un punto
(lo que transforma el entero en un decimal en coma otante).
>>> 5./3.
1.6666666666666667
Finalmente, si una operaci on mezcla n umeros enteros y reales, Python convierte automatica-
mente los operandos en reales antes de efectuar la operacion:
>>> 4*2.5/3
3.3333333333333335
3.2. Datos y variables
Un programa maneja datos. Estos pueden ser de diversos tipos. Por ejemplo, n umeros,
enteros, reales, o complejos. Otro tipo de datos, habitual en los modernos lenguajes de pro-
gramaci on son las cadenas literales (strings en ingles). En Python encontraremos adem as
otros tipos de alto nivel, como tuplas, listas y diccionarios.
Todos estos tipos se representan en la memoria del ordenador como una determinada
secuencia de n umeros binarios. Para poder acceder a dicha secuencia, los lenguajes de pro-
gramacion utilizan variables. Por ejemplo, en Python, la sentencia:
>>> pi = 3.1415926535897931
asigna el n umero en coma otante 3.1415926535897931 a la variable pi. Para recuperar el
valor asignado a pi basta con teclear:
>>> pi
3.1415926535897931
La variable pi no es otra cosa que un nombre que permite acceder al dato al que ha sido
asignada. Si cambiamos la asignacion:
>>> pi = 2.7182818284590451
el valor de la variable (el dato al que hace referencia el nombre pi) cambia:
>>> pi
2.7182818284590451
Es decir, una variable es una referencia a cierta direcci on de la memoria, donde se alma-
cena el valor de un determinado dato. En el ejemplo anterior, estos datos son los n umeros
3.1415926535897931 y 2.7182818284590451. Cuando la variable pi se asigna a 3.1415926535897931,
establecemos una referencia a la direcci on de memoria donde se almacena este n umero. En
el momento en que pi se asigna a 2.7182818284590451 no hacemos otra cosa que cambiar
la referencia al lugar de la memoria donde reside este segundo dato.
En lenguajes estaticos, como FORTRAN, C o C++, las variables que designan un de-
terminado tipo de datos deben declararse previamente, del mismo tipo que el dato al que
reeren. Por ejemplo, en C++, la instrucci on:
16
double pi = 3.1415926535897931;
declara la variable pi como de tipo double (es decir, real en doble precision) y le asigna el
valor 3.1415926535897931. Si m as adelante en el programa escribimos:
pi = 2.7182818284590451;
se trata de una instruccion sint acticamente correcta, puesto que el dato 2.7182818284590451
(un n umero real) se corresponde con el tipo de la variable pi (real en doble precisi on). En
otras palabras, el nombre pi, en un programa C++ puede asignarse a cualquier n umero real.
Tambien es legal asignar pi a un dato que puede convertirse a un n umero real (por ejemplo
a un entero). Sin embargo, la instrucci on:
pi = razon entre el area y el radio al cuadrado del circulo;
resultara en un error de compilaci on, ya que intentamos asignar una variable de tipo real a
un dato de tipo cadena literal, lo cual no es legal en lenguajes est aticos. S lo es, en cambio,
en Python:
>>> pi =razon entre el area y el radio al cuadrado del circulo
>>> pi
razon entre el area y el radio al cuadrado del circulo
En Python el tipo de las variables se asigna dinamicamente es decir, en funci on del dato
al que hacen referencia. Consecuentemente, la variable pi ha dejado de ser de tipo real para
ser de tipo cadena literal. Si ahora intentamos realizar una operaci on ilegal para este tipo
(por ejemplo, sumarle un n umero), el interprete da un error:
>>> pi+4
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: cannot concatenate str and int objects
que, de hecho, nos informa que es ilegal intentar concatenar objetos de tipo cadena y de tipo
entero. En cambio es legal escribir:
>>> pi+. El volumen de la esfera es proporcional a su cubo
y naturalmente, si reasignamos pi a su valor original, la variable recupera el tipo inicial (real
en coma otante). Veamos como calcular el area de un crculo de radio 5 cm.
>>> pi = 3.1415926535897931
>>> A=pi*5**2
>>> A
78.539816339744831
La generalizaci on al c alculo del area de un crculo de radio arbitario r parece inmediata.
Bastara con escribir A=pi*r**2. Sin embargo, si lo intentamos, el interprete protesta:
17
>>> A=pi*r**2
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: name r is not defined
Informandonos de que el nombre r no ha sido denido. Estamos intentando una operaci on
con una variable (un nombre) al que no se le ha asignado previamente ning un dato (es decir
no reere a ning un tipo en la memoria), lo cual es sint acticamente (y logicamente) incorrecto.
Para resolver el problema basta con inicializar r.
>>> r = 5
>>> A=pi*r**2
>>> A
78.539816339744831
En modo iterativo la ultima expresi on procesada por el interprete se asigna a la variable .
Se trata de una sencilla estratagema para simplicar las operaciones, cuando usamos Python
como calculadora. Por ejemplo:
>>> iva = 12.5 / 100
>>> precio = 100.50
>>> precio * iva
12.5625
>>> precio + _
113.0625
>>> round(_, 2)
113.06
>>>
3.3. Nombres de variables y nombres reservados
Los nombres de las variables son escogidos libremente por el programador. Conviene es-
coger nombres tan cortos como sea posible, pero siempre signicativos. (es mejor usar volumen
que v, y quiz as preferible, por ejemplo, paralep a paralepipedo). En Python, los nombres
de variables deben seguir las siguiente reglas:
Pueden escogerse como una secuencia cualquiera de letras (desde la a a la z y desde la
A a la Z) y /o n umeros (del 0 al 9), si bien debe empezar por una letra.
S olo deben utilizarse letras corrientes, evitando acentos y caracteres especiales (tales
como $, #, etc.). Puede utilizarse, sin embargo el caracter .
El tipo es signicativo. Las variables Lancelot, lancelot y LANCELOT son diferentes.
En este curso seguiremos la convencion de empezar los nombres de las variables siempre por
min usculas. Las may usculas o el caracter pueden utilizarse para aumentar la legibilidad, por
ejemplo, splineCubica o bien spline cubica, pero no SplineCubica o SPLINE CUBICA. Los
18
nombres usando s olo may usculas suelen reservarse para variables globales (que describiremos
mas adelante) y los nombres que empiezan por may uscula para las instancias de clases, como
se comentara en su momento.
Finalmente existen una serie de palabras reservadas (representan elementos sintacticos del
lenguaje) que no pueden utilizarse, a saber:
and del for is raise
assert elif from lambda return
break else global not try
class except if or while
continue exec import pass yield
def finally in print
3.4. Operadores y expresiones
Como ya hemos visto en los ejemplos precedentes, podemos manipular los datos y las
variables que los referencian, mediante el uso de operadores para formar expresiones. Por
ejemplo:
>>> a,b=7.3
>>> b=12
>>> y=3*a+(b/5)-4+b**2
>>> y
163.9000000000000
donde asignamos los valores de a y b a los n umeros 7.3 (coma otante) y 12 (entero) y a
continuaci on asignamos a la variable y el resultado de una expresion, donde se combinan
los valores de a y b mediante los operadores *,+,-,/ y **. Estos operadores representan
operaciones matematicas (multiplicacion, suma, resta, divisi on y exponenciaci on) entre los
operandos (las variables a y b y los n umeros 3,4 y 5). Existen otros operadores, adem as de
estos que se describiran en su momento. Por ejemplo, el operador m odulo:
>>> 10%3
1
>>> 10%5
0
>>> 10%2
0
>>> 10%4
2
que nos da el resto de dividir un n umero entre otro (y por lo tanto arroja cero siempre que
un n umero es divisor exacto de otro).
En una expresi on el orden en que se eval uan los diferentes operandos conectados por
operadores depende de la prioridad o precedencia de estos. Las reglas de precedencia son:
19
Parentesis. El uso de parentesis garantiza siempre que la operacion se eval ua en el orden
indicado por estos. As por ejemplo 2*(3-1)=4 y (1+1)**(5-2)=8.
Exponenciaci on. El exponente se eval ua antes que cualquier otra operaci on (si los
parentesis no indican lo contrario). Es decir, 2**1+1 =3 y no 4.
Multiplicaci on y division que tienen la misma precedencia y se eval uan por tanto antes
que la suma y la resta. En el caso de operaciones con operadores de la misma precedencia
se eval ua el resultado de izquierda a derecha.
Las operaciones suma y resta son las ultimas en evaluarse si los parentesis no indican
lo contrario.
Los parentesis suelen utilizarse para hacer mas legible las operaciones incluso si no son
necesarios estrictamente hablando (como en el caso de la expresion en el ejemplo anterior).
3.5. Resumen
En este captulo hemos introducido el concepto de dato objetos tales como n umeros,
cadenas literales, etc., que se representan en la memoria del ordenador como una secuencia
binaria almacenada en una direcci on concreta y el concepto de variable un nombre que
introduce una referencia a un dato concreto y nos permite acceder a este. Hemos visto que,
a diferencia de otros lenguajes, las variables en Python se asignan dinamicamente.
Podemos agrupar variables, mediante operadores, que representan acciones matematicas
suma, resta, producto, exponenciaci on o l ogicas mayor, menos, igual en sentencias.
Finalmente, hemos visto como utilizar el interprete para experimentar con cualquier car-
acterstica del lenguaje de manera interactiva.
20
Captulo 4
Principales tipos en Python
4.1. Introducci on
En este captulo describimos someramente los principales tipos de datos en Python. Al-
gunos como los n umeros y las cadenas literales ya fueron introducidos en el captulo anterior.
A nadiremos a estos otros nuevos, tales como las listas, las tuplas y los diccionarios. Final-
mente, comentaremos el manejo de cheros en Python.
4.2. N umeros
Python implementa los n umeros enteros (tales como 0,-24,1234) utilizando al menos
32 bits. Pueden por tanto, representarse n umeros entre -2147483648 y 2147483647. Fuera
de este rango, Python dene un tipo denominado entero largo (long int) que permite
representar n umeros de tama no arbirario (la unica limitaci on es la memoria disponible en la
CPU).
Los n umeros en coma otante, que en Python reciben el nombre de tipo float se corre-
sponden a reales en doble precisi on Para especiar que un n umero debe interpretarse como
real basta escribirlo con un punto decimal.
La funci on type() devuelve el tipo de un n umero. Por ejemplo:
>>> pi=3.1415926535897931
>>> type(pi)
<type float>
>>> i=666
>>> type(i)
<type int>
>>> l=8999999993338888
>>> type(l)
<type long>
Para convertir n umeros de un tipo a otro podemos usar las funciones float(), int() y
long()
21
>>> ipi=int(pi)
>>> ipi
Ademas, Python permite el uso de n umeros complejos. Un n umero puramente imaginario
se escribe con un sujo j o J. Si la parte real no es nula el n umero se escribe como
(real+imagj), o puede crearse con la funci on complex(real, imag).
>>> 1j * 1J
(-1+0j)
>>> 1j * complex(0,1)
(-1+0j)
>>> 3+1j*3
(3+3j)
>>> (3+1j)*3
(9+3j)
>>> (1+2j)/(1+1j)
(1.5+0.5j)
Los n umeros complejos se representan siempre como dos n umeros en coma otante, uno
para la parte real y otra para la parte imaginaria. Para extraer las partes reales e imaginaria
de un complejo z, usamos z.real y z.imag.
>>> a=1.5+0.5j
>>> a.real
1.5
>>> a.imag
0.5
Las funciones de conversi on (float(), int() y long()) no funcionan para n umeros com-
plejos no existe una manera corecta de convertir un n umero complejo en un n umero real.
Utilizamos abs(z) para obtener la magnitud del complejo z o z.real para obtener su parte
real.
>>> a=3.0+4.0j
>>> float(a)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: cant convert complex to float; use abs(z)
>>> a.real
3.0
>>> a.imag
4.0
>>> abs(a) # sqrt(a.real**2 + a.imag**2)
5.0
22
4.3. Cadenas literales
Como ya hemos visto, ademas de n umeros Python puede manipular cadenas literales.
Estas pueden escribirse entre comillas simples o dobles.
>>> arturo lance
arturo lance
>>> "Excalibur," dice Arturo.
"Excalibur," dice Arturo
Una cadena puede extenderse a lo largo de m ultiples lneas de diferentes maneras. Por
ejemplo utilizando una barra invertida para indicar la continuaci on de la lnea:
hola = "Esta es una cadenas bastante larga, que contiene\n\
varias lneas de texto, usando la misma tecnica que en C.\n\
Notar que el espacio al principio de la linea es\
significativo."
Notar que para incluir el caracter de nueva lnea en la cadenas tenemos que usar
n.
Otra posibilidad es rodear la cadena de un par de comillas triples ". En este caso, no es
necesario usar el signo de salto de carro para indicar el nal de la lnea.
print """
Los caballeros de la mesa cuadrada:
-Arturo El rey
-Lancelot El invencible
-Tristan El fuerte
"""
Lo que resulta en:
Los caballeros de la mesa cuadrada:
-Arturo El rey
-Lancelot El invencible
-Tristan El fuerte
Dos cadenas pueden concatenarse utilizando el operador +. Una cadena puede repetirse
utilizando el operador *:
>>> reina=Gweniver+e
>>> reina
Gwenivere
>>> <+5*reina+>
<GwenivereGwenivereGwenivereGwenivereGwenivere>
Es posible acceder a los elementos de una cadena va ndices. El primer caracter lleva
asociado el ndice 0. Dada una cadena, podemos formar una subcadena a partir de esta,
accediendo a una porcion (slice en ingles) de la cadena mediante la siguiente notaci on:
23
>>> reina[4]
i
>>> reina[0:2]
Gw
>>> reina[2:4]
en
En particular, si omitimos el primer ndice en esta notacion, nos referimos implcitamente
al primer caracter de la cadena (0) y si omitimos el ultimo ndice nos referimos al ultimo
caracter.
>>> reina[:2] # los 2 primeros caracteres
Gw
>>> reina[2:] # Toda la cadenas menos los dos primeros caracteres
enivere
Una cadena de Python es inmutable, es decir no puede cambiarse. Si intentamos asignar
un caracter a uno de sus ndices obtenemos un error:
>>> reina[0] = J
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: object doesnt support item assignment
Por otra parte, es f acil y eciente crear una nueva cadena:
>>> J+reina[1:]
Jwenivere
Cuando un ndice excede el tama no de la cadena, se reemplaza automaticamente por el
tama no de la cadena. Si el lmite superior de la cadena es demasiado peque no, obtenemos la
cadena nula.
>>> reina[1:100]
wenivere
>>> reina[10:]

Los ndices negativos indican que contamos desde la derecha, por ejemplo:
>>> reina[-1]
e
>>> reina[-2]
r
>>> reina[-2:]
re
>>> reina[:-2]
Gwenive
24
Notar que -0 y 0 son identicos.
>>> reina[-0]
G
Llamamos operaciones de corte o simplemente cortes a una cadena a las operaciones
que nos permiten acceder a un conjunto cualquiera de sus elementos mediante ndices. Una
manera gr aca de recordar como funciona un corte es imaginarse los ndices como fronteras
entre dos caracteres, de tal manera que el lado izquierdo del primer caracter se denota por
cero y el lado derecho del ultimo caracter se denota por n (la longitud de la cadena). Por
ejemplo:
+---+---+---+---+---+---+---+---+---+
| G| w | e | n | i | v | e | r | e |
+---+---+---+---+---+---+---+---+---+
0 1 2 3 4 5 6 7 8 9
-9 -8 -7 -6 -5 -4 -3 -2 -1
La primera la de n umeros da la posicion de los ndices 0...9 en la cadena; la segunda da
la posicion de los correspondientes ndices negativos. La porci on entre i y j consiste de los
caracteres entre los lados que hemos enumerado como i y j, respectivmente.
En el caso de ndices positivos, la longitud de una porci on de cadena es la diferencia entre
los ndices. Por ejemplo la longitud de reina[1:3] es 2.
La funci on len() devuelve la longitud de una cadena.
>>> len(reina)
9
La funci on str() transforma a un objeto en una cadena:
>>> "Lancelot, Arturo y Tristan eran "+3+" caballeros"
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: cannot concatenate str and int objects
>>> "Lancelot, Arturo y Tristan eran "+str(3)+" caballeros"
Lancelot, Arturo y Tristan eran 3 caballeros
A su vez, una cadena que representa un n umero puede convertirse a este mediante las
funciones int() y float().
>>> float(3.5)+3.5
7.0
>>> int(2)+3
5
El uso del operador % permite formatear cadenas. Veamos algunos ejemplo de impresion
de una cadena con formato:
25
>>> caballero_negro=No huyas cobarde!
>>> amenaza =Te matare a bocados
>>> "El caballero negro dijo: %s %s" %(caballero_negro,amenaza)
El caballero negro dijo: No huyas cobarde! Te matare a bocados
>>> mandobles=3
>>> accion=Te cortare la cabeza
>>> "El caballero negro dijo.:%s de %d mandobles!" %(accion, mandobles)
El caballero negro dijo.:Te cortare la cabeza de 3 mandobles!
Como veremos mas adelante, la funci on print() puede utilizar la salida con formato para
producir una presentaci on elegante de tablas y listados.
Notar que en la salida con formato, sustituimos el valor de la variable de acuerdo con
su tipo. %s signica string (cadena), y %d signica decimal que, por razones hist oricas
se utiliza junto con la notaci on %i (integer) para formatear enteros. Los n umeros en coma
otante pueden formatearse con %f (oat) %e (exponente) o %g (vale para ambos). La
precision tambien puede especicarse. Por ejemplo:
>>> pi
3.1415926535897931
>>> "pi = %f" %pi
pi = 3.141593
>>> "pi = %10.8f" %pi
pi = 3.14159265
>>> "pi = %12.10f" %pi
pi = 3.1415926536
>>> "pi = %12.10e" %pi
pi = 3.1415926536e+00
>>> "pi = %12.2e" %pi
pi = 3.14e+00
>>>
4.4. Listas
Una lista es una colecci on ordenada de objetos arbitrarios. El termino ordenada quiere
decir que es posible acceder a los miembros de la coleccion mediante unndice que especica la
posici on (el orden) del objeto en esta. Puesto que una lista puede almacenar cualquier tipo de
objeto, es posible formar colecciones heterogeneas que contengas n umeros, cadenas literales
o incluso otras listas. La longitud de una lista es variable (puede expandirse o contraerse a
voluntad) y pueden anidarse arbitrariamente (es posible crear listas de listas de listas...).
Veamos como denir una lista en Python. Para ello, entramos en el interprete y tecleamos:
>>> L=[Camelot,9,0.5,3+2j]
>>> L
[Camelot, 9, 0.5, (3+2j)]
para asignar una lista a una cierta variable nos limitamos a teclear los diferentes objetos que
la componen, separados por comas y entre corchetes. En nuestro ejemplo, la lista L contiene
26
cuatro objetos, cada uno de ellos de un tipo diferente. Camelot es una cadena literal, 9 es
un entero, 0.5 un real en coma otante y (3+2j) un n umero complejo.
Al igual que en el caso de las cadenas, puede accederse a cada objeto de una lista por
ndice. El primer ndice de una lista es siempre el 0. As, por ejemplo:
>>> L[0]
Camelot
>>> L[1]
9
>>> L[2]
0.5
>>> L[3]
(3+2j)
pero tambien:
>>> L[-1]
(3+2j)
>>> L[-2]
0.5
>>> L[-3]
9
>>> L[-4]
Camelot
Podemos acceder a cualquier porcion de la lista mediante un corte:
>>> L[:2]
[Camelot, 9]
o, equivalentemente L[0:2]. Dada una lista de n elementos L, L[i:j] nos devuelve otra
lista que contiene los elementos entre i y j-1:
>>> L[1:3]
[9, 0.5]
Dos listas cualesquiera pueden concatenarse:
>>> L2=[Merlin,10,1.,2+3j]
>>> L+L2
[Camelot, 9, 0.5, (3+2j), Merlin, 10, 1.0, (2+3j)]
y sus elementos pueden modcarse. Es decir, a diferencia de las cadenas que eran inmutables
(sus elementos se pueden leer pero no modicar) las listas son mutables.
>>> L[0]=Fata Morgana
>>> L
[Fata Morgana, 9, 0.5, (3+2j)]
27
Tambien es posible asignar porciones de una lista a otras listas, porciones de lista u
elementos, lo que permite una gran riqueza de operaciones, por ejemplo:
Reemplazar elementos:
>>> L[0:2]=[Modred,1960]
>>> L
[Modred, 1960, 0.5, (3+2j)]
>>>
eliminar elementos:
>>> L[2:-1]=[]
>>> L
[Modred, 1960, (3+2j)]
insertar elementos:
>>> L[1:1]=[Arturo,1984,Brian]
>>> L
[Modred, Arturo, 1984, Brian, 1960, (3+2j)]
La funci on len() nos da la longitud ( length en ingles) de la lista:
>>> len(L)
6
Las listas pueden anidarse:
>>> matriz = [[1,2,3],[0.1,0.2,0.3],[Arturo,Gwenivere,Lancelot]]
>>> matriz
[[1, 2, 3], [0.10000000000000001, 0.20000000000000001, 0.29999999999999999],
[Arturo, Gwenivere, Lancelot]]
>>> len(matriz)
3
>>> matriz[0][0]
1
>>> matriz[1][2]
0.29999999999999999
>>> matriz[2][2]
Lancelot
Finalmente, enumeramos algunas de las funciones m as utiles para manejar estos objetos.
Si L es una lista entonces: objestos son:
L.append(x) : A nade un elemento al nal de la lista; equivalente a L[len(L):] = [x].
L.extend(L); Extiende la lista a nadiendole todos los elementos de la lista L; equivalente
a L[len(L):] = L.
28
L.insert(i, x) : Inserta un elemento en una posici on dada. El primer argumento es
el ndice del elemento antes del cual queremos insertar x, por lo tanto L.insert(0,
x) inserta x al principio de la lista mientras que a.insert(len(L), x) equivale a
L.append(x).
L.remove(x) : Elimina el primer elemento de la lista cuyo valor es x. Si el elemento no
se encuentra arroja un error.
L.pop(i) : Elimina el elemento de la lista en la posicion i y lo devuelve como resultado
de la operaci on. Si no se especica un ndice a.pop() devuelve el ultimo elemento de la
lista y lo elimina de esta (los corchertes que rodean i en la rma de la funci on indican
que el par ametro es opcional no que deban usarse explcitamente)
L.index(x) : Devuelve el ndice de la lista del primer elemento cuyo valor es x. Arroja
un error si dicho elemento no existe.
L.count(x) Devuelve el n umero de veces que x aparece en la lista.
L.sort() : Ordena los elementos de la lista, en la propia lista.
L.reverse() : Invierte los elementos de la lista, en la propia lista.
El siguiente ejemplo utiliza la mayora de estos metodos:
>>> L = [66.25, 333, 333, 1, 1234.5]
>>> print L.count(333), L.count(66.25), L.count(x)
2 1 0
>>> L.insert(2, -1)
>>> L.append(333)
>>> L
[66.25, 333, -1, 333, 1, 1234.5, 333]
>>> L.index(333)
1
>>> L.remove(333)
>>> L
[66.25, -1, 333, 1, 1234.5, 333]
>>> L.reverse()
>>> L
[333, 1234.5, 1, 333, -1, 66.25]
>>> L.sort()
>>> L
[-1, 1, 66.25, 333, 333, 1234.5]
4.5. Tuplas y Secuencias
Hemos visto que las listas y cadenas de caracteres tienen muchas propiedades en com un,
tales como el acceso por ndice y las operaciones de corte que nos permiten acceder a porciones
29
de estas. De hecho, tanto unas como otras son ejemplos de un tipo particular de datos llamado
secuencias. En Python existen otra secuencia intrnsecas al lenguaje, a saber, las tuplas (tuples
en ingles).
Una tupla, al igual que una lista, es un conjunto, en general inhomogeneo de objetos. Sin
embargo, a diferencia de esta y al igual que las cadenas de caracteres, una tupla es inmutable.
Una tupla se asigna igualando un nombre a una serie de objetos separados por una coma,
por ejemplo:
>>> t = 12345, 54321, Crucifixion?
>>> t[0]
12345
>>> t
(12345, 54321, Crucifixion?)
Al imprimirse, una tupla aparece entre parentesis (no entre corchetes como la lista). Sus
propiedades son las que ya hemos estudiado para cadenas y listas (con la restricci on de que
son inmutables). Acceso a ndice, cortes, encadenado, etc. Como veremos en su momento se
trata de un tipo muy util que permite simplicar muchas operaciones.
A veces es necesario construir tuplas vacas o con un s olo elemento. En este caso la notacion
es como sigue:
>>> t0elem = ()
>>> t1elem = Solitario estoy, # <-- notar la coma al final de la cadena!
>>> len(t0elem)
0
>>> len(t1elem)
1
>>> t1elem
(Solitario estoy,)
La sentencias t = 12345, 54321, Crucifixion? es un ejemplo de empaquetado de una
tupla: es decir los valores 12345, 54321 y Crucifixion? son empaquetados juntos en una
tupla. La operaci on inversa tambien es posible.
>>> x, y, z = t
Y se llama, correctamente, desempaquetado de una secuencia. Esta operaci on requiere que
la lista de variables a la izquierda del signo igual tenga el mismo n umero de elementos que la
longitud de la secuencia. La operaci on de desempaquetado funciona para cualquier secuencia,
mientras que el empaquetado de varios valores separados por comas resulta siempre en una
tupla.
4.6. Diccionarios
Otro de los tipos intrnsecos de Python es el dictionario. A diferencia de las secuencias,
en las que se accede a los elementos mediante ndices numericos, en los diccionarios se accede
30
a los elementos mediante el uso de llaves, que pueden ser de cualquier tipo inmutable por
lo tanto los n umeros y las cadenas pueden usarse siempre como llaves. Las tuplas pueden
utilizarse como llaves si contienen s olo otro objetos inmutables como n umeros, cadenas u
otras tuplas. Un diccionario puede visualizarse como un conjunto desordenado de pares llave:
valor en el que las llaves verican el requisito de ser unicas.
Para crear un diccionario vaco utilizamos un par de llaves . Para crear un diccionario con
una serie de valores, escribimos una lista llave:valor, separada por comas. Las operaciones
mas importantes en un diccionario son guardar un valor con una llave y acceder a dicho valor
por medio de la llave. Una pareja de valores puede borrarse mediante la instrucci on del. Si
un valor se guarda utilizando una llave ya en uso el valor anterior se descarta. Es un error
intentar acceder a una llave que no ha sido registrada en el diccionario.
Para obtener una lista de todas las llaves utilizadas en un diccionario utilizamos el metodo
keys(). Para comprobar si una cierta llave existe en el diccionario utilizamos el metodo
has key(). Los metodos values() e items() nos devuelven respectivamente una lista de los
valores almacenados en el diccionario y una lista de tuplas con los valores llave:valor.
Por ejemplo:
>>> tel = {lance: 4098, arthur: 4139}
>>> tel[gweni] = 4127
>>> tel
{arthur: 4139, gweni: 4127, lance: 4098}
>>> tel[lance]
4098
>>> del tel[arthur]
>>> tel[tristan] = 4127
>>> tel
{gweni: 4127, tristan: 4127, lance: 4098}
>>> tel.keys()
[gweni, tristan, lance]
>>> tel.has_key(gweni)
True
>>> tel.values()
[4098, 4127, 4139]
>>> tel.items()
[(lance, 4098), (gweni, 4127), (arthur, 4139)]
Es posible construir un diccionario directamente a partir de de una lista de pares llave:valor
almaecenados en la lista como tuplas utilizando dict().
>>> dict([(arthur, 4139), (gweni, 4127), (lance, 4098)])
{arthur: 4139, lance: 4098, gweni: 4127}
31
4.7. Ficheros
El manejo de cheros de datos archivos residentes en la memoria del ordenador en los
que se almacena alg un tipo de dato y a los que puede accederse mediante un nombre se
realiza mediante el uso de un tipo intrnseco al lenguaje llamado objeto de chero (le
object en ingles), o, simplemente, chero.
Un chero se crea cuando invocamos a la funci on open(), cuya funci on es asociar el nombre
del chero en el disco con el objeto chero que nos permite manipularlo. Tpicamente open()
se invoca con dos argumentos, open(filename, mode):
>>> f=open(mesa_redonda.txt, w)
>>> print f
<open file mesa_redonda.txt, mode w at 0x37e7b8>
El primer argumentos es una cadena que contiene el nombre del chero. El segundo argu-
mento es otra cadena que describe el modo en el que el chero sera utilizado. Por ejemplo,
para abrir el chero en modo s olo lectura utilizamos r; en modo solo escritura w en este
caso sobreescrimos cualquier chero previo que exista con el mismo nombre. Finalmente, en
modo apendice cualquier dato que escribamos en el chero se a nade al nal del chero
usamos el modo a.
Veamos con un ejemplo como manejar estos objetos:
Para escribir datos en el chero f que acabamos de abrir utilizamos la instrucci on f.write(string)
que escribe el contenido de la cadena string al chero.
>>> f.write(Listado de caballeros de la Mesa Redonda\n)
Cuando deseamos imprimir objetos que no son del tipo cadena debemos convertirlos pre-
viamente. Por ejemplo:
>>> a=Caballero +str(1)+: Arturo\n
>>> b=Caballero +str(2)+: Lancelot\n
>>> c=Caballero +str(3)+: Tristan\n
>>> lista=a+b+c
>>> print lista
Caballero 1: Arturo
Caballero 2: Lancelot
Caballero 3: Tristan
>>> f.write(lista)
Una vez que hemos terminado de escribir datos en el chero lo cerramos con f.close().
Si ahora examinamos el directorio de trabajo en el cual hemos abierto el interprete en-
contraremos un chero mesa redonda.txt que contiene la informacion que hemos escrito
previamente:
Listado de caballeros de la Mesa Redonda
32
Caballero 1: Arturo
Caballero 2: Lancelot
Caballero 3: Tristan
Para leer este chero, en primer lugar lo abrimos para lectura:
>>> f=open(mesa_redonda.txt,r)
>>> print f
<open file mesa_redonda.txt, mode r at 0x37e770>
Y a continuaci on utilizamos la instruccion f.read() que nos devuelve el contenido del
chero como una cadena.
>>> lista2 = f.read()
>>>> print lista2
Listado de caballeros de la Mesa Redonda
Caballero 1: Arturo
Caballero 2: Lancelot
Caballero 3: Tristan
Si queremos leer el chero lnea a lnea podemos usar la instrucci on f.readline().
>>> f.close()
>>> f=open(mesa_redonda.txt,r)
>>> linea=f.readline()
>>> print linea
Listado de caballeros de la Mesa Redonda
>>> linea=f.readline()
>>> print linea
Caballero 1: Arturo
>>> linea=f.readline()
>>> print linea
Caballero 2: Lancelot
>>> linea=f.readline()
>>> print linea
Caballero 3: Tristan
Por ultimo, la instrucci on f.readlines() devuelve una lista que contiene cada una de las
lneas del chero como veremos mas adelante esta opcion es mas pr actica que leer todo el
chero en una cadena si deseamos iterar sobre las lneas.
>>> f.close()
>>> f=open(mesa_redonda.txt,r)
>>> ll=f.readlines()
>>> ll
[Listado de caballeros de la Mesa Redonda\n, Caballero 1: Arturo\n,
Caballero 2: Lancelot\n, Caballero 3: Tristan\n]
33
4.8. Resumen: Tipos en Python
En resumen, aparte de los objetos de tipo chero, hemos visto tres tipos de objetos en
Python. N umeros, Secuencias (cadenas, listas, tuplas) y diccionarios. Todas las secuencias
comparten caractersticas comunes (se puede iterar sobre ellas, cortarlas y acceder por ndice),
siendo la diferencia mas importante el hecho de que las cadenas y tuplas son inmutables
mientras que las listas son mutables.
34
Captulo 5
Control del ujo en Python
5.1. Control del ujo en un programa Python
Un programa consiste en una secuencia de instrucciones, escritas en la sintaxis propia de
un cierto lenguaje de programaci on, El modo en que dichas instrucciones son ejecutadas se
denomina ujo de instrucciones o simplemente, ujo.
Para controlar el ujo, Python dispone de una serie de instrucciones que permiten intro-
ducir condiciones. Por ejemplo una sentencia if establece que el bloque o cuerpo de instruc-
ciones que delimita debe ejecutarse solamente si se cumple una cierta condici on l ogica. Otras
instrucciones permiten ejecutar repetidamente un bloque de instrucciones (como es el caso
de una sentencia while), o iterar sobre una secuencia (sentencia for).
En ese captulo describiremos brevemente estas estructuras de control.
5.2. Bucle while
Consideremos la serie de Fibonacci, en la que cada termino es la suma de los dos terminos
anteriores. Vamos a escribir directamente en el interprete un peque no programa que imprime
sus diez primeros terminos.
>>> #Serie de Fibonacci
>>> # La suma de dos elementos define el siguiente
>>> a,b=0,1
>>> while b < 10:
print b...
a,b = b, a+b
1
2
3
5
8
Este ejemplo introduce varias novedades que comentamos a continuaci on:
35
asignaci on m ultiple. En la primera lnea asignamos simultaneamente los valores 0 y 1
a las variables a y b. Hacemos lo mismo en la ultima lnea. La variable a se asigna al
valor (anterior) de la variable b y la variable b a la suma a+b.
El bucle while se ejecuta mientras la condici on b <10) sea cierta. En Python, cualquier
valor entero no nulo es equivalente a la condici on l ogica verdadero, mientras que el
cero es equivalente a falso. La condici on en el bucle while puede ser tambien cualquier
secuencia (una cadena, lista, o tupla). Cualquier secuencia de longitud no nula se traduce
como verdadero, mientras que una secuencia vaca se traduce como falso. En el ejemplo
usamos una comparaci on, (b menor que 10). Los operadores de comparaci on en Python
son: < (menor que), > (mayor que), == (igual a), <= (menor o igual que), >= (mayor o
igual que) and != (no igual a).
El cuerpo del bucle (el conjunto de sentencias que se ejecutan repetitivamente mientras
la condici on sea cierta) esta sangrado a la derecha. Python agrupa sentencias de esta
manera. Para introducir el cuerpo del bucle en el interprete de manera sencilla, basta
con teclear un tabulador delante de cada una de sus sentencia, a n de sangrarla a
la derecha. Para nalizar el cuerpo del bucle, en el interprete, introducimos una lnea
en blanco. En el pr oximo captulo veremos como escribir programas de Python usando
editores de texto.
La sentencia print escribe el valor de la expresion o expresiones que la siguen. Es capaz
de manejar expresiones m ultiples y cadenas de caracteres. Por ejemplo:
>>> i = 256*256
>>> print El valor de i es, i
El valor de i es 65536
Si dejamos una coma al nal de la sentencia la impresi on se realiza en una sola lnea:
>>> a, b = 0, 1
>>> while b < 1000:
... print b,
... a, b = b, a+b
...
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
5.3. La sentencia if
El bloque if, elif, else permite ejecutar sentencias condicionalmente. Por ejemplo:
x=raw_input("Dime, amigo, y entra") # El se~nor de los anillos, libro I
if x == "amigo":
print "Bienvenido a Moria!"
elif x =="friend":
print "Welcome to Moria!"
else:
print "No puedes pasar!"
36
Las novedades en este ejemplo son:
La sentencia raw input,imprime el mensaje entre comillas y captura una variable, que
interpreta como una cadena, desde la pantalla. Al ejecutar el c odigo del ejemplo obten-
emos el mensaje Dime, amigo y entra y el interprete aguarda a que introduzcamos
un valor que asigna a x.
La sentencia if, seguida, opcionalmente por sentencias elif y else. Literalmente: Si
x entonces... en otro caso, si x entonces... en otro caso.... En el ejemplo, si tecleamos
amigo, la comparaci on l ogica del primer if sera cierta y obtendremos un mensaje
Bienvenido a Moria. Si tecleamos friend, la primera comparaci on sera falsa y la
segunda cierta, resultando en un mensaje Welcome to Moria. Finalmente, si tecleamos
cualquier otra cosa, las dos primera comparaciones son falsas y se ejecuta la sentencia
en otro caso que viene a ser el caso por defecto del bloque. Obtenemos por lo tanto
el mensaje No puedes pasar!.
Como en el caso del bucle while, el cuerpo del bloque if se escribe sangrado a derecha.
5.4. La sentencia for
La sentencia for de Python diere sustancialmente de la de otros lenguaje de m as bajo
nivel, en los que tpicamente s olo se itera sobre una secuencia numerica. El for de Python,
en cambio, itera sobre los elementos de cualquier secuencia, tal como una lista, una tupla o
incluso una cadena literal. Por ejemplo:
>>> mesa_redonda =[Arturo,Lancelot,Tristan,Gawain,Galahad,Percival]
>>> for caballero in mesa_redonda:
print El nombre del caballero ,caballero, tiene,\
len(caballero), letras
Cuando ejecutamos este peque no programa obtenemos:
El nombre del caballero Arturo tiene 6 letras
El nombre del caballero Lancelot tiene 8 letras
El nombre del caballero Tristan tiene 7 letras
El nombre del caballero Gawain tiene 6 letras
El nombre del caballero Galahad tiene 7 letras
El nombre del caballero Percival tiene 8 letras
5.5. La funci on range()
En ocasiones resulta conveniente iterar sobre una secuencia de n umeros. En ese caso pode-
mos usar la funci on range(), cuya funci on es la de generar listas que contienen progresiones
aritmeticas.
37
>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Resaltemos que el nal del rango no es parte de la lista. As range(10) genera una lista
de 10 valores que van del 0 al 9, es decir los ndices, si se quiere de una secuencia de longitud
10.
Para denir un rango entre dos pares arbirarios de valores, hacemos:
>>> range(5, 10)
[5, 6, 7, 8, 9]
Tambien podemos controlar el paso de la secuencia, por ejemplo:
>>> range(0, 10, 3)
[0, 3, 6, 9]
>>> range(-10, -100, -30)
[-10, -40, -70]
Consecuentemente, si queremos iterar sobre los ndices de una secuencia basta con com-
binar la func on range() y la len() como sigue:
>>> mesa_redonda =[Arturo,Lancelot,Tristan,Gawain,Galahad,Percival]
for i in range(len(mesa_redonda)):
print El caballero ,i+1, se llama ,mesa_redonda[i]
obteniendo el listado:
El caballero 1 se llama Arturo
El caballero 2 se llama Lancelot
El caballero 3 se llama Tristan
El caballero 4 se llama Gawain
El caballero 5 se llama Galahad
El caballero 6 se llama Percival
5.6. Sentencias break y continue
La sentencia break, fuerza la salida del bucle for o while mas interno que la contenga.
La sentencia continue, contin ua con la siguiente iteraci on en el bucle.
5.7. Cla usula else en bucles
Los bucles for y while pueden contener una cla usula else que se ejecuta cuando el bucle
termina normalmente (tras agotar la secuencia sobre la que se itera, en el caso del for o
cuando la condici on se hace falsa en el caso del while), pero no se ejecuta si el bucle termina
por causa de una sentencia break. El siguiente c odigo, que busca n umeros primos, ejemplica
esta caracterstica.
38
#Busca numeros primos entre 0 y 10
>>> for n in range(2, 10):
for x in range(2, n):
if n % x == 0:
print n, es igual a, x, *, n/x
break
else:
# completamos el bucle tras agotar la lista
# por lo tanto se ejecuta la clausula else:
print n, es un numero primo
2 es un numero primo
3 es un numero primo
4 es igual a 2 * 2
5 es un numero primo
6 es igual a 2 * 3
7 es un numero primo
8 es igual a 2 * 4
9 es igual a 3 * 3
5.8. Sentencia pass
Por ultimo la sentencia pass cuya funci on es no hacer nada. Se utiliza cuando es necesario
una sentencia sint acticamente, pero no se requiere ninguna accion por parte del programa.
5.9. Resumen
En este captulo hemos estudiado las princiaples instrucciones que nos permiten controlar
el ujo en un programa Python. Estas son: la sentencia if, que permite introducir una
condici on l ogica. El bucle while, gracias al cual podemos repetir un conjunto de instrucciones
mientras una determinada condici on sea cierta y el bucle for que nos permite iterar sobre
una secuencia cualquiera.
39
40
Captulo 6
Rudimentos de programaci on en
Python
6.1. Ficheros ejecutables en Python
En los captulos anteriores hemos utilizado Python solamente en modo interactivo. Esta
modalidad es muy util, para experimentar con cualquier detalle del lenguaje, pero natu-
ralmente tiene serias limitaciones a la hora de expresar un algoritmo con un mnimo de
complejidad. Esto requiere, como en agrupar nuestro c odigo en un programa.
6.2. La serie de Fibonacci
En el captulo 5 introdujimos la serie de Fibonacci, cada uno de cuyos terminos es la
suma de los dos anteriores. El programa fibonacci.py imprime los primeros terminos de la
serie. Esta primera version contiene exactamente el mismo codigo que escribimos usando el
interprete en el captulo 5.
#!/usr/bin/env python
#
#Serie de Fibonacci
# La suma de dos elementos define el siguiente
a,b=0,1 # asignacion multiple de a y b (a=0, b = 1)
while b < 10:
print b
a,b = b, a+b # asignacion multiple de a y b (a=b, b = a+b)
Como ya comentamos, las caractersticas interesantes que introducimos en este programa
son la asignaci on m ultiple y el uso de un bucle while. Recordemos que el codigo del cuerpo
del bucle esta sangrado a derechas.
Para ejecutar:
41
fibonacci.py
1
1
2
3
5
8
La segunda version, fibonacci2.py permite al usuario decidir cu antos elementos de la
serie deben calcularse, e imprime una tabla mas detallada.
#!/usr/bin/env python
#
#Serie de Fibonacci
# La suma de dos elementos define el siguiente
# permite al usuario decidir el numero de elementos a calcular
# imprime una tabla formateada
nelem=input("Cuantos elementos quiere imprimir? ")
a,b,i=0,1,1
print " i a b a+b"
print "------------------------"
while i <= nelem:
print "%5d %5d %5d %5d" %(i,a,b,a+b)
a,b = b, a+b
i+=1
La funci on input() lee un dato por pantalla y lo eval ua a su valor numerico, a diferencia
de la funci on raw input() que, como ya se vio, asume que el dato es una cadena literal.
El dato que el usuario introduce es el n umero de elementos de la serie y por tanto el bucle
while se ejecuta mientras un contador que incializamos previamente a uno no exceda ese
n umero.
Al ejecutarse, el programa imprime una tabla formateada.
fibonacci2.py
Cuantos elementos quiere imprimir?10
i a b a+b
------------------------
1 0 1 1
2 1 1 2
3 1 2 3
4 2 3 5
5 3 5 8
6 5 8 13
42
7 8 13 21
8 13 21 34
9 21 34 55
10 34 55 89
6.3. N umeros primos
En el captulo 5 vimos un sencillo algoritmo para buscar n umeros primos entre 0 y 10, que
codicamos en el programa primos.py:
#!/usr/bin/env python
#
#Busca numeros primos entre 0 y 10
for n in range(2, 10):
for x in range(2, n):
if n % x == 0:
print n, es igual a, x, *, n/x
break
else:
# completamos el bucle tras agotar la lista
# por lo tanto se ejecuta la clausula else:
print n, es un numero primo
Observemos que a pesar de ser muy conciso, el programa implementa un algoritmo no
trivial, con dos bucles for anidados, el m as interno de los cuales se completa con una cla usula
else y un bloque if, cuya condici on l ogica utiliza el operador % (modulo) y que, en caso de
ser cierto fuerza la salida del bucle for mas interno mediante una sentencia break.
Para ejecutar:
primos.py
2 es un numero primo
3 es un numero primo
4 es igual a 2 * 2
5 es un numero primo
6 es igual a 2 * 3
7 es un numero primo
8 es igual a 2 * 4
9 es igual a 3 * 3
Una segunda versi on permite al usuario decidir el rango de b usqueda y almacena los primos
que encuentra en una lista que se imprime al nalizar el bucle.
#!/usr/bin/env python
#Busca numeros primos
43
rango=input("Que rango desea explorar? ")
primos = [] # creamos una lista vaca
for n in range(2, rango):
for x in range(2, n):
if n % x == 0: # numero divisible
break
else: # numero primo
primos.append(n) # a~nadimos a la lista de primos
print " La lista de los numeros primos entre 1 y", rango, " es:\n" ,primos
Para ejecutar:
primos2.py
Que rango desea explorar?100
La lista de los numeros primos entre 1 y 100 es:
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67,
71, 73, 79, 83, 89, 97]
6.4. Algoritmo de Newton para el calculo de races cuadradas
el programa newton.py implementa el conocido algoritmo de Newton, que proporciona
aproximaciones sucesivamente mejores de la raz cuadrada de un n umero:
#!/usr/bin/python
import math
#
# Implementa el algoritmo de Newton para calcular el valor de
# la raz cuadrada de un numero.
#
# El algoritmo consiste en hallar aproximaciones sucesivamente mejores
# de la raz cuadrada x=sqrt(y), basadas en la siguiente formula iterativa:
#
# x(n+1) = 1/2 * ( x(n) + y / x(n) )
TOLERANCIA = 1.0e-6 # tolerancia del calculo
print "Introduce el numero cuya raz quieres calcular: "
y=float(input());
#Tomamos como (burda) aproximacion inicial de sqrt(y) el
44
# propio valor "y".
x = y;
# El bucle while evalua las sucesivas aproximaciones a la raz,
# deteniendose cuando la aproximacion "x" es lo suficientemente buena,
# es decir, cuando x^2 - y < TOLERANCIA. El bucle se evalua
# al menos una vez.
#
while abs(x*x - y) > TOLERANCIA:
x = (x + y/x) / 2
print "La raz de %8.1f por newton es %8.4f, exacta = %8.4f" \
%(y,x,math.sqrt(y))
Para ejecutar:
newton.py
Introduce el numero cuya raiz quieres calcular:
515
La raiz de 515.0 por newton es 22.6936, exacta = 22.6936
La unica novedad en este ejemplo es el uso del modulo math. Un m odulo no es otra
cosa que un chero que contiene deniciones, sentencias, funciones, etc. La sentencia import
da acceso a dichas deniciones, funciones, etc. En nuestro ejemplo, importamos uno de los
modulos estandar de Python, en el que se re une buena parte de la funcionalidad matem atica
del lenguaje. En particular, math contiene la denici on de constantes como los n umeros e y
pi as como la denici on de funciones tales como sqrt(), funciones trigonometricas, etc.
La razon para importar el m odulo matem atico es comparar el resultado de la aproximaci on
a la raz por el metodo de Newton con el resultado que proporciona la implementaci on de la
funci on raz cuadrada.
6.5. Resumen
En este captulo hemos visto una serie de programas sencillos que ilustran los rudimentos
de programaci on en Python. Hemos visto como escribir un programa en un chero de texto,
que podemos ejecutar a continuaci on invocando al interprete.
45
46
Captulo 7
Funciones y m odulos
7.1. Funciones en Python
Como todo lenguaje de programaci on de alto nivel, Python permite denir funciones. Para
introducirlas, recurramos de nuevo a la serie de Fibonacci. Nuestro objetivo es escribir una
rutina, que proporcione, al invocarla, la serie hasta un rango arbitrario.
Para ello consideremos el programa fib.py:
def fib(n):
"""
Serie de Fibonacci
La suma de dos elementos define el siguiente
La funcion escribe la serie hasta el termino n
"""
a,b,i=0,1,1
print " i a b a+b"
print "------------------------"
while i <= n:
print "%5d %5d %5d %5d" %(i,a,b,a+b)
a,b = b, a+b
i+=1
if __name__ == __main__:
n =input("Cuantos elementos quiere imprimir? ")
fib(n)
Como vemos, el algoritmo que calcula los terminos sucesivos de la serie ha sido encapsulado
en la funci on fib(n), que toma un argumento el n umero de elementos de la serie que
deseamos imprimir. En Python, la denici on de una funci on se realiza mediante el uso de
la palabra reservada def, que debe ir seguida del nombre de la funci on y de una lista de
47
argumentos a esta, entre parentesis la denicion naliza con dos puntos. Las sentencias
que forman el cuerpo de la funci on comienzan en la siguiente lnea y deben estar sangrados a
la derecha. La primera sentencia de la funci on puede ser, opcionalmente, una cadena literal
de caracteres, que se utiliza para documentar la funci on. Esta cadena de documentacion
puede luego visualizarse desde el interprete o utilizando una herramienta de software. En
particular, desde el interprete, podemos invocar a la funci on help(mod-fun), donde mod-fun
hace referencia a un m odulo (cualquier chero declarado al interprete mediante la instruccion
import) o a una funci on dentro de un m odulo. La funci on help(nombre) imprime la cadena de
documentaci on asociada al objeto mod-fun. En este caso hemos importado el chero fib.py
como un modulo que contiene una sola funci on, fib(), cuya cadena de documentacion se
imprime junto con otras informaciones relevantes, tales como el nombre y la localizaci on del
modulo, su cadena de documentaci on si la hubiere, etc.
python
>>> import fib
>>> help(fib)
Help on module fib:
NAME
fib
FILE
/Users/jj/Development/pynum/pytut/fib.py
FUNCTIONS
fib(n)
Serie de Fibonacci
La suma de dos elementos define el siguiente
La funcion escribe la serie hasta el termino n
Las variables denidas en una funci on son locales a la funcion. En este primer ejem-
plo, fib(n) no devuelve ning un resultado, limit andose a realizar un c alculo, de tal man-
era que se usa mas como una subrutina que como una autentica funci on (que suele tomar
una serie de argumentos y devolver un resultado). Sin embargo, en Python no existe dis-
tinci on formal entre subrutinas y autenticas funciones. Ambas se introducen con def
nombre-fun(argumentos):.
Los argumentos de la funci on se pasan por asignaci on. En la pr actica, esto quiere decir lo
siguiente. Si el objeto que pasamos como argumento es inmutable (una cadena, por ejemplo),
cualquier modicaci on que hagamos en la funci on a este objeto es local a esta y no se propaga
al bloque del programa que la llama, mientras que si pasamos un objeto mutable (tal como
una lista), las modicaciones al objeto se mantienen despues de la llamada.
Ilustremos este importante aspecto con un ejemplo. En la pelcula Los caballeros de la
Mesa Cuadrada, el rey Arturo se enfrenta al valiente caballero negro. Tras un encarnizado
combate en el que este ultimo pierde piernas y brazos, Arturo contin ua su camino, perseguido
48
por el tronco mutilado del aguerrido caballero, que a un tiene el animo de proferir amenazas:
No huyas cobarde. Te matare a bocados!.
#!/usr/bin/env python
"""
Ilustra el paso de argumentos por asignacion (o referencia a objeto).
La llamada a no_huyas_cobarde() se hace con un argumento inmutable
(una cadena literal), que se modifica dentro de la funcion.
sin embargo, en el programa principal, la cadena es todava la misma
despues de llamar a la funcion.
La llamada a miembros_cortados() se hace con un argumento mutable,
en este caso una lista. Dentro de la funcion se a~naden varios
elementos a la lista, que permanecen en esta despues de la llamada.
"""
def no_huyas_cobarde(amenaza):
""" Imprime las amenazas del caballero negro"""
print amenaza
amenaza = Te matare a bocados
print amenaza
def miembros_cortados(miebros):
""" Detalla las extremidades perdidas en la pelea"""
miembros.append(brazos)
miembros.append(piernas)
if __name__ == __main__:
amenaza = No huyas cobarde!
no_huyas_cobarde(amenaza)
print amenaza
miembros=[]
miembros_cortados(miembros)
print "El caballero negro ha perdido los siguiente miembors\n", miembros
Notad que en este ejemplo hemos a nadido una cadena de documentaci on no s olo a cada una
de las funciones del m odulo caballero negro1.py sino tambien al modulo en s mismo. Si
importamos el modulo e invocamos la funci on help() obtenemos:
>>> import caballero_negro1
>>> help(caballero_negro1)
Help on module caballero_negro1:
49
NAME
caballero_negro1 - Ilustra el paso de argumentos por referencia.
FILE
/Users/jj/Development/pynum/pytut/caballero_negro1.py
DESCRIPTION
La llamada a no_huyas_cobarde() se hace con un argumento inmutable
(una cadena de caracteres), que se modifica dentro de la funcion.
sin embargo, en el programa principal, la cadena es todava la misma
despues de llamar a la funcion.
La llamada a miembros_cortados() se hace con un argumento mutable,
en este caso una lista. Dentro de la funcion se a~naden varios
elementos a la lista, que permanecen en esta despues de la llamada.
FUNCTIONS
miembros_cortados(miebros)
Detalla las extremidades perdidas en la pelea
no_huyas_cobarde(amenaza)
Imprime las amenazas del caballero negro
La llamada a la funci on no huyas cobarde() se realiza con el argumento amenaza que se
ha denido en el programa principal hablaremos del concepto de programa principal en
breve como la cadena literal, No huyas cobarde!. En la funci on, se imprime la cadena y a
continuaci on la variable amenaza se asigna a una cadena diferente, que tambien se imprime.
De vuelta al programa principal, si imprimimos amenaza comprobamos que su valor no ha
sido afectado por la reasignaci on dentro de la funci on no huyas cobarde().
Consideremos ahora la llamada a una funci on con un argumento mutable. En el programa
principal denimos una lista vaca, miembros que pasamos a la funci on miembros cortados().
Dentro de esta a nadimos dos elementos a la lista. Cuando imprimimos la lista en el programa
principal vemos, que, en efecto, ha sido modicada.
caballero_negro1.py
No huyas cobarde!
Te matare a bocados
No huyas cobarde!
El caballero negro ha perdido los siguiente miembros:
[brazos, piernas]
La denici on de una funci on introduce el nombre de esta en la tabla de smbolos del
interprete. El valor asignado a dicho nombre tiene un tipo especco, que podramos llamar
funci on de usuario. Consecuentemente, como todo tipo puede ser asignado a un nombre
que puede ser utilizado como un pseud onimo de la funci on.
50
Para ilustrar este punto, vamos a usar la funci on de Fibonacci dentro del interprete:
>>> import fib #importamos la defincion de la funcion
>>> fib.fib(5) #accedemos a la funcion: modulo.funcion
i a b a+b
------------------------
1 0 1 1
2 1 1 2
3 1 2 3
4 2 3 5
5 3 5 8
>>> f=fib.fib # f es un sinonimo de fib.fib
>>> f(5)
i a b a+b
------------------------
1 0 1 1
2 1 1 2
3 1 2 3
4 2 3 5
5 3 5 8
>>> f2=f # otro sinonimo
>>> f2(5)
i a b a+b
------------------------
1 0 1 1
2 1 1 2
3 1 2 3
4 2 3 5
5 3 5 8
Como hemos comentado anteriormente, fib() se comportan como una subrutina m as que
como una funci on en el sentido de que no devuelve un valor. Veamos un ejemplo de funci on
que devuelve un valor. Consideremos una variante del c odigo que ya vimos para buscar
n umeros primos. El programa primos2.py calcula n umeros primos en un determinado rango
devolviendo el resultado en una lista. de tal manera
#!/usr/bin/env python
"""
Ejemplo de funcion en Python: La funcion prim()
toma como argumento el rango en el que deseamos buscar numeros primos y
devuelve el resultado en una lista
"""
def prim(rango):
51
"""
Busca numeros primos en un determinado rango y
devuelve el resultado en una lista
"""
primos = []
for n in range(2, rango):
for x in range(2, n):
if n % x == 0: # numero divisible
break
else: # numero primo
primos.append(n) # a~nadimos a la lista de primos
return primos
if __name__ == __main__:
rango = 100
print " Numeros entre 1 y",rango," -->:\n", prim(100)
Si ejecutamos directamente:
prim.py
Numeros entre 1 y 100 -->:
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61,
67, 71, 73, 79, 83, 89, 97]
o bien, en el interprete:
>>> import prim
>>> p=prim.prim
>>> p10 = p(10)
>>> print p10
[2, 3, 5, 7]
>>> p100 = p(100)
>>> print p100
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,
53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
Donde, como en el ejemplo anterior, accedemos en primer lugar a la denici on de la
funci on prim() importando el m odulo en el que est a denida. A continuaci on denimos por
comodidad el sin onimo p=prim.prim. Observemos que la funci on prim() devuelve uan lista
(va la instrucci on return) que podemos asignar a una variable, (tal como p10 o p100).
52
En la denici on de una funci on es posible especicar valores por defecto de los argumentos,
que son los que se utilizan en el cuerpo de la funci on a no ser que el usuario la invoque con
valores explcitamente diferentes.
Consideremos el algoritmo de Newton para el calculo de races cuadradas y que reescribi-
mos en forma de funci on en el chero newt.py.
#!/usr/bin/python
def newt(y,tol=1e-6, nmax=10000):
"""
Implementa el algoritmo de Newton para calcular el valor de
la raz cuadrada de un numero.
El algoritmo consiste en hallar aproximaciones sucesivamente mejores
de la raz cuadrada x=sqrt(y), basadas en la siguiente formula iterativa:
x(n+1) = 1/2 * ( x(n) + y / x(n) )
"""
x = float(y)
nint = 0
while abs(x*x - y) > tol or nint < nmax:
x = (x + y/x) / 2
nint +=1
return x
if __name__ == __main__:
print " La raz cuadrada de 2 es:", newt(2.)
print " La raz cuadrada de 20 es:", newt(20.,1e-5)
print " La raz cuadrada de 200 es:", newt(200.,1e-3,10)
Los argumentos de newt() son el valor del n umero cuya raz cuadrada queremos calcular,
la tolerancia del c alculo y el n umero maximo de iteraciones en caso de que no se alcance
la tolerancia. Los dos ultimos argumentos toman valores por defecto, de tal manera que
la funci on newt() puede llamarse con uno, dos, o tres argumentos, como se ilustra en el
programa principal. Desde el interprete:
>>> import newt
>>> n=newt.newt
>>> n(2.)
53
1.4142135623730949
>>> n(20.,1e-5)
4.4721359549995796
>>> n(200.,0.001,10)
14.14213562373095
7.2. Resumen: Codicaci on de funciones
Resumamos algunos de los conceptos que hemos introducido en las secciones anteriores:
La sentencia def es codigo ejecutable: Contrariamente a lo que ocurre en otros lenguajes
como C o C++, def es una sentencia en Python. Esto quiere decir que la funci on a
la que reere no se dene hasta que se ejecuta la sentencia. En C o C++ la funciones
deben declararse de antemano para evitar un error de compilaci on. Puesto que esto no
es necesario en Python, una funci on puede denirse en cualquier parte en el c odigo.
En el cuerpo de otra funci on, en el programa principal, o dentro de un bucle si as lo
deseamos.
La sentencia def crea un objeto y lo asigna a un nombre: En consecuencia, al igual
que cualquier otro objeto en Python, podamos asignar otro nombre a este nombre. De
ah que sea legal asignar a un nombre cualquiera el nombre de una funci on.
La sentencia return devuelve un objeto a quien haya invocado la funci on: Cuando
invocamos una funci on, el control no se devuelve a la porci on del programa que la
invoca hasta que se alcanza la sentencia return.
Los argumentos de la funcion se pasan por asignacion o referencia a objeto. En partic-
ular, esto quiere decir que si cambiamos dentro de la funci on un objeto inmutable que
se nos pasa por argumento, este objeto todava tiene su valor original cuando salimos
de la funci on. En cambio, si el objeto es mutable, los cambios a este se mantienen al
salir de la funci on.
No es necesario declarar de antemano los argumentos, valores devueltos o variables de
una funci on: Como cualquie otro tipo de objeto en Python, los argumentos de una
funci on adiquiere su tipo din amicamente y no es por tanto necesario declararlos.
7.3. Funciones de tipo lambda
Una funci on de tipo lambda es una funci on anonima (es decir que no esta asociada a un
nombre) que se invoca mediante el uso de la palabra clave lambda. Por ejemplo, una funci on
que devuelve la suma de sus dos argumentos utilizando esta forma sera lambda a, b: a+b.
La forma Lambda se utiliza a menudo para susituir la denici on formal de funciones sencillas.
Sint acticamente, una forma Lambda esta restringuida a una sola expresion.
54
7.4. Mapas
Una operaci on corriente cuando se programa utilizando secuencias, tales como listas, tu-
plas, etc., es la de aplicar una determinada funci on a todos los elementos de la secuencia.
Para ello, Python proporciona la funci on map().
Consideremos el siguiente ejemplo. El rey Arturo se propone armar nuevos caballeros de
la mesa cuadrada, cuyos nombres especicamos en la siguiente lista:
caballeros =[Percival,Gawain,Tirant,Brian,JJ]
Para ello aplica la funci on map() a la lista de nuevos caballeros:
map(lambda x: Sir +x,caballeros)
[Sir Percival, Sir Gawain, Sir Tirant, Sir Brian, Sir JJ]
La funci on map(f,sec) aplica la funci on f a la secuencia sec. En este caso hemos utilizado
una forma Lambda para denir f al vuelo. Alternativamente, podramos haber escrito:
def caballero(x):
return Sir + x
map(caballero,caballeros)
[Sir Percival, Sir Gawain, Sir Tirant, Sir Brian, Sir JJ]
7.5. Programaci on funcional
La funci on map() es el ejemplo mas sencillo de una clase de objetos Pitonicos que permite la
programaci on funcional es decir, la aplicaci on de funciones a secuencias. Otras dos funciones
interesantes son filter() y reduce().
La funci on filter() permite ltrar una secuencia de acuerdo a una condici on l ogica.
Consideremos por ejemplo la siguiente secuencia numerica:
range(-5,5)
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4]
Si queremos seleccionar ltrar los elementos de la secuencia mayores que cero, basta con
aplicar filter()
xf = filter( (lambda x: x>0), range(-5,5))
xf
[1, 2, 3, 4]
Para ilustrar el uso de la funci on reduce() supongamos que queremos sumar los elementos
de la secuencia anterior. Para ello nos basta con utilizar reduce(f,sec) que aplica la funci on
f a pares consecutivos de elementos en la secuencia sec.
reduce((lambda x,y: x+y),xf)
10
55
El efecto global es equivalente a aplicar la operaci on suma (denida en la Lambda) sobre las
parejas sucesivas formadas a partir del primer termino de la secuencia.
1+2
3+3
6+4
7.6. Operaciones de comprensi on en listas
Existe una manera mas concisa todava de aplicar funciones arbitrarias a listas. Como
ejemplo, consideremos el problema de calcular el cuadrado de los diez primeros n umeros
enteros. Utilizando map() necesitamos una lnea de codigo:
map(lambda x: x**2, range(11))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
Pero una comprensi on de la lista tiene el mismo efecto y es a un m as concisa:
[x**2 for x in range(11)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
Una comprension de lista no es mas que una operaci on arbitraria (tal como elevar al
cuadrado) aplicada sobre los elementos de una lista.
7.7. M odulos
El concepto de m odulo ya ha sido introducido informalmente en la secci on anterior. Pode-
mos denirlo ahora, de manera m as precisa como una unidad elemental en un programa
Python.
Un m odulo no es otra cosa que un chero Python, (con la correspondiente extensi on
.py) en el que hemos escrito una serie de deniciones. Como ya hemos visto, los cheros
fib.py, prim.py y newt.py pueden tratarse como m odulos. Es decir, podemos acceder a las
deniciones que contienen import andolos a otro chero de c odigo Python o al interprete.
En todos estos cheros, hemos a nadido un programa principal el c odigo que sigue a la
instrucci on if name == main : que se ejecuta cuando invocamos directamente al
interprete, pero se ignora cuando importamos el m odulo.
El nombre del m odulo coincide con el del chero donde lo almacenamos sin la extensi on py
en los ejemplos de la seccion precedente, tendramos los modulos fib, prim y newt. Para
acceder a las funciones, constantes, etc., denidas en el m odulo, tenemos que usar el forma-
to modulo.nombre, donde nombre representa el de una funci on, constante, etc., denida en
modulo. Existe la posibilidad de acceder a un n umero limitado de nombres (nombre1, nom-
bre2...) en un m odulo, mediante la sentencia, from modulo import nombre1, nombre2....
Tambien puede accederse directamente a todos los nombres que dene un m odulo mediante
la sentencia from modulo import *. Por ejemplo:
56
>>> from newt import newt
>>> newt(10.)
3.1622776601683791
>>> from fib import *
>>> fib(5)
i a b a+b
------------------------
1 0 1 1
2 1 1 2
3 1 2 3
4 2 3 5
5 3 5 8
Un m odulo puede importar otros m odulos. Por convenci on aunque no es obligatorio las
sentencias import se escriben al principio del m odulo o programa.
7.7.1. Localizaci on de m odulos en Python
Cuando importamos el nombre de un m odulo, por ejemplo, newt, el interprete busca en
primer lugar en el directorio de trabajo un chero newt.py. Si no lo encuentra, busca en
la lista de directorios especicada por la variable de entorno PYTHONPATH, cuya sintaxis es
identica a la variable de entorno PATH simplemente una lista de nombres de directorio. Si
la variable no se ha denido o si el chero no se encuentra en los directorios especicados en
esta, la b usqueda contin ua en una lista de directorios cuya denici on depende del sistema.
En Unix, a menudo, este lista por defecto es .:/usr/local/lib/python.
7.8. M odulos Estandar
Python se distribuye con una biblioteca de m odulos estandar. Ya hemos visto uno de ellos,
que utilizaremos con frecuencia en este curso, el modulo math, en el que se denen constantes
y funciones. Otro m odulo importante es sys, que permite acceso a los comandos del sistema
operativo. Adem as de los modulos est andar de Python, en este curso usaremos los m odulos
Gnuplot para gr acos y Numeric para manejo de vectores, matrices y en general todo
tipo de arreglos numericos.
7.9. La funci on dir()
La funci on dir() lista los nombres denidos por un m odulo. Por ejemplo:
>>> import math
>>> dir(math)
[__doc__, __file__, __name__, acos, asin, atan, atan2, ceil,
cos, cosh, degrees, e, exp, fabs, floor, fmod, frexp,
hypot, ldexp, log, log10, modf, pi, pow, radians, sin,
sinh, sqrt, tan, tanh]
57
58
Captulo 8
Vectores, matrices y arreglos
numericos en Python
8.1. Numerical Python
Numerical Python [2] es una extensi on de Python que permite manipular de manera r apida
y eciente arreglos numericos tales como vectores y matrices (pero tambien arreglos multi-
dimensionales de rango arbitrario). Un programa Python que maneje estos objetos ejecuta a
velocidades comparables con un programa escrito en C o C++. De hecho, Numerical Python
esta escrito como el propio interprete y toda extension a Python usando C. Adem as, las
operaciones entre vectores y matrices se realizan internamente recurriendo a las bibliote-
cas BLAS (Basic Linear Algebra System, http://www.netlib.org/blas/ ) LAPACK (Linear
Algebra Package, http://www.netlib.org/lapack/index.html) las cuales proporcionan una extensa
coleccion de rutinas para realizar de manera muy r apida y eciente operaciones entre vectores
y matrices as como operaciones de algebra lineal.
Numerical Python consiste de un conjunto de m odulos. El m as importante es Numeric.
Este modulo dene dos nuevos objetos. Arreglos numericos (objetos de tipo array) y funciones
universales que operan sobre estos arreglos (objetos de tipo ufunc).
Otro m odulo importante para este curso es el modulo de algebra lineal LinearAlgebra
que proporciona funciones para resolver sistemas lineales de ecuaciones, invertir matrices,
calcular autovalores, etc.
8.2. Objetos de tipo array
Un arreglo numerico (un objeto de tipo array) es una secuencia, similar a una lista o
una tupla. Se trata, sin embargo de una secuencia homogenea todos los elementos son del
mismo tipo, optimizada para almacenar n umeros y realizar operaciones entre ellos de manera
eciente y rapida.
Un array) se caracteriza especicando cuatro cantidades:
1. El tama no (size en ingles) del arreglo es el n umero total de elementos que contiene. Es
tama no de un arreglo no puede modicarse una vez creado este. Aunque es posible y
59
frecuente expandir o contraer un arreglo, estas operaciones resultan, como veremos,
en un nuevo arreglo. Dado un arreglo a, la funci on size(a) nos devuelve su tama no.
2. La forma (shape) del arreglo es el n umero de dimensiones del arreglo y su longitud en
cada una de estas dimensiones. Se especica mediante una tupla de enteros, cada uno
de los cuales representa una dimensi on del arreglo, mientras que su valor informa de la
longitud del arreglo en esa dimensi on. La forma de un arreglo a es uno de sus atributos,
a.shape. Como tal, puede modicarse. La funci on shape(a) tambien nos devuelve la
forma del atributo.
3. El rango (rank) de un arreglo es el n umero de dimensiones en el que esta denido, es
decir la longitud de su forma. Por lo tanto rango=len(a.shape). Tambien lo devuelve
la funci on rank(a).
4. El tipo (typecode) de un arreglo determina el tipo de n umeros (enteros, reales, com-
plejos...) que contiene.
Concretamente. Un vector es un arreglo de rango uno (s olo puede indexarse en una dimen-
sion). Una matriz es un arreglo de rango 2 (puede indexarse en dos dimensiones). Un arreglo
de rango 0 contendra un s olo n umero. Los arreglos de orden superior a dos representan
objetos multidimensionales.
>>>from Numeric import array
>>> vector1=array((1,2,3,4,5))
>>> vector1
array([1, 2, 3, 4, 5])
>>> len(vector1)
5
>>> vector1.shape
(5,)
>>> len(vector1.shape)
1
>>> matriz1=array(((0,1,2),(3,4,5),(0.1,0.5,7.)))
>>> len(matriz1)
3
>>> matriz1
array([[ 0. , 1. , 2. ],
[ 3. , 4. , 5. ],
[ 0.1, 0.5, 7. ]])
>>> matriz1.shape
(3, 3)
>>> len(matriz1.shape)
2
60
8.3. Manejo de arreglos numericos
8.3.1. Creaci on de un arreglo
Como hemos visto en el ejemplo anterior, la manera mas b asica de crear un arreglo es
mediante la funci on array().
>>> a=array([1.,2.,0.3,-1.])
>>> a
array([ 1. , 2. , 0.3, -1. ])
Formalmente, la funci on array(secuencia numerica,tipo,espacio) toma tres argu-
mentos. El primero es una secuencia numerica, es decir una lista o una tupla de n umeros.
El segundo argumento (opcional) es el tipo de los elementos(enteros, reales, complejos). El
tipo por defecto es entero, pero si especicamos n umeros reales (complejos) en la secuencia
inicial, el tipo autom aticamente se toma como real (complejo). El tercer argumento, tambien
opcional, sirve para optimizar espacio.
Los tipos mas corrientes son Numeric.Int, Numeric.Float y Numeric.Complex:
>>> ai=array((1,2,3,4),Numeric.Int)
>>> ai
array([1, 2, 3, 4])
>>> af=array((1,2,3,4),Numeric.Float)
>>> af
array([ 1., 2., 3., 4.])
>>> ac=array((1,2,3,4),Numeric.Complex)
>>> ac
array([ 1.+0.j, 2.+0.j, 3.+0.j, 4.+0.j])
8.3.2. Arreglos multidimensionales
Repasemos como denir una matriz. Por ejemplo:
>>> ma=array(((0.1,0.2,0.3),(1,2,3),(10,20,30)))
>>> ma
array([[ 0.1, 0.2, 0.3],
[ 1. , 2. , 3. ],
[ 10. , 20. , 30. ]])
El argumento que toma array() es una secuencia. En este caso una tupla, pero una lista
tambien sera un argumento correcto. En el ejemplo, la tupla contiene a su vez tres tuplas
(cada tupla representa una la de la matriz), cada una de ellas con tres n umeros. Hemos
denido por tanto una matriz 3 3. La forma del arreglo se obtiene mediante el atributo
ma.shape
>>> ma.shape
(3, 3)
61
La forma del arreglo es tambien una tupla, que especica simult aneamente el n umero de
dimensiones del arreglo o rango (la longitud de la tupla) y la longitud del arreglo en cada
dimensi on (en este caso la longitud en cada dimension es 3). En resumen, la forma del arreglo
nos informa que se trata de una matriz 3 3.
La longitud de la forma del arreglo es el rango. En este caso el rango es dos, como corre-
sponde a una matriz.
La funci on reshape() (que podramos traducir por algo as como reformatea) permite
crear un arreglo del mismo tama no que el arreglo original y diferente forma.
>>> va=Numeric.reshape(ma,(9,))
>>> va
array([ 0.1, 0.2, 0.3, 1. , 2. , 3. , 10. , 20. , 30. ])
La funci on reshape() toma como argumentos el arreglo cuya forma queremos modicar y
una tupla con la nueva forma y devuelve otro arreglo reformateado.
Ya hemos dicho que el tama no del arreglo es una cantidad inmutable. Esto no quiere
decir que no se pueda expandir, sino que cuando ejecutamos esta operaci on el arreglo se
sobreescribe. Existen muchas formas de expandir un arreglo. Una de ellas es usar la funci on
resize(), que de hecho puede expandir o encoger el arreglo, dependiendo de la nueva forma
que especiquemos en el segundo argumento (el primero es el arreglo original). Resaltemos
que (resize()) devuelve un nuevo arreglo, de tal manera que el original no se ve afectado.
>>> ma
array([[ 0.1, 0.2, 0.3],
[ 1. , 2. , 3. ],
[ 10. , 20. , 30. ]])
>>> ma_encoge=Numeric.resize(ma,(2,2))
>>> ma_encoge
array([[ 0.1, 0.2],
[ 0.3, 1. ]])
>>> ma_expande=Numeric.resize(ma,(4,4))
>>> ma_expande
array([[ 0.1, 0.2, 0.3, 1. ],
[ 2. , 3. , 10. , 20. ],
[ 30. , 0.1, 0.2, 0.3],
[ 1. , 2. , 3. , 10. ]]
Cuando encogemos el arreglo, el resultado contiene los elementos del principio del arreglo
original ordenados por las. Cuando lo expandimos a nadimos copias de los elementos del
arreglo original, tambien por las.
8.3.3. Creaci on de arreglos cuyos elementos se especican al vuelo
Muy a menudo es necesario manejar arreglos cuyos elementos no se conocen de antemano.
Una posibilidad, en ese caso es crear el arreglo inicializ andolo a ceros o a unos y luego
reescribir sus elementos del arreglo.
62
>>> z=Numeric.zeros((3,3))
>>> z
array([[0, 0, 0],
[0, 0, 0],
[0, 0, 0]])
>>> o=Numeric.ones((2,3))
>>> o
array([[1, 1, 1],
[1, 1, 1]])
Notad, sin embargo, que en este caso es importante especicar el tipo del arreglo, puesto que
por defecto nos devuelve un arreglo entero. Si por ejemplo queremos sobreescribir ahora el
primer elemento del arreglo con un n umero real:
>>> z[0][0]=0.5
>>> z
array([[0, 0, 0],
[0, 0, 0],
[0, 0, 0]])
Vemos que el valor ha sido truncado para darnos un entero. Si queremos un arreglo de reales,
por lo tanto, debemos especicar el tipo:
>>> z=Numeric.zeros((3,3),Numeric.Float)
>>> z
array([[ 0., 0., 0.],
[ 0., 0., 0.],
[ 0., 0., 0.]])
>>> z[0,0]=0.5
>>> z
array([[ 0.5, 0. , 0. ],
[ 0. , 0. , 0. ],
[ 0. , 0. , 0. ]])
8.3.4. Acceso a los elementos de un arreglo
Como cualquier otra secuencia, podemos acceder a los elementos de un arreglo numerico
mediante el operador []. En el caso de arreglos de rango uno (vectores) la notaci on es identica
a la que usamos para listas. Consideremos el siguiente ejemplo:
>>> from Numeric import *
>>> a=arrayrange(10)
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> a[0]
63
0
>>> a[1:5]
array([1, 2, 3, 4])
>>> a[-1]
9
>>> a[:-1]
Donde hemos introducido dos peque nas novedades. from Numeric import * nos da ac-
ceso directo a todos los nombres denidos en Numeric sin necesidad de que esten precedidos
por el nombre del m odulo. La funci on arrayrange() (que tambien puede escribirse, en no-
tacion m as concisa como arange()) es equivalente en el caso de arreglos numericos a la
funci on range() que vimos para listas. Aquella nos proporcionaba una lista de enteros y esta
nos proporciona un arreglo.
Las operaciones que nos permiten acceder a ndices y a porciones del arreglo son identicas
a las an alogas para una lista.
En el caso de arreglos multidimensionales, la notaci on vara. Consideremos:
>>> a=arrayrange(9)
>>> a.shape=(3,3)
>>> a
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
En este ejemplo creamos en primer lugar un arreglo cuyo tama no total son nueve elementos
y a continuaci on especicamos su forma (ya hemos dicho que la forma es un atributo y puede
modicarse). El arreglo resultante es una matrix 3 3.
En este caso, a[0] nos permite acceder a la primera la de la matriz (y no al primer
elemento!):
>>> a[0]
array([0, 1, 2])
Para acceder al primer elemento especicamos sus ndices en notacion matricial:
>>> a[0,0]
0
>>> a[0,1]
1
>>> a[0,2]
2
La misma notaci on es valida para escribir los elementos del arreglo:
>>> a[0,0]=10
64
>>> a[0,1]=20
>>> a[0,2]=30
>>> a
array([[10, 20, 30],
[ 3, 4, 5],
[ 6, 7, 8]])
>>> a[1]=[100,200,300]
>>> a
array([[ 10, 20, 30],
[100, 200, 300],
[ 6, 7, 8]])
Cuando accedemos directamente a una la de la matriz, como en el ejemplo es necesario
que la lista de valores de entrada sea del tama no correcto (tres en este caso).
8.3.5. Cortes sobre un arreglo
Para ilustrar las operaciones de corte sobre un arreglo, consideremos el siguiente ejemplo:
>>> a=reshape(arrayrange(9),(3,3))
>>> a
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
El operador [n,:0] nos permite acceder a la la n del arreglo
>>> a[0,:]
array([0, 1, 2])
>>> a[1,:]
array([3, 4, 5])
>>> a[2,:]
array([6, 7, 8])
Mientras que el operador [:n] nos permite acceder a la columna n del arreglo
>>> a[:,0]
array([0, 3, 6])
>>> a[:,1]
array([1, 4, 7])
>>> a[:,2]
array([2, 5, 8])
8.3.6. Operaciones sobre un arreglo
En general, una operaci on sobre un arreglo numerico esta denida elemento a elemento.
Por ejemplo:
65
>>> a=arrayrange(5)
>>> a
array([0, 1, 2, 3, 4])
>>> a+5
array([5, 6, 7, 8, 9])
>>> a*3
array([ 0, 3, 6, 9, 12])
>>> sin(a)
array([ 0., 0.84147098, 0.90929743, 0.14112001, -0.7568025 ])
Donde podemos ver que las operaciones suma y producto (con un escalar) se realizan para
cada uno de los elementos del arreglo.
An alogamente, dos arreglos operan entre s elemento a elemento.
>>> b=2*arrayrange(5)
>>> b
array([0, 2, 4, 6, 8])
>>> a
array([0, 1, 2, 3, 4])
>>> a+b
array([ 0, 3, 6, 9, 12])
>>> a*b
array([ 0, 2, 8, 18, 32])
Es importante darse cuenta que estas operaciones no se corresponden a las operaciones de
algebra lineal entre vectores. Tampoco es as en el caso de matrices:
>>> a=reshape(arrayrange(9),(3,3))
>>> a
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
>>> b=2*reshape(arrayrange(9),(3,3))
>>> b
array([[ 0, 2, 4],
[ 6, 8, 10],
[12, 14, 16]])
>>> a+b
array([[ 0, 3, 6],
[ 9, 12, 15],
[18, 21, 24]])
>>> a*b
array([[ 0, 2, 8],
[ 18, 32, 50],
[ 72, 98, 128]])
Las operaciones de algebra lineal se denen mediante funciones especicas. Por ejemplo, el
producto escalar de dos vectores se calcular mediante las funciones innerproduct() y dot().
66
El productor vectorial mediante outerproduct()
>>> a=arrayrange(1,10,2)
>>> a
array([1, 3, 5, 7, 9])
>>> b=arrayrange(1,15,3)
>>> b
array([ 1, 4, 7, 10, 13])
>>> innerproduct(a,b)
235
>>> dot(a,b)
235
>>> outerproduct(a,b)
array([[ 1, 4, 7, 10, 13],
[ 3, 12, 21, 30, 39],
[ 5, 20, 35, 50, 65],
[ 7, 28, 49, 70, 91],
[ 9, 36, 63, 90, 117]])
An alogamente, para matrices:
>>> a=reshape(arrayrange(1,12,2),(3,2))
>>> a
array([[ 1, 3],
[ 5, 7],
[ 9, 11]])
>>> b=reshape(arrayrange(2,18,3),(2,3))
>>> b
array([[ 2, 5, 8],
[11, 14, 17]])
>>> dot(a,b)
array([[ 35, 47, 59],
[ 87, 123, 159],
[139, 199, 259]])
>>> dot(b,a)
array([[ 99, 129],
[234, 318]])
8.3.7. Funciones que operan sobre arreglos numericos
Numeric dene un amplio n umero de funciones universales (objetos de tipo ufunc) que
operan sobre arreglos numericos, ejecutando la operaci on que especican elemento a elemento.
Esta es la lista completa:
add logical_or exp
67
subtract logical_xor log
multiply logical_not log10
divide maximum sin
divide_safe minimum sinh
conjugate bitwise_and sqrt
power bitwise_or tan
absolute bitwise_xor tanh
negative invert ceil
greater left_shift fabs
greater_equal right_shift floor
less arccos arctan2
less_equal arcsin fmod
equal arctan hypot
not_equal cos around
logical_and cosh sign
arccosh arcsinh arctanh
As, por ejemplo:
>>> from Numeric import *
>>> pi
3.1415926535897931
>>> e
2.7182818284590451
>>> a=0.1*pi*arrayrange(10)
>>> a
array([ 0., 0.31415927, 0.62831853, 0.9424778 , 1.25663706, 1.57079633,
1.88495559, 2.19911486, 2.51327412, 2.82743339])
>>> sin(a)
array([ 0, 0.30901699, 0.58778525, 0.80901699, 0.95105652, 1.,
0.95105652, 0.80901699, 0.58778525, 0.30901699])
8.3.8. Funciones que manipulan arreglos
Numeric dene una serie de funciones muy utiles para manejar arreglos y en general
cualquier secuencia de Python. Algunas de las m as importantes son:
take(a, indices, eje=0). Permite extraer una porci on cualquiera de un arreglo, re-
sultando en otro arreglo del mismo rango que el original.
>>> a
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
68
[12, 13, 14, 15],
[16, 17, 18, 19]])
>>> take(a,(0,)) #primera fila (indice es el 0, eje es el 0=x)
array([ [0, 1, 2, 3]])
>>> take(a,(0,1)) #primera y segunda fila (indices 0 y 1 eje x)
array([[0, 1, 2, 3],
[4, 5, 6, 7]])
>>> take(a,(0,-1)) #primera y ultima fila
array([[ 0, 1, 2, 3],
[16, 17, 18, 19]])
>>> take(a,(0,),1) #primera columna (indice 0 eje 1 = y)
array([[ 0],
[ 4],
[ 8],
[12],
[16]])
>>> take(a,(0,1),1) #primera y segunda columna (indice 0 y 1 eje y)
array([[ 0, 1],
[ 4, 5],
[ 8, 9],
[12, 13],
[16, 17]])
put(a, ndices, valores). Es la opuesta a take. Los valores de a, en la posici on
especicada por los ndices, se asignan a los valores.
>>> x=arange(6)
>>> x
array([0, 1, 2, 3, 4, 5])
>>> put(x,[2,4],[20,40])
>>> x
array([ 0, 1, 20, 3, 40, 5])
transpose(a, eje=ninguno). Devuelve un arreglo de acuerdo al orden de los ejes
especicado por el segundo argumento. Por defecto invierte los ejes (para una matriz
produce la matriz transpuesta).
>>> a
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19]])
>>> transpose(a)
array([[ 0, 4, 8, 12, 16],
69
[ 1, 5, 9, 13, 17],
[ 2, 6, 10, 14, 18],
[ 3, 7, 11, 15, 19]])
diagonal(a, k=0, eje1=0, eje2=1). Devuelve los elementos de la k-esima diagonal,
donde k mide el desplazamiento con respecto a la diagonal principal ( que vale k = 0).
>>> a
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19]])
>>> diagonal(a)
array([ 0, 5, 10, 15])
>>> diagonal(a,1)
array([ 1, 6, 11])
trace(a, k=0). Devuelve la suma de los elementos en la diagonal k.
>>> trace(a)
30
>>> trace(a,1)
18
sort(a, eje=-1) Devuelve un arreglo identico a a, en el que sus elementos han sido
ordenados respecto al eje especicado.
dot(m1,m2) Multiplicaci on de matrices (sin transponer).
innerproduct(a,b). Producto interno de a y b. Es el producto escalar para vectores.
Para matrices es equivalente a matrixmultiply(a,transpose(b)). Tambien multiplica
una matrix por un vector.
outerproduct(a,b). Producto vectorial de los vectores a y b.
identity(n). Devuelve un arreglo la matriz identidad n n.
8.3.9. El m odulo de

Algebra Lineal
El m odulo LinearAlgebra da acceso a las operaciones de algebra lineal m as importantes:
solve linear equations(a, b).
Resuelve un sistema de ecuaciones lineales donde a es una matriz cuadrada no singular
y b un vector columna. La funci on inverse(a) permite calcular la matriz inversa de a,
resolviendo el sistema de ecuaciones lineales con un conjunto de vectores base de a. El
determinante viene dado por la funci on determinant(a).
70
eigenvalues(a).
Devuelve los autovalores de la matriz cuadrada a
eigenvectors(a).
Devuelve los autovalores (u) y autovectores (v, donde v es una matriz de autovectores, en
la que v[i] es el vector que se corresponde al autovalor u[i]) de a. Consecuentemente
los u,v satisfacen la ecuaci on: dot(a, v[i]) = u[i]*v[i]
Heigenvalues(a).
Devuelve los autovalores (reales y positivos) de la matriz hermtica, cuadrada, positiva
denida a.
Heigenvectors(a).
Devuelve los autovalores y autovectores de la matriz hermtica, cuadrada, positiva
denida a.
cholesky decomposition(a).
Realiza la descomposicion de Choleski de una matriz cuadrada, hermtica y denida
positiva. Devuelve una matriz triangular inferior L, que multiplicada por su traspuesta
resulta en la matriz original.
inverse(a).
Calcula la inversa de la matriz cuadrada, no singular a.
determinant(a).
Calcula el determinante de a.
71
72
Captulo 9
Representaci on graca de funciones
9.1. Representaci on graca de funciones
Numerosos problemas en fsica y matematicas requieren la posibilidad de representar gr a-
camente funciones de una o mas dimensiones. Por ejemplo la soluci on de la ecuaci on no lineal:
x = cos(x)
puede obtenerse sin m as que representar ambas funciones gr acamente para ver d onde se
cruzan. Alternativamente, podemos representar la funci on x cos(x) para estudiar d onde
corta el eje de abcisas.
-8
-6
-4
-2
0
2
4
6
-6 -4 -2 0 2 4 6
f(x) = x-cos x
Figura 9.1: La funci on x cos x en el intervalo [, ].
En este curso vamos a adoptar como herramienta gr aca el paquete gnuplot (http://www.gnuplot.info/).
Se trata de un programa r apido, vers atil, potente y relativamente sencillo de utilizar. Adem as,
un programa Python puede comunicarse directamente con gnuplot gracias al modulo Gnuplot
(http://gnuplot-py.sourceforge.net/). En este captulo ilustraremos el uso tanto de gnuplot como
del modulo Python Gnuplot.
73
9.2. El programa graco gnuplot
El programa gnuplot puede obtenerse libremente en la red para una variedad de platafor-
mas, incluyendo sistemas Unixy Windows. Al igual que Python, gnuplot puede utilizarse
de manera interactiva. En Unix, asumiendo que el ejecutable esta denido en el campo de
b usqueda de binarios del sistema (por ejemplo, si se instala en uno de los directorios est andar
(tal como /usr/bin o /usr/local/bin) basta con teclear:
gnuplot
G N U P L O T
Version 4.0 patchlevel 0
last modified Thu Apr 15 14:44:22 CEST 2004
System: Darwin 7.7.0
Copyright (C) 1986 - 1993, 1998, 2004
Thomas Williams, Colin Kelley and many others
This is gnuplot version 4.0. Please refer to the documentation
for command syntax changes. The old syntax will be accepted
throughout the 4.0 series, but all save files use the new syntax.
Type help to access the on-line reference manual.
The gnuplot FAQ is available from
http://www.gnuplot.info/faq/
Send comments and requests for help to
<gnuplot-info@lists.sourceforge.net>
Send bugs, suggestions and mods to
<gnuplot-bugs@lists.sourceforge.net>
Terminal type set to x11
gnuplot>
Gnuplot Donde la llamada de atenci on gnuplot> nos indica que el programa est a esperando
una acci on del usuario. Por ejemplo, para representar gr acamente la la funci on x cos x
(gura 9.1)hacemos:
gnuplot> set zeroaxis
gnuplot> plot[-pi:pi] x-cos(x)
Para salir del interprete de gnuplot, al igual que para el interprete de Python, tecleamos
Control-D en Unix.
Continuando con la analoga entre gnuplot y Python, podramos armar que, de hecho,
gnuplot no es otra cosa que un sencillo lenguaje de programaci on, orientado especcamente
74
a la representacion gr aca de funciones. Como tal, el interprete de gnuplot reconoce cier-
tos tipos de datos, en este caso n umeros enteros, reales o complejos que puede asociar a
variables y constantes. Dichas variables pueden relacionarse entre s para formar expresiones,
mediante una serie de operadores. Por ultimo, gnuplot reconoce funciones, tanto intrnsecas
como denidas por el usuario.
Las expresiones m as importantes en gnuplot son los comandos esto es instrucciones que
resultan en una acci on especca, como la de dibujar una funci on plot,splot y replot, que
permiten la representaci on gr acas de curvas en dos y tres dimensiones.
9.2.1. Expresiones en gnuplot
En general, cualquier expresi on matematica aceptada por C, FORTRAN o Python es
v alida en gnuplot. La precedencia de los operadores es la misma que en Python.
Tambien al igual que Python gnuplot distingue entre aritmetica de enteros y reales. El
n umero 10 se interpreta como un entero, mientras que 10. se toma como un real. La divisi on
real resulta en un real 5.0/2.0 = 2.5, mientras que la entera resulta en un entero que
trunca la parte decimal 5/2 = 2. En operaciones mixtas los enteros son promocionados a
reales autom aticamente.
9.2.2. Funciones en gnuplot
Las funciones de gnuplot son las mismas que las correspondientes funciones de la bib-
lioteca matematica de Unix.
75
Funciones de la biblioteca matem atica
Funci on Argumento Devuelve
abs(x) cualquiera valor absoluto de x, [x[;
abs(x) complejo

real(x)
2
+ imag(x)
2
acos(x) cualquiera cos
1
x
acosh(x) cualquiera cosh
1
x
arg(x) complejo fase de x
asin(x) cualquiera sin
1
x
asinh(x) cualquiera sinh
1
x
atan(x) cualquiera tan
1
x
atan2(y,x) int o real tan
1
(y/x)
atanh(x) cualquiera tanh
1
x
besj0(x) int o real j
0
funci on de Bessel de x
besj1(x) int o real j
1
funci on de Bessel de x
besy0(x) int o real y
0
funci on de Bessel de x
besy1(x) int o real y
1
funci on de Bessel de x
ceil(x) cualquiera x|, menor entero mas peque no que x (parte real)
cos(x) cualquiera cos x
cosh(x) cualquiera cosh x
erf(x) cualquiera erf(real(x)), funci on error de x real
erfc(x) cualquiera erfc(real(x)), 1.0 - funci on error de x real
exp(x) cualquiera e
x
oor(x) cualquiera x|, Mayor entero no m as grande que x (parte real)
gamma(x) cualquiera gamma(real(x)), funci on gamma
ibeta(p,q,x) cualquiera ibeta(real(p, q, x)), funci on ibeta del real(p,q,x)
inverf(x) cualquiera funci on error inversa del real(x)
igamma(a,x) cualquiera igamma(real(a, x)), funci on igamma del real(a,x)
imag(x) complejo parte imaginaria part de x
invnorm(x) cualquiera inversa de la distribuci on normal
int(x) real parte entera de x, truncada hacia cero
lambertw(x) real Funci on de Lambert W
lgamma(x) cualquiera lgamma(real(x)), funci on lgamma
log(x) cualquiera log
e
x, logaritmo natural (base e) de x
log10(x) cualquiera log
10
x, logaritmo (base 10) de x
norm(x) cualquiera distribuci on normal (Gaussiana)
rand(x) cualquiera rand(x), generador de n umeros pseudo aleatorios
real(x) cualquiera parte real de x
sgn(x) cualquiera 1 si x > 0, -1 if x < 0, 0 si x = 0. ignora imag(x)
sin(x) cualquiera sin x
sinh(x) cualquiera sinh x
sqrt(x) cualquiera

x
tan(x) cualquiera tan x
tanh(x) cualquiera tanh x
76
9.2.3. Operadores
Los operadores en gnuplot son los mismos que en Python, incluyendo el operador ** para
exponenciaci on. La precedencia es la misma que en Python. El uso de parentesis permite
cambiar la precedencia.
9.2.4. Representaci on graca de funciones
Existen tres comandos en gnuplot que producen un gr aco: plot, splot y replot. El
comando plot genera gracas de dos dimensiones, splot genera gracas de tres dimensiones
(en realidad proyecciones bidimensionales, por supuesto) y replot permite repetir la gr aca
anterior en la misma pantalla.
Existe un amplio n umero de comandos set que proporcionan control sobre ejes, escala,
ttulos, etc., para plot y splot.
9.2.5. El comando plot
El comando mas importante de gnuplot es plot, que puede crear representaciones gr acas
de funciones y datos de muchas maneras diferentes.
La sintaxis es la siguiente:
plot {<ranges>}
{<function> | {"<datafile>" {datafile-modifiers}}}
{axes <axes>} {<title-spec>} {with <style>}
{, {definitions,} <function> ...}
Donde el comando require bien una funci on (<function> ) o el nombre de un chero de
datos entre comillas Una funci on es una expresion matematica v alida o una pareja de el-
las en el modo parametrico. Una forma de entender el concepto de funci on en gnuplot es
imagin arselas como variantes de la forma Lambda de Python, es decir una secuencia de fun-
ciones elementales (como las denidas en la table 9.2.2), variables y constantes, relacionadas
mediante operadores. Por ejemplo:
gnuplot> f(x)=x*sin(x)+(1./2.)*cos(x)**2+exp(abs(x)/100.)
gnuplot> plot[-pi:pi] f(x)
Produce una representaci on gr aca de la funci on xsin(x) +
1
2
cos(x)
2
exp(x/100), en el
intervalo cerrado, [, ] (gura 9.2).
En modo parametrico las expresiones matematicas deben proporcionarse en pares. Por
ejemplo:
plot sin(t),t**2
Produce la funci on de la gura 9.3.
Como ya hemos visto, es posible especicar los rangos en los que se desea dibujar una
determinada funci on. Por ejemplo, para denir el rango s olo en x:
77
plot [-10:30] sin(pi*x)/(pi*x)
mientras que para denir el rango en x e y:
plot [-pi:pi] [-3:3] tan(x), 1/x
Ademas de funciones plot puede representar el contenido de un chero de datos, si se
especica el nombre del chero entre comillas. La sintaxis es:
plot <file_name> {index <index list>}
{every <every list>}
{thru <thru expression>}
{using <using list>}
{smooth <option>}
Donde el papel de los modicadores index, every, thru, using, y smooth es el siguiente:
index selecciona el suboconjunto de datos relevante en un chero que contiene un conjunto
mas amplio del que se desea representar; every especica que puntos se representan dentro
del subconjunto especicado (cada cu antos puntos dibuja); using dene una lista espcecca
a representar dentro del conjunto de datos ( thru es un caso particular de using) y smooth
permite aproximar o interpolar curvas a los datos.
Los cheros de datos deben contener al menos un punto con una pareja de datos (x, y) por
lnea. Si una lnea comienza por # se considera un comentario, como en Python. Si se quieren
incluir errores, hay diferentes posibles formatos, dependiendo del nivel de informaci on que se
requiera en los errores. En notaci on evidente: (x, y, ydelta), (x, y, ylow, yhigh), (x, y, xdelta),
(x, y, xlow, xhigh), or (x, y, xlow, xhigh, ylow, yhigh).
Cada n umero en el chero viene separado por un blanco o tabulador, que divide cada lnea
en columnas.
La opcion with
En gnuplot tnato los datos como las funciones pueden representarse utilizando una amplia
variedad de estilos, proporcionados por la palabra clave with.
with <style> { {linestyle | ls <line_style>}
| {{linetype | lt <line_type>}
{linewidth | lw <line_width>}
{pointtype | pt <point_type>}
{pointsize | ps <point_size>}
{fill | fs <fillstyle>}
{palette}}
}
donde <style> se reere a los siguientes estilos: lines, points, linespoints, impuls-
es, dots, steps, fsteps, histeps, errorbars, xerrorbars, yerrorbars, xyerrorbars, er-
rorlines, xerrorlines, yerrorlines, xyerrorlines, boxes, lledcurves, boxerrorbars,
78
boxxyerrorbars, nancebars, candlesticks, vectors or pm3d. Con with podemos tam-
bien modicar el estilo, tipo y anchura de la lnea, el tama no del punto, etc.
Algunos ejemplos:
Dibuja sin(x) con impulsos:
plot sin(x) with impulses
Dibuja x con puntos, x
2
con el defecto:
plot x w points, x**2
Dibuja sin(x) y cos(x) con linespoints, usando la misma lnea y puntos de diferente
tama no:
plot sin(x) with linesp lt 1 pt 3, cos(x) with linesp lt 1 pt 4
La gura 9.4 ilustra estos ejemplos.
9.2.6. El comando splot
El comando splot permite dibujar supercies tridimensionales (o, para ser m as exactos,
proyecciones de estas en supercies bidimensionales). Al igual que plot, puede crear un gr aco
a partir de una funci on o un chero de datos.
La sintaxis es la siguiente:
splot {<ranges>}
<function> | "<datafile>" {datafile-modifiers}}
{<title-spec>} {with <style>}
{, {definitions,} <function> ...}
Donde el comando requiere bien una funci on, <function> o el nombre de un chero de
datos entre comillas. En el modo parametrico se requieren tres funciones.
Las opciones para denir rangos, ejes, ttulos etc., son similares a las de plot.
Tambien, como en el caso de plot, podemos representar datos almacenados en un chero.
La sintaxis es:
splot <file_name> {binary | matrix}
{index <index list>}
{every <every list>}
{using <using list>}
Donde binary y matrix indican que los datos tienen una forma especial (por ejemplo
estan escritos en formato binario) index seleciona las columnas que quieren representars y
every especica los puntos dentro de esas columnas. El signicado de using es el mismo que
para plot.
Como ejemplo la gura 9.5 muestra el gr aco 3d y la proyeccion bidimensional en lneas
de nivel (contorno o mapa de isobaras) de la funci on f(x, y) = cos(x) cos(y) obtenida a partir
de los comandos:
79
set xrange [-pi/2:pi/2]; set yrange [-pi/2:pi/2]
set style function lp
set contour
set isosamples 10,10; set samples 10,10;
splot cos(x)*cos(y)
set samples 4,10; replot
set samples 10,4; replot
9.3. Uso del m odulo Gnuplot
El m odulo Gnuplot, tambien disponible libremente en la red (http://gnuplot-py.sourceforge.net/)
permite acceder directamente a gnuplot desde un programa Python.
Para ilustrar su uso, hemos preparado una serie de ejemplos en los m odulos gfun.py y
gnplot.py. El primero contiene las funciones f1 (que generan la gura 9.2), param1 (gura
9.3), rangos (ejemplos en el texto de denici on del rango de una funci on), estilos (gura
9.4) y cos2d (gura 9.5)
Para utilizarlo, basta con importar el m odulo:
>>> import gfun
Para generar cualquiera de los gr acos invocamos a la funci on apropiada. Por ejemplo,
para el gr aco de la gura 9.2:
>>> gfun.f1()
Veamos el codigo de la funci on f1():
import Gnuplot
def f1():
"""
Ilustra el concepto de funcion en gnuplot
"""
# g es un objeto de tipo Gnuplot.
# Para enviar comandos directamente desde Python hasta gnuplot
# basta con hacer g(comando), donde comando es una cadena literal
# que se corresponde a un comando de gnuplot.
g = Gnuplot.Gnuplot()
# f(x) es una funcion matematica valida para gnuplot.
# consiste en una combinacion de funciones elementales
# (sin(x), cos(x), exp(x), abs(x), constantes, variables
80
# y operadores (+,-,*,**).
g("f(x)=x*sin(x)+(1./2.)*cos(x)**2+exp(abs(x)/100.)")
g("plot[-pi:pi] f(x)")
# Creamos un fichero postscript en color
g("set terminal postscript color")
# y desviamos la salida hacia un fichero postscript
g("set output plots/f1.ps")
# Repetimos el plot (la salida va al fichero postscript)
g("plot[-pi:pi] f(x)")
print (\n****** Figura escrita en el fichero "plots/f1.ps" ******\n)
raw_input(Return para continuar...\n)
En las primera instruccion importamos el m odulo Gnuplot que nos permite crear un objeto
de tipo gnuplot mediante la instrucci on g=Gnuplot.Gnuplot(). Utilizando este objeto
podemos enviar comandos a gnuplot, escritos como cadenas de caracteres. Por ejemplo:
g("f(x)=x*sin(x)+(1./2.)*cos(x)**2+exp(abs(x)/100.)")
g("plot[-pi:pi] f(x)")
Todas las funciones del m odulo gfun se limitan a enviar comandos a gnuplot, utilizando
la interfase. Sin embargo, el m odulo Gnuplot ofrece una funcionalidad m as amplia, que se
ilustra en el modulo gnplot.
El m odulo gnplot contiene las funciones g1, g2,g3,g4,g5 y g3da que comentamos a con-
tinuaci on. Para ejectuar estas funciones (g1 en el ejemplo):
import gnplot
gnplot.g1()
La funci on g1() representa gr acamente la funcion f(x) = x cos(x) de la gura 9.1.
Como todas las funciones del m odulo gfun, se limita a crear un objeto de tipo Gnuplot y
utilizarlo para enviar comandos al programa gr aco. Este es el codigo:
from Numeric import *
import Gnuplot, Gnuplot.funcutils
def g1():
"""
Representa graficamente la funcion f(x)=x-cos(x) tanto en pantalla
81
como en un fichero postscript
Para ello crea un objeto grafico de tipo g=Gnuplot() que
puede comunicarse directamente con el programa gnuplot.
En este ejemplo g se limita a pasar directamente comandos
a gnuplot, via cadenas de caracteres.
"""
g = Gnuplot.Gnuplot() # g es un objeto de tipo Gnuplot
g("set zeroaxis") # dibuja los ejes
g("set xlabel x") # leyenda en el eje x
g("set ylabel x -cos(x)") # leyenda en el eje y
# dibujamos la funcion x-cos(x) en el rango entre -pi pi
# usando el comando "plot" de gnuplot.
g("plot[-pi:pi] x-cos(x) title f(x)=x-cos(x) ")
# Creamos un fichero postscript en color
g("set terminal postscript color")
# y desviamos la salida hacia un fichero postscript
g("set output plots/xcosx.ps")
# Repetimos el plot (la salida va al fichero postscript)
g("plot[-pi:pi] x-cos(x)")
print (\n****** Figura escrita en el fichero "plots/xcosx.ps" ******\n)
raw_input(Return para continuar...\n)
En este modulo, adem as de Gnuplot, importamos Gnuplot.funcutils y Numeric cuyo
uso ilustraremos mas adelante. La funci on g1() nos permite ilustrar algunos de los comandos
set de gnuplot, tales como set zeroaxis (dibuja los ejes), set xlabel etiqueta (escribe una
etiqueta bajo el eje x), set ylabel etiqueta (escribe una etiqueta bajo el eje y). El comando
plot nos permite dibujar la funci on x cos(x) en el rango [, ].
La funci on g2() es una variante de g1() en la que se utilizan algunos metodos espec-
cos de los objetos de tipo Gnuplot, cuyo efecto es el mismo que los correspondientes co-
mandos de gnuplot, pero cuya sintaxis es mas concisa. As, por ejemplo, podemos us-
ar g.xlabel(etiqueta) en lugar de g("set xlabel etiqueta") y an alogamente para
g.ylabel(etiqueta) y g.title(etiqueta). Tambien podemos usar el metodo g.plot(f)
en lugar de g(plot f) donde f es una funci on. Finalmente, el metodo g.hardcopy()
produce una copia del gr aco en un chero .ps.
def g2():
82
"""
Representa graficamente la funcion f(x)=x-cos(x) tanto en pantalla
como en un fichero postscript
Introduce el uso de algunos metodos especificos de los objetos
de tipo Gnuplot, concretamente:
g.xlabel(), g.ylabel(), g.title() y g.hardcopy()
"""
g = Gnuplot.Gnuplot()
g("set zeroaxis")
g("set xrange[-pi:pi]") # define el rango de x
# Leyendas en los ejes. Utiliza las funciones
# g.xlabel(leyenda), g.ylabel(leyenda) y g.title(leyenda) donde
# leyenda es una cadena de caracteres.
g.xlabel(x)
g.ylabel(x -cos(x))
g.title(f(x)=x-cos(x))
# dibujamos la funcion
# usando el comando "g.plot("f") donde f es una funcion
# escrita en sintaxis de gunplot
g.plot("x-cos(x)")
# copia en ps
g.hardcopy(plots/xcosx2.ps, enhanced=1, color=1)
print (\n****** Figura escrita en el fichero "plots/xcosx2.ps" ******\n)
raw_input(Return para continuar...\n)
g.reset()
Las funciones g1(), g2() y g3() identica a g2() excepto por el uso del comando g.plot(Gnuplot.Func(x-cos
title=")) en lugar de g.plot("x-cos(x)") ilustran la representacion gr aca de fun-
ciones denidas por gnuplot. El cliente en este caso nuestro programa Python se limita
a especicar va el objeto gr aco del modulo Gnuplot una funci on que el programa gnuplot
reconoce, utilizando la sintaxis de gnuplot.
Para representar una funci on arbitraria, f, por otra parte, es deseable contar con la ca-
pacidad de denir la funci on en Python y enviar a gnuplot una serie de arreglos en los que se
denen las abcisas y ordenadas, x, f(x). Los siguientes ejemplos utilizan esta tecnica. g4()
crea un arreglo numerico para representar las abcisas y lo eval ua utilizando la funci on map()
para representar las ordenadas. La funci on Gnuplot.Data() permite almacenar en un objeto
de datos d ambos arreglos, junto con algunas opciones como el ttulo del gr aco o el tipo de
representacion, puntos, lneas, etc. Finalmente el metodo g.plot(d) representa este objeto
de datos.
83
def g4():
"""
Representa graficamente la funcion f(x) =x-cos(x).
Para ello crea un arreglo
con una tabla de abcisas x, y un arreglo con una tabla de ordenadas
f(x).
"""
g = Gnuplot.Gnuplot()
g("set zeroaxis")
g("set xrange[-pi:pi]")
g.xlabel(x)
g.ylabel(x -cos(x))
g.title(f(x)=x-cos(x))
# crea un arreglo con los valores de las abcisas
xx = arange(-pi,pi,0.1)
# calcula las ordenadas
# map(f, xx) aplica la funcion f a todos los elementos de la
# secuencia xx
# f se define al vuelo como f(x)=x-cos(x) usando una forma Lambda
yy = map(lambda x: x-cos(x),xx)
# Creamos un objeto grafico y lo almacenamos en la variable d
d = Gnuplot.Data(xx, yy,
title=f(x) = x-cos(x): Python,
with=points 1 2)
# Representamos el objeto grafico
g.plot(d)
g.hardcopy(plots/xcosx4.ps, enhanced=1, color=1)
print (\n****** Figura escrita en el fichero "plots/xcosx4.ps" ******\n)
raw_input(Return para continuar...\n)
g.reset()
La funci on g5() es una variante de g4() en la que denimos el arreglo que representa las ab-
cisas y la funci on que deseamos representar y utilizamos Gnuplot.funcutils.compute Data()
para evaluar autom aticamente el valor de las ordenadas.
def g5():
84
"""
Representa graficamente la funcion x-cos(x). Para ello crea un array
con una tabla de abcisas que se evalua con la funcion ComputeGrid
"""
g = Gnuplot.Gnuplot()
g("set zeroaxis")
g("set xrange[-pi:pi]")
g.xlabel(x)
g.ylabel(x -cos(x))
g.title(f(x) = x-cos(x))
g(set data style lines) # lineas
# vector de abcisas
xx = arange(-pi,pi,0.1)
# dibujamos la funcion x-cos(x)
# usando el comando "plot" con la opcin
# funcutils.compute_Data(x,f, binary=0)
# que calcula el valor de la funcion f en el arreglo x y
# lo manda directamente a Gnuplot.
# En lugar de una forma lambda como en el ejemplo anterior
# definimos explicitamente
# la funcion f. Notad que f puede definirse en cualquier
# parte del codigo.
# binary = 0 por compatibilidad con versiones antiguas de gnuplot
# (binary=1 es mas rapido pero solo esta implementado en versiones
# muy recientes de gnuplot)
def f(x):
return x-cos(x)
g.plot(Gnuplot.funcutils.compute_Data(xx,f, binary=0))
g.hardcopy(plots/xcosx5.ps, enhanced=1, color=1)
print (\n****** Figura escrita en el fichero "plots/xcosx5.ps" ******\n)
raw_input(Return para continuar...\n)
g.reset() # clean up
Finalmente, la funci on g3da ilustra el uso de funciones 3D, utilizando splot().
85
def g3da():
"""
Ilustra el uso de splot
"""
g = Gnuplot.Gnuplot()
g.xlabel(x)
g.ylabel(y)
g.title(Graficos en 3d)
# define los nodos -- puntos (x,y)-- donde evaluaremos la funcion
x = arange(35)/2.0
y = arange(30)/10.0 - 1.5
# Construimos un arreglo 2-d con una funcion de x e y. Primero creamos
# dos matrices xm e ym
xm = x[:,NewAxis] # crea un vector columna (shape(xm)=(35,1))
ym = y[NewAxis,:] # crea un vector fila (shape(ym)=(1,30))
# crea una matrix (35,30) usando funciones universales:
# m(x,y) = sin(x) + 0.1*x - y**2
m = (sin(xm) + 0.1*xm) - ym**2
# Ajusta gnuplot a modo parametrico
# Para graficos en 2-d
# una funcion parametrica se determina a partir de un par de funciones
# que operan sobre un parametro. Un ejemplo seria
# "plot sin(t),cos(t)" que dibuja un circulo
# Para graficos en 3-d
# la superficie a dibujar se describe mediante x = f(u,v),
# y=g(u,v), z=h(u,v), por tanto se necesita un triplete de funciones.
# Por ejemplo "plot cos(u)*cos(v), cos(u)*sin(v), sin(u)"
# dibuja una esfera.
g(set parametric)
g(set data style lines)
# elimina lineas ocultas del dibujo
86
g(set hidden)
# dibuja un contour plot
g(set contour base)
# splot: Comando de gnuplot para dibujar graficos en 3d
#( es decir proyecciones en superficies 2d)
g.splot(Gnuplot.GridData(m,x,y, binary=0))
g.hardcopy(plots/plot3d-1.ps, enhanced=1, color=1)
raw_input(Return para continuar...\n)
El resultado se muestra en las gura 9.6.
9.4. Resumen
En este captulo hemos ofrecido una breve descripci on de la herramienta gr aca gnuplot
as como del modulo Gnuplot que proporciona una interfase a Python. Estas herramientas
nos permitir an representar gr acamente las funciones matematicas que estudiaremos en este
curso.
87
1.4
1.6
1.8
2
2.2
2.4
2.6
2.8
3
-3 -2 -1 0 1 2 3
f(x)
Figura 9.2: La funci on xsin(x) +
1
2
cos(x)
2
exp(x/100) en el intervalo [, ].
0
5
10
15
20
25
-1 -0.8 -0.6 -0.4 -0.2 0 0.2 0.4 0.6 0.8 1
sin(t), t**2
Figura 9.3: La funci on sin(t), t
2
, especicada en modo parametrico.
88
-1
-0.8
-0.6
-0.4
-0.2
0
0.2
0.4
0.6
0.8
1
-10 -5 0 5 10
sin(x)
-20
0
20
40
60
80
100
-10 -5 0 5 10
x
x**2
-1
-0.8
-0.6
-0.4
-0.2
0
0.2
0.4
0.6
0.8
1
-10 -5 0 5 10
sin(x)
cos(x)
Figura 9.4: Diferentes estilos (ver ejemplos en el texto).
89
-1.5
-1
-0.5
0
0.5
1
1.5
-1.5
-1
-0.5
0
0.5
1
1.5
-0.1
0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1
cos(x)*cos(y)
0.8
0.6
0.4
0.2
0
Figura 9.5: La funci on f(x, y) = cos(x) cos(y).
Graficos en 3d
2
1
0
-1
-2
0
2
4
6
8
10
12
14
16
18
x
-1.5
-1
-0.5
0
0.5
1
1.5
y
-3
-2
-1
0
1
2
3
Figura 9.6: La funci on f(x, y) = sin(x) + 0,1 x y 2.
90
Captulo 10
Series de Taylor
10.1. Expansi on de Taylor de una funcion entorno a un punto
Sea f una funci on continuamente derivable de la variable real x. La expansi on de Taylor
de f(x) entorno a un punto c se escribe como:
f(x) f(c) + f

(c)(x c) +
f

(c)
2!
(x c)
2
+
f

(c)
3!
(x c)
3
+ ...
f(x)

k=0
f
k
(c)
k!
(x c)
k
(10.1)
Para el caso particular c = 0 tenemos la serie de Maclaurin:
f(x) f(0) + f

(0)x +
f

(0)
2!
x
2
+
f

(c)
3!
x
3
+ ...
f(x)

k=0
f
k
(0)
k!
x
k
(10.2)
Conviene resaltar aqu un punto importante. La expansi on 10.1 es, a priori, tan s olo
aproximada. Para evaluar el error que se comete al aproximar una funci on por la serie de la
ecuaci on 10.1 recurrimos (sin demostrarlo) al teorema de Taylor:
Teorema 10.1.1
Si una funci on f posee derivadas continuas de orden 0,1,2... (n+1) en el inervalo cerrado
I = [a, b], entonces para todo x y c en I se verica que:
f(x) =
n

k=0
f
k
(c)
k!
(x c)
k
+ E
n+1
(10.3)
donde el termino de error E
n+1
puede expresarse como:
E
n+1
=
f
n+1
()
(n + 1)!
(x c)
n+1
(10.4)
y = (x) es un punto que se encuentra entre c y x.
91
Notemos que el termino de error es similar al resto de los terminos de la expansi on de
Taylor. Sin embargo, la derivada f
n+1
debe evaluarse en un punto desconocido a priori
comprendido entre x y c depende por lo tanto de x.
Precisamente, dado que es un punto arbitrario, no es posible garantizar, en general, la
existencia de una serie de Taylor que represente exactamente el valor de una funci on dada.
Veamos un caso donde s es posible. La expansion en serie de Taylor de la funci on e
x
entorno
al origen, c = 0, es inmediata:
e
x
=
n

k=0
x
k
k!
+
e

(n + 1)!
x
n+1
(10.5)
Consideremos un intervalo simetrico [s, s] entorno al origen. Para todo valor de x con-
tenido en ese intervalo se verica que:
x [s, s] [x[ s [[ s e

e
s
En consecuencia, el resto verica la igualdad:
lm
n

(n + 1)!
x
n+1

lm
n
e
s
(n + 1)!
s
n+1
= 0
Y por lo tanto, tomando el lmite n en ambos lados de la ecuacion 10.5, obtenemos
que el valor de la funci on e
x
puede representarse exactamente por la serie:
e
x
= lm
n
n

k=0
x
k
k!
=

k=0
x
k
k!
Veamos ahora un ejemplo de una funci on que no puede representarse exactamente por una
serie de Taylor. Consideremos f(x) = ln(1 + x) y expandamos entorno a c = 0. Queremos
determinar el rango de x positivos para los cuales la serie representa f(x). La expansi on de
Taylor es:
f(x) = ln(1 + x) f(0) = 0
f

(x) = (1 + x)
1
f

(0) = 1
f

(x) = (1 + x)
2
f

(0) = 1
f

(x) = 2(1 + x)
3
f

(0) = 2
f
(4)
(x) = 6(1 + x)
4
f
(4)
(0) = 6
.
.
.
.
.
.
f
(k)
(x) = (1)
k1
(k 1)!(1 + x)
k
f
(k)
(0) = (1)
k1
(k 1)!
Y por lo tanto:
ln(1 + x) =

n
k=1
(1)
k1
(k1)!
k!
x
k
+
(1)
n
n!(1+)
n1
(n+1)!
x
n+1
=

n
k=1
(1)
k1 x
k
k
+
(1)
n
(n+1)
(1 + )
n1
x
n+1
=

n
k=1
(1)
k1 x
k
k
+
(1)
n
(n+1)

x
1+

n+1
92
Para que la serie de Taylor represente ln(1 + x) es necesario y suciente que el termino
de error converja a cero cuando n tiende a innito. Veamos si es el caso. Si x es un numero
positivo menor que uno 0 x 1, entonces, puesto que estamos expandiendo entorno al
cero, 0 x y por lo tanto 0 x/(1 + ) 1. En consecuencia:
lm
n

x
1 +

n+1
= 0
Sin embargo, si x > 1, no es posible garantizar que 0 x/(1 + ) 1. Por lo tanto el
termino de error no se acerca a cero a medida que n crece y en consecuencia la serie no
converge.
En general, una serie de Taylor converge r apidamente cerca del punto de expansi on y
mas lentamente (o en absoluto) en puntos m as lejanos. Muchos de los metodos que vamos
a estudiar en este curso se basan precisamente en expansiones de Taylor y solo arrojan
resultados sensatos si la aproximacion en la que se basan proximidad al punto de expansi on
es cierta.
10.2. Teorema del valor medio
El caso especial de n = 0 en el teorema de Taylor se conoce como Teorema del valor medio.
Tomando n = 0 en la ecuaci on 10.3, obtenemos:
f(x) =
n

k=0
f
k
(c)
k!
(x c)
k
f(x) = f(c) + (x c)f

()
Lo que nos permite enunciar el teorema del valor medio como:
Teorema 10.2.1 Si f en una funcion continua en el intervalo cerrado [a, b] y derivable en
cada punto del intervalo abierto (a, b), entonces: existe un en (a, b) tal que:
f(b) = f(a) + (b a)f

() (a, b)
En consecuencia, el cociente [f(b)f(a)]/(ba) es igual a la derivada de f en alg un punto
comprendido entre a y b, esto es:
f

() =
f(b) f(a)
b a
(a, b)
Lo que nos permite usar [f(b) f(a)]/(b a) como una aproximacion a la derivada de f
en el intervalo (a, b).
10.3. Teorema de Taylor en terminos de h
Otra forma muy util del teorema de Taylor que usaremos a lo largo del curso es la expansi on
en terminos de h. Partiendo de:
93
f(x) =
n

k=0
f
k
(c)
k!
(x c)
k
+ E
n+1
Llamando h a la distancia x c:
f(x) =
n

k=0
f
k
(x h)
k!
(h)
k
+ E
n+1
Y realizando el cambio de variable x = x + h obtenemos:
f(x + h) =

n
k=0
f
k
(x)
k!
(h)
k
+ E
n+1
E
n+1
=
f
n+1
()
(n+1)!
h
n+1
, x < < x + h
El termino de error E
n+1
converge a cero con la misma velocidad con que h
n+1
converge
a cero. Explcitamente:
f(x + h) = f(x) + f

(
1
)h
= f(x) + O(h)
f(x + h) = f(x) + f

(x)h +
1
2!
f

(
2
)h
2
= f(x) + f

(x)h + O(h
2
)
f(x + h) = f(x) + f

(x)h +
1
2!
f

(x)h
2
+
1
3!
f

(
3
)h
3
= f(x) + f

(x)h +
1
2!
f

(x)h
2
+ O(h
3
)
10.4. Teorema de las series alternas
Otro importante teorema del calculo que se utiliza a menudo para establecer la convergen-
cia de una serie y determinar el error asociado con su truncaci on es el teorema de las series
alternas, esto es, series en las que los terminos sucesivos alternan el signo.
Teorema 10.4.1 Si a
1
a
2
... a
n
..,0 para todo valor de n y lim
n
= 0, entonces
la serie alterna
a
1
a
2
+ a
3
a
4
+ ++
converge, esto es:

k=1
(1)
k1
a
k
= lm
n
n

k=1
(1)
k1
a
k
= lm
n
S
n
= S
donde S es la suma de la serie y S
n
la suma parcial hasta el termino enesimo. Adem as,
para todo n se verica que:
[S S
n
[ a
n+1
94
La consecuencia practica de este teorema es la siguiente. Si la magnitud de los terminos en
una serie alterna converge mon otonamente a cero, entonces el error que se comete al truncar
la serie no es mayor que la magnitud del primer termino omitido.
Veamos un ejemplo. Consideremos la expansion en series de Taylor de la funci on seno:
sin x = x
x
3
3!
+
x
5
5!
...

k=0
(1)
k
x
2k+1
(2k + 1)!
([x[ < )
Cu antos terminos seran necesarios para calcular sin 1 con un error menor de (1/2)10
6
?
La respuesta es una aplicacion inmediata del teorema de las series alternas. La expansion
para x = 1 es:
sin 1 = 1
1
3!
+
1
5!
...
1
(2n 1)!
+
1
(2n + 1)!
Si truncamos la serie en
1
(2n1)!
el error no excede de acuerdo a dicho teorema el primer
termino que despreciamos, esto es
1
(2n+1)!
. En consecuencia, basta con seleccionar un n tal
que:
1
(2n + 1)!
<
1
2
10
6
Tomando el logaritmo decimal a ambos lados de la igualdad:
log(2n + 1)! > log 2 + 6 = 6,3
Para n 5 la ecuacion anterior se verica siempre.
95
96
Captulo 11
Soluci on de ecuaciones no lineales
11.1. Introducci on
Sea f una funci on real o compleja de una variable x que puede, as mismo, ser real o
compleja. Denominamos raz de f a un n umero r que satisface la ecuacion f(r) = 0. Por
ejemplo, la funci on:
f(x) = 6x
2
7x + 2 (11.1)
-0.1
0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
0.2 0.3 0.4 0.5 0.6 0.7 0.8
6
x
*
*
2
-
7
x
+
2
x
6*x**2-7*x+2
Figura 11.1: La funci on 6x
2
7x + 2 en el intervalo [0,2, 0,8].
representada en la gura 11.1 tiene dos ceros, correspondientes a los valores 1/2 y 3/2
como puede vericarse sin mas que resolver la ecuacion de segundo grado 6x
2
7x + 2 = 0.
El problema de encontrar las races de una ecuaci on ocurre frecuentemente en problemas
97
cientcos, que, a menudo, pueden expresarse en terminos de una ecuacion matematica. As,
por ejemplo, la ecuaci on de Kepler proporciona la relaci on entre las coordenadas (polares) de
un cuerpo celeste un planeta, por ejemplo y el tiempo transcurrido desde un cierto intante
inicial. En terminos de la llamada anomala media (que no es sino una parametrizaci on del
tiempo) y de la anomala excentrica (una parametrizaci on del angulo polar) de un cuerpo
siguiendo una orbita elptica de excentricidad e, la ecuaci on de Kepler se escribe como:
M = E e sin E (11.2)
La soluci on de 11.2 proporciona la posici on de un cuerpo celeste para un tiempo dado. Sin
embargo se trata de una ecuacion transcendente que no puede resolverse analticamente para
E dado un M arbitrario. No obtante, es posible encontrar su soluci on aplicando metodos
numericos que encuentren las races de la ecuacion:
M E + e sin E = 0
Tal como se ilustras en la gura 11.2.
Si la ecuaci on que describe nuestro problema es lineal o tiene una soluci on trivial, como
la ecuaci on de segundo grado de la ecuaci on 11.1 el problema de encontrar sus ceros puede
resolver analticamente. Viceversa, el problema de resolver ecuaciones no lineales, para las
que no existe una soluci on analtica inmediata como es el caso de la ecuacion de Kepler,
puede expresarse en terminos de encontrar los ceros de la ecuacion correspondiente.
-4
-2
0
2
4
6
8
10
12
-10 -5 0 5 10
M

-

e

s
i
n

E
E
Kepler
M - x*e*sin(x)
Figura 11.2: La funci on M E + e sin E = 0 para una elipse de excentricidad unidad y
M = 3/2.
Dada una funci on unidimensional arbitraria no es posible, en general, dise nar un algoritmo
que determine todas sus races. Por el contrario, si sabemos que una raz existe en un de-
terminado intervalo [a, b], podemos siempre encontrarla. En consecuencia, el primer paso en
98
la determinaci on numerica de una raz consiste en acotarla. Para funciones continuas, dado
un intervalo [a, b], el teorema del valor medio asegura que si f(a) f(b) < 0 entonces existe
al menos una raz c, tal que f(c) = 0.. El teorema contrario no es cierto, si f(a) f(b) > 0,
pueden darse los siguientes casos:
1. Existe una sola raz.
2. No existe raz en el intervalo.
3. Hay m as de una raz.
La gura 11.3 ilustra cuatro casos diferentes. La par abola y = x
2
(gura 11.3:a) corta el eje
de abcisas en x = 0. La par abola y = x
2
+5 (gura 11.3:b) no corta el eje de abcisas, mientras
que la par abola y = x
2
10x 10 (gura 11.3:c) corta al eje dos veces. En los tres casos
f(a) f(b) > 0, luego esta condici on no nos permite concluir nada. Sin embargo, la par abola
y = x
2
20x 10 (gura 11.3:d) corta el eje de abcisas una vez (y f(10) f(10) < 0).
Por otra parte, el hecho de que f(a) f(b) < 0 para un cierto intervalo [a, b] no garantiza
la existencia de una sola raz, como se ilustra en la gura 11.4 que representa la funci on seno
entre 3 y 3, f(3) f(3) < 0 donde encontramos cinco races.
En este captulo describiremos tres metodos numericos para encontrar una raz que sabe-
mos acotada en un cierto intervalo. El primero de ellos, bisecci on, se limita a dividir el intervalo
repetidamente, hasta que la anchura de este sea menor que la precision requerida. El algorit-
mo converge siempre, pero es relativamente lento. Regula falsi consigue una mayor velocidad
de convergencia para funciones suaves, tomando como raz aproximada la interseccion de la
recta que pasa por los extremos del intervalo y sus imagenes, con el eje de abcisas. A un m as
r apido es el algoritmo de Newton-Raphson, que requiere el conocimiento de la derivada de la
funci on para calcular una nueva aproximaci on a partir de la interseccion de la recta tangente
a la curva en la raz aproximada, con el eje de abcisas.
11.2. Metodo de Bisecci on
Consideremos una funci on que tiene una raz acotada en un determinado intervalo [a, b].
El metodo de bisecci on comienza por tomar, como raz aproximada, el punto medio:
c =
a + b
2
A continuaci on:
1. Si f(a)f(c) < 0 escoge como nuevo intervalo [a, c].
2. Si f(c)f(b) < 0 escoge como nuevo intervalo [c, b].
Una vez establecido el nuevo intervalo se repite el procedimiento, hasta alcanzar la pre-
cision requerida por el usuario. Dicha precisi on puede ser absoluta o relativa. La condici on de
convergencia en el primer caso es:
[b a[ <
abs
(11.3)
99
Es decir, requerimos que la anchura del intervalo sea menor que la precisi on especicada. El
problema de esta condicion es que no tiene en cuenta el valor concreto de la raz. Claramente
no es lo mismo alcanzar una precisi on absoluta de 10
6
cuando la raz esta cercana al cero,
que cuando vale, digamos, 10
6
. Resulta por tanto, preferible, especicar una condici on de
convergencia relativa:
[b a[ <
rel
[[ (11.4)
Donde es la raz. De ah que:

abs
=
rel
[[
Es decir, utilizamos el valor absoluto de la raz como escala de la precision que queremos
alcanzar.
Por otra parte, la ecuaci on 11.4 presenta dos problemas. El primero es que no conocemos
el valor exacto de la raz y por lo tanto tenemos que sustituir por una aproximaci on a esta.
En el caso que nos ocupa, para cada iteracion, podemos aproximar la raz por el centro del
intervalo:
[[
[b + a[
2
Sustituyendo en 11.3:
[b a[ <
rel
[b + a[
2
(11.5)
El segundo problema es que hacer si el intervalo inicial es simetrico alrededor de cero, o, mas
generalmente, c omo especicar la precisi on relativa cuando la raz es igual o esta muy cercana
al cero. En este caso, podemos modicar la condicion de convergencia de tal manera que la
precision relativa multiplique la anchura del intervalo (es decir, escogemos [b a[ como escala
de la precision). La ecuaci on 11.5 se transforma entonces en:
[b a[ <
rel
MAXIMO
[b + a[
2
, [b a[ (11.6)
Si la raz esta acotada en el intervalo inicial, el metodo de bisecci on, converge siempre. Sin
embargo converge lentamente. Tras cada iteracion, los lmites entre los cuales esta contenida
la raz disminuyen en un factor dos. Es decir, si tras la enesima iteracion la raz esta en el
intervalo de tama no
n
, entonces tras la siguiente iteracion estara contenida en el intervalo:

n+1
=

n
2
(11.7)
Supongamos que nuestro intervalo de partida es
0
y queremos encontrar la raz con
tolerancia absoluta . Los intervalos sucesivos seran:

1
=
0
/2

2
=
1
/2 =
0
/2
2
...

n
=
0
/2
n
Igualando el tama no del intervalo con la tolerancia deseada:
100

n
=

0
2
n
=
obtenemos:
n = log
2

= 3,32 log
10

(11.8)
Donde n es el n umero de iteraciones necesarias para alcanzar la raz con la precisi on
absoluta especicada. La relacion entre un intervalo n + 1 y el anterior, n, es:

n+1
= C (
n
)
m
(11.9)
donde C = 1/2 y m = 1. Cuando un metodo converge como en la ecuacion 11.9, con m = 1, se
dice que es lineal. Este es el caso del metodo de bisecci on. Cuando m > 1 se dice que el metodo
converge supralinealmente. Un metodo donde m = 2, se dice que converge cuadraticamente.
11.3. Regula falsi
Si la funci on es suave (es decir se comporta de manera aproximadamente lineal) cerca de
la raz, el metodo de falsa posici on o regula falsi converge supralinealmente.
La idea es muy sencilla. Dado un intervalo [a, b], el metodo de regula falsi determina la
raz aproximada calculando la recta que pasa por los puntos (a, f(a)) y (b, f(b)):
y = x +
donde:
=
f(a) f(b)
a b
y
=
bf(a) af(b)
b a
La intersecci on de dicha recta con el eje de abcisas:
y = x + = 0
se toma como la raz aproximada:
c =

=
af(b) bf(a)
f(b) f(a)
(11.10)
La gure 11.5 muestra la funci on f(x) = xcos(x) en el intervalo [, ], superpuesta a la
recta que pasa por los puntos (1, f(1)), (1, f(1)). El corte de la recta con el eje de abcisas
proporciona la aproximaci on a la raz. Como puede verse, la aproximaci on es buena y la
convergencia en este caso es supralineal. En la pr actica, el metodo de regula falsi se combina
con el de biseccion, ensay andose primero la raz proporcionada por el corte de la recta con
el eje de abcisas. A continuaci on se decide que mitad del intervalo descartar (alla donde la
funci on no cambia de signo) y se calcula la anchura del intervalo que retenemos. Si es mayor
que la mitad del intervalo original, la aproximaci on por regula falsi es peor que por bisecci on
101
y, consecuentemente, se descarta, realizandose una bisecci on en su lugar. El proceso se repite
hasta alcanzar la tolerancia deseada. La combinaci on de regula falsi y bisecci on converge
siempre y a menudo converge supralinealmente, pero en funciones patol ogicas puede llegar a
converger mas lentamente que biseccion, debido a las evaluaciones extras de la funci on. Sin
embargo, el algoritmo que presentamos codica tan solo el metodo de Regula Falsi con el
animo de ilustrar las ventajas y limitaciones del algoritmo.
11.4. Newton-Raphson
Si conocemos la derivada de la funci on y si la funci on que queremos evaluar es aproxi-
madamente lineal en el intervalo de interes, el metodo de Newton Raphson ofrece convergencia
cuadr atica. Geometricamente el metodo consiste en extender la tangente a la curva en la im-
agen de uno de los extremos del intervalo hasta que corte el eje de abcisas, escogiendo ese
punto como nueva raz. Algebraicamente, expandimos en serie de Taylor la funci on f(x) en
torno a un punto:
f(x + ) = f(x) + f

(x) +
f

(x)
2

2
+ ...
En la vecindad de la raz podemos quedarnos a primer orden:
f(x + ) = f(x) + f

(x)
Si c = x + es una raz aproximada, entonces f(x + ) 0 y por tanto = f(x)/f

(x).
Partiendo de un extremo del intervalo [a, b], digamos a, la raz aproximada es:
c = a
f(a)
f

(a)
(11.11)
Para estudiar la convergencia del metodo supongamos que r es una raz simple de f(x)
(f(r) = 0) y que adem as f

(r) = 0 y la segunda derivada, f

es continua. Si x
n
es la raz
aproximada en la iteracion n, entonces el error cometido es
n
= r x
n
. Y el error en la
iteraci on siguiente,
n+1
, sera:

n+1
= r x
n+1
= r x
n
+
f(x
n
)
f

(x
n
)
=
n
+
f(x
n
)
f

(x
n
)
=

n
f

(x
n
) + f(x
n
)
f

(x
n
)
(11.12)
Por otra parte:
f(r) = f(x
n
+
n
) = 0
expandiendo en serie de Taylor entorno a x
n
:
f(x
n
+
n
) = f(x
n
) +
n
f

(x
n
) +
1
2

2
n
f

(x
n
) + ... = 0 (11.13)
Qued andonos ahora en segundo orden obtenemos:

n
f

(x
n
) + f(x
n
) =
1
2

2
n
f

(x
n
)
Sustituyendo en 11.12:

n+1

1
2
f

(x
n
)
f

(x
n
)

2
n
= C
2
n
(11.14)
102
Comparando con la ecuaci on 11.9, obtenemos que m = 2. Es decir, el metodo converge
cuadr aticamente.
Notemos sin embargo que, para obtener 11.14 hemos hecho la hip otesis de que podemos
quedarnos a segundo orden en la expansi on de Taylor de la ecuaci on 11.13, lo cual implica
que estamos bastante cerca de la raz. Lejos de esta, los terminos de orden superior pueden
ser importantes, restando validez a la deducci on anterior. Adem as, si la derivada se anula en
cualquiera de las aproximaciones a la raz, el algoritmo diverge.
Como ilustracion del metodo, deduciremos la f ormula de Newton para el calculo aproxi-
mado de una raz cuadrada. Consideremos la funci on:
f(x) = N x
2
(11.15)
donde N es un n umero real positivo. Obviamente, hallar la raz de la funci on en la ecuaci on
11.15, f(x) = 0, corresponde a encontrar la raz cuadrada de N.
Sea x
0
una raz aproximada de la funci on. El metodo de Newton Raphson estipula que:
x
1
= x
0
f(x)/f

(x)[
x=x
0
es una aproximacion mejor a la raz. Sabiendo que la funci on viene dada por 11.15 obtenemos:
x
1
=
1
2
(x
0
+
N
x
0
)
que es la f ormula de Newton para determinar la raz de un n umero N, dada una raz aprox-
imada x
0
.
11.5. Programaci on de algoritmos de b usqueda de races
11.5.1. Metodo de Bisecci on
Comenzemos por programar el metodo de bisecci on. Una implementaci on sencilla y e-
ciente de este algoritmo sera la siguiente:
def bisec(f, a, b, maxiter=100, tol_abs=1e-6, tol_rel=1e-6):
"""
Devuelve la raz de f en el intervalo [a,b], reduciendo el
intervalo a la mitad en cada paso y tomando el subintervalo en el
que se encuentra la raz.
"""
fa, fb = f(a), f(b) # calcula las imagenes de a, b
# termina si la raiz no esta acotada
if fa*fb >0:
print "la raz no esta acotada!"
103
return -999999
# Repite mientras no se supere el maximo numero de iteraciones y
# la distancia a la raz sea mayor que la tolerancia.
for i in range(maxiter):
c = (a+b)/2.0 # punto medio del intervalo
fc = f(c) # imagen del punto medio
# Imprime el estado de las variables
print "%2d %9.6f %9.6f %9.6f %9.6f %9.6f" % (i, a, b, c, b-a, abs(fc))
# Si el resultado es suficientemente bueno para la tolerancia
# especificada, devuelve la raz.
if (b-a < tol_abs or abs(fc) < tol_rel):
return c
# En otro caso retiene la mitad del intervalo que encierra la raz.
if fa * fc < 0: # si el producto es negativo, el cero esta en [a,c]
b, fb = c, fc # as que el nuevo extremo derecho (b) sera c
else:
a, fa = c, fc # y si no, movemos el extremo izquierdo (a) hasta c
return c
Analyzemos este algoritmo con detalle. La funcion bisec() toma como argumentos el
nombre de la funci on cuyos ceros queremos determinar f, los extremos del intervalo a,b y
tres par ametros opcionales, a saber: el n umero maximo de iteraciones (100 por defecto) la
tolerancia absoluta (10
6
) y la tolerancia relativa (10
6
). Devuelve la aproximaci on a la raz,
una vez que se ha alcanzado convergencia o se ha excedido el n umero maximo de iteraciones.
La denici on de la funci on es:
def bisec(f, a, b, maxiter=100, tol_abs=1e-6, tol_rel=1e-6):
Sigue la cadena de documentaci on entre comillas triples. A continuacion se eval uan las
imagenes de los extremos de la funci on:
fa, fb = f(a), f(b) # calcula las imagenes de a, b
Y se comprueba que la raz esta acotada. En otro caso el algoritmo termina, devolviendo el
extremo inferior del intervalo e imprimiendo un mensaje de aviso.
# termina si la raz no esta acotada
if fa*fb >0:
print "la raz no esta acotada!"
return -999999
104
Si la raz esta acotada el algoritmo entra en un bucle que se repite hasta el n umero maximo
de iteraciones permitidas, si antes no se alcanza convergencia:
for i in range(maxiter):
Dentro de ese bucle, el algoritmo:
Eval ua el punto medio del intervalo.
fa, fb = f(a), f(b) # calcula las imagenes de a, b
Calcula la imagen del punto medio.
c = (a+b)/2.0 # punto medio del intervalo
fc = f(c) # imagen del punto medio
Comprueba si se ha alcanzado la tolerancia especicada en cuyo caso devuelve la raz.
if (b-a < tol_abs or abs(fc) < tol_rel):
return c
En caso contrario selecciona el extremo del intervalo que encierra la raz y cierra el
bucle
# Nos quedamos con la mitad del intervalo que encierra la raz.
if fa * fc < 0: # si el producto es negativo, el cero esta en [a,c]
b, fb = c, fc # el nuevo extremo derecho (b) sera c
else:
a, fa = c, fc # en otro caso mueve (a) hasta c
La funci on bisec() es un ejemplo de lo que podramos llamar un algoritmo de bucle
cerrado. Tras invocarlo, el usuario s olo recupera el control cuando se alcanza convergencia
o se excede el n umero maximo de iteraciones.
Una limitaci on de los algoritmos de bucle cerrado es que no permiten la combinaci on
con otros algoritmos de b usqueda de races. En particular, biseccion tiene la ventaja de
garantizar convergencia y el inconveniente de converger lentamente. En consecuencia, una
estrategia optimizada para buscar las races de una funci on, podra intentar aproximarse a
esta utilizando un algoritmo tan r apido como fuera posible (Newton-Rapson, por ejemplo),
permitiendo, sin embargo, recurrir a biseccion si este falla.
Para hacer posible una estrategia de este tipo, es necesario reimplementar el algoritmo
de biseccion en forma de bucle abierto, en el que el usuario recupera el control tras cada
iteraci on y puede por tanto decidir si desea utilizar otro algoritmo para la siguiente iteracion.
Un algoritmo de este tipo consta generalente de dos funciones. Un inicializador, que
ajusta las condiciones iniciales y un iterador que ejecuta, cada vez que se le invoca una
iteraci on del algoritmo.
Veamos en primer lugar el inicializador:
105
def bisecIni(f,ival):
"""
Inicializa el metodo de biseccion
Toma como argumentos la funcion f cuya raz quiere determinarse
y una tupla, ival con los extremos del intervalo de busqueda.
Devuelve True si la raz esta acotada (fa*fb < 0) y False
en otro caso
"""
# calcula las imagenes de ival.
fa,fb = map(f,ival)
if fa*fb <0:
return True
else:
return False
La funci on de bisecIni() es asegurar que la raz esta acotada, puesto que en otro caso
es in util buscarla en el intervalo seleccionado. Los argumentos son el nombre de la funci on
bajo estudio y una tupla que contiene los extremos del intervalo. Para calcular las im agenes
de dichos extremos aplicamos la funcion map() a la tupla. Recordemos que map(f,s) aplica
la funci on f a cada uno de los elementos de la secuencia s.
El c odigo del iterador es el siguiente:
def bisecIter(f, ival):
"""
Ejecuta una iteracion del metodo de biseccion.
Devuelve una tupla, cuyo primer valor es True o False
dependiendo de que se haya encontrado o no la raz exacta.
El segundo valor es la aproximacion actual a la raz.
Si no se ha alcanzado convergencia exacta el tercer y cuarto
valor es el nuevo intervalo.
"""
a,b = ival
# Dividimos el intervalo y calculamos la imagen del punto medio
r = (a + b)/2.0;
fr = f(r)
# Comprobamos si hemos dado con la raz exacta
if fr == 0.0:
return True,r;
106
# O bien nos quedamos con la mitad del intervalo que encierra la raz
if f(a) * fr < 0.0 :
b = r
else:
a = r;
return False,r,a,b
En cada iteraci on bisecIter() divide el intervalo y calcula la imagen del punto medio. Si
esta es nula convergencia exacta devuelve True indicando que el algoritmo ha convergido
y el valor de la raz en una tupla. En caso contrario, selecciona la mitad del intervalo que
contiene la raz y devuelve False lo que indica que todava no se ha alcanzado convergencia,
la aproximacion actual a la raz y el nuevo intervalo.
Puesto que bisecIter() se limita a ejecutar una iteraci on del algoritmo de biseccion, la
condici on de convergencia, cuando se alcanza una cierta tolerancia (o se excede un n umero
maximo de iteraciones) se impone en una funci on externa cuyo cometido es invocar a bisecIter()
repetidas veces y decidir el criterio por el que se acepta como v alida una de las sucesivas aprox-
imaciones a la raz. A menudo nos referimos a estas funciones como funciones conductoras
(drivers en ingles).
Un ejemplo de conductor para el metodo de bisecci on es el siguiente:
def driveBisec(f,a,b, NITER=100,EPSREL=1e-3,EPSABS=1e-3):
"""
Conduce el metodo de biseccion, version bucle abierto
"""
# La instruccion assert, "afirma" que su predicado es cierto
# En este caso afirmamos que bisecIni() devuelve True, esto es
# que la raz esta acotada entre los extremos del intervalo.
# Si esto no es asi, assert resulta en un
# AsertionError
print "+++++Biseccion++++++++"
assert bisecIni(f,(a,b))
tol = EPSREL* max( abs(b-a), abs(a+b)/2);
print " tolerancia relativa ", EPSREL
print " tolerancia ", tol
print " numero maximo de iteraciones ", NITER
107
it = 0 # contador del numero de iteraciones
eps = b-a # valor inicial de la distancia a la raz
r0 = b # valor inicial de la raz
# repite mientras no se supere el maximo numero de iteraciones
# o la distancia a la raz sea mayor que la tolerancia.
print " iter eps a b r "
while it < NITER and eps > tol:
it+=1 # incrementa en uno
ite = bisecIter(f,(a,b)) # ejecuta una iteracion
if ite[0] == True: # raz exacta
print " raz exacta encontrada! r = ", r
break # salta del bucle
conv,r,a,b = ite # desempaqueta la tupla
eps = abs(r-r0)
r0 = r
print " %d % 9.6f%9.6f %9.6f %9.6f" %(it, eps,a,b,r)
Como podemos ver driveBisec() comienza por inicializar el algoritmo:
assert bisecIni(f,(a,b))
Donde la instrucci on assert, ama que su predicado es cierto. En este caso armamos que
bisecIni() devuelve True, esto es que la raz esta acotada entre los extremos del intervalo.
En otro caso, la instrucci on resultara en una excepcion (un error controlado que el interprete
captura, inform andonos de este).
El uso de la instruccion assert en este ejemplo se debe a que estamos tratando con una
funci on conocida y sabemos de antemano que el intervalo ([0,1]) acota la raz. De ah que nos
limitemos a armar que ese es el caso.
Por el contrario, si no conocemos de antemano el intervalo que encierra la raz podramos
usar bisecIni() para encontrarlo, comenzando con una aproximaci on dada y expandiendo
el intervalo cada vez que bisecIni() devolviera False.
Volviendo a driveBisec(), denimos a continuaci on la tolerancia del c alculo:
tol = EPSREL* max( abs(b-a), abs(a+b)/2);
Para encontrar la raz, el conductor ejecuta un bucle que se repite mientras el numero de
iteraciones sea menor que el maximo deseado o no se haya alcanzado la tolerancia:
108
while it < NITER and eps > tol:
Dentro del bucle, incrementamos el contador de iteraciones y llamamos a bisecIter(), que
nos devuelve una tupla cuyo primer valor es True si se ha alcanzado convergencia exacta. En
ese caso saltamos del bucle:
if ite[0] == True: # raz exacta
print " raz exacta encontrada! r = ", r
break # salta del bucle
En caso contrario calculamos la distancia entre la aproximaci on actual a la raz (r) y la
aproximacion anterior (r0), imprimimos una lnea y ejecutamos el bucle siguiente:
conv,r,a,b = ite # desempaqueta la tupla
eps = abs(r-r0)
r0 = r
print " %d % 9.6f%9.6f %9.6f %9.6f" %(it, eps,a,b,r)
Todas las funciones que hemos comentado se han codicado en bisec.py, junto con un
progama principal. Recordemos, que en un m odulo, el c odigo que sigue a la instruccion:
if __name__ == __main__:
se ejecuta cuando invocamos al interprete pero no se ejecuta cuando importamos el m odulo.
En bisec.py el programa principal es muy sencillo:
import math
def xcosx(x):
return x-math.cos(x)
print " Iniciamos el algoritmo en el intervalo [0,1]"
testBisec(xcosx,0.,1.)
driveBisec(xcosx,0.,1.)
Donde testBisec(xcosx,0.,1.) se limita a invocar la funci on de bucle cerrado bisec():
def testBisec(f,a,b, NITER=100,EPSREL=1e-3,EPSABS=1e-3):
"""
Comprueba el metodo de biseccion, version bucle cerrado
109
"""
print "+++++Biseccion: modo bucle cerrado++++++++"
print \
"""
Busca la raz en el intervalo [0, 1]
iter a b c abs rel
-----------------------------------------------------
"""
raiz = bisec(xcosx, a, b, maxiter=NITER,tol_abs=EPSABS,tol_rel=EPSREL)
print x - cos(x) tiene una raz en x =, raiz
Mientras que, como hemos visto, driveBisec(xcosx,0.,1.) conduce la versi on del algo-
ritmo basada en un bucle abierto.
El resultado del algoritmo en su versi on bucle abierto, para la funci on x cos x en el
intervalo [0, 1], cuando la tolerancia se especica como 10
3
, es:
+++++Biseccion: modo bucle abierto++++++++
tolerancia relativa 0.001
tolerancia 0.001
numero maximo de iteraciones 100
iter eps a b r
1 0.500000 0.500000 1.000000 0.500000
2 0.250000 0.500000 0.750000 0.750000
3 0.125000 0.625000 0.750000 0.625000
4 0.062500 0.687500 0.750000 0.687500
5 0.031250 0.718750 0.750000 0.718750
6 0.015625 0.734375 0.750000 0.734375
7 0.007812 0.734375 0.742188 0.742188
8 0.003906 0.738281 0.742188 0.738281
9 0.001953 0.738281 0.740234 0.740234
10 0.000977 0.738281 0.739258 0.739258
11.5.2. Metodo de Regula Falsi
Hemos codicado la versi on de bucle abierto de el metodo en el modulo rfalsi.py:
El algoritmo se programa de manera muy similar al de biseccion, con la diferencia de la
aproximacion a la raz que en este caso se toma como la interseccion de la recta que pasa
entre los extremos del intervalo y sus imagenes (a, f(a)), (b, f(b) con el eje de abcisas:
r = (fa*b-fb*a)/(fa-fb);
110
fr = f(r)
Al igual que en el caso de bisecci on, el m odulo incluye una funci on conductora, testRFalsi().
Si ejecutamos el modulo con el interprete obtenemos:
python rfalsi.py
Iniciamos el algoritmo en el intervalo [0,1]
+++++Regula Falsi++++++++
tolerancia relativa 0.001
tolerancia 0.001
numero maximo de iteraciones 100
iter eps a b r
1 0.314927 0.685073 1.000000 0.685073
2 0.051226 0.736299 1.000000 0.736299
3 0.002646 0.738945 1.000000 0.738945
4 0.000133 0.739078 1.000000 0.739078
Como podemos comprobar, para funciones suaves, como es el caso de xcos x, el metodo
converge supralinealmente.
11.5.3. Metodo de Newton Rapson
Hemos codicado el metodo en el modulo newtonRapson.py:
A diferencia de los dos metodos anteriores, aqu no comprobamos si la raz esta acotada en
un intervalo dado antes de ejecutar una iteraci on. La raz on es la siguiente. Tanto en biseccion
como en Regula Falsi, una vez que la raz esta acotada en un intervalo, est a garantizado que
la raz sigue acotada a lo largo de las sucesivas iteraciones del metodo. Biseccion converge
siempre y Regula Falsi lo hace en general mas rapido, con la excepcion de funciones muy
patol ogicas (sin embargo, incluso para esas funciones la raz contin ua acotada en las sucesivas
iteraciones del metodo).
No es el caso para Newton-Rapson, en el que la aproximaci on a la raz es la interseccion de
la tangente a la funci on en la aproximaci on anterior a la raz con el eje de abcisas. Cerca de
un cero de la funci on, cuando la aproximaci on en la que se basa el metodo es buena (es decir
cuando la expansi on en serie de potencias hasta primer orden esta justicada) la convergencia
es muy rapida pero lejos de la raz el metodo puede arrojar resultados absurdos. La derivada
puede tomar valores muy peque nos o nulos y en consecuencia la tangente a la curva en la
aproximacion a la raz puede cortar al eje de abcisas en puntos arbitrariamente lejanos del
cero de la funci on.
En consecuencia, a un partiendo de una raz acotada, la convergencia no est a garantizada
y por lo tanto no tiene sentido inicializar el metodo buscando un intervalo que encierre el
cero de la funci on.
Las sucesivas iteraciones se limitan a tomar como mejor aproximacion a una raz ya exis-
tente, r0, la raz r1 calculada como:
r1 = r0 - f(r0)/df_r0
111
Donde f(r0) es la imagen de la funci on en la raz aproximada r0 y df r0 es la derivada
de la funci on en el punto r 0.
La funci on driveNewton() permite ejercitar el metodo. Si ejecutamos el modulo obten-
emos:
python newtonRapson.py
Iniciamos el algoritmo en el intervalo [0,1]
+++Newton Rapson++++++
tolerancia relativa 0.001
tolerancia 0.001
numero maximo de iteraciones 100
iter eps r
1 0.249636 0.750364
2 0.011251 0.739113
3 0.000028 0.739085
Como vemos, la convergencia es cuadratica.
11.5.4. El m odulo raices
Finalmente, podemos importar los tres algoritmos en un solo modulo, raices.py:
"""
Incluye los modulos bisec, rfalsi y newtonRapson para busqueda
de raices
"""
from bisec import *
from rfalsi import *
from newtonRapson import *
Basta con importar el modulo raices a cualquier programa Python para tener acceso a los
tres metodos que hemos programado.
11.6. Resumen
En esta captulo hemos estudiado tres metodos para localizar ceros de funciones. Biseccion,
lento y seguro. Regula Falsi, el m as sencillo de una familia de metodos (casi) tan robustos como
biseccion, pero capaces de ofrecer convergencia supralineal. Y Newton-Rapson, el m as rapido
(ofrece convergencia cuadr atica cerca de la raz) pero tambien el mas inestable. A menudo,
la estrategia optima para localizar los ceros de una funci on consiste en una combinaci on m as
o menos heurstica de los metodos anteriores. Todo un arte.
112
0
10
20
30
40
50
60
70
80
90
100
-10 -5 0 5 10
a) f(x) = x**2
0
10
20
30
40
50
60
70
80
90
100
110
-10 -5 0 5 10
b) f(x) = x**2+5
-50
0
50
100
150
200
250
-10 -5 0 5 10
c) f(x) = x**2-10x+10
-100
-50
0
50
100
150
200
250
300
350
-10 -5 0 5 10
d) f(x) = x**2-20x+10
Figura 11.3: Cuatro par abolas ilustrando diferentes posibilidades: a) corta el eje de abcisas
exactamente; b) no lo corta nunca, c) lo corta dos veces y d) lo corta una vez. En los tres
primeros casos f(10) f(10) > 0, en el el ultimo f(10) f(10) < 0 garantizando, por el
teorema del valor medio, la existencia de al menos una raz.
113
-1
-0.8
-0.6
-0.4
-0.2
0
0.2
0.4
0.6
0.8
1
-8 -6 -4 -2 0 2 4 6 8
f(x) = sin(x)
Figura 11.4: La funci on seno(x) en el intervalo [3, 3].
-4
-3
-2
-1
0
1
2
3
4
5
-3 -2 -1 0 1 2 3
f(x)
r(x)
Figura 11.5: La funci on f(x) = x cos(x) en el intervalo [, ], superpuesta a la recta
que pasa por los puntos (1, f(1)), (1, f(1)). El corte de la recta con el eje de abcisas
proporciona la aproximaci on a la raz.
114
Captulo 12
Sistemas de ecuaciones lineales
12.1. Introducci on
En este captulo abordamos la resolucion de sistemas de ecuaciones lineales, del tipo:
a
11
x
1
+ a
12
x
2
+ + a
1n
x
n
= w
1
a
21
x
1
+ a
22
x
2
+ + a
2n
x
n
= w
2
(12.1)
a
m1
x
1
+ a
m2
x
2
+ + a
mn
x
n
= w
m
Donde las n inc ognitas estan relacionadas entre s por m ecuaciones. Los coecientes a
ij
son
n umeros conocidos, al igual que los coecientes w
i
.
La ecuaci on 12.1 puede escribirse usando notaci on matricial como:
A x = w (12.2)
Donde A es la matriz de coecientes, w el vector de terminos independientes y x el vector de
inc ognitas. Para el caso n = m, que es el unico que estudiaremos en este captulo, podemos
escribir, explcitamente:

a
11
a
12
... a
1n
a
21
a
22
... a
2n
...
a
n1
a
n2
a
nn

x
1
x
2
...
x
n

w
1
w
2
...
w
n

(12.3)
Resolver el sistema de ecuaciones 12.3 es equivalente, desde el punto de vista algebraico, a
encontrar la inversa de la matriz A, aunque, como veremos en breve, el problema numerico de
resolver un sistema lineal de ecuaciones admite soluciones mas sencillas que la de encontrar
la inversa de la matriz de coecientes.
En este captulo estudiaremos un metodo particularmente elegante y eciente para re-
solver sistemas lineales de ecuaciones, que implica factorizar la matriz de coecientes, descom-
poniendola en el producto de una matriz triangular inferior y una matriz triangular superior.
115
Este metodo, llamado genericamente metodo de descomposici on LU admite diversas vari-
antes, dependiendo de si se escoge la matriz triangular inferior (que denotaremos como L del
ingles, lower) tal que los elementos de la diagonal valen uno, (l
ii
= 1, i = 1, 2, ..., n), o bien es
la matriz triangular superior (U del ingles upper) la que se escoge tal que u
ii
= 1, i = 1, 2, ..., n.
El primer algoritmo se llama factorizaci on de Doolittle y es el que desarrollaremos explcita-
mente. El segundo, llamado de Crout, es totalmente equivalente. Por ultimo, en el caso de
matrices simetricas (a
ij
= a
ji
) y denidas positivas, existe una poderosa variante del algorit-
mo LU, en el cual U = L
T
, llamada factorizaci on de Choleski.
12.2. Sistemas lineales faciles de resolver
Para comprender por que resulta util factorizar una matriz arbitraria en el producto de
una triangular inferior y otra superior, consideremos primero la soluci on de un sistema lineal
de ecuaciones cuando la matriz de coecientes es de tipo L o U. En el primer caso:

l
11
0 0 ... 0
l
21
l
22
0 ... 0
l
31
l
32
l
33
... 0
...
l
n1
l
n2
l
n3
... l
nn

x
1
x
2
x
3
...
x
n

w
1
w
2
w
3
...
w
n

(12.4)
El sistema 12.4 admite una solucion muy sencilla, en la que cada termino se calcula partiendo
del anterior:
l
11
x
1
= w
1
x
1
= w
1
/l
11
l
21
x
1
+ l
22
x
2
= w
2
x
2
= (w
2
l
21
x
1
)/l
22
l
31
x
1
+ l
32
x
2
+ l
33
x
3
= w
3
x
3
= (w
3
l
31
x
1
l
32
x
2
)/l
33
.... .... ....
obteniendose la formula general para la llamada sustituci on progresiva:
x
i
=
w
i

i1
j=1
l
ij
x
j
l
ii
(12.5)
An alogamente, en el caso de una matriz triangular superior:

u
11
u
12
u
13
... u
1n
0 u
22
u
23
... u
2n
0 0 u
33
... u
3n
...
0 0 0 ... u
nn

x
1
x
2
x
3
...
x
n

w
1
w
2
w
3
...
w
n

(12.6)
116
La soluci on es igualmente inmediata, resolviendo de abajo arriba:
u
nn
x
n
= w
n
x
n
= w
n
/u
nn
u
n1n1
x
n1
+ u
n1n
x
n
= w
n1
x
n1
= (w
n1
u
n1n
x
n
)/u
n1n1
u
n2n2
x
n2
+ u
n2n1
x
n1
+ u
n2n
x
n
= w
n2
x
n2
= (w
n2
u
n2n1
x
n1
u
n2n
x
n
)/u
n2n2
... ...
Resultando en la f ormula general de la sustituci on regresiva:
x
i
=
w
i

n
j=i+1
u
ij
x
j
u
ii
(12.7)
Las ecuaciones 12.5 y 12.7 plantean, en apariencia, un problema cuando alguno de los
terminos diagonales l
ii
, u
ii
, i = 1, 2, ..., n es nulo. En ese caso, el determinante de la matriz
que contiene el termino nulo es cero, y por tanto, la matriz A del sistema es singular.
12.3. Factorizaci on LU
Si es posible descomponer la matriz del sistema en el producto de una matriz triangular
inferior y una matriz triangular superior:
A = L U (12.8)
entonces la ecuaci on 12.2 se transforma en:
(L U)x = w L(Ux) = w (12.9)
que puede resolverse, resolviendo los sistemas:
Ly = w
Ux = y (12.10)
El primero de estos es del tipo 12.4, mientras que el segundo es del tipo 12.6. Como acabamos
de ver, la soluci on de estos sistemas por sustitucion progresiva (regresiva), ecuaciones 12.5 y
12.7 es inmediata.
Veamos como proceder a la factorizacion. Resaltemos, en primer lugar, que las ecuaciones
12.8 no determinan unvocamente los valores de L y U, puesto que al resolver el sistema van
a aparecer productos de la forma l
kk
u
kk
que permiten un grado de libertad en la elecci on de
los coecientes de la diagonal. Una opci on puede ser imponer que una de la matrices tenga
sus terminos diagonales iguales a la unidad. Si es la matriz L, es decir, l
kk
= 1, k = 1, 2, ..., n,
hablamos de la factorizaci on de Doolittle. Si por el contrario, u
kk
= 1, k = 1, 2, ..., n hablamos
de la factorizaci on de Crout.
117
Para deducir un algoritmo para la factorizaci on LU de la matriz A, comenzamos con la
f ormula para la multiplicaci on de matrices:
a
ij
=
n

s=1
l
is
u
sj
(12.11)
Puesto que l
is
= 0 para s > i y u
sj
= 0 para s > j, la ecuaci on anterior se transforma en:
a
ij
=
min(i,j)

s=1
l
is
u
sj
(12.12)
Explcitamente:
a
11
= l
11
u
11
a
12
= l
11
u
12
a
13
= l
11
u
13
a
1n
= l
11
u
1n
a
21
= l
21
u
11
a
22
= l
21
u
12
+ l
22
u
22
a
23
= l
21
u
13
+ l
22
u
23
a
2n
= l
21
u
1n
+ l
22
u
2n
a
31
= l
31
u
11
a
32
= l
31
u
12
+ l
32
u
22
a
33
= l
31
u
13
+ l
32
u
23
+ l
33
u
33
a
3n
= l
31
u
1n
+ l
32
u
2n
+ l
33
u
3n
....
a
n1
= l
n1
u
11
a
n2
= l
n1
u
12
+ l
n2
u
22
a
n3
= l
n1
u
13
+ l
n2
u
23
+ l
n3
u
33
a
nn
= l
n1
u
1n
+ ... + l
nn
u
nn
(12.13)
En el proceso especicado en las ecuaciones anteriores, cada paso determina una nueva
columna de U y L, o bien una nueva la. Por ejemplo, si nos jamos en la primera columna,
el primer termino:
a
11
= l
11
u
11
nos permite determinar un valor para u
11
a condici on de jar l
11
a la unidad. Si usamos la
factorizacion de Doolittle, (l
kk
= 1, k = 1, 2, ...n) obtenemos u
11
= a
11
. El segundo termino
de la columna:
a
21
= l
21
u
11
nos permite obtener el valor de l
21
a partir del coeciente conocido de la matriz original,
a
21
y el termino que acabamos de calcular, u
11
. El resto de la columna arroja sucesivamente
los valores de l
31
, l
41
...l
n1
. En la segunda columna el primer termino permite calcular u
12
directamente a partir del termino correspondiente de la matriz original, mientras que el
segundo termino arroja u
22
= a
22
l
21
u
12
, donde u
12
se calculo en el paso anterior y l
21
en la
columna anterior. Descendiendo a lo largo de la columna se calculan los terminos l
32
, l
42
...l
n2
.
El proceso se repite en la tercera columna, en la que calculamos primero u
13
, u
23
y u
33
seguidos de l
43
, l
53
...l
n3
. En resumen: avanzando por columnas calculamos sucesivamente las
columnas de U y L de manera que, en cada paso tan s olo necesitamos los terminos previamente
calculados.
Haciendo i = j = k en las ecuaciones 12.12 (lo que corresponde a tomar los terminos
diagonales en 12.13) obtenemos:
a
kk
=
k1

s=1
l
ks
u
sk
+ l
kk
u
kk
(12.14)
Como ya hemos indicado, si l
ii
se ha especicado (por ejemplo l
ii
= 1, i = 1, 2, ...n para la
factorizacion de Doolittle) la ecuacion 12.14 nos permite calcular u
ii
. An alogamente, si u
ii
se
118
ha especicado (por ejemplo u
ii
= 1, i = 1, 2, ...n para la factorizaci on de Crout) la ecuaci on
12.14 nos permite calcular l
ii
.
Conocidas l
ii
y u
ii
, podemos escribir los terminos por encima de la diagonal como:
a
kj
=
k1

s=1
l
ks
u
sj
+ l
kk
u
kj
(k < j n) (12.15)
Por ejemplo, poniendo k = 3, j = n, obtenemos:
a
3n
= l
31
u
1n
+ l
32
u
2n
+ l
33
u
3n
que corresponde al ultimo elemento de la tercera la en las ecuaciones 12.13. An alogamente,
podemos escribir los elementos que se encuentran por debajo de la diagonal como:
a
ik
=
k1

s=1
l
is
u
sk
+ l
ik
u
kk
(k < i n) (12.16)
Por ejemplo, poniendo k = 3, i = n, obtenemos:
a
n3
= l
n1
u
13
+ l
n2
u
23
+ l
n3
u
33
que corresponde al ultimo elemento de la tercera columna en las ecuaciones 12.13. Si l
kk
= 0
la ecuaci on 12.15 puede utilizarse para calcular los elementos u
kj
. An alogamente, si u
kk
= 0
la ecuaci on 12.16 puede utilizarse para calcular los elementos l
ik
.
12.4. Factorizaci on de Doolittle
Escogiendo ahora L como una matriz triangular inferior cuyos elementos diagonales son
la unidad, podemos escribir f ormulas explcitas para los elementos de las matrices U y L. A
partir de la ecuaci on 12.14 obtenemos los terminos diagonales de U:
u
kk
= a
kk

k1

s=1
l
ks
u
sk
(12.17)
Los terminos de U por encima de la diagonal se obtienen a partir de la ecuaci on 12.15:
u
kj
= a
kj

k1

s=1
l
ks
u
sj
(k < j n) (12.18)
Mientras que los terminos de L por debajo de la diagonal se obtienen a partir de la ecuaci on
12.16:
l
ik
=
l

ik
u
kk
=
a
ik

k1
s=1
l
is
u
sk
u
kk
(k < i n) (12.19)
Una vez calculados los coecientes de las matrices L y U, resolvemos el sistema:
Ly = w (12.20)
119
usando sustituci on progresiva:
y
i
= w
i

i1

j=1
l
ij
y
j
(12.21)
A continuaci on resolvemos:
Ux = y (12.22)
usando sustituci on regresiva:
x
i
=
y
i

n
j=i+1
u
ij
x
j
u
ii
(12.23)
Sin embargo, podemos tener un grave problema si alguno de los elementos u
kk
en la
ecuaci on 12.19 es nulo. La forma de resolverlo es efectuar una permutaci on entre la la que
contiene al termino diagonal y alguna de las las por debajo de esta, de manera que el nuevo
termino u
kk
, denominado pivote, sea distinto de cero. Fijemonos en la similaritud entre la
expresion del termino diagonal u
kk
(12.17) de la matriz U, y los terminos l

ik
en (12.19). Un
algoritmo sencillo de pivoteo, y a la vez robusto, consiste en escoger como pivote el elemento de
mayor valor absoluto en el conjunto (u
kk
, l

k+1k
, l

k+2k
, ..., l

nk
). Escogido el pivote, se permutan
la la que lo contiene con la la k-esima y as, para cada una de las n columnas de la matriz
L. Cada una de estas permutaciones se guarda en una matriz de permutaciones P que se
obtiene a partir de las n permutaciones aplicadas (efectuamos una permutaci on entre las al
resolver cada columna mediante la ecuaci on 12.19, en particular, en el caso de que u
kk
resulte
ser el pivote, la permutaci on correspondiente es la unidad). De este modo, la descomposicion
LU que resulta no se corresponde con la matriz A del sistema original sino con una matriz
donde las las estan cambiadas de acuerdo con la permutaci on resultante. Puesto que las
las estan cambiadas, los terminos independientes tambien han de ser reordenados. As pues,
aplicamos al vector de terminos independientes w la misma matriz de permutaciones que
hemos aplicado a la matriz A. Finalmente, el sistema que resolvemos es el mismo, salvo que
el orden de las las no tiene porque ser el inicial:
PAx = (LU)x = L(Ux) = Pw (12.24)
La ecuaci on 12.20 se modica de manera muy sencilla, a n de tomar en cuenta las per-
mutaciones de L en el proceso de factorizacion, que deben aplicarse al vector w antes de
resolver:
Ly = Pw (12.25)
Mientras que la ecuaci on 12.22 no se modica, puesto que el sistema 12.25 es equivalente al
sistema 12.20 y por lo tanto el vector y que se obtiene en ambos casos es identico.
12.5. Permutaciones
Examinemos a continuaci on como representar las sucesivas permutaciones asociadas al
proceso de pivotaje. Dado un vector de dimensi on n (o una matriz cuadrada de dimensiones
nn), podemos representar la operaci on que permuta los elementos i y j del vector (las las
i y j de la matriz), i < j mediante la permutaci on (1, 2, 3...j...i...n), donde (1, 2, 3...i...j...n)
es la permutaci on unidad.
120
Por ejemplo. Supongamos que en la factorizaci on LU de una cierta matriz de dimensi on
4 4 nos encontramos con la siguiente situacion al resolver columna a columna:
1. El m aximo elemento en valor absoluto del conjunto u
11
, l

21
, l

31
, l

41
es l

21
. Por tanto hay
que permutar la la 1 y la la 2.
2. El m aximo elemento en valor absoluto del conjunto u
22
, l

32
, l

42
es l

42
. Por tanto hay que
permutar la la 2 y la la 4.
3. El m aximo elemento en valor absoluto del conjunto u
33
, l

43
es u
33
. Por lo tanto no hay
que permutar.
4. No es necesario permutar en la ultima columna ya que u
44
no se usa como pivote.
La permutaci on unidad para n = 4 es (1, 2, 3, 4). La primera operaci on resulta en la
permutaci on p1 = (2, 1, 3, 4) que especica que el segundo elemento del conjunto ordenado
sobre el que la permutaci on act ua (las las de la matriz problema o los elementos del vector
de terminos independientes) ha intercambiado su posici on con el primer elemento.
La segunda operacion es permutar la la 2 y la la 4. Si partieramos de la permutaci on
unidad, obtendramos p2 = (1, 4, 3, 2). Puesto que partimos de un conjunto al que se ha
aplicado previamente la permutaci on (2, 1, 3, 4), debemos componer ambas, p = p2 p1 =
(2, 4, 3, 1). Las ultimas dos columnas no nos obligan a permutar. El resultado nal se lee
directamente en la permutaci on. La primera la en la matriz sin permutar ha acabado en
cuarto lugar en la matriz permutada, la segunda en primero, la cuarta en segundo y la tercera
no se ha movido. Para deshacer la permutaci on no hay m as que leerla al reves, de derecha a
izquierda.
Formalmente, podemos construir una matriz de permutaciones P a partir de la per-
mutaci on p. Para ello, partimos de la matriz unidad de la dimensi on correspondiente (4 4
en nuestro ejemplo) y permutamos, para cada la, el uno de la diagonal, con la cifra corre-
spondiente a la columna especicada por la permutaci on, es decir, el uno en la diagonal de la
primera la lo permutamos con el 0 en la segunda columna, el de la segunda la con el cero en
la cuarta columna, el de la tercera con el uno en la tercera columna (o sea, no permutamos)
y el uno en la diagonal de la cuarta la con el cero en la primera columna. Ergo, los terminos
p
12
, p
24
, p
33
y p
41
de la matriz de permutaci on P valen uno y el resto valen cero. Esto es:

0 1 0 0
0 0 0 1
0 0 1 0
1 0 0 0

a
11
a
12
a
13
a
14
a
21
a
22
a
23
a
24
a
31
a
32
a
33
a
34
a
41
a
42
a
43
a
44

a
21
a
22
a
23
a
24
a
41
a
42
a
43
a
44
a
31
a
32
a
33
a
34
a
11
a
12
a
13
a
14

Naturalmente, la misma permutacion, aplicada al vector de terminos independientes, (w


1
, w
2
, w
3
, w
4
)
asociado con el sistema, resulta en un vector permutado (w
2
, w
4
, w
3
, w
1
).
12.6. Calculo de la matriz inversa
El c alculo de la inversa de una matriz cuadrada es inmediato una vez que se conoce su
descomposici on LU. Puesto que, por denici on:
M M
1
= I (12.26)
121
Para una matriz n n tenemos, si M = LU:
LU

a
11
a
12
... a
1n
a
21
a
22
... a
2n
...
a
n1
a
n2
a
nn

1 0 ... 0
0 1 ... 0
...
0 0 1

(12.27)
donde los a
ij
son los coecientes, a determinar de la matriz M
1
.
Dada la estructura diagonal de la matriz unidad, podemos descomponer la ecuaci on ma-
tricial 12.27 en n sistemas de ecuaciones lineales independientes:
LU

a
11
a
21
...
a
n1

1
0
...
0

LU

a
12
a
22
...
a
n2

0
1
...
0

.....
LU

a
1n
a
2n
...
a
nn

0
0
...
1

Como hemos visto, cada uno de estos n sistemas de ecuaciones lineales puede resolverse
f acilmente una vez que la factorizaci on LU de M ha sido calculada. La soluci on de cada
sistema proporciona una columna de la matriz inversa.
Vale la pena, sin embargo, anotar que el c alculo de M
1
implica la resoluci on de n sistemas
de ecuaciones. Consideremos ahora, de nuevo, el problema de resolver el sistema:
M x = w
Numericamente, la solucion directa del sistema implica la factorizaci on LU de la matriz,
seguida de la soluci on de los sistemas intermedios por sustituci on progresiva y regresiva. En
cambio, la soluci on calculada a partir de la inversa:
x = M
1
w
implica, ademas de la factorizaci on LU, la soluci on de n sistemas de ecuaciones. El calculo
de la inversa, por lo tanto, es mucho m as ineciente que la resoluci on directa del sistema.
12.7. Determinante de una matriz
El c alculo del determinante de una matriz cuya descomposici on LU se conoce es inmediato.
En efecto:
det(M) = det(LU) = det(L) det(U)
122
Por otra parte el determinante de una matriz triangular es igual al producto de sus elementos
diagonales. Por construcci on los elementos diagonales de la matriz L son unos. Por lo tanto:
det(M) =
n

i
u
ii
(1)
j
(12.28)
donde j es el n umero de permutaciones que hemos efectuado en la descomposicion LU (cada
permutaci on de las cambia el signo del determinante).
12.8. Programaci on del algoritmo de descomposici on LU
12.8.1. El m odulo lu.py
Hemos programado todos los metodos relevantes a la descomposicion LU en un s olo chero
python, lu.py, donde se incluye una versi on muy sencilla del algoritmo (sin permutaciones
del pivote), otra versi on m as sosticada hemos adaptado la correspondiente funci on de la
GNU Scientic Library, GSL, [9] y algunas funciones auxiliares, adem as del consabido
codigo de prueba en el programa principal de m odulo.
12.8.2. Matrices
Las matrices que vamos a utilizar no son otra cosa que variantes de los arreglos numericos
que ya hemos estudiado. Para manejar objetos de tipo matriz basta importar el correspon-
diente m odulo:
import Matrix
o bien, si queremos acceder directamente a los tipos y funciones del modulo:
from Matrix import *
Una matriz se crea a partir de una lista de listas (o una tupla de tuplas), puesto que no
es otra cosa que un arreglo numerico de rango 2. Por ejemplo la matriz:
A =

1 2 3
0,1 0,2 0,3
10 20 30

podra crearse como:


a = [[1,2,3],[0.1,0.2,0.3],[10,20,30]]
A=Matrix.Matrix(a)
print A
Matrix([[ 1. , 2. , 3. ],
[ 0.1, 0.2, 0.3],
[ 10. , 20. , 30. ]]
Alternativamente, podemos inicializar la matriz a cero:
123
b=[[0.0]*3]*3
print b
[[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
B=Matrix(b)
print B
Matrix([[ 0., 0., 0.],
[ 0., 0., 0.],
[ 0., 0., 0.]])
Y luego rellenarla elemento a elemento. Por ejemplo, para rellenar la diagonal:
B[0,0]=1
B[1,1]=0.2
B[2,2]=30
print B
Matrix([[ 1. , 0. , 0. ],
[ 0. , 0.2, 0. ],
[ 0. , 0. , 30. ]])
Notad que los elementos de B son reales en coma otante, ya que la matriz se ha inicializado
con 0,0 (y no con enteros 0). La forma de acceder a los elementos es B[i,j] donde i es el
ndice de la la y j el de la columna. Recordemos por otra parte que la notaci on A[i] nos da
acceso directamente a una la de la matriz:
print A
Matrix([[ 1. , 2. , 3. ],
[ 0.1, 0.2, 0.3],
[ 10. , 20. , 30. ]])
print A[0]
Matrix([ [ 1., 2., 3.]])
print A[0,0]
1.0
Finalmente, la funci on print matrix() permite imprimir de forma elegante una matriz:
def print_matrix(a):
"""Imprime de forma elegante una matriz."""
n, m = a.shape
for i in range(n):
for j in range(m):
print %2.3f % a[i,j],
print
Por ejemplo:
print_matrix(A)
124
1.000 2.000 3.000
0.100 0.200 0.300
10.000 20.000 30.000
12.8.3. Descomposici on LU sin permutaciones
La primera versi on del algoritmo de descomposicion LU asume que ninguno de los pivotes
es nulo y por lo tanto no realiza permutaci on alguna. El c odigo es una simple transcripcion
de las ecuaciones 12.18 y 12.19. Concretamente, para los terminos de la matriz U obtuvimos:
u
kj
= a
kj

k1

s=1
l
ks
u
sj
(k < j n)
La transcripci on literal a Python de esta f ormula no es otra que:
for i in range(n): # Para cada "marco" superior izquierdo
for j in range(i, n): # Rellena la U a partir de la fila
suma = 0.0
for k in range(0, j):
suma += L[i,k] * U[k,j]
U[i,j] = A[i,j] - suma
Mientras que para la matriz L, la f ormula:
l
ik
=
l

ik
u
kk
=
a
ik

k1
s=1
l
is
u
sk
u
kk
(k < i n)
se traduce en el siguiente codigo:
for j in range(i+1, n): # Rellena la L a partir de la columna
suma = 0.0
for k in range(0, i):
suma += L[j,k]*U[k,i]
L[j,i] = (A[j,i] - suma) / U[i,i]
Esta version del algoritmo esta programada (a prop osito) de manera muy sencilla. La
funci on LU(A) toma como argumento una matriz A:
def LU(A):
A continuaci on obtiene el n umero de las y columnas a partir de la forma (shape) de la
matriz. Recordemos que la forma de una matriz (de hecho, de un arreglo numerico cualquiera)
nos da una tupla con el n umero de elementos en cada una de sus dimensiones. Concretamente,
para la matriz de nuestro ejemplo:
125
A.shape
(3,3)
se corresponde al n umero de las y columnas de la matriz cuadrada A. El algoritmo exige de
hecho que el n umero de las sea identico al de columnas, mediante una instrucci on assert:
n, m = A.shape
assert n == m
A continuaci on creamos las matrices L y U, incializ andolas a cero:
L = Matrix.Matrix([[0.0]*n]*n)
U = Matrix.Matrix([[0.0]*n]*n)
# En realidad podramos empaquetar toda la informacion en una sola matriz
En la factorizaci on de Doolitle los terminos diagonales de A son iguales a la unidad:
for i in range(n):
L[i,i] = 1.
A continuaci on rellenamos las matrices L y U:
for i in range(n): # Para cada "marco" superior izquierdo
for j in range(i, n): # Rellena la U a partir de la fila
suma = 0.0
for k in range(0, j):
suma += L[i,k] * U[k,j]
U[i,j] = A[i,j] - suma
for j in range(i+1, n): # Rellena la L a partir de la columna
suma = 0.0
for k in range(0, i):
suma += L[j,k]*U[k,i]
L[j,i] = (A[j,i] - suma) / U[i,i]
Y las devolvemos como una tupla.
return L, U
12.8.4. Descomposici on LU al estilo GSL
Hemos programado una segunda versi on de la descomposicion LU, GSL LU, siguiendo paso a
paso el algoritmo de la GSL, que utiliza permutaciones para garantizar que el pivote es siempre
el elemento mayor en valor absoluto en una columna dada. El algoritmo tambien optimiza
el espacio, empaquetando las matrices L y U en una sola matriz esta optimizacion puede
ser relevante si se tienen muchas matrices de gran dimension. La cadena de documentaci on
explica todo esto:
126
def GSL_LU(A):
"""
Factoriza una matriz cuadrada A en
P A = L U
donde P es una matriz de permutacion, L es triangular inferior
unitaria y U es triangular superior.
L se guarda en la parte triangular estrictamente inferior de la
matriz de entrada A. Los elementos de la diagonal de L son la
unidad y no se guardan.
U se guarda en la diagonal y la parte triangular superior de la
matriz de entrada A.
P (perm) se guarda en el formato [(i0,j0),(i1,j1),...]
signum da el signo de la permutacion, (-1)^n, donde n es el numero
de intercambios en la permutacion.
Referencia: Golub & Van Loan,Matrix Computations, Algoritmo
3.4.1 (Eliminacion de Gauss con pivote parcial).
"""
El algoritmo se inicializa imponiendo que la matriz sea cuadrada, reservando una lista vaca
para guardar las sucesivas permutaciones y asignando +1 al signo inicial de la permutaci on:
# La matriz debe ser cuadrada
n, m = A.shape
assert n == m
perm = []
signum = 1
A continuaci on encuentra el pivote, es decir el maximo de la j-esima columna (contando
a partir de la diagonal):
for j in xrange(n-1):
# Encuentra el maximo de la j-asima columna
maximo = A[j,j]
pivote = j
for i in xrange(j+1, n):
aij = A[i,j]
127
if aij > maximo:
maximo = aij
pivote = i
Intercambia las si es necesario, para usar el mayor pivote. Con cada intercambio se cambia
el signo de la permutacion que se guarda, a su vez en la lista de permutaciones.
# Intercambia filas si es necesario, para usar el mayor pivote
if pivote != j:
intercambia_filas(A, j, pivote)
perm.append((j,pivote))
signum = -signum
Donde la funci on intercambia filas(A,i,j) intercambia las las i y j de la matriz A:
def intercambia_filas(A, i, j):
"""
Intercambia las filas i <--> j de la matriz A.
"""
nfil, ncol = A.shape
for k in xrange(ncol):
A[i,k], A[j,k] = A[j,k], A[i,k]
Finalmente, el algoritmo calcula las matrices L y U, empaquet andolas en la matriz A cuyo
contenido inicial se reescribe:
# Calcula y empaqueta
ajj = A[j,j] # esquina superior izquierda
if (ajj != 0.0):
for i in xrange(j+1, n):
aij = A[i,j] / ajj # divide los elementos de la columna por
A[i,j] = aij # el pivote
for k in xrange(j+1, n): # halla los elementos de U a partir
aik = A[i, k] # de la fila
ajk = A[j, k]
A[i,k] = aik - aij * ajk
return perm, signum # A tambien ha cambiado
Notad que el algoritmo devuelve la lista de permutaci on y su signo, pero a la salida del
algoritmo la matriz A que es un objeto mutable tambien ha cambiado, de hecho contiene
las matrices L y U empaquetadas.
12.8.5. Ejemplo
Como de costumbre en el programa principal:
128
if __name__ == __main__:
Hemos incluido un ejemplo para ilustrar el uso de la descomposici on LU.
n = 3 # usaremos matrices 3x3
# Matriz de coeficientes.
A = Matrix.Matrix([[0.0]*n]*n) # los nueve valores iniciales son cero
for i in range(n):
for j in range(n):
A[i,j] = 1 + i*n + j
# A = [ [1,2,3], [4,5,6], [7,8,9] ]
# Descomposicion LU
L, U = LU(A)
print Con el primer algoritmo:
print A =
print_matrix(A)
print
print L, U =
for m in [L, U]:
print_matrix(m)
print
print A - L * U
print_matrix(A - L * U)
# Descomposicion LU usando el algoritmo de la GSL
A_save = A.copy()
perm, signum = GSL_LU(A)
print
print Con el algoritmo de la GSL:
print A (LU empaquetada) =
print_matrix(A)
print
print Permutacion:, perm
print Signo de la permutacion:, signum
print P =
print_matrix(perm_matrix(perm, A.shape[0]))
L, U = desempaqueta(A)
print
print L, U =
129
print_matrix(L)
print
print_matrix(U)
print
print A - P^-1 * L * U
perm.reverse()
print_matrix(A_save-perm_matrix(perm, A.shape[0])*L*U)
Al ejecutarlo obtenemos:
python lu.py
Con el primer algoritmo:
A =
1.000 2.000 3.000
4.000 5.000 6.000
7.000 8.000 9.000
L, U =
1.000 0.000 0.000
4.000 1.000 0.000
7.000 2.000 1.000
1.000 2.000 3.000
0.000 -3.000 -6.000
0.000 0.000 0.000
A - L * U
0.000 0.000 0.000
0.000 0.000 0.000
0.000 0.000 0.000
Con el algoritmo de la GSL:
A (LU empaquetada) =
7.000 8.000 9.000
0.143 0.857 1.714
0.571 0.500 0.000
Permutacion: [(0, 2), (1, 2)]
Signo de la permutacion: 1
P =
0.000 0.000 1.000
1.000 0.000 0.000
0.000 1.000 0.000
L, U =
1.000 0.000 0.000
130
0.143 1.000 0.000
0.571 0.500 1.000
7.000 8.000 9.000
0.000 0.857 1.714
0.000 0.000 0.000
A - P^-1 * L * U
0.000 0.000 0.000
0.000 0.000 0.000
0.000 0.000 0.000
12.9. Soluci on de sistemas lineales de ecuaciones
En la practica, a la hora de resolver sistemas lineales de ecuaciones (y otros problemas
asociados, como el de invertir una matriz), utilizaremos las funciones del m odulo de algebra
lineal a las que podemos acceder importando el correspondiente m odulo:
from LinearAlgebra import *
Hemos preparado un ejemplo, linAlgExample.py, donde se manejan todas estas funciones.
# Ejemplo de uso de funciones de algebra lineal
"""
Ejemplo de utilizacion de algunas de las funciones disponibles en el modulo
de algebra lineal de Numeric, a saber:
1) Solucion de ecuaciones lineales: A* x = b
solve_linear_equations(a, b):
2) Inversion de matrices
inverse(a)
3) Descomposicion de Choleski
cholesky_decomposition(a):
4) Determinante
determinant(a)
"""
from LinearAlgebra import *
from Numeric import *
from lu import *
if __name__ == __main__:
131
a=[[1.,1.,0.],[2.,1.,1.],[1.,2.,3.]]
A=array(a)
b=[1.,1.,2.]
B=array(b)
print "Matriz del sistema A.X = B: A "
print_matrix(A)
print "Vector de coeficientes B= "
print_vector(B)
x = solve_linear_equations(A, B)
print "Vector de incognitas= "
print_vector(x)
check = B - matrixmultiply(A, x)
print "B - A*x (deber ser proximo a cero)= ", check
a_inv = inverse(A)
print "inversa de A= "
print_matrix(a_inv)
check = matrixmultiply(a, a_inv)
print "A*A^{-1} (deber ser proxima a la matrix identidad)= "
print_matrix(check)
print "determinante de A=", determinant(A)
12.9.1. Resumen
En este captulo hemos estudiado la resoluci on de sistemas lineales de ecuaciones, uti-
lizando en primer lugar la factorizaci on LU de la matriz del sistema, seguida de la resolucion
(por sustitucion progresiva y regresiva) del sistema LU asociado. Hemos visto tambien que
el calculo del determinante de una matriz es inmediato una vez que esta se ha descompuesto
LU. Para calcular la inversa es necesario resolver el sistema de ecuaciones para los vectores
de la base. No obstante, la resoluci on de un sistema lineal mediante el calculo de la inversa
es mucho mas lento que su resoluci on directa, raz on por la cual este segundo metodo debe
ser el preferido.
132
Bibliografa
[1] Toda la informaci on relevante sobre Python puede encontrase en el sitio web
www.python.org
[2] Numeric es una potente extension de Python que proporciona arreglos numericos muy
r apidos y ecientes. Para m as detalles consultar el sitio web http://numeric.scipy.org/.
[3] SciPy es un proyecto para extender Python proporcion andole una amplia funcionalidad
util para c alculos cientcos. Para m as detalles consultar el sitio web http://www.scipy.org.
http://www.stsci.edu/resources/software hardware/numarray
[4] F.B. Hildebrand Introduction to Numerical Analysis, McGraw-Hill (New York, 1964).
[5] J. Stoer and R. Burlisch, Introduction to Numerical Analysis, Second Edition, Springer,
1991.
[6] D. Kincaid and W.Cheney, Numerical Analysis, Second Edition, Brooks & Cole, 1996.
[7] D. Kincaid and W.Cheney, Numerical Mathematics and Computing, Fourth Edition,
Brooks & Cole, 1999.
[8] W.H. Press et al, Numerical Recipes. Existen variantes en C, FORTRAN y PASCAL.
Cambridge University Press.
[9] GNU Scientic Library http://www.gnu.org
[10] R. Guardiola, E. Hig on y J. Ros, M`etodes Num`erics per a la fsica, Universidad de
Valencia.
133

Вам также может понравиться