Práctica 3 - Dinámica de manipuladores

List comprehensions

En esta práctica nos enfocaremos en temas avanzados de programación que se aplican directamente al lenguaje de programación Python y a algunos otros lenguajes de programación. En primer lugar veamos la instrucción range:


In [ ]:
range(5)

Mmmm..., realmente no hizo nada... bueno, el objetivo de esta función de la libreria standard de Python es crear un arreglo de enteros desde $0$ hasta el numero que le demos como argumento:


In [ ]:
for i in range(5):
    print(i)

En este caso es obvio como se estan generando los numeros, desde $0$ hasta ¿$4$?. Mas bien hasta que el numero de elementos sea el numero dado, o bien $n-1$; de cualquier manera, esta forma de utilizar el ciclo for es la que nos da el vinculo con el for tradicional de otros lenguajes de programación, pero en Python tenemos una manera diferente de usar este mismo for, List Comprehensions:


In [ ]:
[i for i in range(5)]

Si recuerdas la práctica 1, para crear un arreglo con numeros adentro, podiamos utilizar el siguiente código:


In [ ]:
A = []
for i in range(5):
    A.append(i)
    
A

Sin embargo, comparandolo con la simplicidad del código anterior, este enfoque palidece, por lo que en Python es normal ver este tipo de construcciones, podemos diseccionarlo en dos partes:

[i for i in range(5)]

en la primera, i ocupa el lugar del elemento que nos dicta que es lo que vamos a guardar en el arreglo final; en este caso, es el numero a secas, por lo que no hacemos ninguna operación, pero si queremos guardar en un arreglo, por ejemplo, los cuadrados de los primeros $10$ enteros positivos, tendremos:


In [ ]:
[i**2 for i in range(10)]

La segunda parte de este código,

[i for i in range(5)]

es el for, esta es la razon por la que usamos i anteriormente, da lo mismo escribir:


In [ ]:
[x**2 for x in range(10)]

y por supuesto no funcionará si:


In [ ]:
[x**2 for i in range(10)]

Pero regresemos por un momento al primer pedazo de código que escribimos:


In [ ]:
range(5)

Si ese... lo que esta pasando aqui es que Python realmente no quiere evaluar esta expresión hasta que sea completamente necesario, a este concepto se le llama Lazy Evaluation, o evaluación floja; a pesar de la mala reputación que tiene Python por ser lento, y por ocupar demasiada memoria de ejecución, tiene caracteristicas bastante interesantes, como el hecho de no evaluar expresiones que no van a ser necesarias.

Hagamos un ejemplo para que quede mas claro:


In [ ]:
if False:
    A = []
    for i in range(5):
        A.append(i)
else:
    pass

En este código las lineas dentro del if nunca serán ejecutadas, por lo que si tuvieramos un lenguaje de programación compilado (como C), en primer lugar tendría que reservar espacio en memoria para el arreglo que va a guardar los datos de A, sin embargo nunca se utilizaria ese espacio, en Python nunca se ejecutarán esas lineas y lo demostraremos:


In [ ]:
%%timeit
A = [i for i in range(5)]

Una de las funciones especiales de Jupyter (no de Python) es que si escribo %%timeit al inicio de cualquier celda, la ejecutará muchas veces y me reportará el promedio de tiempo que se tardó en ejecutar esta celda, en este caso nuestro programa se tardó $739ns$ en promedio.

Si por el otro lado, ejecuto las lineas en donde saltará especificamente la creación de este arreglo tendremos:


In [ ]:
%%timeit
if False:
    A =[]
    for i in range(5):
        A.append(i)
else:
    pass

En esta ocasión se tarda $12.4ns$ ya que en realidad no esta haciendo nada...

Por cierto, una cosa más... las list comprehensions funcionan no solo con range, sino con cualquier arreglo, como en el siguiente caso:


In [ ]:
[x**2 + 1 for x in [2,4,6,8,10]]

o incluso este:


In [ ]:
[caracter + " abc" for caracter in "pizza"]

Ejercicio

Utilizando list comprehensions:

  • Genera un arreglo con los simbolos de sympy que representan la longitud de 5 eslabones, recuerda que para generar el simbolo de $l_1$ tenemos que escribir:
var("l1")

In [ ]:
from sympy.physics.mechanics import mechanics_printing
mechanics_printing()

In [ ]:
from sympy import var
# ESCRIBE TU CODIGO AQUI
raise NotImplementedError
longs

In [ ]:
from nose.tools import assert_equal
from sympy import var
assert_equal(longs, [var("l1"), var("l2"), var("l3"), var("l4"), var("l5")])
  • Genera un arreglo con las matrices simbolicas de sympy que contengan las matrices de transformación homogéneas de los 5 grados de libertad descritos en el siguiente arreglo con parametros DH:

In [ ]:
parametros_DH = [[ "0", "l1", "0", "q1"],
                 ["l2",  "0", "0", "q2"],
                 [ "0", "l3", "0", "q3"],
                 ["l4",  "0", "0", "q4"],
                 [ "0", "l5", "0", "q5"]]

In [ ]:
from sympy import var
# ESCRIBE TU CODIGO AQUI
raise NotImplementedError
matrices

In [ ]:
from nose.tools import assert_equal
from sympy import Matrix, var, sin, cos
l1, q1, cero = var("l1"), var("q1"), var("0")
A1 = Matrix([[cos(q1), -sin(q1)*cos(cero), sin(cero)*sin(q1), cero*cos(q1)],
             [sin(q1), cos(cero)*cos(q1), -sin(cero)*cos(q1), cero*sin(q1)],
             [0, sin(cero), cos(cero), l1],
             [0, 0, 0, 1]])
assert_equal(matrices[0], A1)
l2, q2, cero = var("l2"), var("q2"), var("0")
A2 = Matrix([[cos(q2), -sin(q2)*cos(cero), sin(cero)*sin(q2), l2*cos(q2)],
             [sin(q2), cos(cero)*cos(q2), -sin(cero)*cos(q2), l2*sin(q2)],
             [0, sin(cero), cos(cero), cero],
             [0, 0, 0, 1]])
assert_equal(matrices[1], A2)
l3, q3, cero = var("l3"), var("q3"), var("0")
A3 = Matrix([[cos(q3), -sin(q3)*cos(cero), sin(cero)*sin(q3), cero*cos(q3)],
             [sin(q3), cos(cero)*cos(q3), -sin(cero)*cos(q3), cero*sin(q3)],
             [0, sin(cero), cos(cero), l3],
             [0, 0, 0, 1]])
assert_equal(matrices[2], A3)
l4, q4, cero = var("l4"), var("q4"), var("0")
A4 = Matrix([[cos(q4), -sin(q4)*cos(cero), sin(cero)*sin(q4), l4*cos(q4)],
             [sin(q4), cos(cero)*cos(q4), -sin(cero)*cos(q4), l4*sin(q4)],
             [0, sin(cero), cos(cero), cero],
             [0, 0, 0, 1]])
assert_equal(matrices[3], A4)
l5, q5, cero = var("l5"), var("q5"), var("0")
A5 = Matrix([[cos(q5), -sin(q5)*cos(cero), sin(cero)*sin(q5), cero*cos(q5)],
             [sin(q5), cos(cero)*cos(q5), -sin(cero)*cos(q5), cero*sin(q5)],
             [0, sin(cero), cos(cero), l5],
             [0, 0, 0, 1]])
assert_equal(matrices[4], A5)