miércoles, 26 de agosto de 2015

Definiciones de Programación Paralela y Distribuida

Procesamiento Pipeline o Segmentado:


Es una técnica por medio de la cual se puede traslapar la ejecución de instrucciones. En la actualidad la segmentación es una de las tecnologías utilizadas para hacer procesadores más rápidos. Permite aumentar el rendimiento del funcionamiento en computadoras y dispositivos similares aplicándolo al microprocesador.

Consiste en la descomposición de la ejecución de un programa en varias etapas especializadas en realizar una tarea en específico, si bien estas etapas pueden requerir de que se ejecute una antes de ellos para ellas realizar su función, funcionan independientemente por lo cual, cuando una instrucción es procesada en la primera etapa y pasa a la segunda etapa, la primera etapa puede procesar inmediatamente la siguiente instrucción, sin esperar que la anterior sea procesada por todas las etapas.

Gráficamente se puede observar en la siguiente imagen:



Ley de Amdahl


La ley de Amdhal pone un límite superior a la ganancia en velocidad, y por tanto también a la eficiencia, de un sistema paralelo atendiendo al hecho, de que los procesos suelen tener partes que no pueden ser ejecutadas en paralelo, sino solo de forma secuencial pura.

Del tiempo total de ejecución del proceso, llamaremos s a la parte que no puede ser paralelizable y p al resto (paralelizable). Suponiendo condiciones ideales en la parte paralelizable del proceso p, tendremos que los tiempos mínimos de ejecución del proceso con un solo procesador y en el sistema paralelo con N procesadores.

De forma sencilla podemos enunciar la ley de Amdahl de la siguiente manera:

$$F_m = F_a ((1 - F_m)+ \frac{F_m}{A_m})$$
Donde:
$F_m$ = Tiempo de Ejecución mejorado
$F_a$ = Tiempo de Ejecución antiguo
$A_m$ = Factor de Mejora 

Lo más rescatable de la ley de Amdahl es el hecho de que el rendimiento de un sistema no aumenta por incrementarse indefinidamente el número de procesadores.

Ley de Gustafson


Establece que cualquier problema lo suficientemente grande puede ser eficientemente paralelizado, Se refiere a problemas con volumen de cálculo fijo en que se aumenta el número de procesadores, en la mayoría de los casos, cuando el volumen del problema crece, lo hace solo en su parte paralela, no en su parte secuencial. Ello hace que el cuello de botella secuencial tienda a cero cuando el volumen del problema aumenta.

Al aumentar el número de procesadores, el volumen de cálculo es mayor, esto afecta más a la parte paralela del problema, que a la parte secuencial. Esta ley puede quedar enunciada de la siguiente manera:

$$ S(N) = N - (N - 1)a$$
Donde:

$N = $ es el numero de procesadores
$S = $ es el aumento en velocidad
$a = $ es la parte no paralelizable del proceso

Esta ley indica que si existe una mejora en el procesamiento de la parte paralela de un proceso, al aumentar el número de procesadores, la cual se mantiene al momento de seguir aumentado el número de procesadores, siendo esto contradictorio a la ley de Amdhal, pero esto se debe a que parten de un fundamento diferente, mientras la de Amdahl considera procesos con un volumen de procesamiento fijo, la ley de Gustafson se refiere a problemas cuyo volumen de procesamiento puede aumentar según el número de procesadores, siendo esta última una situación más real.

Referencias:


lunes, 24 de agosto de 2015

Practica No.3: Programación en Android con Python

Actualmente los teléfonos están viviendo un boom tecnológico, lo que permite que evolucionen a un ritmo increíblemente acelerado, es por esto que la gran mayoría de lenguajes de programación han tratado de acercarse a esta nueva plataforma y poder crear aplicaciones que corran sobre ella.

Existen muchos S.O para celulares pero el gran dominador del mercado actualmente es Android, debido a esto no es raro que hayan surgido diversas librerías que permitan programar en Android. Y entre todos ellos Python no es la excepción y en la actualidad ya cuenta con varias formas de acércanos a la plataforma Android.

Algunas de las más reconocidas son Kivy, SL4A y QPython, sin embargo la opción QPython está descartada en este post debido a que está hecho para ejecutarse y programar directamente sobre un dispositivo Android, lo mismo que SL4A por lo tanto nos vamos a enfocar a la programación con Kivy al ser multiplataforma.

¿Cómo instalar Kivy?

Para instalar Kivy basta con ir a la página oficial y en ella bajar la versión adecuada de acuerdo a nuestro sistema, en este caso, la versión para Windows, después de bajarla y descomprimirla copiamos el archivo kivy-3.4.bat y lo mandamos a la carpeta Shell:sendto como acceso directo y le cambiamos el nombre a kivy-1.9.

De esta manera al tener nuestro archivo *.py le damos con click derecho y luego a “enviar a” y elegimos como opción kivy-1.9, así podemos probar nuestras aplicaciones.

Programando con Kivy

Realizaremos un ejemplo sencillo en kivy el cual simplemente desplegara el mensaje hola mundo en pantalla usando un botón, que en este ejemplo no realizara ninguna acción, el código es el siguiente:

from kivy.app import App
from kivy.uix.button import Button
 
class Hello(App):
    def build(self):
        btn = Button(text='Hello World')
        return  btn
 
Hello().run()

Como podemos observar lo único que hace esta clase es regresar un botón al que se le agrega la palabra “Hola Mundo” y ejecutar la aplicación con el método run(). Este ejemplo se puede descargar desde este link.

El siguiente ejemplo es tomado de los ejemplos de prueba de la propia herramienta Kivy, la cual obtiene la posición en pantalla cuando damos clic sobre ella, además nos indica el tipo de evento que es llamado y el número de eventos que han ocurrido, todo esto en colores generados aleatoriamente:

import kivy
kivy.require('1.0.6')
 
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
from kivy.graphics import Color, Rectangle, Point, GraphicException
from random import random
from math import sqrt
 
 
def calculate_points(x1, y1, x2, y2, steps=5):
    dx = x2 - x1
    dy = y2 - y1
    dist = sqrt(dx * dx + dy * dy)
    if dist < steps:
        return None
    o = []
    m = dist / steps
    for i in xrange(1, int(m)):
        mi = i / m
        lastx = x1 + dx * mi
        lasty = y1 + dy * mi
        o.extend([lastx, lasty])
    return o
 
 
class Touchtracer(FloatLayout):
 
    def on_touch_down(self, touch):
        win = self.get_parent_window()
        ud = touch.ud
        ud['group'] = g = str(touch.uid)
        with self.canvas:
            ud['color'] = Color(random(), 1, 1, mode='hsv', group=g)
            ud['lines'] = (
                Rectangle(pos=(touch.x, 0), size=(1, win.height), group=g),
                Rectangle(pos=(0, touch.y), size=(win.width, 1), group=g),
                Point(points=(touch.x, touch.y), source='particle.png',
                      pointsize=5, group=g))
 
        ud['label'] = Label(size_hint=(None, None))
        self.update_touch_label(ud['label'], touch)
        self.add_widget(ud['label'])
        touch.grab(self)
        return True
 
    def on_touch_move(self, touch):
        if touch.grab_current is not self:
            return
        ud = touch.ud
        ud['lines'][0].pos = touch.x, 0
        ud['lines'][1].pos = 0, touch.y
 
        points = ud['lines'][2].points
        oldx, oldy = points[-2], points[-1]
        points = calculate_points(oldx, oldy, touch.x, touch.y)
        if points:
            try:
                lp = ud['lines'][2].add_point
                for idx in xrange(0, len(points), 2):
                    lp(points[idx], points[idx+1])
            except GraphicException:
                pass
 
        ud['label'].pos = touch.pos
        import time
        t = int(time.time())
        if t not in ud:
            ud[t] = 1
        else:
            ud[t] += 1
        self.update_touch_label(ud['label'], touch)
 
    def on_touch_up(self, touch):
        if touch.grab_current is not self:
            return
        touch.ungrab(self)
        ud = touch.ud
        self.canvas.remove_group(ud['group'])
        self.remove_widget(ud['label'])
 
    def update_touch_label(self, label, touch):
        label.text = 'ID: %s\nPos: (%d, %d)\nClass: %s' % (
            touch.id, touch.x, touch.y, touch.__class__.__name__)
        label.texture_update()
        label.pos = touch.pos
        label.size = label.texture_size[0] + 20, label.texture_size[1] + 20
 
 
class TouchtracerApp(App):
    title = 'Touchtracer'
    icon = 'icon.png'
 
    def build(self):
        return Touchtracer()
 
    def on_pause(self):
        return True
 
if __name__ in ('__main__', '__android__'):
    TouchtracerApp().run()

El ejemplo se puede descargar del siguiente link. Como podemos observar Kivy es una herramienta poderosa, que nos permite hacer cosas muy interesantes, que si bien no tiene métodos tan eficientes como otras opciones al ser multiplataforma, es una buena forma de comenzar en la programación de aplicaciones para Android.

Practica No. 3: Programación Google App Engine con Python

¿Qué es Google App Engine?

Google App Engine es un servicio de la familia de Google Cloud Platform que ofrece un servicio del tipo plataforma como servicio (PaaS), es decir permite que realicemos aplicaciones web sin necesidad de preocuparnos por la parte de infraestructura y centrarnos 100% en la aplicación, ya que la infraestructura utilizada es la propia de Google.

Esta plataforma facilita construir, mantener y escalar nuestras aplicaciones fácilmente, además de que soporta varios lenguajes como Java, Python, PHP, etc.  Además no tenemos que preocuparnos de la escalabilidad, la misma plataforma cuenta con un balanceador de cargas, es decir que nuestra aplicación automáticamente será atendida por las maquinas necesarias para que tenga un tiempo de respuesta óptimo.

Ofrece también herramientas seguras de almacenamiento persistente y veloz, especialmente recomendado es utilizar Google Cloud Datastore, la cual es una base de datos NoSQL, una de sus principales características es que es eventualmente consistente, es decir los cambios hechos no son registrados inmediatamente, sino que se realizara eventualmente.

Restricciones de Google App Engine

Todo esto puede sonar muy bien y es válido hacernos la pregunta de cuanto nos costara utilizar una infraestructura de este tipo, y la respuesta es nada, es gratis, mientras nos ajustemos a ciertos límites que se nos imponen, estos son:
  • 1.300.000 solicitudes diarias o 7.400 por minuto. 
  • 10 GB de subida y de bajada de datos diaria o 56 MB por minuto.
  • 1 GB de almacenamiento en el almacén de datos (el datastore).
  • 10.000.000 llamadas al almacén de datos diarias o 57.000 por minuto.
  • 7.000 llamadas al API de correo diarios o 32 llamadas por minuto.
  •  2.000 destinatarios de correo electrónico diarios u 8 por minuto.
Entre otras cosas, la lista completa de cuotas la podremos encontrar aquí, y hay que revisarla cuidadosamente para evitar meternos en problemas posteriormente. Como podemos observar esta plataforma ofrece características muy interesantes que merecen ser vistas a profundidad, y nos permite explorar un nuevo mundo de posibilidades sin ningún costo, la última parte de este post es la integración del GAE con Python.

Como utilizar Python con Google App Engine

Antes que nada hay que aclarar que todavía no tenemos compatibilidad con Python 3 por lo que es necesario utilizar la versión 2.7, en este post estaremos usando el framework de desarrollo oficial de Google, el webapp2. Primero que nada vamos a descargar el SDK de GAE desde la página principal en este link e instalarlo.

Después ejecutaremos el Google App Engine Launcher y en esta aplicación dentro de la pestaña file crearemos una nueva aplicación a la que nombraremos ejemplo, seleccionamos con que lenguaje queremos programar, la ruta donde queremos que se cree el proyecto y los puertos de administración, dentro de esta carpeta se crearan los siguientes archivos main.py el cual tendrá el código que ejecutara nuestra aplicación al recibir una petición, para nuestro caso lo llamaremos ejemplo.py; y por otro lado tenemos un archivo de configuración app.yaml.



La aplicación crea otras cosas también pero para nuestros fines solo nos importa lo anterior, por lo cual eliminaremos lo demás y modificaremos el archivo app.yaml para que se va de la siguiente manera:

application: ejemplo
version: 1
runtime: python27
api_version: 1
threadsafe: false

handlers:
- url: .*
  script: main.py

De este sencillo ejemplo lo único interesante es que en application indicamos el nombre de la carpeta que creamos, en runtime el lenguaje de programación a utilizar y en scripts el archivo que responderá a las peticiones. Una vez que tenemos configurado nuestro archivo de configuración, procedemos a modificar nuestro archivo main.py en este caso es como se muestra a continuación:

# -*- encoding: utf-8 -*-
import sys
import random
print 'Content-Type: text/html'
print ''
print '
'
# Leemos la entrada desde el formulario
data = sys.stdin.read()
try:
    resp = int(data[data.find('=')+1:])
except:
    resp = -1
print 'Tu número es ', resp
answer = random.randint(1, 50)
if resp < answer:
    print 'Tu número es demasiado bajo'
if resp == answer:
    print 'Lo has conseguido los numeros son iguales '
if resp > answer:
    print 'Tu número es demasiado alto'
print '
' print '''
Introduce un número entre 1 y 50:
'''

Como podemos observar este sencillo ejemplo lo único que hace es pedir un numero entre el 1 y el 100 y regresar si acertamos o no, en esta parte hay que destacar que con “print 'Content-Type: text/html'” indicamos que estamos creando una página web y que con la propia instrucción print podemos ir creando nuestra página usando php, además con el método sys.stdin podemos obtener la respuesta del método post. Si queremos correr nuestra aplicación desde el Google App Engine Launcher corremos nuestra aplicación y después vamos a la acción browse que nos abrirá nuestro navegador para probar nuestra aplicación.

En este ejemplo sin embargo no utilizamos el framework webapp2, así que para finalizar mostraremos otra aplicación que ahora si utiliza este framework en su funcionamiento, los elementos básicos son los mismos, sin embargo los archivos deberán modificarse, el archivo app.yaml cambia de la siguiente manera:

application: ejemplo2
version: 1
runtime: python27
api_version: 1
threadsafe: false

handlers:

- url: .*
  script: main.py

libraries:
- name: webapp2
  version: "2.5.2"

Mientras que el archivo main.py es el que se muestra a continuación:

# -*- encoding: utf-8 -*-
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
import random
class MainHandler(webapp.RequestHandler):
    formdata = '''
Introduce un número entre 1 y 100:
''' def get(self): self.response.headers['Content-Type'] = 'text/html' self.response.out.write(self.formdata) def post(self): resp = self.request.get('resp') try: resp = int(resp) except: resp = -1 answer = random.randint(1, 100) if resp < answer: msg = 'Tu número es demasiado bajo' if resp is answer: msg = 'Has acertado campeón, toma un pin!' if resp > answer: msg = 'Tu número es demasiado alto' self.response.out.write('Tu número es : '+str(resp)+' \n') self.response.out.write(msg+'\n') self.response.out.write(self.formdata) def main(): application = webapp.WSGIApplication([('/.*', MainHandler)],debug=True) run_wsgi_app(application) if __name__ is '__main__': main()
Si bien los cambios en el archivo app.yaml no son muchos y queda claro lo que se agregó, vale la pena mencionar que cambios ocurren el manejar el framework webapp2. Los elementos principales son:

·         Una o más clases ResquestHandler para procesar las peticiones y devolver una respuesta
·         Una instancia de WSGIApplication que encaminar la peticiones hacia sus manejadores basándose en su URL
·         Una función main que ejecuta el bucle principal utilizando el adaptador CGI

Dentro del archivo lo primero que vemos es el MainHandler esta clase es la encargada de responder a los solicitudes, a diferencia del ejercicio anterior donde solo escribíamos el componente form, en este lo debemos asiganar a una variable que en este caso denominamos formdata, después se definen dos métodos uno para responder al método post y otro al método get, en este caso el método post se encarga de mandar a pantalla el form que creamos en formato html para que podamos interactuar con el usuario.


Por su lado la función post responde cuando se ingresa el numero en la página y realiza la comparación, y después de desplegar el resultado de igual manera mandar a pantalla de nuevo el form.

Por último la función main crea una WSGIApplication en la cual se le manda a llamar al manejador principal y ejecuta la aplicación en un ciclo propio de wsgi. Si desea puede bajar el primer ejemplo desde aquí y el segundo desde aquíLos ejemplos fueron tomados desde la siguiente fuente

martes, 18 de agosto de 2015

Practica No.2 Programación Web en Python

Actualmente el poder realizar aplicaciones web es un requisito indispensable en cualquier lenguaje que quiera tener un lugar en la industria y Python no es la excepción, existen una gran cantidad de frameworks que permiten realizar aplicaciones web en Python, desde los más sencillos hasta los más complicados, pero entre todos ellos el que se considera el más completo y robusto es el framework Django. 

En este post vamos a realizar la instalación del framework bajo la plataforma de Windows y hacer un ejemplo sencillo para asegurarnos de que todo esté en orden, primero que nada vamos a hacer a darnos una pequeña idea de lo que es Django. 

¿Qué es Django? 

Django es un framework web de alto nivel, escrito en Python, que ayuda al desarrollo rápido y a un diseño limpio y pragmático. Construido por desarrolladores experimentados, resuelve una buena parte de los problemas del desarrollo web de tal manera que uno se pueda enfocar en escribir su app sin necesidad de reinventar la rueda. Es gratis y de código abierto. 

Django pone énfasis en el re-uso, la conectividad y extensibilidad de componentes, el desarrollo rápido y el principio No te repitas (DRY, del inglés Don’t Repeat Yourself). Python es usado en todas las partes del framework, incluso en configuraciones, archivos, y en los modelos de datos. Al igual que otros frameworks de desarrollo web, Django también trabaja con el patrón MVC (Modelo Vista Controlador). 

Instalación del Django 

Para instalar Django en la plataforma de Windows primero necesitamos tener instalado Python, para esto solo hay que bajar el instalador apropiado del sitio oficial aquí, de acuerdo a nuestro sistema operativo, una vez que hemos terminado la instalación de Python necesitamos verificar que las variables de entorno de del sistema estén correctamente agregadas y aparezcan las siguientes:

"C:\Python27;C:\Python27\Scripts"

Si las variables no están correctas, podemos agregarlas de forma manual con cuidado, después de verificar lo anterior hay que descargar la paquetería setuptools, este paquete permite gestionar los paquetes propios de Python, para ello entramos a la página oficial aquí y buscamos la opción Windows (simplified), descargamos el archivo ez.setup.py  y lo ejecutamos, si nuestras variables de entorno son correctas, se ejecutara la línea de comandos de Python y se instalara el paquete.

Una vez instalado el paquete anterior simplemente ingresamos en una terminal el siguiente comando y la instalación se realizara rapidamente:

pip install Django

Para verificar que todo esté en orden verificamos con el siguiente comando desde la línea de comando de Python y la salida debera ser parecida a la imagen solo cambiando la version de Django instalada.


Ejemplo del Funcionamiento del Django

Primero que todo tenemos realizar una configuración inicial. Esto es, necesitamos auto-generar código que define un proyecto Django (conjunto de configuraciones para una instancia de Django, incluyendo configuración de base de datos). Para realizar esto desde línea de comando nos ubicamos en el directorio donde queramos crear nuestro proyecto y ejecutamos el comando:
 
django-admin.py startproject ejemplo
Starproject crea dos directorios y un conjunto de archivos distribuidos de la siguiente manera:
  • ejemplo/: El directorio externo ejemplo/ es solo el contenedor del proyecto. No importa para Django por lo que podemos renombrarlo si queremos.
  • manage.py: Una utilidad en línea de comando que nos permite interactuar con el proyecto Django de diversas formas. No debemos editarlo de ninguna manera.
  • ejemplo/ejemplo/: El directorio interno ejemplo/ es el paquete Python actual del Proyecto, es usado para importar cualquier cosa dentro de él.
  •  __init__.py: Un archiva requerido por Python para tratar el directorio ejemplo como paquete.
  • settings.py: Configuración para este proyecto Django.
  •  urls.py: Las URLs para este proyecto Django; una "tabla de contenidos" de tu sitio basado en Django.
  • wsgi.py: Un punto de entrada para servidores web compatibles con WSGI.
Para asegurarnos de que nuestro proyecto esté funcionando entrar al directorio ejemplo/ y ejecutar el comando:
 
python manage.py runserver
.
Con lo cual debemos ver una salida como la siguiente si es que todo salió bien


Finalmente accedemos a la dirección IP http://127.0.0.1:8000/ con la cual accederemos a la página de bienvenida del servidor Django.


Aquí hay que aclarar algo importante este servidor tiene como objetivo solo ser un entorno de desarrollo, no de producción, por lo que no debe ser utilizado a nivel empresarial.

Ahora vamos a crear el archivo que necesitamos para implementar una parte del modelo MVC con el que trabaja el framework Django, para esto creamos un archivo llamado views.py en el directorio ejemplo/ejemplo el contenido de este archivo es el siguiente:
 
from django.http import HttpResponse

def hello(request):
    return HttpResponse("Hello world")
El objetivo del archivo views.py es tener funciones de Python que reciban un HttpRequest como primer parámetro (puede tener más parámetros) y regrese una instancia de HttpResponse, que se despliega como una pagina web.

Para que podamos observar nuestro Hello World en el navegador necesitamos asignarle una dirección URL a la función hello de la clase views, de esta manera a cada URL o página desplegada se le asigna una función que desplegara su contenido. Vamos a modificar el archivo urls.py de la siguiente manera:
 

from django.conf.urls import include, url
from django.contrib import admin
from Ejemplo import views

urlpatterns = [
   url(r'^admin/', include(admin.site.urls)),
   url(r'^$', views.hello, name='hello')
]
De esta manera al acceder a la dirección IP http://127.0.0.1:8000/ en vez de desplegarse en pantalla el mensaje de bienvenida de Django se desplegara nuestro Hello World. Con esto terminamos nuestro pequeño ejemplo con Django hay muchas más cosas que podemos realizar con el pero esto es solo una primera aproximación a todo lo que nos brinda.

Practica No.2 Interfaz Gráfica (GUI) en Python

Actualmente uno de los pilares del diseño de aplicaciones es el poder realizar interfaces graficas de usuario o GUI amigables con el usuario y eficientes, de tal manera que se pueda interactuar adecuadamente con la aplicación, esto en muchos de los lenguajes de programación más conocidos y sobre todo en los orientados a objetos no es un problema y podemos encontrar muchos ejemplos en la red.

En un lenguaje tan sencillo de utilizar como Python llega a surgir la duda de si es posible realizar de forma adecuada una GUI y la respuesta es sí, de hecho existen muchos módulos que permiten realizar interfaces graficas de manera sencilla y muchas de ellas son variantes de librerías utilizadas en el lenguaje de programación C/C++.

A continuación se mostraran ejemplos de dos de los módulos más importantes y que son compatibles con la versión 3.4 de Python. Hay que aclarar que el propósito de este post no es dar una guía completa de todo lo que podemos realizar con estas librerías, sino más bien ejemplificar las instrucciones básicas para poder realizar la interfaz gráfica.

Tkinter

Tkinter es un módulo que ya viene incluido al momento de instalar Python, utiliza el conocido toolkit Tk, siendo muy robusto y sencillo de aprender. Al venir por defecto en cualquier instalación de Python es el más utilizado de todos, y a la vez el que cuenta con una mayor documentación.

Este módulo fue conocido en sus inicios por tener widgets poco atractivos, cosa que cambio con la versión 8.5 que se empezó a distribuir con la versión 2.6 de Python, el cual ya incluye cosas tan interesantes como textos con antialiasing o Treeview.

TkInter se distribuye bajo la PSFL (Python Software Foundation License) una licencia compatible con la GPL creada para la distribución de software relacionado con el proyecto Python. La PSFL carece de la naturaleza viral de la GPL, por lo que permite crear trabajos derivados sin que estos se conviertan necesariamente en software libre.

A continuación se describe una pequeña aplicación que cuenta con algunos de los elementos básicos de Tkinter:



En la imagen anterior podemos observar un ejemplo de GUI básica, primero que nada hay que importar el paquete lo cual se hace con la siguiente instrucción:

from tkinter import *  

De esta manera podemos acceder a todos los elementos que necesitamos para nuestra aplicación, para la creación de la ventana principal necesitamos dos funciones:

 
root = Tk()
root.mainloop() 

La primera instrucción hace que la variable root herede todas las funciones de Tkinter y la segunda permite la inicialización de la ventana y que esta sea desplegada, todos los códigos que queramos agregar a la ventana deberán agregarse entre estas dos líneas de código.

Para agregar los distintos elementos a la pantalla se realiza con una inicialización normal, como puede apreciarse en el siguiente código se pasan como parámetros la ventana donde queremos que aparezca el elemento y el nombre con el que queremos que se despliegue.

 
label = Label(frame, text="Hola mundo")
c1 = Checkbutton(frame, text="Uno")

Así mismo podemos modificar la configuración por default de los distintos elementos gráficos, cada uno de ellos tiene sus propios atributos configurables, en el ejemplo siguiente modificamos el color de fondo y de la letra de una etiqueta.

 
label.config(bg="cyan")
label.config(fg="blue")

El último tema a tratar en este post es como hacer que los elementos de la interfaz gráfica se despliegue como queramos, para esto tenemos dos opciones usando la instrucción pack() delegando al lenguaje donde los ubique pero nos asegura que se desplieguen completamente o bien haciéndonos cargos nosotros mismos utilizando la instrucción grid(), en este caso la ventana es tratada como un conjunto de renglones y columnas y nosotros debemos indicar directamente en qué posición queremos agregar nuestros elemento gráficos. 

El código fuente del ejemplo anterior se puede descargar desde aquí.

PyQt

PyQt es probablemente una de las opciones menos populares para realizar interfaces gráficas en Python, sin embargo es muy sencillo de utilizar y brinda varias posibilidades, para instalarlo basta con ir a la página oficial y descargar la opción adecuada a nuestra plataforma, al ser un binding de Qt aplicaciones destinadas a funcionar bajo KDE (que fue complementa diseñado en Qt) son fáciles e interesantes de realizar con este módulo.

Sin embargo no solo se puede utilizar en KDE, sino que es muy útil para todo tipo de aplicaciones multiplataforma, ya que desde la versión 4 utiliza widgets nativos para las distintas plataformas en vez de simplemente emular el aspecto de la plataforma sobre la cual se ejecuta.

Se distribuye con una licencia dual GPL/PyQt Commercial, es decir, que si vamos a publicar el código fuente y permitir a los usuarios modificar nuestra aplicación, podremos usar PyQt sin más preocupaciones. En caso contrario tendremos que pagar para obtener una licencia comercial.

A continuación se describe una pequeña aplicación que cuenta con algunos de los elementos básicos de PyQt:


Para utilizar adecuadamente esta librería necesitamos utilizar un enfoque orientado a objetos, antes que nada vamos a importar las librerías donde se encuentran los distintos elementos gráficos, para esto se utilizan las siguientes instrucciones, se pueden importar una gran cantidad de elementos gráficos mas, estos son solo un ejemplo:
 
from PyQt5 import QtGui,  QtCore
import sys
Para iniciar y definir los componentes de la interfaz gráfica utilizamos las siguientes sentencias:
 
app = QApplication
form = AppForm()
form.show()
app.exec_()
Con la primera definimos un atributo del tipo QApplication desde el cual ejecutaremos posteriormente nuestra aplicación, con la segunda instrucción definiremos un objeto del tipo de clase que tenemos que definir y sobre la cual agregaremos los elementos gráficos, la tercera instrucción despliega esos elementos y la cuarta instrucción permite la ejecución de la aplicación.

En esta ocasión utilizamos un objeto del tipo QBoxLayout para agregar los elementos y acomodarlos en la pantalla, también es posible utilizar el grid e indicar la posición de los elementos directamente, pero en este ejemplo no es considerado. Para agregar elementos a la ventana se realiza la siguiente parte de código:
 
page = QWidget()
self.button = QPushButton('Unir', page)
La primera instrucción crea el contenedor de todos los elementos de la interfaz gráfica de usuario, el cual se agregara a la ventana en sí misma, los elementos al momento de instanciarse deben indicar el nombre con el que aparecen y el elemento al que se agregaran, en este caso al contenedor, para agregar los distintos elementos a la ventana se agregan al QBoxLayout con la instrucción pack(), para que se acomoden de la mejor manera y finalmente el contenedor se agrega a la ventana.
vbox1 = QVBoxLayout()
vbox1.addWidget(self.label)
vbox1.addWidget(self.edit1)
vbox1.addWidget(self.button)
page.setLayout(vbox1)
Para cambiar los atributos de los componentes, hacemos referencia de la misma manera en que hacemos referencia a los atributos o métodos de una clase en leguaje orientado a objetos:
self.label.resize(self.label.sizeHint())
self.label.setPalette(palettef)
Lo mismo pasa con los eventos cuando al momento de presionar un botón queremos que ocurra cierta acción, los eventos deben definirse como métodos de la clase principal y agregarse a los botones de la siguiente manera:

def  Mostrar(self):
     QMessageBox.about(self, "Mensaje", "Text1 = %s, Text2 = %s" % (self.edit1.text(), self.edit2.text()))

self.button.clicked.connect(self.Mostrar)
El código fuente del ejemplo anterior se puede descargar desde aquí.

Otros módulos muy conocidos como wxPython,PyGTK no tienen todavía integración con Python 3.

miércoles, 12 de agosto de 2015

Practica No.1 Algoritmos de Ordenamiento

Ordenamiento de Burbuja
Este algoritmo de ordenamiento es de los más sencillos de implementar pero al mismo tiempo el que peor rendimiento tiene, consiste en ir comparando elemento por elemento del vector, de manera que se van intercambiando si están mal acomodados de modo que el valor más pequeño este en la primera posición, volver a comparar los elementos y así sucesivamente, hasta que todo el vector esta ordenado, el problema de este algoritmo es que al realizar las búsquedas siguientes, se vuelven a comparar los elementos ya ordenados, teniendo una complejidad:
$$\Omega(n^2)$$
A continuación se muestra la implementación de este algoritmo en Python:
def BubbleSort(vector):
    print("Algoritmo de Burbuja")
    tam=len(vector)
    for i in range(0,tam):
        for j in range (i+1,tam):
            if (vector[i] > vector[j]):
                temp = vector[i]
                vector[i] = vector[j]
                vector[j] = temp
    return vector

Ordenamiento de Selección

Este algoritmo consiste en encontrar el elemento de menor valor en la primera iteración y colocarlo en la primera posición, después encontrar el segundo menor y ponerlo en la segunda posición y así sucesivamente, hasta ordenar todo el vector, tiene la misma complejidad que el ordenamiento por burbuja, su implementación en Python se muestra a continuación:
def SelectionSort(vector):
    print("Algoritmo de Selección")
    tam=len(vector)
    for i in range(0,tam):
        minimo=i
        for j in range (i+1,tam):
            if (vector[minimo]>vector[j]):
                minimo=j
        temp = vector[i]
        vector[i] = vector[minimo]
        vector[minimo] = temp
    return vector

Ordenamiento de Inserción

Este algoritmo se basa en la idea de ir ordenado los elementos del vector de forma ordenada como se vayan recorriendo asumiendo que los elementos del lado izquierdo ya están ordenados adecuadamente, por lo que solo se necesita encontrar su posición en esos elementos, tiene la misma complejidad que los anteriores y su implementación se muestra a continuación:
def InsertionSort(vector):
    print("Algoritmo de Inserción")
    tam=len(vector)
    for i in range(1,tam):
        valor=vector[i]
        j=i-1
        while j>=0 and vector[j]>valor:
            vector[j+1] = vector[j]
            j=j-1
        vector[j+1]=valor
    return vector

Ordenamiento por Mezclas

Este algoritmo se basa en la técnica de divide y vencerás, el vector original se divide en dos, estas dos listas se ordenan de manera separada, volviéndose a dividir hasta que se obtiene vectores de un solo elemento, entonces consideramos que ya está ordenada. Cuando ambas listas están ordenada se juntan para formar el arreglo ordenado. Este Algoritmo tiene una complejidad de:
$$\Omega(n \log n)$$
Por lo cual ofrece un mejor rendimiento que los algoritmos anteriores. Este método requiere de dos funciones para su implementación una que divida el arreglo, la cual se muestra a continuación en Python:
def MergeSort(vector):
    tam=len(vector)
    if tam==1:
        return vector
    else:
        mitad = len(vector)//2
        mitizq = MergeSort(vector[:mitad])
        mitder = MergeSort(vector[mitad:])
        return Mezcla(mitizq,mitder)
Y una que permita unir los dos arreglos ordenados, esta función se muestra a continuación codificada en Python:
def Mezcla(mitizq,mitder):
    resultado = []
    i=0
    j=0
    tizq=len(mitizq)
    tder=len(mitder)
    while (i < tizq or j < tder):
        if(i >= tizq):
            resultado.append(mitder[j])
            j=j+1
        elif(j >= tder):
            resultado.append(mitizq[i])
            i=i+1
        elif(mitizq[i] < mitder[j]):
            resultado.append(mitizq[i])
            i=i+1
        else:
            resultado.append(mitder[j])
            j=j+1
    return resultado

Ordenamiento QuickSort 

Este es al algoritmo más eficiente de ordenamiento actualmente, y se basa en la recursividad, se escoge un elemento del vector que será considerado pivote y en base a este elemento, se crean dos listas una que contenga los elementos menores y otra que contenga los elementos mayores, este proceso se vuelve a repetir hasta que quedan arreglos de un solo momento, que es cuando ha quedado ordenado el arreglo.
El punto central de este algoritmo es encontrar un pivote adecuado ya que dependiendo de este, la complejidad del algoritmo puede variar desde ser $\Omega(n \log n)$ en el mejor de los casos, hasta $\Omega(n^2)$ en el peor de los casos, la implementación del algoritmo se muestra a continuación.
def QuickSort(vector,primero,ultimo):
    i = primero
    j = ultimo   
    pivote = (vector[i] + vector[j]) / 2
    while i < j:
        while vector[i] < pivote:
            i+=1
        while vector[j] > pivote:
            j-=1
        if i <= j:
            x = vector[j]
            vector[j] = vector[i]
            vector[i] = x
            i+=1
            j-=1
    if primero < j:
        vector = QuickSort(vector, primero, j)
    if ultimo > i:
        vector = QuickSort(vector, i, ultimo)
    return vector
El programa de prueba con la implementación de todos estos algoritmos se puede encontrar en el siguiente link
Los algoritmos de ordenamiento por mezclas y quicksort fueron realizados basándose en las implementaciones encontradas en los siguientes sitios:
Merge Sort
Quick Sort