Atracción entre los quarks

De las 3 partículas que constituyen la materia observables (protones, neutrones y electrones), al menos dos no son elementales. Desde los años 70 se conoce que tanto los neutrones como los protones están compuestos por tres quarks pero nunca se ha podido observar un quark libre.

Para explicar esto, se le asigna a cada quark llevaba una carga conocida como “color” (obviamente no tiene nada que ver con el concepto normal de color) tomando los valores rojo, verde o azul en los quarks y antirrojo, antiverde y antiazul en los antiquarks. Se postula un fenómeno denominado como confinamiento que solo permite observar libres a combinaciones “incoloras”, tales como rojo-verde-azul, rojo-antirrojo, etc. Las combinaciones de 3 quarks son denominadas bariones (siendo los protones los únicos bariones estables en estado libre) y las combinaciones quark-antiquark (todas inestables en estado libre) son denominadas mesones (piones, kaones, etc.).

Si bien no se ha conseguido hasta el momento una explicación completa del fenómeno del confinamiento, uno de los factores claves parece ser el hecho de que la atracción entre los quarks no disminuye con la distancia y tiene un valor grande incluso desde el punto de vista macroscópico: ~16 toneladas (!).

Cantidad de ceros al final de un factorial

Un número n (bah, estrictamente el numeral asociado al número n pero vamos a ignorar esa distinción…) termina en k ceros si y solo si puede escribirse como

n = m \cdot 10^k

siendo m un entero no divisible por 10. Un entero es divisible por 10 si y solo si es divisible por 2 y por 5 por lo que, si 5 o 2 no aparecen como factores primos de m, sabremos que n termina con k ceros.

Suponiendo que la descomposición en factores primos de n toma la forma

n = 2^a3^b5^c7^d...

podemos ver que k será min(a, c), ya que de ese modo quedarán o bien 2s o bien 5s como factores primos de m. Esto nos permite reducir la determinación de la cantidad de ceros al final de n! a averiguar la multiplicidad de 2 y de 5 como factores primos de n!.

Como el factorial de n no es más que el producto de los números desde 1 hasta n y los múltiplos de un factor primo k están separados por un intervalo k, sabemos que habrá \lfloor n/k \rfloor múltiplos de k dentro de n!. Esto podría llevarnos a pensar que la multiplicidad de k en n! será \lfloor n/k \rfloor, pero esto omitiría la contribución extra realizada por los múltiplos de las potencias de k.

Teniendo esto en cuenta, la multiplicidad de k como factor primo de n! estará dada por

\displaystyle \sum_{i=0}^\infty \left\lfloor \frac{n}{k^i} \right\rfloor,

una suma que siempre converge ya que consta de una cantidad finita de términos.

Puede verse que la cantidad de factores 2 será siempre mayor o igual que la de factores 5 (la suma es mayor o igual término a término), por lo que alcanzará con calcular la cantidad de factores 5 en n! para conocer la cantidad de ceros al final:

\text{cantidad de ceros al final de } \displaystyle n! = \sum_{i=0}^\infty \left\lfloor \frac{n}{5^i} \right\rfloor.

Escribiendolo como una función en Python:

def fact_num_zeros(n):
    if n > 0:
        return n // 5 + fact_num_zeros(n // 5)
    else:
        return 0

Hacemos un par de funciones adicionales para revisar los resultados:

def factorial(n):
    acum = 1
    for i in range(1,n+1):
        acum *= i
    return acum

def num_zeros_at_end(a):
    num_zeros = 0
    while True:
        a, m = divmod(a, 10)
        if m != 0:
            break
        num_zeros += 1
    return num_zeros

Probando con 10000!:

>>> num_zeros_at_end(factorial(10**4))
2499
>>> fact_num_zeros(10**4)
2499

Coincide internamente y con el resultado de Demian… Ahora con 1016!:

>>> fact_num_zeros(10**16)
2499999999999996L

Como puede observarse, la cantidad es “algo” mayor que 1000, por lo que la respuesta dada por Demian era correcta 😀

Encuadrando imágenes con PIL

(Continuación de Agregando texto a imágenes con PIL.)

Otra tarea que puede realizarse fácilmente con PIL es cambiarle el tamaño a imágenes agregando un fondo de color. Utilizando la componente alfa puede lograrse incluso agregar segmentos transparentes.

Una función que hice con este objetivo es:

import Image

def resize_with_background(im, src_rect, offset,
                           dest_size, bg_color):
    src_im_sec = im.crop(src_rect)
    new_im = Image.new('RGBA', dest_size, bg_color)
    new_im.paste(src_im_sec, (src_rect[0] + offset[0],
                              src_rect[1] + offset[1]))
    return new_im

Lo único que hace esta función es tomar la región delimitada por src_rect en la imagen original im, crear una nueva imagen de dimensiones dest_size rellena con el color bg_color (expresado como una tupla con sus componentes RGBA) y, por último, pegar la región tomada en la nueva imagen desplazándola por offset.

Como ejemplo, si tomamos como entrada a la imagen obtenida como salida en el post anterior

Esta imagen, correspondiendo a 'banner_start.png' en el ejemplo, consiste es un banner de tamaño 500 x 150.

Esta imagen, correspondiendo a 'banner_start.png' en el ejemplo, consiste es un banner de tamaño 500 x 150.

y deseamos recortarle 50 píxeles a la derecha, agregarle un rectángulo de 100 x 150 píxeles verdes a la derecha y agregarle una franja de 50 píxeles transparentes abajo, podemos hacerlo con solo dos llamadas a la función descrita anteriormente:

im = Image.open('banner_start.png')
im = resize_with_background(im, (0, 0, 450, 150),
                            (0, 0), (550, 150),
                            (0, 255, 0, 255))
im = resize_with_background(im, (0, 0, 550, 150),
                            (0, 0), (550, 200),
                            (0, 0, 0, 0))
im.save('banner_end.png')

La primera llamada se encargará de recortar a la imagen agregando el cuadrado verde y la segunda de incorporar la franja transparente. El resultado final será el dado por esta imagen:

Esta imagen corresponde a 'banner_end.png' en el ejemplo y muestra la incorporación del rectángulo verde y la franja transparente, dejando una imagen de 550 x 200.

Esta imagen corresponde a 'banner_end.png' en el ejemplo y muestra la incorporación del rectángulo verde y la franja transparente, dejando una imagen de 550 x 200.

Promedios y más sobre los baldes

(Continuación de Dos baldes)
(Continuación de Promedios)

El problema de los promedios es bastante simple y alcanza con ver un simple ejemplo aplicado a 2 años:

Notas del alumno A en el 1er año: 9 9 9 9
Notas del alumno B en 1er año: 10 10
Notas del alumno A en el 2do año: 4 4
Nota del alumno B en el 2do año: 5 5 5 5

Los promedios anuales son obvios y el promedio general será 7.33 para A y 6.66 para B.

Un aspecto interesante de la solución del problema de los dos baldes que no mencioné anteriormente es que parte de las condiciones son superfluas:

Se tienen dos baldes, que podemos llamar A y B, conteniendo la misma cantidad de arena. En el caso del balde A es arena blanca, mientras que en el balde B es arena negra. Se lleva una cucharita llena de arena del balde A y se la mezcla con la arena del balde B; seguidamente se toma una cucharita llena de arena del balde B y se incorpora al contenido del balde A.

Al finalizar este proceso, ¿cuál de los baldes tiene más arena proveniente del otro?

Si nos interesa la cantidad absoluta de “impurezas”, no es necesario hacer ninguna de las suposiciones resaltadas arriba en el enunciado ya que la cantidad de arena negra en el balde A será siempre 1 cucharita menos la cantidad de arena blanca que se transportó de B hacia A. Como hay, antes del 2do movimiento, una cucharita de arena blanca en B, siempre terminarán siendo iguales las cantidades de “impurezas” en A y B.

Promedios

(Este otro problema robado a Terry Tao.)
(El problema anterior de los dos baldes.)

Supongamos que tenemos dos alumnos (por ejemplo de la FIUBA 😀 ) llamados A y B. Ambos empezaron juntos la carrera en el año 2003 y terminaron en el año 2009. Sabemos que en cada uno de los años que cursaron A tuvo un mejor promedio anual que B pero, al calcular el promedio general de la carrera, B resulta tener un mejor promedio general que A. Cómo es esto posible?

Nota: tener en cuenta que no necesariamente cursaron la misma cantidad de materias en cada uno de esos años.

Dos baldes (solución)

(Continuación de Dos baldes)

A primera vista casi todos pensamos que el balde B será el que quede con más “impurezas”, ya que recibe una cucharada de arena blanca pura mientras que A recibe una cucharada de arena negra mezclada con algo de arena blanca. Sin embargo, esta transferencia de arena blanca también tenderá a disminuir la cantidad de impurezas en B, con lo que no queda inmediatamente claro el signo del efecto.

Cuánto es la diferencia? Bueno, como la cucharada transferida en el segundo movimiento estará compuesta por arena blanca y negra, es claro que la disminución en la cantidad de arena negra transferida respecto a la cucharada entera será igual a la cantidad de arena blanca extraída del balde B. Como el balde B tiene en total una sola cucharada de arena blanca, la cantidad de arena negra transferida en el segundo movimiento será igual a la de arena blanca remanente en el balde B. Por lo tanto, las cantidades de impurezas serán iguales.

Una forma más simple de resolverlo (que es la que utilicé originalmente) es limitarse a hacer la cuentas (o sea, hacer que los símbolos piensen por nosotros :-D).

Si suponemos que cada balde tiene N cucharitas de arena, después del primer movimiento el balde A tendrá N-1 cucharitas de arena blanca y el balde B tendrá N cucharitas de arena negra y una cucharita de arena blanca. Como se postula que la mezcla es homogénea, el segundo movimiento llevará 1/(N+1) cucharitas de arena blanca y N/(N+1) cucharitas de arena negra al balde blanco.

En resumen, al final tendremos N/(N+1) cucharitas de arena negra en el balde A y 1 – 1/(N+1) cucharitas de arena blanca en B, o sea exactamente la misma cantidad.

Dos baldes

Un problema de mezclas (via Terry Tao):

Se tienen dos baldes, que podemos llamar A y B, conteniendo la misma cantidad de arena. En el caso del balde A es arena blanca, mientras que en el balde B es arena negra. Se lleva una cucharita llena de arena del balde A y se la mezcla con la arena del balde B; seguidamente se toma una cucharita llena de arena del balde B y se incorpora al contenido del balde A.

Al finalizar este proceso, ¿cuál de los baldes tiene más arena proveniente del otro?

Agregando texto a imágenes con PIL

Este es un post netamente técnico (o sea aburrido :-D).

En ocasiones puede ser útil agregar texto a una serie de imágenes en forma automatizada, evitando el tedioso proceso de agregarlo a mano (y el aún más tedioso de agregarlo de vuelta cuando descubrimos que nos equivocamos). Sabía (a través de John Walker) que pueden utilizarse para este fin las herramientas para línea de comandos Netpbm pero, si estamos trabajando en un script, estas herramientas pueden ser algo inflexibles e incómodas de llamar.

Mientras armaba uno de los posts anteriores descubrí a PIL (Python Imaging Library) que permite realizar estas operaciones en forma relativamente natural desde Python. Por ejemplo, dibujar texto centrado en un rectángulo puede hacerse mediante la siguiente función:

import ImageFont

def draw_centered_text(im_draw, text, r, font_name, color):
    font = ImageFont.truetype(font_name + '.ttf',
                              r[3] - r[1])
    text_size = font.getsize(text)
    if text_size[0] > r[2] - r[0]:
        new_font_height = (r[3] - r[1]) * (r[2] - r[0]) /\
                          text_size[0]
        font = ImageFont.truetype(font_name + '.ttf',
                                  new_font_height)
        text_size = font.getsize(text)
    im_draw.text(((r[2] + r[0]) / 2 - text_size[0] / 2,
                  (r[3] + r[1]) / 2 - text_size[1] / 2),
                 text, font=font, fill=color)

donde im_draw es un objeto del tipo ImageDraw, representando a la imagen sobre la que trabajamos, text es el texto a dibujar, r es una tupla de 4 puntos representando al rectángulo donde irá encerrado el texto (izquierda, arriba, derecha, abajo), font_name es el nombre del archivo TTF con la fuente a utilizar y color es un tupla representando el color del texto a dibujar (RGB).

Un ejemplo de llamada a la función anterior sería:

import Image, ImageDraw

im = Image.open('banner_start.png')
draw = ImageDraw.Draw(im)
draw_centered_text(draw, 'Text', (0, 0, 150, 150),
                   'arial', (0, 0, 0))
draw_centered_text(draw, 'Text', (250, 50, 500, 100),
                   'arial', (255, 0, 0))
im.save('banner_end.png')

Si tomamos a la siguiente imagen como entrada:

Esta imagen, correspondiendo a 'banner_start.png' en el ejemplo, consiste en un cuadrado amarillo en (0, 0) - (150, 150) y un rectángulo celeste en (250, 50) - (500, 100).

Esta imagen, correspondiendo a 'banner_start.png' en el ejemplo, consiste en un cuadrado amarillo en (0, 0) - (150, 150) y un rectángulo celeste en (250, 50) - (500, 100).

obtendremos a la siguiente imagen como salida:

Esta imagen corresponde a 'banner_end.png' en el ejemplo y muestra como el texto se expande lo máximo posible sin perder su relación de aspecto.

Esta imagen corresponde a 'banner_end.png' en el ejemplo y muestra como el texto se expande lo máximo posible sin perder su relación de aspecto.

Espero que pueda serle útil a alguno de los lectores 😉