jueves, 16 de octubre de 2025

Html y Prolog

 Aquí tienes un ejemplo realista y práctico: un pequeño servidor web de recomendaciones de películas que utiliza una base de conocimientos en Prolog.

Imagina que tienes una base de datos de películas y quieres que los usuarios puedan encontrar una película introduciendo un género y una calificación mínima. Prolog es perfecto para este tipo de consultas lógicas. library(http) nos permite poner esto en la web.


El Escenario Realista

Crearemos un servidor web local que:

  1. Define un conocimiento base sobre películas (título, género, calificación).

  2. Inicia un servidor web en un puerto específico (ej. 8000).

  3. Escucha peticiones en una ruta, por ejemplo /recomendacion.

  4. Recibe parámetros de la URL, como genero y calificacion_minima.

  5. Consulta la base de conocimientos de Prolog para encontrar películas que coincidan.

  6. Devuelve una página HTML dinámica con los resultados al usuario.


El Código Completo

Copia y pega este código en un archivo llamado servidor_peliculas.pl.

Prolog
% Cargar las bibliotecas necesarias para el servidor HTTP y el manejo de HTML
:- use_module(library(http/thread_httpd)).
:- use_module(library(http/http_dispatch)).
:- use_module(library(http/http_parameters)).
:- use_module(library(http/html_write)).

% --- 1. Base de Conocimientos ---
% Hechos: pelicula(Título, Género, Calificación)
pelicula('The Matrix', scifi, 8.7).
pelicula('Inception', scifi, 8.8).
pelicula('The Godfather', crimen, 9.2).
pelicula('Pulp Fiction', crimen, 8.9).
pelicula('Forrest Gump', drama, 8.8).
pelicula('The Dark Knight', accion, 9.0).
pelicula('Interstellar', scifi, 8.6).
pelicula('Parasite', drama, 8.5).

% --- 2. Lógica de Búsqueda ---
% Regla: encontrar_peliculas(Genero, CalificacionMin, Peliculas)
% Encuentra todas las películas que cumplen con el género y la calificación mínima.
encontrar_peliculas(Genero, CalificacionMin, Peliculas) :-
    findall(
        pelicula(Titulo, Genero, Calificacion),
        (pelicula(Titulo, Genero, Calificacion), Calificacion >= CalificacionMin),
        Peliculas
    ).

% --- 3. Manejador de la Petición HTTP ---
% Este predicado se ejecuta cuando alguien visita /recomendacion
manejador_recomendacion(Request) :-
    % Obtener los parámetros de la URL (ej. ?genero=scifi&calificacion=8.7)
    http_parameters(Request,
                    [ genero(Genero, [default('scifi')]),
                      calificacion(CalificacionStr, [default('8.0')])
                    ]),
    % Convertir la calificación de texto a número
    atom_number(CalificacionStr, CalificacionMin),

    % Ejecutar la lógica de búsqueda
    encontrar_peliculas(Genero, CalificacionMin, Resultados),

    % Generar y enviar la respuesta HTML
    reply_html_page(
        title('Recomendador de Películas'),
        [ h1('Recomendador de Películas en Prolog'),
          h2('Resultados de tu búsqueda:'),
          p(['Buscando películas de género: ', b(Genero), ' con calificación mínima de: ', b(CalificacionMin)]),
          \generar_tabla_resultados(Resultados) % Llama a un predicado para crear la tabla
        ]).

% Predicado auxiliar para generar la tabla HTML con los resultados
generar_tabla_resultados([]) --> !, % Si no hay resultados
    html(p(b('No se encontraron películas con esos criterios.'))).
generar_tabla_resultados(Peliculas) --> % Si hay resultados
    html(table([border(1)],
               [ tr([th('Título'), th('Género'), th('Calificación')])
               | \filas_peliculas(Peliculas) % Generar las filas de la tabla
               ])).

% Genera una fila <tr> por cada película en la lista
filas_peliculas([]) --> [].
filas_peliculas([pelicula(Titulo, Genero, Calificacion)|Resto]) -->
    html(tr([td(Titulo), td(Genero), td(Calificacion)])),
    filas_peliculas(Resto).

% --- 4. Configuración y Arranque del Servidor ---
% Definir las rutas (handlers)
:- http_handler('/recomendacion', manejador_recomendacion, []).

% Predicado para iniciar el servidor
servidor(Puerto) :-
    http_server(http_dispatch, [port(Puerto)]).

% Para iniciar, ejecuta: ?- servidor(8000).

¿Cómo Funciona?

Paso 1: Ejecutar el Servidor

  1. Abre SWI-Prolog.

  2. Carga el archivo: ?- [servidor_peliculas].

  3. Inicia el servidor en el puerto 8000: ?- servidor(8000).

Verás un mensaje en la consola indicando que el servidor está corriendo, algo como: % HTTP server running on port 8000

Paso 2: Usar la Aplicación

Abre tu navegador web y ve a la siguiente URL:

http://localhost:8000/recomendacion?genero=scifi&calificacion=8.7

El servidor Prolog recibirá esta petición, ejecutará la lógica y te devolverá una página HTML con este resultado:

Recomendador de Películas en Prolog

Resultados de tu búsqueda:

Buscando películas de género: scifi con calificación mínima de: 8.7

TítuloGéneroCalificación
The Matrixscifi8.7
Inceptionscifi8.8

Si cambias la URL, por ejemplo a ?genero=crimen&calificacion=9.0, obtendrás resultados diferentes, demostrando que la página es totalmente dinámica y controlada por la lógica de Prolog.


Explicación del Código

  • library(http/...): Son las librerías que nos dan todas las herramientas para crear el servidor, manejar las peticiones (Request) y generar respuestas en HTML.

  • pelicula(...): Son nuestros "hechos" en la base de conocimientos. La base de todo.

  • encontrar_peliculas(...): Esta es la lógica principal. Utiliza findall/3 para recopilar en una lista todas las soluciones que cumplen con las condiciones, actuando como un motor de búsqueda.

  • manejador_recomendacion(Request): Es el "controlador". Se activa cuando se visita /recomendacion.

    • http_parameters/2: Extrae los valores de la URL de forma segura (con valores por defecto si no se proporcionan).

    • reply_html_page/2: Es una forma muy cómoda de construir una página HTML. El segundo argumento es una lista de elementos HTML que se renderizan automáticamente.

  • servidor(Puerto): Es el predicado que inicia todo el proceso, creando un servidor que escucha peticiones y las redirige al manejador correcto (http_dispatch).

Este ejemplo muestra perfectamente la separación de responsabilidades: la base de conocimientos (hechos), el motor de inferencia (reglas) y la capa de presentación (el servidor web) trabajan juntos, cada uno haciendo lo que mejor sabe hacer.

Xpce, de Prolog

XPCE es una biblioteca de herramientas (toolkit) para crear Interfaces Gráficas de Usuario (GUI) directamente desde SWI-Prolog. Es un sistema de programación orientado a objetos que está profundamente integrado con el motor lógico de Prolog.

Esto significa que con XPCE puedes construir aplicaciones de escritorio completas, con ventanas, botones, menús, lienzos para dibujar y otros elementos interactivos, todo controlado por la lógica de tu programa en Prolog.

¿Qué se puede hacer con XPCE?

Aquí tienes un desglose de sus capacidades y usos principales, desde lo más simple a lo más complejo:

1. Crear Interfaces Gráficas para tus Programas

En lugar de interactuar con tu programa Prolog solo a través de la consola o terminal, puedes crear una ventana amigable para el usuario. Esto incluye:

  • Ventanas y Diálogos: Crear ventanas principales, cuadros de diálogo para pedir datos (prompt), mostrar mensajes (alert) o confirmaciones.

  • Controles y Widgets: Añadir elementos interactivos como:

    • Botones (button) que ejecutan predicados de Prolog al ser pulsados.

    • Campos de texto (text_item) para que el usuario ingrese datos.

    • Menús (menu_bar, popup_menu) para organizar acciones.

    • Listas (list_browser) para mostrar conjuntos de datos.

    • Sliders, checkboxes, radio buttons, etc.

Ejemplo de uso: Un sistema experto sobre diagnóstico de enfermedades donde el usuario hace clic en síntomas en lugar de escribirlos.

2. Visualización de Datos y Conocimiento

Prolog es excelente para representar estructuras de datos complejas como árboles, grafos y redes. XPCE es ideal para visualizar estas estructuras.

  • Dibujo 2D: Puedes crear un lienzo (picture) y dibujar figuras geométricas (líneas, rectángulos, círculos, polígonos).

  • Grafos y Árboles: Puedes programar la visualización de un árbol de búsqueda, un grafo de dependencias o un árbol genealógico, donde cada nodo puede ser un objeto interactivo.

Ejemplo de uso: El propio depurador gráfico de SWI-Prolog (gtrace.) está hecho con XPCE. Te muestra el árbol de llamadas y el flujo de ejecución de tu programa de forma visual, lo cual es increíblemente útil.

3. Desarrollo de Herramientas y Entornos Interactivos

Debido a su profunda integración, XPCE es perfecto para crear herramientas de desarrollo o software educativo.

  • Editores de código: El editor de código integrado en SWI-Prolog, PceEmacs, está construido enteramente con XPCE.

  • Software educativo: Crear programas para enseñar lógica, matemáticas o cualquier materia donde la interacción y la visualización sean clave. Por ejemplo, un programa para resolver y visualizar puzzles lógicos como el Sudoku o las Torres de Hanoi.

  • Prototipado rápido: Si tienes una idea para una aplicación basada en lógica, puedes usar XPCE para crear rápidamente un prototipo funcional con una interfaz gráfica sin tener que salir del entorno de Prolog.

4. Programación Orientada a Objetos en Prolog

Aunque Prolog es un lenguaje de programación lógica, XPCE introduce un modelo de objetos completo.

  • Clases y Objetos: Puedes definir clases con atributos (variables de instancia) y métodos.

  • Manejo de eventos: El modelo es inherentemente orientado a eventos. Puedes hacer que los objetos reaccionen a acciones del usuario (clics, movimiento del ratón, teclas presionadas).

  • Delegación: Utiliza un mecanismo de envío de mensajes similar a Smalltalk u Objective-C.

Ventajas y Desventajas

  • Ventajas:

    • Integración perfecta: La comunicación entre tu lógica Prolog y la interfaz es directa y natural. No necesitas APIs externas ni complicados puentes entre lenguajes.

    • Viene incluido: No necesitas instalar nada extra, ya es parte de SWI-Prolog.

    • Multiplataforma: Funciona en Windows, macOS y Linux.

    • Potente para herramientas: Es ideal para visualizar estructuras de datos complejas que son el punto fuerte de Prolog.

  • Desventajas:

    • Estética anticuada: La apariencia de los componentes de XPCE no es moderna. Se ve como una aplicación de los años 90 o 2000. No es la mejor opción si buscas una interfaz pulida y moderna.

    • Curva de aprendizaje: Requiere aprender su modelo de programación orientado a objetos, que es un poco diferente al de lenguajes como Java o Python.

    • Alternativas modernas: Hoy en día, es muy común que la lógica de Prolog se ejecute en un servidor y la interfaz de usuario sea una aplicación web (HTML/CSS/JavaScript) que se comunica con el servidor a través de una API. SWI-Prolog tiene excelentes bibliotecas para crear servidores web (library(http)).

Conclusión

XPCE es una herramienta extremadamente poderosa si quieres construir aplicaciones de escritorio, herramientas de visualización o software educativo donde la lógica de Prolog es el núcleo central. Es la forma más rápida y directa de darle una cara gráfica a tu programa Prolog.

Si, por otro lado, tu objetivo es crear una aplicación con una interfaz de usuario moderna y atractiva, probablemente sea mejor opción usar SWI-Prolog como un motor de backend y construir la interfaz con tecnologías web.

jueves, 15 de septiembre de 2016

De lógica

Puntos a tratar:

  1. Todo estaría esencialmente en orden, pero no está demás dar un repaso general y lo siguiente.
  2. No vimos esto de la "diferencia simétrica" entre conjuntos, ya que supuse que estaba basada directamente en las tres operaciones fundamentales: unión, intersección y diferencia de conjuntos. Repasar la definición en la red o en algún libro.
  3. Repasar demostraciones: captar la idea de convencer a alguien de que estamos en lo correcto.
  4. Dar prioridad a los tipos de razonamiento sobre, por ejemplo, inducción matemática.
Mucha suerte.

martes, 5 de julio de 2016

Directivas generales (nuevas)

Nuevo: No espero más aclaraciones, verificaciones y revisiones, así que lo que
sigue es enfocarse, a quienes así convenga, a su 2o. extraordinario, el cual
tomará en consideración el material ya visto junto con algún par de ejercicios
del teorema de Stokes o el de Green. Menciono que tomar dxdy o dydx de una
integral iterada dependera de la simetría del dominio, así que es necesario
tomar en consideración si los barridos son de arriba hacia abajo (forma dydx)
o de derecha a izquierda (forma dxdy).

Para el ejemplo del examen, tendríamos
    2     sqrt(x)
int   int            f(x,y) dy dx
    0      0

y la otra versión (que nadie hizo) es:
    sqrt(2)      2
int            int         f(x,y) dx dy
      0             y*y

Verificando en máxima, tenemos:
(%i6) integrate(integrate(y/(1+x**2),y,0,sqrt(x)),x,0,2);
                                    log(5)
(%o6)                               ------
                                      4


(%i9) integrate(integrate(y/(1+x**2),x,y*y,2),y,0,sqrt(2));
     2
Is y  - 2 positive, negative or zero?

positive;
                                    log(5)
(%o9)                               ------
                                      4

Nuevo (12 de julio de 2016): Ya pueden verificar su calificación en el sistema.
Las aclaraciones sólo serán el día de hoy, de preferencia de 4 a 7.


Nuevo: Tomar en consideración que este examen será colegiado
(departamental), así que se intentará mantener un conjunto básico
de problemas por mi parte, pero otros más pueden venir de otros profesores.
Para este caso, repasar de algunos libros clásicos de cálculo diferencial
e integral.

Nuevo: El examen será el lunes 11 de julio en los salones A9 y A10 de 9 a 11
de la mañana.


El examen está dividido en tres partes:

a) Sería la parte de integración simple:
  1. Integración por partes
  2. Integración por sustitución
  3. Fracciones parciales (por ejemplo: int 1/(x**2+x) dx).
  4. Con integración indefinida.
  5. Manejo de integrales (1/(1+x**2))... sinh x, cosh x, e**x (por cierto, es posible que no se permita el uso de formularios en el examen; recordar algunas fórmulas básicas es, así, indispensable para trabajar sin formularios: escribir unas cuantas veces en un papel las fórmulas trigonométricas varias veces es útil, así como "jugar" con las fórmulas de integración: por ejemplo, la integral de 1/(1+x**2) es... y así en una ronda de memorización).
Advertencias en esta parte: No realizar "operaciones de estudiante novato":
i) 1/(a+b) =/= 1/a+1/b
ii) (a**2)**3 =/= a**5
iii) a**3*a**2 =/= a**6
iv) sqrt(a+b) =/= sqrt(a) +sqrt(b)
v) int (f(x)*g(x)) dx =/= (int f(x) dx) * (int g(x) dx)
x/x =/= 1   (la primera tiene una indefinición en x=0; la igualdad es válida si garantizamos que x=/=0)
Agregando otra falacia:
 vi)  (a+b)**2=a**2+b**2

El caso de las fracciones parciales es también digno de estudiar por sí mismo,
ya que de un denominador complicado se puede pasar a un denominador simple, permitiendo que se aplique alguna fórmula de integración bien conocida (por ejemplo, logaritmos):
Ejemplo sencillo:
1/(x**2-5x+6)=
1/[(x-2)(x-3)]=A/(x-2)+B/(x-3)
y
A/(x-2)+B/(x-3)=(A(x-3)+B(x-2))/[(x-2)*(x-3)]
por lo que
1/[(x-2)(x-3)]=(A(x-3)+B(x-2))/[(x-2)*(x-3)] implica que debemos tener
1=A(x-3)+B(x-2)=Ax+Bx-3A-2B= x(A+B)-3A-2B
Si los polinomios 1 y  x(A+B)-3A-2B deben ser iguales, tendrían que
ser iguales por cada ocasión en que ocurre o no la variable x; así,
1=-3A-2B (*)
A+B=0
De aquí, B=-A, y sustituyendo en (*)
 1=-3A+2A=-A, de donde A=-1, y por lo tanto B=1.
De lo anterior, debería ser cierto que
1/[(x-2)(x-3)]=-1/(x-2)+1/(x-3)
 -1/(x-2)+1/(x-3)=[(3-x)+(x-2)]/[(x-2)(x-3)]=1/[(x-2)(x-3)],
como era requerido.
Lo importante es que integrar esta nueva versión
-1/(x-2)+1/(x-3)

es algo sencillo.



Recordemos además que no está de sobra repasar la factorización de un polinomio, la división de polinomios y la suma y resta. Las prisas o los nervios

a veces nos hacen cometer errores simples en estas operaciones. Es bueno en apartar las operaciones que así se realicen para después complementarlas con los ejercicios que se trabajen.

Cuando el tiempo lo permita, traten siempre de derivar aquella función
que proponen como solución en la integración: se tiene que llegar a la
función original, por el teorema fundamental de cálculo.
Noten también que la definición es:
     b
int   f(x) dx = F(b) - F(a), donde F'(x)=f(x), y no F(a) - F(b)
     a
Alterando el orden se cambia el signo, y puede llevarlos a conclusiones
erróneas.

b) Integrales dobles
  1. Descripción de regiones (arriba a abajo, o izquierda a derecha).
  2. Integrales iteradas; consideraciones sobre las variables.
  3. Integrales dobles sobre regiones.
  4. Teorema de Fubini.
  5. Evaluaciones de integrales sobre regiones con definiciones incluyendo constantes: ejemplo [0,a]x[0,b], con a>0,b>0. 
En el caso de regiones, debe distinguirse bien cómo se caracterizan:
para los casos básicos, es de arriba a abajo (primero dy) o de derecha a
izquierda. No es "conmutativo" este orden!!! (salvo casos simétricos indistinguibles). Por ejemplo, integrando f(x,y)=x*2 en [0,2]x[0,2]
es lo mismo para esta región si evaluamos
     2             2
int          int      f(x,y) dy dx     o si evaluamos
      0            0
     2             2
int          int      f(x,y) dx dy
      0            0

pero no para cuando la región es [0,1]x[0,2].

c) Repasar de Larson, parte de cálculo vectorial.
  1. Gradientes.
  2. Campos vectoriales.
  3. Dominios y codominios.
  4. Rotacional.
  5. Divergencia.
  6. Producto interno.
  7. Producto externo.
  8. Integrales de línea; integrales de longitud de arco.
  9. Repasadita del Teorema de Stokes, de Green. 
En esta parte los errores comúnmente registrados son los de ausencia
de paréntesis, tanto para dar adecuada prioriada al efecto de los operadores
como para señalar con precisión que se trabaja con vectores de cierta dimensión. Además, otro error común en los exámenes previos fue no identificar
los pasos de evaluación finales. A veces es una pena que ya se obtuvieron
en esencia los resultados correctos pero las malas evaluaciones subsiguientes
echan todo a perder.

Un tema en el que muchos fallaron en el examen ordinario fue el de cómo
ensamblar la función potencial f de un campo vectorial conservativo F.

Sea por ejemplo F(x,y)=(x,y)
ya que la derivada parcial de x con respecto a y es 0, y de la derivada
parcial de y con respecto a x es también 0, el campo F es conservativo.
devParcial(f,x)=x implica que f1(x,y)=x**2/2+C1(y)
para una f1(x,y) (incompleta con respecto a f).
devParcial(f,y)=y implica que f2(x,y)=y**2/2+C2(x)

Ahora bien, debemos tener que f1=f2=f!, es solo que f es la que abarca
a f1 y a f2. Pero, por un lado, C1(y) puede ser y**2/2 (que está en la formulación de f2), y por otro C2(x) puede
ser igual a x**2/2, (que está en la formulación de f1)
así que f "completa" es f(x,y)=x**2/2+y**2/2+ C, donde
ahora sí C no tiene compromiso de tener dependencia con respecto a x o
a y: es una constante cualquiera.

C1(y) depende de y, pero al derivarla con respecto a x es 0, así que
C1(y) sí depende y; análogamente para C2(x).

Lo mejor para ver que uno dió la respuesta correcta es verificar que con la
f ensamblada se cumple que grad f = F!!!!
Notemos que para todo lo anterior el antecedente previo es la buena técnica de derivación, y el considerar como bien dominado el concepto de derivada parcial (sin cambiar notaciones bien establecidas).

jueves, 29 de octubre de 2015

Fibonaccis y coálgebras en Haskell


Este es un archivo en modo "Haskell literario"

> x = 2
> y = (\x -> x+2) 2

"Naked expression... ", manejo de este tipo de errores.

Veamos la siguiente álgebra:
<<(+,1)>> = Naturales.
El elemento primigenio, seminal o generador es el 1, y la operación de generación
es el +.

1, 1+1=2, 1+1+1=3, 3+1, ...
1, 2, 3, ...                          
-- #N Cardinalidad de N: El tamaño del conjunto generado. La ocurrencia de un $n$
dentro de la sucesión es su orden (como conjunto ordinal).

Otro ejemplo:
<<({o, y, no},{F,T})>> = Proposiciones lógicas simples con constantes T y F.

F,T,T o F, (T o F) y (no F),...
Cfr. con Prolog.

?- false.
false.

?- true,false.
false.

?- true,true.
true.

?- \+ (true).
false.

?- false < true.
ERROR: </2: Arithmetic: `false/0' is not a function -- ya que < es definido para aritmética
?- false @< true.
true.  --ya que @< compara términos

-----------------------------------------------------------------------------

Para coálgebras:

[1],  %Primer elemento
[1,1], % segundo elemento
[1,1,1]...

en el paso al límite en el crecimiento de esta sucesión tenemos un
elemento "infinito": sería el "último" de una unión de elementos previos:

A1={[1]}
A2= A1 U {[1,1]}
A3= A2 U {[1,1,1]}
....
An = A(n-1) U {[1...replicado n veces]} (U representa la unión de conjuntos)
 A1 C A2 C A3 C A4 C A5 C ... ----> infinito (C representa la contención de conjuntos)

En el paso al límite (cuando n tiende a infinito), tenemos un conjunto infinito, cuyo
´ultimo elemento se dice que ésta en la coálgebra generada por la sucesión An.

Para el ejemplo tratado, se especifica en Haskell así:

> o = 1:o

En el modelo de computación de Haskell que es por medio de evaluación perezosa
un elemento solo se crea si se requiere en un paso de cómputo.

Así se crean los números naturales  a partir de un número n:

> nat n = n: nat(n+1)

Y así se crean todos los números naturales

> l = nat 1

Tomando l, tenemos
[1,2,3,4,5,6...] (infinitamente.

Consideremos ahora la función de Fibonacci y observemos que
si desplazamos la sucesión de Fibonacci con respecto a sí misma y
sumamos columna a columna tenemos otra vez la función de Fibonacci:
1,1,2,3,5,8...
   1,1,2,3,5,8...
____________
1 2 3 5 8 13...
Esto diría que la sucesión  de Fibonacci es más fácil de crear subcreando
dos sucesiones de Fibonacci que creando una sola! Paradójico,  no?


> fibs0 = [1,1,2,3]
> fibs1 = 1:1:[]
> fibs2 = 1:1:[x+y| x <- fibs0, y <- tail fibs0]

x valor 1 y valor 1
x valor 1 y valor 1

Tarea: Generar los números primos por medio de un flujo (comento el cofinal
de una coálgebra).


Si ahora tenemos:
fibs
obtenemos
[1,1,2,3,4,2,3,4,3,4,5,4,5,6]
que no es lo que se desea.

*Main> [x+y | x<-[1,2,3,4],y<-[5,6,7]]
[6,7,8,7,8,9,8,9,10,9,10,11]
*Main> [(x,y) | x<-[1,2,3,4],y<-[5,6,7]]
[(1,5),(1,6),(1,7),(2,5),(2,6),(2,7),(3,5),(3,6),(3,7),(4,5),(4,6),(4,7)]

Hagamos justa (fair) la selección de elementos (1 elemento por lista en cada
ocasión). Utilizamos para ello la función zip:

*Main> zip [1,2,3,4] [5,6,7]
[(1,5),(2,6),(3,7)]

*Main> [(x,y) | (x,y)<-zip [1,2,3,4] [5,6,7]]
[(1,5),(2,6),(3,7)]

*Main> [x+y | (x,y)<-zip [1,2,3,4] [5,6,7]]
[6,8,10]

Finalmente, esta es la función requerida:

> fibs = 1:1:[x+y | (x,y) <- zip fibs (tail fibs)]

He aquí algunas ejecuciones:

*Main> take 5 fibs
[1,1,2,3,5]
*Main> take 8 fibs
[1,1,2,3,5,8,13,21]
*Main> take 12 fibs
[1,1,2,3,5,8,13,21,34,55,89,144]
*Main> take 15 fibs
[1,1,2,3,5,8,13,21,34,55,89,144,233,377,610]
*Main> take 20 fibs
[1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765]
*Main> fibs!!100
573147844013817084101
*Main> fibs!!200
453973694165307953197296969697410619233826

etc.

miércoles, 28 de octubre de 2015

Haskell es especial



*.lhs: Hacen a Haskell intensivamente comentado.

Haskell: Su fundamento es el Cálculo Lambda (Alonzo Church, 1930s).
Haskell: Bloque de trabajo son las funciones (brazo derecho).
Haskell: Los tipos son su brazo izquierdo de trabajo: Char, Int, Float, Double...
              tipos curriados o compuestos vía productos cartesianos.
Haskell: Mónadas: La manera de Haskell de modelar el mundo exterior
               disciplinadamente.
Haskell: Funciones de mayor orden y funciones curriadas.
Haskell: Estrategia genérica de evaluación perezosa (lazy evaluation), lo que
         origina coálgebras: Las coálgebras son estructuras duales a las álgebras.
         En una álgebra queremos la intersección de inclusión; en una coálgebra
         queremos la unión de la inclusión. Las coálgebras permiten justificar la
         introducción y utilizamiento de algo conocido como objetos computacionales
         infinitos.


Ejemplos:
1) Cálculo lambda:

> (\x -> x+1) 2
> map (\x -> (4:)) [[1],[2],[3]]

>  map (\x -> x*x) [1,2,3]

> let s = sin . cos in s 2
> let f = tan . cos . sin in f 10

(Haciendo eco de las palabras del Premio Turing John Backus, de que las
variables son inútiles en la programación.)
El operador punto es composición de funciones.

2) Bloques (sin variables)

> longitud  = sum . unos
> unos = map (\x -> 1)


3) Tipos:

> lonCad :: String -> Int
> lonCad = length

Aquí se enfatiza que lonCad calcula la longitud de cadenas.

4) Visto como el programa Hello.hs.

> filter (\x -> x> 10) [1..100]

A las funciones que toman como argumento a otras funciones se les llama
funciones de mayor orden.

> productoInterno:: ((Float,Float),(Float,Float)) -> Float
> productoInterno ((x1,y1),(x2,y2)) = x1*x2+y1*y2




> productoInterno':: (Float,Float) -> (Float,Float) -> Float
> productoInterno' (x1,y1) (x2,y2) = x1*x2+y1*y2

> productoInterno'':: Float ->Float -> Float -> Float -> Float
> productoInterno''  x1 y1 x2 y2 = x1*x2+y1*y2

> mul2 :: (Float, Float) -> Float
> mul2 (x,y) = x*y+2

Versión curriada (Haskell Curry)

> mul2' :: Float -> Float -> Float
> mul2' x y = x*y+2

map (mul2 2) [1,2,3,4,5]

map (\x -> (mul2 (2,x))) [1,2,3,4,5]
La diferencia es que mul2 trabaja en el dominio (Float,Float) y
y mul2' trabaja en el dominio Funciones: Float -> Float

Esta es la versión (infame) de un programa para crear los
números de Fibonacci.
> fib 1 = 1
> fib 2 = 1
> fib n | n> 2 = fib             (n-1) + fib                 (n-2)
En una próxima ocasión generaremos su versión de flujo.


Mientras, la siguiente función genera un flujo infinito de filas del triángulo de Pascal:

> pascal = p
>   where
> p = [1] : [next a | a <- p]
> next x =  addRows (0:x) x
>                  where
>            addRows (a:x) (b:y) =  (a + b):(addRows x y)
>            addRows [a]   []    =  [a]
>            addRows []    []    =  []

Como ejemplos de ejecución tenemos:

Main> take 5 pascal
[[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]
*Main> take 15 pascal
[[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1],[1,5,10,10,5,1],[1,6,15,20,15,6,1],[1,7,21,35,35,21,7,1],[1,8,28,56,70,56,28,8,1],[1,9,36,84,126,126,84,36,9,1],[1,10,45,120,210,252,210,120,45,10,1],[1,11,55,165,330,462,462,330,165,55,11,1],[1,12,66,220,495,792,924,792,495,220,66,12,1],[1,13,78,286,715,1287,1716,1716,1287,715,286,78,13,1],[1,14,91,364,1001,2002,3003,3432,3003,2002,1001,364,91,14,1]]
*Main> pascal!!4
[1,4,6,4,1]
*Main> (pascal!!4)!!3
4

lunes, 26 de octubre de 2015

Es sencillo, con mónadas



---------------- Y ahora lo siguiente
main :: IO ()
main = do
  putStrLn "Cuál es tu nombre?"
  name <- getLine
  putStrLn ("Gusto en conocerte, " ++ name ++ "!")

--- main tiene tipo IO (): las acciones posibles para cambiar un mundo.
--- do permite realizar acciones secuencialmente
--- Cada acción es ejecutada dentro de la mónada

--- ¿Por qué esto tendría que ser tan difícil? ¿No es este programa una nadería en la
--- programación imperativa?

--- La respuesta es: Se requiere controlar cada efecto lateral, se requiere que el programador
--- sea consciente de cada valor de una expresión, y además se requiere que haya un orden
--- para realizar consecutivamente cada acción. En resumen, se requiere control.
--- Y es que de otra forma la programación (de computadoras) permite fácilmente, sin disciplina,
--- la creación de monstruos amorfos, gelatinosos, escurridizos y fantasmagóricos: son esos
--- programas convencionales que de pronto fallan sin saber por qué, que son difíciles de dar
--- mantenimiento, de actualizar o de ampliar. Sin control, un programador entra fácilmente en
--- un terreno minado.

Los números de Fibonacci, en una infinita lista


---Lo siguiente es una pequeña perla de la programación funcional, en Haskell:

>let fibs = 1:1:[x+y|(x,y) <- zip fibs (tail fibs)] in take 17 fibs
>[1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597]

jueves, 15 de octubre de 2015

Esta vez, Scheme

; Lo siguiente es una codificación de una interfaz ejemplificando las capacidades de
; interfaz gráficas tal como están disponibles en Racket,
; de www.racket-lang.org

mh@zas:$ cat racketNombre01.rkt
#lang racket/gui
; Creación de un diálogo

(define dialog (instantiate dialog% ("Ejemplo de diálogo")))

; Agrega un campo de texto a
(define tf (new text-field% [parent dialog] [label "Escribe tu nombre, por favor"]))

; Agrega un panel horizontal al diálogo
(define panel (new horizontal-panel% [parent dialog]
                                     [alignment '(center center)]))
; Pega un mensaje estático al diálogo
(define msg (new message% [parent dialog]
                          [label "No hay acción..."]))

; Agrega los botones de Cancel y Ok al panel horizontal
(new button% [parent panel] [label "Cancel"]
     [callback (lambda (button event)
                 (message-box "....." "NoNoNNNo  me canceles :("))])
(new button% [parent panel]
     [label "Ok"]
     [callback (lambda (button event)
                         (message-box "Respuesta"
                               (string-append "Hola  "
                                (send tf get-value)
                                )))])
(when (system-position-ok-before-cancel?)
  (send panel change-children reverse))

; Mostrar el diálogo
(send dialog show #t)


Mónadas en Haskell


---De una explicación preliminar de mónadas en Haskell
import Control.Monad
--- data Maybe t = Just t | Nothing


add :: Maybe Int -> Maybe Int -> Maybe Int
add mx my =
  case mx of
    Nothing -> Nothing
    Just x  -> case my of
                 Nothing -> Nothing
                 Just y  -> Just (x + y)

sol n =
    case n of
      2 -> 3
      4 -> 4
      5 -> 6
      _ -> 10

sol2 2 = 3
sol2 4 = 4
sol2 6 = 6
sol2 _ = 10

sol3 n | n== 2 = 3
           | n==4  = 4
           | n==5  = 6
           | otherwise = 10

add2 :: Maybe Int -> Maybe Int -> Maybe Int
add2 mx my =      
    -- Adds two values of type (Maybe Int), where each input value can be Nothing
  mx >>= (\x ->
      -- Extracts value x if mx is not Nothing
    my >>= (\y ->
     -- Extracts value y if my is not Nothing
      return (x + y)))
 -- Wraps value (x+y), returning the sum as a value of type (Maybe Int)

add3 :: Maybe Int -> Maybe Int -> Maybe Int
add3 mx my = do
  x <- mx
  y <- my
  return (x + y)

add4 :: Maybe Int -> Maybe Int -> Maybe Int
add4 = liftM2 (+)

con4 :: Maybe String -> Maybe String -> Maybe String
con4 = liftM2 (++)

lunes, 13 de abril de 2015

Cuestionario de salvamento.

Complejidad

Complejidad

Lea cuidadosamente. a**n se lee como "a elevado a la n".
  1. Se sabe que P=NP.

  2. Verdadero
    Falso

  3. Todo algoritmo ejecutable en espacio constante es lineal en tiempo total de ejecución.

  4. Falso
    Verdadero

  5. O(n) contiene O(n**2).

  6. Falso
    Verdadero

  7. Existen 2**n-2 subconjuntos propios de un conjunto de n elementos.

  8. Verdadero
    Falso

  9. Prolog es el único lenguaje de programación determinista.

  10. Falso
    Verdadero

  11. Toda función periódica de los naturales a los naturales expresa una función recursiva primitiva.

  12. Verdadero
    Falso

  13. Con f(1)=1, y f(n) = f(n-1) se tiene una función recursiva primitiva, con valor f(n)=n.

  14. Verdadero
    Falso

  15. Es bueno utilizar apuntadores en el análisis de complejidad de un algoritmo.

  16. Verdadero
    Falso

  17. El polinomio h(x) = a+b*x+c*x**2 es una función computable según Kleene.

  18. Verdadero, si a,b,c y x toman valores enteros.
    Falso, si a, b, c y x son números reales.

  19. Considera la cadena "abaaaaabbbac".

  20. Puedo formar con esto un palíndromo.
    No puedo formar un palíndromo.

Después de terminar tu cuestionario,mantén durante un periodo de tiempo la pantalla. Salva tu resultado mediante PrScr.

s

Verdadero o falso?

1) P=NP.
2). Todo algoritmo ejecutable en espacio constante es lineal en tiempo total de ejecución
3) O(n) contiene a O(n**2).
4) Existen 2**n-2 subconjuntos propios de un conjunto de n elementos.
5) Con f(1)=1,  y f(n) = f(n-1) se tiene una función recursiva primitiva, con valor f(n)=n.
6) Toda función periódica de los naturales a los naturales puede expresarse como una función recursiva primitiva.
7) Considera la cadena "abaaaaabbbac". Halla un palíndromo con los caracteres (todos) de esta cadena. 
Te costó lo mismo hallar el palíndromo que verificar que lo es.
8) Es bueno utilizar apuntadores en el análisis de complejidad de un algoritmo.
9) Es bueno utilizar Python en el análisis de complejidad de un algoritmo.
10) El polinomio h(x) = a+b*x+c*x**2 es una función computable según Kleene (a,b,c: constantes enteras, x variable entera).

jueves, 19 de marzo de 2015

Micro-repaso conceptual en relaciones, funciones e inducción

Intermedio: Relaciones, funciones e inducción

Intermedio: Relaciones, funciones e inducción

  1. ¿Es la composición de dos funciones inyectivas una función inyectiva?

  2. Sí
    No

  3. Si existe una función biyectiva entre los conjuntos A y B, estos tienen la misma cardinalidad.

  4. Sí
    No

  5. El principio de inducción matemática permite probar propiedades definidas sobre los números reales

  6. Sí
    No

  7. La conversa de una relación en unión con la relación misma es una relación simétrica.

  8. Sí
    No

  9. La relación <= (menor que o igual) es una relación de equivalencia.

  10. Sí
    No

  11. La composición de dos funciones biyectivas es una función biyectiva.

  12. Sí
    No

  13. Existen exactamente (n+1)! funciones biyectivas de un conjunto en sí mismo.

  14. Sí
    No

  15. El complemento de la relación a<b (menor que) es la relación a>b.

  16. No
    Sí

  17. Sea f(x)=1/x, con f(0)=0. Esta función es total, de R a R.

  18. Sí
    No

  19. La inducción matemática consiste en probar que para un predicado P, P(k) implica P((k+1)+1).

  20. No.
    Sí.

miércoles, 18 de marzo de 2015

De unas propuestas de tesis de maestría en sistemas distribuidos.

En esta entrada planteo unas cuantas posibles vertientes de investigación que serían adecuadas para lograr una tesis de maestría en sistemas distribuidos. Los temas están enfocados en el tratamiento de cómputo distribuido, aunque no es de descartar su enfoque económico, social, de e-gobierno, o administrativo en general, aunque para ello se requiere de una co-asesoría de alguien experto en el tema lateral. Tales colaboraciones son deseables, pero no siempre posibles, al no existir tales expertos dentro del personal académico de este tipo de maestrías, orientadas a aspectos tecnológicos computacionales.

Para comenezar y de manera genérica, se tendría que adoptar un lenguaje de programación para actividades prácticas tal como Erlang (www.erlang.org). ¿Por qué? Por que es un lenguaje diseñado para tratar con concurrencia desde su diseño original, principalmente, y tiene además un esquema de trabajo basado en paso de mensajes muy limpio. Eso sí, no es un lenguaje ni muy conocido ni muy comercial. Inspeccionando en la red, en lo primero, apenas hay una docena de libros, todos de publicación reciente, que tratan de Erlang. En lo segundo, solo ocasionalmente se escucha que Erlang da vida al chat de Facebook o que Amazon lo incorpora de forma accesoria en algunos de sus servicios. Lejos de ser desventajas, la falta de popularidad de Erlang no es objeción contra la calidad de su diseño, y brinda un nicho de exploración académica en contraposición a un papel que tradicionalmente ha sido adjudicado a, por ejemplo, Java. La comparación en este momento se vuelve injusta, ya que Java tiene apoyos monetarios estratosféricos para proyectos de enorme impacto comercial, haciendo que su lado académico languidezca, al no permitirse compartir el código y ni siquiera los generales de diseño. Para esto de las aplicaciones, la comunidad de Erlang es proclive a aceptar nuevas posibles aplicaciones de Erlang como casos de estudio que muestren las bondades del lenguajes, por lo que siempre están dispuestos a ayudar y son promovedores del código fuente libre.

Para manejar la parte de complejidad conceptual de los sistemas distribuidos la idea es utilizar los conceptos plasmados en SCEL:

http://dl.acm.org/citation.cfm?id=2642710.2619998&coll=DL&dl=GUIDE&CFID=645236426&CFTOKEN=35421267

SCEL es un lenguaje de especificación de sistemas distribuidos basados en
componentes autónomos que se comunican mediante envío y recepción de mensajes. Cada componente tiene cierto grado de capacidad de procesamiento para formar parte de grupos, así como tomar decisiones básicas basadas en su "estado de salud" actual, entre otros factores.

La parte principal de este amplio esquema teórico radica en estudiar
componentes autonómicos de sistemas distribuidos basados en mensajes, pero sin restricciones que pudieran ocurrir en primera instancia. Se utilizan para ello sistemas de transición etiquetados, con una buena dosis
de cálculo pi. Una ventaja de este amplio esquema es que puede adaptarse
a un tema sencillo o específico, sirviendo así como de "almacén conceptual"
para el tratamiento adecuado de instancias distribuidas.  A la gente de SCEL
esta parte le llama mucho la atención por que conforma las "pruebas de
ácido" de su propuesta teórica, e inclusive se les puede escribir para resolver
dudas concretas (conozco personalmente a algunos de sus creadores, y son
gente sencilla y accesible ---realmente sabias).

Finalmente, antes de detallar los posibles tópicos de investigación, tenemos
el tema de los agentes. Un agente tiene un modelo muy particular de
cómputo que no sigue necesariamente aquel tradicional de resolución de  problemas
basados en máquinas de Turing (el principal proponente de este enfoque es Peter Wegner, junto con la idea de interacción: http://cs.brown.edu/~pw/).
El punto esencial de un "nodo-agente" distribuido es que siempre debe estar "atento" de lo que pasa a su alrededor o en su interior: eso incluye el tiempo, el estado de la batería, la temperatura, el buen funcionamiento del sistema, el
adecuado estado de sus llantas, o bien, atento a organizarse adecuadamente para lograr un objetivo común con otros nodos-agentes, o bien manejar con
la debida respuesta el intento de hackeo de intrusos o en general, las
perturbaciones externas al sistema. Este tipo de tareas se complementa
con aquellas llamadas "self-*" en SCEL, junto con otras tradicionales de agentes relacionadas con su inmersión en un ambiente. Los agentes son a su vez instancias de un enfoque de resolución de problemas basado en la constante interacción con el ambiente, a diferencia de una máquina de Turing que sólo toma una entrada y vuelve a interactuar con el ambiente (incluido un usuario) sino hasta brindar (posiblemente) una salida. La intermitencia de aspectos sensoriales y de guía hace que estos agentes resuelvan problemas que una máquina de Turing con su enfoque cerrado no podría.

Ahora, teniendo ya algunas cartas sobre la mesa, propongo unos tres temas como posibles tesis de maestría en sistemas distribuidos:

* El primer tema tiene que ver con construir un escenario virtual donde unos
robots deambulan, comunicándose entre sí y teniendo una noción de cooperación, y en su caso, de competencia. Con la robótica en el estado actual (microcontroladores programables, servos, y sensores), tal simulación sería trasladable a un escenario realista en principio, aunque con objetivos concretos en mente y posiblemente una inversión monetaria alta.

* El segundo tema es con respecto al tratamiento del tiempo de unos
agentes que monitorean y dan mantenimiento a un sitio virtual. Los agentes que actualmente actúan de esta forma (con algunas otras funciones más) están presentes en las redes sociales y los comercios internacionales tales como Amazon. Tal tecnología está en una etapa madura, pero todavía faltan algunos aspectos a tratar que impiden cierta flexibilidad de los agentes actuales.
 
* El tercer tema es para validar redes distribuidas mediante "model checking"
(construcción de modelos sencillos para verificar que las redes funcionan
como se debe). La ventaja de un enfoque como éste es que se puede partir de un sistema distribuido complejo y analizarlo con herramientas sencillas, o bien comenezar con una red sencilla y por capas de provisión de riqueza en servicios ir ampliándolo siempre bajo una disciplina de creación de modelos.

Cabe mencionar que esta no es una lista exhaustiva de posibles temas: más bien digo que los temas aquí presentados indican la incorporación en su desarrollo de las anteriores herramientas mencionadas. Llegado el caso, se aceptarían propuestas que involucraran al menos dos de
tres siguientes aspectos: Erlang, cálculo-pi, y  distribución de carga computacional.

A reserva de otras consideraciones metodológicas, es necesario enfatizar que
la selección de una herramienta computacional para implementar algoritmos
o simulaciones es ya un avance sustancial en el logro de un proyecto de tesis
de maestría. La misma observación en el ámbito teórico: si nos ponemos a
pensar al respecto, es enorme la variedad de "ofertas teóricas" que se
presentarían. Al delimitar algunas de ellas basadas en los criterios de pertinencia, asequibilidad, comprensibilidad y complejidad notaremos que
las herramientas teóricas mencionadas ya poseen de entrada ciertas ventajas.

Una nota importante: El manejo del tiempo entre el comienzo de una tesis
de maestría y su final es algo digno de consideración, y requiere tanta atención  como lo es el considerar la desventaja de la distancia geográfica entre los participantes en el caso de estudios a distancia. Una buena actitud de parte del estudiante es fundamental: si el estudiante solo tiene un interés mediano en el tema (o peor, ninguno), los tiempos se ampliarán como si fueran por descripción recursiva (notemos, jocosamente, que 1+1/2+1/3+1/4+.. es una serie divergente, como cuando un estudiante dice: "En un semestre haré la mitad de la tesis; en el otro semestre la mitad de la otra mitad; etc."). Tan importante como el interés en el tema, por lo tanto, es plantearse tiempos cortos de avances efectivos de tesis y tácticas para sortear el distanciamiento geográfico en comunicación. Suerte. 

miércoles, 11 de marzo de 2015

Micro-cuestionario (versión de familiarización)

Intermedio de Conjuntos y Relaciones

Intermedio de Conjuntos y Relaciones

  1. Es el mismo conjunto {{}}={{{}}} ?

  2. Sí
    No

  3. Si A es {1,2,3}, esta bien P(A)={{},{1},{2},{1},{2,3},{3,1},{2,3},{1,2,3}} ?

  4. Sí
    No

  5. Está bien {x | x es 1 o 0}={0} ?

  6. Sí
    No

  7. Si R = {(1,2),(1,3)} y S={(2,1),(3,1)}, es R o S ={(1,1),(1,1)}?

  8. Sí
    No

  9. Si R = {(x,y) | x pertenece a {1,2} y y pertenece a {1,2} con x < y} Es R={(1,1),(1,2),(2,2)}?

  10. Sí
    No

Conserven su pantalla de evaluación por un momento. Gracias.

martes, 10 de marzo de 2015

Un mini-cuestionario


Basico


  1. Vas comprendiendo el material de Python?

  2. Sí
    No

  3. Conoces la diferencia entre una función y una relación?

  4. Sí
    No

  5. Sabes qué es una relación identidad?

  6. Sí
    No

Pequeñas definiciones en Python

#Ejemplos en Python.

>>> def fib(n):
...     if n==0 or n==1: return 1
...     else: return fib(n-1)+fib(n-2)
...
>>> fib(5)
8
>>> map(fib,range(0,11))
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
>>> def fastfib(n):
...     a,b=1,1
...     while (b<n):
...             a,b=b,a+b
...     return b
...
>>> fastfib(10)
13
>>> fastfib(11)
13
>>> fastfib(15)
21
>>> fastfib(80)
89
#Pregunta: ¿qué hace fastfib con respecto a n?

>>> def nthfib(n):
...     a,b=1,1
...     for i in range(1,n+1):
...             a,b=b,a+b
...     return b
...
>>> nthfib(1)
2
>>> nthfib(2)
3
>>> nthfib(3)
5
>>> nthfib(4)
8
>>> map(nthfib,range(0,11))
[1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144]

# Pregunta: ¿coincide este resultado con aquel de fib? Corregir.
#Notar para grandes valores:
>>> nthfib(100)
927372692193078999176L
>>> nthfib(1000)
113796925398360272257523782552224175572745930353730513145086634176691092536145985470146129334641866902783673042322088625863396052888690096969577173696370562180400527049497109023054114771394568040040412172632376L
#Dándole una oportunidad al factorial de un número:
>>> def fact(n):
...     if n==0: return 1
...     else: return n*fact(n-1)
...
>>> fact(10)
3628800
>>> fact(30)
265252859812191058636308480000000L
#Miscelánea, listas y cadenas:
>>> ls="hola"
>>> ms=ls
>>> ls.reverse()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'reverse'
>>> ls=list("hola")
>>> ls.reverse()
>>> ls
['a', 'l', 'o', 'h']
>>> ms+ms
'holahola'
>>> ms*5
'holaholaholaholahola'
>>> ms[2]
'l'
>>> ms[2:]
'la'
>>> ms[:2]
'ho'
>>> ms=ms+ms
>>> ms[3:4]
'a'
>>> ms[3:7]
'ahol'


lunes, 9 de marzo de 2015

Notas acerca de estos programas y del blog.

Los anteriores programas funcionan módulo la provisión de los archivos de gráficas y audio faltantes. Se pueden poner tentativamente algún audio en formato .wav, por ejemplo. La idea es seguir el bosquejo descrito en cada uno de estos programas para un posible proyecto posterior. Me parece que en algún lugar del blog se puede poner en activo la opción de "Seguir", para ser notificados de nuevas entradas o de entradas que se modifiquen. Cordiales saludos.

domingo, 8 de marzo de 2015

Ejemplo de sonido (gruñido de puerco)


import pygame,time

#-----------------------------------------------------------------------

#Más información de Pygame en http://www.pygame.org

#-----------------------------------------------------------------------

pygame.init()
#Necesario tener pig.wav, es fácil hallar sonidos de este tipo en la red...
sonidoPuerco = pygame.mixer.Sound('pig.wav')

sonidoPuerco.play()
pygame.mixer.music.load('claps.wav') #Musica de fondo
pygame.mixer.music.play(3,0.0) #-1, infinito; 0.0, inicio del rebobinado.

sonidoPuerco.play()
sonidoPuerco.stop()

time.sleep(10)
pygame.mixer.music.stop()