Mostrando entradas con la etiqueta wxMaxima. Mostrar todas las entradas
Mostrando entradas con la etiqueta wxMaxima. Mostrar todas las entradas

lunes, 13 de julio de 2026

Vértice de un n-paralelepípedo más cercano a un punto. Algoritmo de Babai.

 En una entrada anterior planteé el siguiente problema:

 Sea $\mathcal{F}$ un n-paralelepípedo (sólido) generado por el conjunto de vectores linealmente independientes $B = \{\vec{b}_1,...,\vec{b}_n\}$. Sea $P\in\mathcal{F}$ un punto de dicho n-paralelepípedo. ¿Cuál es el vértice del n-paralelepípedo más cercano a $P$?

Expliqué y ejemplifiqué una posible estrategia consistente en el método exhaustivo, es decir, comprobar todos los posibles vértices. Concluí la entrada con la observación de que el número de vértices crece de manera exponencial con la dimensión y esto supone un problema de coste computacional en dimensiones grandes.

En esta entrada vamos a trabajar otra posible estrategia, basada en el algoritmo de Babai, desarrollado por el matemático húngaro László Babai.

El fundamento detrás del procedimiento es relativamente sencillo.

Si $P\in\mathcal{F}$ entonces $P$ se puede escribir como combinación lineal de la base $B$:

$$P = \sum_{i=1}^{n}{a_i·\vec{b}_i}$$

Lo que hacemos es redondear al entero los coeficientes $0 \leq a_i \leq 1$ de la combinación lineal:

$$z_i = redondear(a_i)$$

Entonces, el vértice del n-paralelepípedo más próximo a $P$ viene dado por:

$$V = \sum_{i=1}^{n}{z_i·\vec{b}_i}$$

 

Ejemplo: Hagamos este método con el mismo ejemplo que utilizamos en el método exhaustivo, en $\mathbb{R}^2$.

$B=\{(30, 3), (5, 0)\}$ y el punto del paralelogramo $Q=(25.5, 2.5)$. Queremos hallar el vértice del paralelogramo más cercano a $Q$.

 Primero calcularemos la combinación lineal de la base $B$ que da el punto $Q$:

$$\vec{a} = B^{-1} · \overrightarrow{OQ} =\begin{pmatrix}30 & 5\\3 & 0\end{pmatrix}^{-1} · \begin{pmatrix}25.5 \\ 2.5\end{pmatrix} \simeq \begin{pmatrix}0.8333333333333333 \\ 0.10000000000000053\end{pmatrix}$$

Ahora redondeamos los coeficientes obtenidos:

$$\vec{z} = \begin{pmatrix}1 \\ 0\end{pmatrix}$$

Y calculamos a qué vértice corresponde dicha combinación lineal:

$$\overrightarrow{OV} = B · \vec{z} = \begin{pmatrix}30 & 5\\3 & 0\end{pmatrix} · \begin{pmatrix}1 \\ 0\end{pmatrix} = \begin{pmatrix}30 \\ 3\end{pmatrix}$$

Es decir, el vértice más cercano al punto $Q$ es (30, 3). (Coincide con el obtenido por el método exhaustivo)

Los cálculos del ejemplo han sido realizados con wxMaxima:

 

Desde un punto de vista geométrico e informal podríamos decir que el procedimiento anterior es equivalente a dividir con "hiperplanos medianeros" el n-paralelepípedo y seleccionar el vértice del "trozo" en el que queda el punto.

 

 El algoritmo de Babai rebaja considerablemente el coste computacional, dado que no necesita recorrer todos los vértices del n-paralelepípedo y se basa en operaciones bastante rápidas desde el punto de vista del cálculo computacional.

Sin embargo, el algoritmo de Babai presenta un gran problema: solo en determinadas condiciones la solución que devuelve es la correcta.

Veamos esto con un ejemplo. Seguimos utilizando la misma base que en el ejemplo anterior, pero cambiamos el punto a "aproximar" (encontrar el vértice más cercano) por $R=(30, 2.7)$.

Los cálculos del algoritmo devuelven el vértice $(35, 3)$ como el más cercano al punto $R$.

 

Sin embargo, esto no es cierto. El vértice más cercano es claramente el $(30, 3)$. 

 

Puede observarse en la representación gráfica que, tras trazar las medianas, el punto cae en el "trozo" del vértice $(35, 3)$ y por eso es la respuesta que devuelve el algoritmo de Babai. Pero no es el vértice más cercano.

Llegados a este punto lo razonable es descartar por completo este algoritmo porque ni tan siquiera devuelve la solución correcta.

Sin embargo, el algoritmo sí funciona con fiabilidad cuando la base es ortogonal (o "cerca" de ser ortogonal).

¿Y esto tiene alguna utilidad práctica? Habrá que esperar a las siguientes entradas para averiguarlo. 

domingo, 12 de julio de 2026

Vértice de un n-paralelepípedo más cercano a un punto. Método exhaustivo.

 

Sea $\mathcal{F}$ un n-paralelepípedo (sólido) generado por el conjunto de vectores linealmente independientes $B = \{\vec{b}_1,...,\vec{b}_n\}$. Sea $P\in\mathcal{F}$ un punto de dicho n-paralelepípedo. ¿Cuál es el vértice del n-paralelepípedo más cercano a $P$?

 Estrategia 1. Método exhaustivo.

Podemos calcular las coordenadas de todos los vértices del n-paralelepípedo.

Por ejemplo, en $\mathbb{R}^3$, los 8 vértices del paralelepípedo son:

$V_1 = \vec{0} = (0,0,0)$

$V_2 = \vec{b}_1$

$V_3 = \vec{b}_2$

$V_4 = \vec{b}_3$

$V_5 = \vec{b}_1 + \vec{b}_2$

$V_6 = \vec{b}_1 + \vec{b}_3$

$V_7 = \vec{b}_2 + \vec{b}_3$

$V_8 = \vec{b}_1 + \vec{b}_2 + \vec{b}_3$ 

Después calculamos la distancia de cada uno de ellos al punto $P$

$$d_i = \|P-V_i\|$$ 

 Y nos quedamos con el que tenga menor distancia (puede haber más de uno).

 

Ejemplo: Hagamos este método con un caso muy sencillo en $\mathbb{R}^2$.

$B=\{(30, 3), (5, 0)\}$ y el punto del paralelogramo $Q=(25.5, 2.5)$. Queremos hallar el vértice del paralelogramo más cercano a $Q$.

Los vértices del paralelogramo son:

$V_1=(0, 0); V_2=(30, 3); V_3=(5, 0); V_4=(35, 3)$

Y las correspondientes distancias al punto $Q$:

$d_1 \simeq 25.622255950637914$

$d_2 \simeq 4.527692569068709$

$d_3 \simeq 20.65187642806338$

$d_4 \simeq 9.513148795220223$ 

Por tanto, el vértice con menor distancia al punto $Q$ es $V_2=(30, 3)$.

 

Los cálculos han sido realizados con wxMaxima:

 

Contras del método exhaustivo.

Para dimensiones pequeñas el método exhaustivo es rápido y muy eficiente, pero para dimensiones grandes el coste computacional se incrementa exponencialmente, dado que el número de vértices de un n-paralelogramo es $2^n$.

Por ejemplo, en $\mathbb{R}^{100}$ tenemos $2^{100} = 1267650600228229401496703205376$ vértices.

domingo, 28 de junio de 2026

Bases que generan el mismo retículo

En la teoría de retículos sobre $\mathbb{R}^n$ hay un resultado muy interesante que es el siguiente: 

Sean $\varLambda(B)$ y $\varLambda(C)$ dos retículos completos sobre $\mathbb{R}^n$ generados por las bases $B$ y $C$ respectivamente.

$\varLambda(B) = \varLambda(C) \Longleftrightarrow \exists U \in M_{nxn}(\mathbb{Z}) \mid U$ es invertible y $B = C · U$ 

Voy a destacar dos aplicaciones del resultado anterior.

APLICACIÓN 1. Si conocemos las bases de 2 retículos completos, podemos saber si generan el mismo retículo. Como $C$ es invertible en $M(\mathbb{R})$ (por ser base):

$$B = C · U \Leftrightarrow C^{-1} · B = C^{-1} · C · U \Leftrightarrow C^{-1} · B = I · U \Leftrightarrow C^{-1} · B = U$$ 

Por tanto, si $C^{-1} · B \in M(\mathbb{Z})$ (todos sus elementos son enteros) y es invertible en $M(\mathbb{Z})$ (su determinante es 1 o -1), entonces $B$ y $C$ generan el mismo retículo.
 
Ejemplo: 
En la entrada anterior utilizamos la siguiente base $B = \pmatrix{5 && 5 \\ 3 && 0}$ de un retículo completo sobre $\mathbb{R}^2$.
 
Y acabé afirmando que era exactamente el mismo retículo que generaría el conjunto $C = \pmatrix{0 && 5 \\ 3 && 0}$ o el conjunto $D = \pmatrix{-5 && 0 \\ 3 && -3}$.

Vamos a realizar la comprobación con $D$. Es decir, queremos llegar a la conclusión de que $B$ y $D$ generan el mismo retículo.
 
Calculamos
$D^{-1} · B = \pmatrix{-5 && 0 \\ 3 && -3}^{-1} · \pmatrix{5 && 5 \\ 3 && 0} = \pmatrix{-1 && -1 \\ -2 && -1}$
 
Ahora calculamos su determinante:
$|D^{-1} · B| = \begin{vmatrix}-1 && -1 \\ -2 && -1\end{vmatrix} = -1$
 
Así pues, hemos visto que todos sus elementos son enteros y que el resultado del determinante es -1. Por tanto, podemos afirmar que $B$ y $D$ generan el mismo retículo.
 
Nota: las operaciones anteriores las he realizado con wxMaxima.
 
 APLICACIÓN 2. Si tenemos una base $B$ de un retículo completo $\varLambda(B)$, podemos construir otra base $C$ que genera el mismo retículo multiplicando $B$ por una matriz $U \in M_{nxn}(\mathbb{Z})$ con determinante 1 o -1.
 
Ejemplo: 

 Utilizamos el retículo completo del ejemplo anterior, generado por $C = \pmatrix{0 && 5 \\ 3 && 0}$.

Ahora creamos una matriz aleatoria con elementos enteros y cuyo determinante sea 1 o -1.

$U = \begin{pmatrix}2283 & -118\\1838 & -95\end{pmatrix}$; $|U| = -1$ 

Y multiplicamos la base original por esta matriz.

$C · U = \pmatrix{0 && 5 \\ 3 && 0} · \begin{pmatrix}2283 & -118\\1838 & -95\end{pmatrix} = \begin{pmatrix}9190 & -475\\6849 & -354\end{pmatrix}$

El resultado es otra base que genera el mismo retículo.

Cálculos con wxMaxima:

 

 ¿Qué utilidad puede tener generar otra base de esta manera? Esto lo trataré en otra entrada de esta serie sobre retículos.

sábado, 21 de febrero de 2026

Introducción a la criptografía (ESTALMAT-IB 17-18)

Rescato la presentación que utilicé en el curso 2017-2018 en una de las sesiones del programa de Estímulo del Talento Matemático (ESTALMAT) de les Illes Balears, dirigido a alumnado de 12-13 años.

En esta sesión hice una pequeña introducción a la Criptografía. Realizaron la actividad típica y sencilla del cálculo de la letra del DNI para pasar a mostrar el funcionamiento del algoritmo RSA con números pequeños y realizando los cálculos con wxMaxima.

Ver documento en Academia.edu

Tan importante como poco reconocida y recompensada la labor de divulgación científica con contextos cercanos.

martes, 12 de agosto de 2025

Polinomios de Laguerre con wxMaxima y Python

Los polinomios de Laguerre son unos polinomios conocidos principalmente (aunque no únicamente) por ser soluciones de la ecuación diferencial

x · y'' + (1 - x) · y' + n · y = 0 

Su nombre se debe al matemático francés Edmond Nicolas Laguerre, quien publicó muchos artículos, principalmente en las áreas de geometría y análisis.


 Una de las formas de calcular los polinomios de Laguerre viene dada por la siguiente expresión:

 

 También se pueden calcular de manera recursiva:

 ;   ;  

En wxMaxima podemos calcular muy fácilmente los polinomios de Laguerre utilizando la función laguerre().

Ejemplo de cálculo de los primeros 5 polinomios de Laguerre:


 En Python también existen maneras de calcular los polinomios de Laguerre, utilizando funciones de las librerías NumPy, SciPy o SymPy.

A modo de ejemplo, el siguiente código calcula y representa gráficamente los primeros polinomios de Laguerre:

# Cálculo y representación gráfica de los polinomios de Laguerre
# Félix Rodríguez Díaz
# 25 de agosto de 2025

import matplotlib.pyplot as plt
from scipy.special import laguerre as laguerre_sci
from numpy import arange
from numpy.polynomial.laguerre import lag2poly
from numpy.polynomial import Polynomial
from sympy.functions.special.polynomials import laguerre as laguerre_sym
from sympy import symbols, Poly

# Definimos la variable n_polinomios con la cantidad de polinomios que
# queremos calcular (desde grado 0 hasta grado n_polinomios-1)
n_polinomios = 5

# Calculamos los polinomios de Laguerre con SciPy
laguerre_scipy = [laguerre_sci(z) for z in range(n_polinomios)]
# Los mostramos por pantalla
print("Polinomios de Laguerre calculados con SciPy")
for lag_s in laguerre_scipy:
    print(lag_s)

# Calculamos los polinomios de Laguerre con NumPy
# Dado que lag2poly devuelve los coeficientes utilizamos Polynomial
# para crear el correspondiente polinomio
laguerre_numpy = [Polynomial(lag2poly([0] * i + [1])) for i in range(n_polinomios)]
# Los mostramos por pantalla
print("\nPolinomios de Laguerre calculados con NumPy")
for lag_n in laguerre_numpy:
    print(lag_n)
    
# Calculamos los polinomios de Laguerre con SymPy
x_sym = symbols("x")
laguerre_sympy = [laguerre_sym(z, x_sym) for z in range(n_polinomios)]
# Los mostramos por pantalla
print("\nPolinomios de Laguerre calculados con SymPy")
for lag_sym in laguerre_sympy:
    print(lag_sym)
# Si queremos representar gráficamente los polinomios de SymPy con pyplot debemos
# convertir las expresiones simbólicas a expresiones que reconozca numpy
laguerre_sympy_numpy = []
for lag_expr in laguerre_sympy:
    # Obtener coeficientes (del término de mayor grado al menor)
    coeffs = Poly(lag_expr, x_sym).all_coeffs()
    # Convertir a float
    coeffs_float = [float(c) for c in coeffs]
    # Invertir para que NumPy los interprete correctamente (menor a mayor grado)
    coeffs_float.reverse()
    # Crear polinomio de NumPy
    poly_numpy = Polynomial(coeffs_float)
    laguerre_sympy_numpy.append(poly_numpy)

# Representamos gráficamente los polinomios
x = arange(-1, 3.5, 0.01)
fig, ax = plt.subplots()
ax.set_title('Polinomios de Laguerre $L_n$')
for n in range(n_polinomios):
    # Utilizamos por ejemplo los calculados con SciPy
    ax.plot(x, laguerre_scipy[n](x), label=f"$L_{n}$")
    # Si quisiéramos utilizar los calculados con NumPy:
    #ax.plot(x, laguerre_numpy[n](x), label=f"$L_{n}$")
    # Si quisiéramos utilizar los calculados con SymPy:
    #ax.plot(x, laguerre_sympy_numpy[n](x), label=f"$L_{n}$")
plt.legend(loc='best')
plt.grid(True)
plt.show()

 Este es el resultado de ejecutarlo:


Los polinomios asociados/generalizados de Laguerre se utilizan en campos como por ejemplo la mecánica cuántica.

domingo, 12 de marzo de 2017

Representación gráfica de familia de funciones con wxMaxima

Las últimas semanas he estado utilizando wxMaxima para comprobar la solución de EDOs de primer orden.

Ejemplo:

yg:ode2(x*'diff(y,x)+2*y+x^5*y^3*exp(x)=0,y,x);

Como puede observarse, este tipo de ecuaciones tienen por solución general una familia de funciones.

Podemos dar un valor concreto a la constante %c y representar la función resultante, pero con wxMaxima podemos representar varias funciones de una familia.

Para ello creamos una lista (con makelist) en la que damos valores a la constante, pero antes debemos sustituir la constante por un parámetro (con subst) que diremos que varíe.

listaf:makelist(rhs(subst(%c=i,yg)),i,-100,100);

El comando rhs se utiliza para quedarnos sólo con la parte derecha de la función, dado que ahora utilizamos plot2d para representar gráficamente la lista de funciones creadas.

plot2d(listaf,[x,-5,5],[y,-1,5],[legend,""],[style,[lines,2]]);

Y el resultado es el siguiente:
Representación gráfica de una familia de funciones