Números Modulares

Se trata más bien de una curiosidad o divertimento matemático, en el mismo espíritu del modulador de números primos: ¿podemos ver patrones en las tablas de multiplicar?

Una forma bastante interesante de representar esta operación es de forma modular, es decir, en la multiplicación 10 × 2:

El primer factor (10) define la cantidad de puntos, es decir el módulo para todo n ∈ ℕ y el segundo constituye la forma para trazar el producto: Si 1 × 2 es 2, una línea unirá el 1 y el 2; 2 × 2 = 4, se unirá el 2 y el 4, etc.

Esta forma modular de representar los productos arroja regularidades muy interesantes. Por ejemplo, si aumento el número del módulo, pero mantengo el multiplicador, es decir de 10 × 2 paso a 1000 × 2 aparece la siguiente figura:

Cardioide, llamado así por su semejanza a un corazón. Esta figura emerge al multiplicar ×2 independiente del módulo (mayor el módulo, mayor resolución de la figura). Al multiplicar por ×3 aparecerá un Nefroide (un riñón).

La figura del cardioide aparece cotidianamente en la taza, cuando la luz del sol se refleja en las caras internas (curvas) y se proyectan sobre la superficie del café.

Un aspecto significativo resulta ser que el módulo constituye también la cantidad de figuras posibles de obtener, ya que comenzarán a repetirse cíclicamente. Es decir, en 9 × n tendré sólo 9 figuras, independiente del n. Como demostración, te invito a comprobarlo tú mismo con esta herramienta.

Entonces, en el ánimo de visualizar los patrones que pueden emerger a partir de estas figuras únicas, las dispuse en una grilla donde horizontalmente voy aumentando el módulo y verticalmente el multiplicador:

Grilla para visualizar las tablas de multiplicar a partir de las figuras únicas. Aparecen patrones en diferentes ángulos diagonales. Acá un PDF en alta resolución.

La primera fila corresponde a la multiplicación por cero, donde todas las líneas se conectan con ese punto1; la segunda fila (×1) corresponde a la identidad, la tercera fila (×2) va revelando el cardioide, la cuarta fila (×3) el nefroide, etc.

La figura describe un triángulo2 porque verticalmente las figuras se repiten en la misma secuencia y orden, tanto positivos como negativos3.

Son interesantes los patrones que se identifican en diversos ángulos de la diagonal, por ejemplo, los que llamo “productos ortogonales”: 2 × 0; 4 × 1; 6 × 2; 8 × 3; 10 × 4 … 2n + 2 × n

¿Viste algo interesante? gracias por tus comentarios

Descarga: Poster (76×75)

Notas
  1. Estas figuras están rotadas en 90 grados respecto al ejemplo inicial, para efectos de ubicar el cero en la parte superior del círculo []
  2. Como los números triangulares []
  3. Obviamente no puedo hacer lo mismo con el módulo, ya que no existe la forma negativa de representarlo []

Pequeños Múltiples

Había una vez una empresa llamada CitiSent, donde una de las primeras ideas que tuvimos para ofrecer servicios de visualización se refería a comprender y comparar la calidad de vida de las distintas ciudades del país1.

Para construir esta visualización desarrollamos un tesauro2 de 6 grandes temas urbanos que generaban un indicador de percepción a partir del análisis de texto (sentiment analysis) en redes sociales. Cada uno de estos indicadores determina el tamaño de un pétalo, debidamente codificado con un color. La idea es que este sistema de representar (y condensar) la imformación permite comparar muy eficientemente las diferencias y contrastes entre los datos (las disparidades). Esta modalidad se denomina pequenos múltiples (small multiples). Esto es similar a las caras de Chernoff.

show code

<br />
CitiPulse model;<br />
Petal current;</p>
<p>color[] c = {<br />
#D63F09,<br />
#FFA94D,<br />
#FAE203,<br />
#8FCB35,<br />
#00828E,<br />
#00426E,<br />
#A64DFF,<br />
#EB12EB,<br />
#AE1D04,<br />
#FF8408,<br />
#DECC02,<br />
#7EB331,<br />
#0F8CA5,<br />
#135589,<br />
#8A27EC,<br />
#CA0DCA,<br />
#870101,<br />
#C46200,<br />
#B8AE01,<br />
#6C9A2E,<br />
#2096C0,<br />
#2D6EAD,<br />
#6C00D7,<br />
#A809A8,<br />
#690808,<br />
#984805,<br />
#929100,<br />
#59802A,<br />
#31A1DA,<br />
#4688D1,<br />
#4C0098,<br />
#860486<br />
};<br />
String file;</p>
<p>float MAX = 120; // radio máximo del pétalo<br />
float offset = 5;<br />
color currentCol = color(255);</p>
<p>void setup() {<br />
int side = 350;<br />
size(350, 350);<br />
smooth();<br />
noStroke();<br />
model = new CitiPulse(width/2, height/2);<br />
populateCitiPulse(model);<br />
current = new Petal();<br />
file = ""+year()+month()+day()+hour()+minute()+".mov";<br />
}</p>
<p>/**<br />
*<br />
* alfa + PI<br />
* beta = ––––------<br />
* 2<br />
*<br />
*<br />
*<br />
* MAX * sin(alfa/2)<br />
* radio = -----------------<br />
* sin(alfa/2) + 1<br />
*<br />
*/</p>
<p>void draw() {<br />
background(255);<br />
noFill();<br />
stroke(#E3E3E3);<br />
strokeWeight(1);<br />
ellipse(width/2, height/2, MAX*2 + offset*2, MAX*2 + offset*2);<br />
model.draw();<br />
}</p>
<p>void keyPressed() {<br />
if (key == 'v') {<br />
for (int i = 0; i &lt; model.petal.length; i++) {<br />
println("petal["+i+"].value = "+model.petal[i].value);<br />
}<br />
println("---------------------------------------------");<br />
}<br />
if (key == ' ') {<br />
populateCitiPulse(model);<br />
}<br />
if (key == 'x') {<br />
exit();<br />
}<br />
if (key == 's') {<br />
saveFrame("img/citipulse-#####.png");<br />
}<br />
}</p>
<p>void mouseMoved() {<br />
currentCol = get(mouseX, mouseY);<br />
}</p>
<p>void mousePressed() {<br />
println(current.name+", cuyo valor es "+current.value);<br />
}</p>
<p>class CitiPulse {</p>
<p>float x, y;<br />
Petal[] petal;</p>
<p>CitiPulse(float x, float y) {<br />
this.x = x;<br />
this.y = y;<br />
}</p>
<p>void draw() {<br />
float offset = 5;<br />
for (int i = 0; i &lt; petal.length; i++) {<br />
pushMatrix();<br />
{<br />
translate(x, y);<br />
rotate(petal[i].alfa * (float)i);<br />
petal[i].be();<br />
}<br />
popMatrix();<br />
}<br />
}<br />
}</p>
<p>void populateCitiPulse(CitiPulse mod) {</p>
<p>int num = round(random(3, 10)); // número de pétalos o términos de primer nivel</p>
<p>float alfa = TWO_PI / (float)num;<br />
float beta = (alfa + PI) / 2;</p>
<p>float radio = (MAX * sin(alfa/2))/(1 + sin(alfa/2));<br />
float ac = MAX - radio;</p>
<p>println(" num = "+num);<br />
println(" alfa = "+alfa+"\t ("+degrees(alfa)+" grados)");<br />
println(" beta = "+beta);<br />
println("radio = "+radio);<br />
float result = radio + ac;<br />
println(" AC = "+ac+"\t radio + AC = "+result);<br />
println("---------------------------------------------");</p>
<p>mod.petal = new Petal[num];</p>
<p>for (int i = 0; i &lt; mod.petal.length; i++) {<br />
mod.petal[i] = new Petal();<br />
mod.petal[i].alfa = alfa;<br />
mod.petal[i].beta = beta;<br />
mod.petal[i].r = radio;<br />
mod.petal[i].ac = ac;<br />
mod.petal[i].x = mod.x;<br />
mod.petal[i].y = mod.y;</p>
<p>// lo único de cada pétalo<br />
mod.petal[i].value = random(.2, 1);<br />
mod.petal[i].name = "Elemento "+i;<br />
mod.petal[i].c = c[i];<br />
}<br />
}</p>
<p>class Petal {<br />
float x, y;<br />
color c, co; // color &amp; color over<br />
float value;<br />
String name;<br />
int seed;</p>
<p>/* los valores a continuación son comunes para todos los pétalos */<br />
float alfa, beta;<br />
float r; // radio<br />
float ac; // distancia desde el centro de la flor al centro del círculo</p>
<p>Petal() {<br />
seed = round(random(99999));<br />
}</p>
<p>Petal(float x, float y, float value, color col, String name) {<br />
this.x = x;<br />
this.y = y;<br />
this.value = value;<br />
this.name = name;<br />
c = col;<br />
}</p>
<p>void be() {<br />
noiseSeed(seed);<br />
value = noise(seed + (float)millis()/6000);</p>
<p>if (over(currentCol)) {<br />
current = this;<br />
co = color(red(c)-25, green(c)-25, blue(c)-25);<br />
draw(0, 0, r + offset, co);<br />
}</p>
<p>draw(offset, 0, r, c);</p>
<p>}</p>
<p>boolean over(color col) {<br />
if (c == col) {<br />
return true;<br />
}<br />
else {<br />
return false;<br />
}<br />
}</p>
<p>void draw(float ox, float oy, float radio, color col) {<br />
fill(col);<br />
noStroke();<br />
pushMatrix();<br />
{<br />
translate(ox, oy);<br />
beginShape();<br />
vertex(0, 0);</p>
<p>for (float t = -beta; t &lt;= beta; t+=.1) {</p>
<p>float xpos = value*cos(t)*radio;<br />
float ypos = value*sin(t)*radio;</p>
<p>vertex(ac*value + abs(r-radio) + xpos, ypos);<br />
}<br />
endShape(CLOSE);<br />
}<br />
popMatrix();<br />
}<br />
}</p>
<p>

Este ejemplo de la unidad de visualización puede ser regenerado al presionar ESPACIO, pero es preciso ganar foco sobre el elemento haciendo click sobre él

Notas
  1. a este servicio lo llamamos CitiPulse []
  2. Un tesaurio es un diccionario jerárquico de palabras. En el caso de Citipulse definimos 6 grandes categorías: Medioambiente, Movilidad, Entorno Urbano, Sociabilidad, Gobernanza y Economía Local y Oportunidades. Cada una de ella dividias, a su vez, en otras sub-categorías, hasta completar un vocabulario de alrededor de 500 palabras. []

Civilscope

Civilscope Logo

La idea de este proyecto es mostrar de manera fácil y ní­tida las capas y fronteras cí­vicas en las cuales estamos inmersos. Civilscope es un servicio web que, a partir de una dirección determinada, mapea todas las divisiones, distritos y circunscripciones que la rigen. Este servicio funciona solamente para la gente de Chicago porque opera sobre la API de Civic Footprint, una iniciativa del Center for Neighborhood Technology de Chicago.

Pienso que tener algo así­ en Chile serí­a buení­simo para poder transparentar en algo las oscuras y arcanas fronteras polí­ticas que nos gobiernan. En parte por eso me entusiasmé cuando Simon me propuso la idea; para poderlo mostrar como ejemplo y poder desarrollar algo así­ para nosotros. De hecho, nuestra estructura es bastante más sencilla, con menos capas y jerarquí­as traslapadas.

Particularmente en Chicago existen distritos verdaderamente extraí±os en cuanto figura. Esto se debe a una práctica de distritage llamada “gerrymandering”. En el sistema norteamericano los votantes son divididos por distritos. Lo que cuenta al final no es la cantidad total de votos sino la cantidad de distritos en los que tal o cual candidato ha ganado. Esto lleva a practicar estrategias de “pack & crack”, es decir, agrupar a la oposición y concentrarla lo más posible en un distrito para que arrase, pero para que pierda por poco en todas las demás. Esta práctica de redibujar los distritos ocurre cada vez que hay alternancia en el poder, para perjudicar a la opsición. Cada dí­a esta operación se vuelve más sofisticada ya que se ocupan programas computacionales para redibujar los distritos basados en los registros de votantes. Es por eso que herramientas como esta permiten transparentar en algo estas prácticas.

http://www.civilscope.org/