miércoles, 21 de noviembre de 2012

Una humilde imitación y un poco de programación



Desde hace unas semanas circula por la red un atractivo vídeo en el que se visualiza la factorización de los números como conjuntos de puntos en forma de árboles poligonales circulares muy cercanos a los conjuntos fractales.

http://miscuriosidadesmatematicas.blogspot.com.es/2012/11/diagrama-animado-sobre-factorizacion-de.html

http://www.datapointed.net/visualizations/math/factorization/animated-diagrams/

http://mathlesstraveled.com/2012/10/05/factorization-diagrams/


En la imagen se puede ver el desarrollo para el número 18, en el que los niveles están definidos por los factores 3, 3 y 2.


Como en este blog no nos salimos de los números y de la hoja de cálculo nos planteamos un reto:

¿Hasta dónde podíamos imitar estos esquemas usando tan sólo la programación de una hoja de cálculo?

Es evidente que el resultado obtenido ha de ser muy inferior al original, y que el interés de esta tarea está en la adaptación a una herramienta menos potente. Por tanto, quien no esté interesado en esta programación es mejor que disfrute del vídeo original sin embarcarse en el proceso que aquí hemos seguido.

El resultado lo tienes en http://hojamat.es/blog/arbofactor.xlsm


Ideas previas

Para imitar lejanamente el vídeo necesitaremos concretar aspectos del problema en sí mismo (representar cada factor como un polígono) y después superar las carencias de la hoja de cálculo (en esta ocasión, dado el distinto comportamiento de las mismas en los gráficos, lo hemos desarrollado sólo en Excel)

El gráfico

La única posibilidad que nos ofrece Excel para estas representaciones es el gráfico de dispersión. Tiene la ventaja de no depender del orden de los datos y adaptarse muy bien al uso de coordenadas cartesianas (X,Y). También permite dejar la zona en blanco y ocultar los ejes. Por contra, presenta gran dificultad en cambiar el tamaño de los distintos puntos según el número de factores. Todos los esquemas, pues, presentarán el mismo tamaño en los puntos



Aquí puedes ver el esquema para 1050. Se puede observar que los últimos triángulos de puntos parecen confundirse, por no haber controlado el tamaño.

Salvo este inconveniente, las figuras resultan atractivas. Las hemos  orientado circularmente en lugar de buscar siempre la vertical. En la siguiente imagen puedes observar la estructura casi fractal que presentan los números que como el 486 contienen potencias altas de primos.



Lo único que hay que explicar del gráfico es que su área de datos está formada por las columnas B y C en las que volcaremos las coordenadas adecuadas.

El algoritmo

Sacar los primos

Necesitamos, en primer lugar, la lista de factores primos del número, con repetición y en orden decreciente. Hemos aludido bastante en este blog a estas técnicas, por lo que a nuestros seguidores les resultará familiar. Normalmente se comienzan a buscar los factores pequeños, pero en este trabajo, por razones estéticas, se comienza por los mayores. Por eso al final de la rutina se invierte el orden.

Sub sacaprimos(n)
Dim f, a, indi

a = n
f = 2: nprimos = 0
indi = 0

While f * f <= a
While a / f = Int(a / f)
  indi = indi + 1
 ff(indi) = f  ‘La variable ff va recogiendo los primos
a = a / f
Wend

If f = 2 Then f = 3 Else f = f + 2
Wend
If a > 1 Then  ‘Último factor
indi = indi + 1
ff(indi) = a
End If

' se ordenan al revés

nprimos = indi
For indi = 1 To nprimos
xx(indi) = ff(nprimos - indi + 1)
Next indi
For indi = 1 To nprimos
ff(indi) = xx(indi)
Next indi

End Sub

Después de esta rutina tendremos el número de factores primos en la variable nprimos y sus valores en ff(i). En este caso no nos interesan los exponentes.

Recorrido en cada factor

Una vez obtenidos los factores primos necesitamos convertirlos en polígonos. Para cada uno harán falta las coordenadas del centro (xx(i),yy(i)), su radio rr(i) y un contador de puntos ii(i) que nos evite el problema de los decimales al final de cada polígono. En cada paso incrementaremos el ángulo de giro necesario para que se forme el polígono y el contador de lados



En la imagen hemos comenzado con ff(1)=13, por lo que los elementos se incrementarán así:

 ii(i) = ii(i) + 1
aa(i) = aa(i) + dospi / 13

Marcado el ángulo que va girando el punto pasamos de coordenadas polares a cartesianas y volcamos el punto en la columnas B y C, donde lo capturará el gráfico y aparecerá un punto nuevo.

    fila = fila + 1
    px = xx(i) + rr(i) * Cos(aa(i))
    py = yy(i) + rr(i) * Sin(aa(i))
    ActiveWorkbook.Sheets(1).Cells(fila, 2).Value = px
    ActiveWorkbook.Sheets(1).Cells(fila, 3).Value = py

Esto se repite tantas veces como indique el factor y se formará el polígono básico


Algoritmo de cambio de nivel 

Aquí reside el nudo de esta programación. Es un caso claro de procedimiento recursivo, pero como hay que gestionar bastantes parámetros lo hemos dejado para una posible extensión y se ha usado en su lugar un esquema muy sencillo que ya se ha publicado en este blog: la subida y bajada de nivel.

Procedimientos iniciales: definir primer radio, sacar los primos…

Mientras haya un nivel activo  (nivel>0)

Incrementamos el ángulo y el contador para avanzar en el polígono

Si se llega al final del polígono 
Hemos terminado y bajamos de nivel (nivel=nivel-1)

En caso contrario pueden ocurrir dos cosas:

Si hemos llegado al último factor hay que imprimir el punto volcándolo en las columnas B y C

Si no hemos llegado hay que subir de nivel(nivel=nivel+1)
Esto significa que hay que determinar nuevos centro y radio

Fin del Mientras
Fin de la rutina

No incluimos el código y preferimos que las personas interesadas lo estudien en el archivo de Excel.

Animación

Para conseguir la animación basta con una estructura repetitiva tipo FOR-NEXT y la creación de pausas para conseguir el efecto de transición continua. El problema radica en que cualquier operación aparentemente sencilla puede borrar el gráfico y perderse su persistencia en nuestra retina. Hemos tenido que acudir al recálculo para refrescarlo y que no desaparezca.

La pausa se consigue leyendo el reloj e introduciendo a la hoja en un bucle continuo hasta que transcurra la pausa. Queda así:

Call arbol  ‘se construye el árbol de factores
t1 = Timer ‘ leemos el reloj y tomamos nota en t1 y t2
t2 = t1
While t2 - t1 < pausa: t2 = Timer: Calculate: Wend  ‘bucle continuo de recálculo
Call borrar ’terminada la pausa se borra el gráfico

Controles

Nos gusta tener todo el poder posible sobre la hoja de cálculo. Por eso se han añadido los controles de Reducción, que se puede cambiar (no en la animación) para mejorar la estética del gráfico y Pausa, que ralentiza o acelera la animación.


A quienes hayan llegado hasta aquí les recomendamos el estudio de los detalles del código y les invitamos a intentar mejorarlo.






No hay comentarios: