Archivos de Tags: Python

Usando Theano (Python Con Matemáticas)

Hola, hace un par de semanas me encontré con unas librerías matemáticas basadas en Python llamadasTheano, en honor a la mujer de Pitágoras. Me parecieron interesantes y las empaqueté para Mandriva; están disponibles en MIB, por si a alguien le interesa. Con ellas podemos definir, evaluar y optimizar expresiones matemáticas que involucren arrays multidimensionales de forma eficiente.

Lo cierto es que viene muy bien para definir funciones matemáticas de cualquier dimensión, pudiendo especificar los parámetros de las funciones. Otra característica que he encontrado muy interesante es que calcula las derivadas de las funciones con un código sencillo y claro.
Destacar que estas librerías son totalmente compatibles con Numpy, Scipy y las he usado sin problemas con Mathplotlib para dibujar las gráficas de funciones.
Tienen una característica, la cual no he utilizado aún, y es que si tienes una tarjeta Nvidia con soporte Cuda puedes obtener una mayor eficiencia en cálculos grandes, pero esto poco a poco ;-)
Bien, para que veáis cómo se usan con un ejemplo un poco más elaborado que los que vienen en su documentación he realizado un pequeño programa que dibuja la función logística y su recta tangente en un punto dado, para ello he usado Mathplotlib, de esa forma podéis aprender a dibujar funciones de forma sencilla, con soporte LateX en las figuras, creación de leyendas y guardado de las imágenes en formato .png. El código es el siguiente:

#!/usr/bin/python

from matplotlib import rc
from pylab import *
from theano import *
import theano.tensor as T
import numpy

rc('text', usetex=True)
rc('font', family='serif')

x = T.fvector('x')
x1 = T.fscalar('x1')
y = 1/(1 + T.exp(-x))
y1 = 1/(1 + T.exp(-x1))
logistic = function([x], y)
logistic1 = function([x1], y1)
grady = T.grad(y1, x1)
derivada = function([x1], grady)

a = float(input('Introduce el extremo izqdo. \n'))
b = float(input('Introduce el extremo drcho. \n'))
particion = float(input('Introduce la longitud de particion del intervalo. \n'))
pderiv = float(input('Introduce el punto donde hallar su recta tangente. \n'))

xval = arange(a,b,particion, dtype='float32')
z,w,w1=T.fscalars('z', 'w', 'w1')
rectatg2 = (x-z)*w+w1
rectatg3 = function([x, Param(z, default=pderiv), Param(w, default=derivada(pderiv)), Param(w1, default=logistic1(pderiv))], rectatg2)

figure(1)

plot(xval, logistic(xval), linewidth=1.5, color='r')
plot(xval, rectatg3(xval), linewidth=1.0, color='g')
ylim([0,1])

xlabel(r'\textbf{Abcisa}', fontsize=12)
ylabel(r'\textit{Ordenada}',fontsize=12)
title(r"Funcion logistica f(x) = $\displaystyle\frac{1}{1+e^{-x}}$", fontsize=12, color='r')
legend(('Funcion Logistica', 'Recta Tangente'),'upper left', shadow=True, fancybox=True)

leg = gca().get_legend()
ltext  = leg.get_texts()
llines = leg.get_lines()
frame  = leg.get_frame()

frame.set_facecolor('0.80')
setp(ltext, fontsize='small')
setp(llines, linewidth=1.5)

grid(True)
axhline(linewidth=1.5, color='b')
axvline(linewidth=1.5, color='b')

figure(2)

plot(xval, logistic(xval), 'k.')
plot(xval, rectatg3(xval), linewidth=1.0, color='g')
ylim([0,1])
legend(('Funcion Logistica', 'Recta Tangente'),'upper left', shadow=True, fancybox=True)
leg = gca().get_legend()
ltext  = leg.get_texts()
llines = leg.get_lines()
frame  = leg.get_frame()

frame.set_facecolor('0.80')
setp(ltext, fontsize='small')
setp(llines, linewidth=1.5)

xlabel(r'\textbf{Abcisa}', fontsize=12)
ylabel(r'\textit{Ordenada}',fontsize=12)
title(r"Funcion logistica f(x) = $\displaystyle\frac{1}{1+e^{-x}}$", fontsize=12, color='r')
grid(True)
axhline(linewidth=1.5, color='r')
axvline(linewidth=1.5, color='r')

figure(1)
savefig('fig1')
figure(2)
savefig('fig2')

show()

Y el resultado del código es éste:


Nota: En esa web encontraréis un enlace de descarga de la documentación en PDF.

Saludos :-)

Translate-me En Mandriva

Hola, para el que no lo sepa Translate-me es una pequeña aplicación basada en Python que sirve para traducir textos entre diferentes lenguas, creado por el atareao. Esta pequeña aplicación me resulta muy útil, como uso más Mandriva que Ubuntu he decidido empaquetarla para Mandriva. Para instalarla es muy sencillo, sólo debéis tener añadidos los repositorios del MIB para Mandriva 2010.2, luego lo podéis instalar desde la terminal con:

usuario@nombrepc:~$
su
urpmi translate-me
exit

Saludos :-)

Programación Lineal Con Python

Hola, en Python hay diversidad de librerías para hacer programación lineal tanto la normal como la entera. En esta ocasión os voy ha hablar de PyMathPrpog, unas librerías basadas en Glpk y PyGlpk con las cuales podemos calcular nuestros problemas en métodos como el Simplex, Exacto e Interior; o Plain y Avanzado si lo que buscamos son soluciones enteras. También podemos obtener un informe detallado de nuestra solución, las primales, las primales factibles, las duales, etc. y todo ello de forma sencilla. Esta librería no se encuentra (que yo sepa) en los repositorios oficiales de Ubuntu, pero bueno si añades mi repositorio de Launchpad la puedes instalar bajo el nombre de python-mathprog. Supongamos que queremos solucionar el siguiente problema:
Max: z=10x+6y+4z
s.a.  \begin{cases}        x+y+z \le 100 \\   10x+4y+5z \le 600 \\ 2x+2y+6y \le 300 \\ x,y,z \ge 0     \end{cases}

El código en Python usando estas librerías es el siguiente:

from pymprog import *  # Importar el modulo
# indices y datos
xid, rid = range(3), range(3)
c = (10.0, 6.0, 4.0)
mat = [ (1.0, 1.0, 1.0),
        (10.0, 4.0, 5.0),
        (2.0, 2.0, 6.0)]
b = (100.0, 600.0, 300.0)
#definicion del problema
beginModel('basic')   #Lo definimos como basico
verbose(True)
x = var(xid, 'X') #crear variables
maximize( #funcion objetivo
  sum(c[i]*x[i] for i in xid), 'miobjetivo'
)
r=st( #Conjunto de restricciones
  sum(x[j]*mat[i][j] for j in xid) <= b[i] for i in rid
)
solve() #Solucion e Informe
print "Estado Solucionador:", status()
print 'Z = %g;' % vobj()  # Valor funcion Objetivo
#Impresion de nombre de las variables y las primales
print ';\n'.join('%s = %g {dual: %g}' % (
   x[i].name, x[i].primal, x[i].dual)
                    for i in xid)
print ';\n'.join('%s = %g {dual: %g}' % (
   r[i].name, r[i].primal, r[i].dual)
                    for i in rid)

print reportKKT()
print "Environment:", env
for pn in dir(env):
    if pn[:2]=='__'==pn[-2:]: continue
    print pn, getattr(env, pn)

print ' '
print evaluate(sum(x[i]*(i+x[i])**2 for i in xid))
print sum(x[i].primal*(i+x[i].primal)**2 for i in xid)
endModel() #Finalizar el Modelo

Y la solución por terminal es:


MAX 'miobjetivo': 10 X[0]+ 6 X[1]+ 4 X[2]
s.t. R0[0]: X[0]+ X[1]+ X[2] <= 100.0
s.t. R0[1]: 10 X[0]+ 4 X[1]+ 5 X[2] <= 600.0
s.t. R0[2]: 2 X[0]+ 2 X[1]+ 6 X[2] <= 300.0
Estado Solucionador: opt
Z = 733.333;
X[0] = 33.3333 {dual: 0};
X[1] = 66.6667 {dual: 0};
X[2] = 0 {dual: -2.66667}
R0[0] = 100 {dual: 3.33333};
R0[1] = 600 {dual: 0.666667};
R0[2] = 200 {dual: 0}

Karush-Kuhn-Tucker optimality conditions:
=========================================

1) Error in Primal Solutions:
-----------------------------
Largest absolute error: 0.000000 (row id: 1)
Largest relative error: 0.000000 (row id: 1)
Quality of primal solution: H

2) Error in Satisfying Primal Bounds:
-------------------------------------
Largest absolute error: 0.000000 (var id: 0)
Largest relative error: 0.000000 (var id: 0)
Quality of primal feasibility: H

3) Error in Dual Solutions:
-----------------------------
Largest absolute error: 0.000000 (col id: 0)
Largest relative error: 0.000000 (col id: 0)
Quality of dual solution: H

4) Error in Satisfying Dual Bounds:
-------------------------------------
Largest absolute error: 0.000000 (var id: 0)
Largest relative error: 0.000000 (var id: 0)
Quality of dual feasibility: H

Environment:
blocks 45
blocks_peak 72
bytes 27508
bytes_peak 28998
mem_limit None
term_hook None
term_on True
version (4, 38)

342288.888889
342288.888889


Como vemos en la salida por terminal obtenemos un informe muy detallado de la solución y sus posibles soluciones.
Obviamente al ser este ejemplo de 3 variables no es factible dibujar su región, al igual que no lo son la mayoría de estos problemas. Tan sólo son posibles sus soluciones gráficas para problemas de 2 variables, que se dan mayoritariamente en Bachiller. A mi estas librerías me parecen una buena alternativa al programa no libre LINGO. Me queda pendiente verlo con python-cvxopt, pero eso os lo cuento otro día ;-)

Saludos :-)

Método Newton-Raphson Con Python

Hola, durante las fallas Carlos Sessa me pidió si podía añadir en el código que hice en Python sobre métodos aproximativos de búsqueda de raíces de funciones el método de Newton y le dije que encantado, que no había ningún problema porque el código que hice es totalmente libre, sin ningún tipo de licencia restrictiva, para que todo el mundo aprenda de ello o mejore el código si lo desea. También le prometí publicarlo en el blog, así que eso es lo que voy ha hacer ahora, aunque con algo de retraso ;)

Bueno al meollo. El método de Newton parte de la idea de calcular la raíz (o cero) de una función en un intervalo mediante aproximaciones a la raíz mediante el cálculo de la recta tangente en esas aproximaciones. Para ello utilizamos la ecuación de la recta a la curva de la forma punto-pendiente.

Así pues partiendo de la curva (función) f:[a,b]\longrightarrow\mathbb{R} derivable en un punto incial x_0 cercano a la raíz que buscamos, sabemos que la ecuación punto-pendiente de la curva f tiene la expresión:

y-y_0 = f\prime (x_0)(x-x_0)

Al ser x_0 y todas sus aproximaciones las aproximaciones de la raíz que buscamos, tenemos que y_0=0 , ya que las raíces de cualquier curva, son gráficamente hablando, los puntos de la gráfica de f que cortan en el eje de abcisas, por lo que su ordenada es cero. Así pues tenemos:

y = f\prime (x_0)(x-x_0)

Si ahora consideramos que y=f(x) , podemos considerar la expresión anterior en términos de sucesiones. Así pues, sea x_{n} la sucesión  infinita de términos reales que representan a las distintas aproximaciones de la raíz que buscamos. Como f es derivable en ]a,b[ tenemos que f es continua en [a,b], así pues por el Teorema del Límite Vinculante podemos considerar que existen las sucesiones f(x_n )\quad y\quad f\prime (x_n ) . Así pues, sustituyendo en la expresión anterior obtenemos:

f(x_n ) = f\prime (x_n)(x_{n+1}-x_n)

Si despejamos x_{n+1} obtenemos:

x_{n+1}=x_{n}-\frac{f(x_n)}{f\prime (x_n)}

Que es la expresión propia del algoritmo de Newton-Raphson si hacemos iterar el número natural "n" desde 0 hasta un número determinado de iteraciones, que vendrá determinado principalmente por la precisión que queramos que tenga la aproximación de nuestra raíz, que es lo que se viene a llamar por el palabro de tolerancia.

Antes es bueno aclarar que una demostración rigurosa de éste método debería hacerse mediante el desarrollo del Polinomio de Taylor de la curva f centrado en el x_0 y hasta orden 2, para así obtener una cota del error, pero la omito porque me parece más fácil de entender mediante la ecuación punto-pendiente, que es la que conocen muchos estudiantes de 2º de bachiller.

Hay que recalcar que el método de Newton falla cuando la curva f no es derivable en un entorno pequeño del valor inicial, también falla si en algún punto del entorno del valor inicial su derivada es nula, o próxima a cero hablando desde el punto de vista computacional.

Si queremos buscar entornos del punto inicial para buscar raíces sin dibujar la gráfica de la curva se pueden usar los teoremas de Bolzano y de Rolle. El primero nos da la existencia de la raíz en un intervalo o entorno, y el segundo nos da su unicidad.

Sin más os dejo el código del método de Newton-Raphson escrito en código Python:

#!/usr/bin/python
 # coding: latin-1

import Evaluar
 from pylab import *
 from Numeric import *

def newton(df, po, TOL, N):

i = 1
 vectorx = zeros(N, Float64)
 vectory = zeros(N, Float64)

while i<=N:

vectorx[i-1] = po
 Evaluar.dicc_seguro['x'] = po
 f  = eval(Evaluar.funcion, {"__builtins__":None}, Evaluar.dicc_seguro)
 df_val = eval(df, {"__builtins__":None}, Evaluar.dicc_seguro)

vectory[i-1] = f

if df_val == 0.0:
 print "La evaluacion de la derivada de la funcion dio 0"
 break

p1 = po - (f/df_val)

if fabs(po-p1) < TOL:
 print "La raiz buscada es: ",po, "con", i-1,"iteraciones"
 break

i += 1
 po = p1

return [vectorx, vectory]

def dibujar(df, po, TOL, N):

x = arange(po-2,po+2,0.1)
 vectores = newton(df, po, TOL, N)

subplot(211)
 plot(x, eval(Evaluar.funcion), linewidth=1.0)
 xlabel('Abcisa')
 ylabel('Ordenada')
 title('Metodo Newton con f(x)=' + Evaluar.funcion)
 grid(True)
 axhline(linewidth=1, color='r')
 axvline(linewidth=1, color='r')

subplot(212)
 plot(vectores[0], vectores[1], 'k.')
 xlabel('Abcisa')
 ylabel('Ordenada')
 grid(True)
 axhline(linewidth=1, color='r')
 axvline(linewidth=1, color='r')

show()

Os pongo un pantallazo del método usando la función f(x)=x^2-\pi
Newton Raphson

Bueno os dejo un zip comprimido con la totalidad del código, con todos los métodos que hay hechos hasta ahora.

DESCARGAR CODIGO

Yo el código lo ejecuto y edito con Geany (lo tenéis en los repositorios de cualquier distro linuxera importante.
En la Wikipedia tenéis más información sobre éste método->Enlace a la Wikipedia
Cuando tenga algo de tiempo haré el método de Müller, para poder aproximar raíces en el campo de los números complejos.

¡Muchas gracias a Carlos Sessa por su colaboración! :-)
Saludos :-)

[TIP] Solucion Warning De Matplotlib En Ubuntu Intrepid

Hola, como muchos ya sabéis estoy aprendiendo a programar en Python cuando tengo ratos libres, y claro al ser matemático mis programas muchas veces utilizan las librerías gráficas Matplotlib para poder dibujar funciones matemáticas de forma muy sencilla y limpia con mis códigos de Python.
Desde que he instalado Ubuntu Intrepid Ibex me he encontrado que Matplotlib me echaba en mis programas un fastidioso Aviso (Warning) que rezaba así:

usr/lib/python2.5/site-packages/pytz/__init__.py:29: UserWarning: Module dateutil was already imported from /var/lib/python-support/python2.5/dateutil/__init__.py, but /var/lib/python-support/python2.5 is being added to sys.path
from pkg_resources import resource_stream

Este warning no es que afectase a mis sencillos programas, pero no es nada estético, y además vete a saber si no esta algo fastidiado sin saberlo, aun siendo un aviso y no un error. Esta mañana he encontrado una solución muy sencilla en Launchpad, sólo debéis abrir terminal y escribir la siguiente línea:

sudo python -c 'import matplotlib'

Ahora cuando ejecutéis vuestros programas o ejecutéis directamente Matplotlib ya no os aparecerá el dichoso warning ;)

Saludos :-h

Page 1 of 3123