lunes, 12 de octubre de 2026

Regresos 16 (3): Particiones condicionadas con PARI

En la anterior entrada se desarrolló un ejemplo de particiones condicionadas con Cartesius y un Buscador. Consistía en descomponer el número 50 en sumandos cuadrados, sin importar el número de ellos que usemos, pero que no pasara de 3. Las soluciones resultaron ser 50=25+16+9=25+25=49+1

Ahora repetiremos el ejemplo con las herramientas del lenguaje PARI.

En PARI se cuenta con la función FORPART, que recorre una partición cualquiera, en la que se pueden integrar condicionantes. Para el ejemplo actual valdría este código:

a(n) = {nb = 0; forpart(p=n, if (#p && (#select(x->issquare(x), Vec(p)) == #p), nb+=1;print(p)), , 3);nb; }
print(a(50))

Cuesta entender todo lo escrito, pero consiste en iniciar un contador nb, recorrer todas las particiones con forpart y condicionarlas con x->issquare(x). El 3 que aparece es el tope para el número de elementos de la partición. Finaliza incrementando el contador e imprimiendo resultados. Así queda en la página oficial de PARI:

 


Coincide con las anteriores herramientas

Segundo ejemplo

Encontrar el número de particiones de un número en números primos sin otro condicionamiento. Por ejemplo, con el número 20:

Utilizamos el código PARI siguiente:

a(n) = {nb = 0; forpart(p=n, if (#p && (#select(x->isprime(x), Vec(p)) == #p), nb+=1), , ); nb; }
print(a(20))

Lo probamos y resulta que son 26:


Si deseamos ver las 26 particiones, le añadimos un print(p) detrás de nb+=1. Observa la imagen:


Con el Buscador se puede comprobar. Basta corregir las líneas de filtro, usando ESPRIMO en lugar de ESCUAD. Se omiten los detalles, ya explicados en la anterior entrada.


Se ha usado como tope el 10, que es máximo número posible de sumandos primos.

Nos puede interesar aplicar otra condición. En el ejemplo anterior se podría exigir que los primos fueran pitagóricos, del tipo 4k+1. Resultaría:


Se ha añadido la condición x%4==1 (el signo % significa MÓDULO)

 Condiciones más exigentes

Partición con sumandos coprimos

He encontrado este ejemplo en https://oeis.org/A000837, y lo uso para resaltar la economía de medios del lenguaje PARI. He adaptado el código a este documento:

s=0;forpart(X=20, s+=(gcd(X)==1);print(s))

Con esta simple línea encontramos que existen 582 particiones en las que el conjunto de sumandos posee MCD igual a 1 (no se afirma que sean primos dos a dos). Aquí, la condición fundamental es gcd(X)==1

Función Q(n)

Se denomina así al número de particiones de un número en elementos distintos. Recordamos aquí que estas particiones son sencillas de encontrar con Cartesius. Basta usar la condición NO REPITE.

Estas son las condiciones para las particiones del número 10 en sumandos distintos:

xrango=10

xt=1..10

no repite

suma=10

creciente

Su solución es


Son diez en total, pero el proceso resulta lento e inestable.

En OEIS (https://oeis.org/A000009) se incluye este código PARI:

{a(n) = my(c); forpart(p=n, if( n<1 || p[1]<2, c++; for(i=1, #p-1, if( p[i+1] > p[i]+1, c--; break)))); c}; /* Michael Somos, Aug 13 2017 */

Es algo oscuro a la hora de entenderlo, pero funciona:

En el elemento correspondiente al 10 observamos que Q(10)=10, tal como resultó en Cartesius.

Con el Buscador

Anulamos los filtros o restricciones, pero en el momento de llegar a la suma de la partición añadimos esta condición:

vale = True

If pp > 1 Then

For j = 2 To pp

For k = 1 To j - 1

If su(e(j)) = su(e(k)) Then vale = False

Next k

Next j

End If

 

If vale Then

De esa forma, sólo nos devolverá las particiones con elementos distintos:


Según un importante teorema ya visto en este blog, el número de estas particiones coincide con las conseguidas si se restringen los sumandos a ser impares.

En el ejemplo del 10 nos resultarían, como era de esperar, 10 particiones con este código:

a(n) = {nb = 0; forpart(p=n, if (#p && (#select(x->x%2==1, Vec(p)) == #p), nb+=1;print(p)), , 3);nb; }
print(a(10))


Con Cartesius bastarían las condiciones

xrango=10

xt=1..10

xt=filtro(impar)

suma=10

creciente

No es recomendable por su lentitud.

Sin más explicaciones, este sería el resultado si eliminamos los sumandos pares:

 



Particiones con un número par o impar de sumandos

En estos ejemplos usaré PARI:

Con un número par:

Es importante la parte #p%2==0,nb+=1, pues % es la operación MODULO y nos indica que la partición tiene un número par de elementos #p.

a(n) = {nb = 0; forpart(p=n, if(#p%2==0,nb+=1), , ); nb; }
print(a(20))

Nos resulta que existen 317 particiones con un número par de elementos. Si deseamos datos de los primeros números obtendremos:


Coinciden con los publicados en
https://oeis.org/A027187

Particiones con número impar de elementos:

Bastaría cambiar #p%2==0 por #p%2==1:


Publicados en
https://oeis.org/A027193

Podemos usar ambas situaciones en funciones separadas, y experimentar algo con ellas. Por ejemplo, que las de número par sean dos más que las de impar:

a(n) = {nb = 0; forpart(p=n, if(#p%2==0,nb+=1), , ); nb; }

b(n) = {nb = 0; forpart(p=n, if(#p%2==1,nb+=1), , ); nb; }

for(i=1,100, if(a(i)==b(i)+2,print1(i,”, “)))


No tiene mucho interés, porque en los primeros números solo se cumple en el 8 y el 10.

También se pueden contar por separado las particiones de cardinal par y las de impar en la misma función. La siguiente busca si el número de particiones de orden par es dos unidades mayor que las de impar en un mismo número n.

c(n) = {my(nb = 0,na=0);forpart(p=n, if(#p%2==0,nb+=1,na+=1,), , ); nb==na+2 }
for(i=1,30, if(c(i)==1,print1(i,”, “)))

Escasean también los resultados.

Lo dejamos aquí. Ya se ha abierto una puerta a más experimentaciones.

Unos detalles para finalizar

PARI posee la función numbpart, que cuenta el número de elementos de una partición. Este código elabora un listado de los números con un número par de particiones distintas:

a(n)={my(c);c=numbpart(n);if(c%2==0,return(c))}
for(i=1,50,if(a(i)>0,print1(i,", ")))


Particiones con producto acotado

En la primera parte de la instrucción forpart se puede incluir toda una línea de código. Esto permite calcular productos en las particiones y condicionarlos.

Por ejemplo, lo siguiente encuentra aquellas particiones de n=5 cuyo producto es mayor que 3. Es importante destacar la forma en la que hay que usar las distintas partes de una partición con Vec(p)[k]):

a(n) = { nn=0; forpart(p=n, pp=1;for(k=1,#p,pp=pp*Vec(p)[k]);if(pp>3,nn+=1;print(p);p));nn }
print(a(5))

Resultado:


Otro ejemplo: podemos reproducir el contenido de
https://oeis.org/A319005

Number of integer partitions of n whose product of parts is >= n.

 1, 1, 1, 1, 2, 2, 5, 7, 13, 18, 28, 40, 60, 80, 113, 152, 205, 266, 353, 454, 590, 751, 959, 1210, 1529, 1905, 2381, 2953, 3658, 4501, …

Usaremos

a(n) = {nn=0; forpart(p=n, pp=1;for(k=1,#p,pp=pp*Vec(p)[k]);if(pp>=n,nn+=1));nn }
for(i=1,30,print1(a(i),", "))

Resultado:



Con estos ejemplos se reconoce la enorme capacidad de PARI para manejar particiones. Paramos ejemplos por ahora.

No hay comentarios: