In [9]:
%pylab inline
#%numpy.linalg inline
%qtconsole
from mpl_toolkits.mplot3d import Axes3D
from ipywidgets import interact, interactive
from IPython.display import clear_output, display, HTML


Populating the interactive namespace from numpy and matplotlib

Programar ¿con qué se come?

La computadora es una gran gran calculadora que permite hacer cualquier tipo de cuenta de las que necesitemos dentro de la Física (y de la vida también) mientras sepamos cómo decirle a la máquina qué cómputos hacer.

La computadora para hacer cuentas tiene que almacenar los números que necesitemos y luego hacer operaciones con ellos. Nuestros valores numéricos se guardan en espacios de memoria, y esos espacios tienen un nombre, un rótulo con el cual los podremos llamar y pedirle a la computadora que los utilice para operar con ellos, los modifique, etc. Ese nombre a cada espacio de memoria se asigna, al menos en Python, con el símbolo = que significa de ahora en más: "asignación".

Pero no sólamente guardaremos valores numéricos. Además de haber distintos tipos de valores numéricos, como veremos ahora, podemos guardar otros tipos de datos, como texto (strings) y listas (lists) entre muchos otros. Todos los tipos de valores que podremos almacenar difieren entre si el espacio en memoria que ocupan y las operaciones que podremos hacer con ellos.

Veamos un par de ejemplos


In [6]:
x = 5
y = 'Hola mundo!'
z = [1,2,3]

Aquí hemos guardado en un espacio de memoria llamado por nosotros "x" la información de un valor de tipo entero, 5, en otro espacio de memoria, que nosotros llamamos "y" guardamos el texto "Hola mundo!". En Python, las comillas indican que lo que encerramos con ellas es un texto. x no es un texto, así que Python lo tratará como variable para manipular. "z" es el nombre del espacio de memoria donde se almacena una lista con 3 elementos enteros.

Podemos hacer cosas con esta información. Python es un lenguaje interpretado (a diferencia de otros como Java o C++), eso significa que ni bien nosotros le pedimos algo a Python, éste lo ejecuta. Así es que podremos pedirle por ejemplo que imprima en pantalla el contenido en y, el tipo de valor que es x (entero) entre otras cosas.


In [4]:
print y
print type(x)
print type(y), type(z), len(z)


Hola mundo!
<type 'int'>
<type 'str'> <type 'list'> 3

Vamos a utilizar mucho la función type() para entender con qué tipo de variables estamos trabajando. type() es una función predeterminada por Python, y lo que hace es pedir como argumento (lo que va entre los paréntesis) una variable y devuelve inmediatamente el tipo de variable que es.

Para las variables integers(enteros) y floats (flotantes) podemos hacer las operaciones matemáticas usuales y esperables. Veamos un poco las compatibilidades entre estos tipos de variables.


In [25]:
a = 5
b = 7
c = 5.0
d = 7.0
print a+b, b+c, a*d, a/b, a/d, c**2


12 12.0 35.0 0 0.714285714286 25.0

Listas

Las listas son cadenas de datos de cualquier tipo, unidos por estar en una misma variable, con posiciones dentro de esa lista, con las cuales nosotros podemos llamarlas. En Python, las listas se enumeran desde el 0 en adelante.

Estas listas también tienen algunas operaciones que le son válidas.

Distintas son las tuplas. Las listas son editables, pero las tuplas no. Esto es importante cuando, a lo largo del desarrollo de un código donde necesitamos que ciertas cosas no cambien, no editemos por error valores fundamentales de nuestro problema a resolver.


In [15]:
lista1 = [1, 2, 'saraza']
print lista1, type(lista1)
print lista1[1], type(lista1[1])
print lista1[2], type(lista1[2])
print lista1[-1]


[1, 2, 'saraza'] <type 'list'>
2 <type 'int'>
saraza <type 'str'>
saraza

In [14]:
lista2 = [2,3,4]
lista3 = [5,6,7]
print lista2+lista3
print lista2[2]+lista3[0]


[2, 3, 4, 5, 6, 7]
9

In [17]:
tupla1 = (1,2,3)
lista4 = [1,2,3]
lista4[2] = 0
print lista4
#tupla1[0] = 0
print tupla1


[1, 2, 0]
(1, 2, 3)

Hay formas muy cómodas de hacer listas. Presentamos una que utilizaremos mucho, que es usando la función range.


In [18]:
listilla = range(10)
print listilla, type(listilla)


[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] <type 'list'>

Booleans

Este tipo de variable tiene sólo dos valores posibles: 1 y 0, o True y False. Las utilizaremos escencialmente para que Python reconozca relaciones entre números.


In [20]:
print 5>4
print 4>5
print 4==5 #La igualdad matemática se escribe con doble ==
print 4!=5 #La desigualdad matemática se escribe con !=
print type(4>5)


True
False
False
True
<type 'bool'>

Bibliotecas

Pero las operaciones básicas de suma, resta, multiplicación y división son todo lo que un lenguaje como Python puede hacer "nativamente". Una potencia o un seno es álgebra no lineal, y para hacerlo, habría que inventarse un algoritmo (una serie de pasos) para calcular por ejemplo sen($\pi$). Pero alguien ya lo hizo, ya lo pensó, ya lo escribió en lenguaje Python y ahora todos podemos usar ese algoritmo sin pensar en él. Solamente hay que decirle a nuestro intérprete de Python dónde está guardado ese algoritmo. Esta posibilidad de usar algoritmos de otros es fundamental en la programación, porque es lo que permite que nuestro problema se limite solamente a entender cómo llamar a estos algoritmos ya pensados y no tener que pensarlos cada vez.

Vamos entonces a llamar a una biblioteca llamada math que nos va a extender nuestras posibilididades matemáticas.


In [24]:
import math as m # Llamamos a una biblioteca y la bautizamos m por comodidad
r1 = m.pow(2,4)
r2 = m.cos(m.pi)
r3 = m.log(100,10)
r4 = m.log(m.e)
print r1, r2, r3, r4


16.0 -1.0 2.0 1.0

Para entender cómo funcionan estas funciones, es importante recurrir a su documentation. La de esta biblioteca en particular se encuentra en

https://docs.python.org/2/library/math.html

Funciones

Pero si queremos definir nuestra propia manera de calcular algo, o si queremos agrupar una serie de órdenes bajo un mismo nombre, podemos definirnos nuestras propias funciones, pidiendo la cantidad de argumentos que querramos.

Vamos a usar las funciones lambda más que nada para funciones matemáticas, aunque también tenga otros usos. Definamos el polinomio $f(x) = x^2 - 5x + 6$ que tiene como raíces $x = 3$ y $x = 2$.


In [27]:
f = lambda x: x**2 - 5*x + 6
print f(3), f(2), f(0)


0 0 6

Las otras funciones, las más generales, se las llama funciones def, y tienen la siguiente forma.


In [29]:
def promedio(a,b,c):
    N = a + b + c # Es importante que toda la función tenga su contenido indentado
    N = N/3.0
    return N
mipromedio = promedio(5,5,7) # Aquí rompimos la indentación
print mipromedio


5.66666666667

Control de flujo: iteraciones y condicionales (if y for para los amigos)

Si en el fondo un programa es una serie de algoritmos que la computadora debe seguir, un conocimiento fundamental para programar es saber cómo pedirle a una computadora que haga operaciones si se cumple una condición y que haga otras si no se cumple. Nos va a permitir hacer programas mucho más complejos. Veamos entonces como aplicar un if.


In [35]:
def ejemplo(parametro):
    if parametro > 0: # un if inaugura también un nuevo bloque indentado
        print 'Tu parametro es', parametro, 'y es mayor que cero'
        print 'Gracias'
    else:            # el else inaugura otro bloque indentado
        print 'Tu parametro es', parametro, 'y es menor o igual que cero'
        print 'Gracias'
    print 'Vuelva pronto'
    print ' '
    
ejemplo(5)
ejemplo(-1)


Tu parametro es 5 y es mayor que cero
Gracias
Vuelva pronto
 
Tu parametro es -1 y es menor o igual que cero
Gracias
Vuelva pronto
 

Para que Python repita una misma acción n cantidad de veces, utilizaremos la estructura for. En cada paso, nosotros podemos aprovechar el "número de iteración" como una variable. Eso nos servirá en la mayoría de los casos.


In [41]:
nuevalista = ['nada',1,2,'tres', 'cuatro', 7-2, 2*3, 7/1, 2**3, 3**2]
for i in range(10):       # i es una variable que inventamos en el for, y que tomará los valores de la 
    print nuevalista[i]   #lista que se genere con range(10)


nada
1
2
tres
cuatro
5
6
7
8
9

La estructura while es poco recomendada en Python pero es importante saber que existe: consiste en repetir un paso mientras se cumpla una condición. Es como un for mezclado con un if.


In [42]:
i = 1
while i < 10: # tener cuidado con los while que se cumplen siempre. Eso daría lugar a los loops infinitos.
    i = i+1
    print i


2
3
4
5
6
7
8
9
10

Un poquito de álgebra lineal

Para esta primera parte, utilizaremos una biblioteca muy útil para cálculo matricial, numpy. De allí sacaremos los tipos de dato ndarray, matrix, y todas las operaciones que utilicemos. Veamos un poco cómo definir vectores fila, matrices, y cómo llamar a determinado componente de determinado vector o matriz.


In [5]:
pos = array([1,4,3])
mat = matrix([[1,2,3], 
             [4,5,6], 
             [7,8,9]])

x = pos[0] # en Python, las posiciones de los vectores comienzan a contarse en 0
y = pos[1]
z = pos[2]
print 'suma de las componentes:', x+y+z, sum(pos)

c = (mat[0,0] + mat[0,1])* mat[1,1]
print 'operación con los elementos de la matriz:' , c

#Nos acostumbraremos a utilizar arrays para matrices
mat = array(mat) # La función array() transforma mat (que era una matrix) en un ndarray
print mat, type(mat)


suma de las componentes: 8 8
operación con los elementos de la matriz: 15
[[1 2 3]
 [4 5 6]
 [7 8 9]] <type 'numpy.ndarray'>

Las matrices especiales pueden armarse "a mano" como ejercicio, como también pueden buscarse entre las funciones que Python ofrece


In [6]:
identidad = zeros([3,3])
for i in range(3):
    for j in range(3):
        if i == j:
            identidad[i,j] = 1       
print 'identidad armada a mano: '
print identidad

identidad2 = identity(3)
print 'identidad de la función de Python: ' 
print identidad2

unos = ones([3,4]) #matriz de unos
print 'matriz de unos: '
print unos

ceros = zeros([4,3]) #matriz de ceros
print 'matriz de ceros: '
print ceros


identidad armada a mano: 
[[ 1.  0.  0.]
 [ 0.  1.  0.]
 [ 0.  0.  1.]]
identidad de la función de Python: 
[[ 1.  0.  0.]
 [ 0.  1.  0.]
 [ 0.  0.  1.]]
matriz de unos: 
[[ 1.  1.  1.  1.]
 [ 1.  1.  1.  1.]
 [ 1.  1.  1.  1.]]
matriz de ceros: 
[[ 0.  0.  0.]
 [ 0.  0.  0.]
 [ 0.  0.  0.]
 [ 0.  0.  0.]]

Entre las operaciones que pueden hacerse con vectores y matrices se encuentran las que esperamos que estén: producto escalar, producto de matrices con vectores, transposición.


In [7]:
print 'teníamos la matriz: '
print mat

trans = transpose(mat)
print 'la traspuesta es: '
print trans

print 'vector pos=', pos

print 'producto escalar: ' , dot(pos, pos) # producto escalar entre vectores

print 'producto componente a componente:' , pos*pos # producto componente a componente. Más útil con funciones

A = array([[1,2],[0,1]]) #Otra forma de definir directamente matrices como arrays sin tener que transformar
x = array([1,2])
print 'A = ',A,'  ', 'x= ', x
print 'Ax=', dot(A, x)


teníamos la matriz: 
[[1 2 3]
 [4 5 6]
 [7 8 9]]
la traspuesta es: 
[[1 4 7]
 [2 5 8]
 [3 6 9]]
vector pos= [1 4 3]
producto escalar:  26
producto componente a componente: [ 1 16  9]
A =  [[1 2]
 [0 1]]    x=  [1 2]
Ax= [5 2]

Y también tenemos esas funciones que siempre quisimos tener desde el CBC: inversa de una matriz, cálculo de determinantes, resolución de sistema de ecuaciones, hallazgo de autovalores y autovectores. Para esto usamos una biblioteca extra llamada linalg.


In [12]:
print 'Podemos encontrar la matriz inversa: ' 
print inv(A)

print 'su determinante:', det(A)
print 'Resolver un sistema de forma Ax=b'
b = x
print 'x =' ,solve(A, b)
print 'Y hallar autovalores y autovectores'
autoval, autovec = eig(A)
print 'Los autovalores: ', autoval
print 'Los autovectores: ', autovec


Podemos encontrar la matriz inversa: 
[[ 1. -2.]
 [ 0.  1.]]
su determinante: 1.0
Resolver un sistema de forma Ax=b
x = [-3.  2.]
Y hallar autovalores y autovectores
Los autovalores:  [ 1.  1.]
Los autovectores:  [[  1.00000000e+00  -1.00000000e+00]
 [  0.00000000e+00   1.11022302e-16]]

Funciones y gráficos

Lo siguiente que Python tiene de interesante para usar son sus facilidades para hacer gráficos. La biblioteca matplotlib nos ayudará en este caso. Primero, definimos un vector que nos hace de dominio, luego, un vector imagen de alguna función, y luego haremos el gráfico. Se muestran aquí algunas de las opciones que tiene matplotlib para presentar un gráfico, pero yendo a la documentación podrán encontrar infinidad de herramientas para hacer esto.


In [10]:
# Ploteos

x = linspace(-10, 10, 200) # con la función linspace generaremos un vector con componentes equidistantes.
y = x**2 # el vector imagen será igual de largo que x
plot(x,y, '-', color = 'red', label = 'Curva x**2') # ver qué pasa con 'r', 'g', '*' entre otros
title('Mi primer ploteo')
xlabel('Eje de las x')
ylabel('Eje de las y')
#xlim(-5,5)
#ylim(0,4)
legend('best')
grid(True)



In [38]:
f = lambda x,n: sin(n*pi*x) # Definimos una sucesión de funciones trigonométricas
y = f(x,0) # vector imagen de la función f(x) = 0

for i in range(5): # este es un caso simple donde sumo las 5 primeras funciones de la sucesión
	y =  y + f(x,i) # a esa y le sumo el valor de las imágenes de las siguientes funciones de la sucesión de funciones

plot(x,y, label = 'Curva')
title('Suma de senos')
xlabel('Dominio')
ylabel('Suma de los primeros 5 senos')
legend('best')

# Podríamos hacer derivación numérica

# Integración sería útil?

# Transformada de Fourier es irse al chori?


Out[38]:
<matplotlib.legend.Legend at 0x7f4adaa9e6d0>

Resolviendo física: pendulos acoplados


In [ ]:

La importancia de las referencias


In [ ]: