Dada una transitiva -colocar . Estoy interesado en encontrar el número de puntos fijos de actuando utilizando la tabla de notas de . Dejar ser representantes de las clases de conjugación de subgrupos de . Para cada uno de ellos, un polinomio
se define, donde . Dejar . El coeficiente de es el número de puntos fijos tiene en . El problema es calcular estos coeficientes de manera eficiente. Mi enfoque fue calcular
Cada transitiva -set corresponde a una fila en la tabla de marcas de desde para algunos . Resulta que calcular los puntos fijos de en para lleva más de 10 horas (todavía sin terminar), lo cual no es aceptable. Para definir el polinomio utilicé las funciones internas GAP Product, Sum y mod. ¿Tiene alguna sugerencia sobre cómo puedo calcular los coeficientes más rápido?
Gracias, esa es realmente una pregunta interesante!
-th enfoque
Al multiplicar polinomios con coeficientes enteros, el valor absoluto de los coeficientes puede aumentar bastante rápido. Es importante verificar que GAP esté compilado con la biblioteca GMP para una aritmética rápida de enteros. Debería ver gmp
en la línea 4 de la pantalla de inicio de GAP:
Libs used: gmp, readline
La compatibilidad con GMP se introdujo en GAP 4.5 (2012) y ahora es una opción predeterminada, por lo que lo más probable es que así sea.
Paso 1
El primer paso es ensamblar directamente el polinomio de la lista de coeficientes en lugar de calcularlo como la suma de monomios. En el siguiente ejemplo creo una lista aleatoria l
de un
enteros entre
y
, y luego compare estas dos formas de crear un polinomio con coeficientes dados por esta lista:
gap> x:=Indeterminate(Rationals,"x");
gap> l:=List([1..10000],i->Random(Integers));;
gap> f:=Sum([1..10000], i-> l[i]*x^i);;time;
2268
gap> f1:=LaurentPolynomialByCoefficients(FamilyObj(1),l,1);;time;
1
gap> f=f1;
true
time
devuelve el tiempo de CPU del último comando en milisegundos, por lo que verá que LaurentPolynomialByCoefficients
lo hace instantáneamente, mientras que el otro enfoque tarda más de dos segundos. Consulte más en "Creación de funciones racionales" del capítulo Polinomios y funciones racionales del manual de referencia de GAP; también hay más funciones de bajo nivel como PolynomialByExtRep
y PolynomialByExtRepNC
, LaurentPolynomialByExtRep
y LaurentPolynomialByExtRepNC
, donde NC
significa "sin verificación" y solo debe usarse si la velocidad es requerida y se sabe que los argumentos están en forma correcta. A menos que esto esté garantizado para los parámetros, LaurentPolynomialByCoefficients
debe usarse para estar seguro.
Obviamente, ahora ya no es necesario realizar mod
este paso, ya que uno podría simplemente truncar la lista de coeficientes (o no calcular la lista completa en absoluto).
Observación: se verificó el paso 1 (consulte los comentarios del autor de la pregunta más arriba) y se redujo en un ejemplo el tiempo de ejecución general de 22 horas a 59 minutos. Los pasos a continuación son solo sugerencias, que requieren más experimentación y ajuste del código.
Paso 2(a)
Quizás esto podría mejorarse aún más usando la funcionalidad descrita en Aritmética para representaciones externas de polinomios o incluso vectores como coeficientes de polinomios . El objetivo principal es evitar conversiones de ida y vuelta entre polinomios como objetos GAP y polinomios dados por sus representaciones externas.
Agregado más adelante: en particular, considere ProductCoeffs
cuál le permite multiplicar polinomios solo parcialmente: ProductCoeffs( list1[, len1], list2[, len2] )
asume que
(y
) son polinomios dados por las primeras len1
( len2
) entradas de la lista de coeficientes list2
( list2
). Si len1
y len2
se omiten, tienen por defecto las longitudes de list1
y list2
. Luego devuelve la lista de coeficientes del producto de
y
.
Si no se restringen las longitudes, el rendimiento es el mismo:
gap> x:=Indeterminate(Rationals,"x");;
gap> deg:=10000;;
gap> l1:=List([1 .. deg],i->Random(Integers));;
gap> f1:=LaurentPolynomialByCoefficients(FamilyObj(1),l1,0);;
gap> l2:=List([1 .. deg],i->Random(Integers));;
gap> f2:=LaurentPolynomialByCoefficients(FamilyObj(1),l2,0);;
gap> f:=f1*f2;;time;
3819
gap> t:=ProductCoeffs(CoefficientsOfUnivariatePolynomial(f1), CoefficientsOfUnivariatePolynomial(f2));;time;
3787
gap> CoefficientsOfUnivariatePolynomial(f)=t;
true
Pero ahora supongamos que queremos calcular el coeficiente para en el producto de y . Entonces no tenemos que usar monomios de grado 11 y superior. Así hacemos:
gap> p:=10;
10
gap> tcut:=ProductCoeffs(CoefficientsOfUnivariatePolynomial(f1), p+1, CoefficientsOfUnivariatePolynomial(f2), p+1);;time;
0
gap> CoefficientsOfUnivariatePolynomial(f){[1..p+1]}=tcut{[1..p+1]};
true
así que estamos obteniendo el resultado instantáneamente, saltándonos el trato con todos los monomios de grados superiores. En la misma configuración, tengo ms para y ms para , por lo que su millaje puede variar, y cuanto menor sea Es decir, mejor debería ser la aceleración.
Paso 2(b)
Se podría intentar experimentar con la multiplicación paralelizante de polinomios (dada por representaciones internas o externas). El número de polinomios a multiplicar es el número de clases de conjugación de , p.ej para . El enfoque más simple sería dividir la lista de polinomios en fragmentos y luego encontrar un producto de cada fragmento en paralelo y luego multiplicar los productos resultantes (posiblemente con otra iteración paralela, según la cantidad de fragmentos y nodos). De todos modos, el grado irá subiendo, y el cuello de botella obvio sería el último paso con la multiplicación secuencial de dos o tres polinomios. Si desea intentar experimentar con esto, mire el paquete SCSCP . También podría proporcionar un código para la multiplicación paralela de polinomios de Karatsuba con el paquete SCSCP: para polinomios de gran grado, también podría acelerarlo un poco.
Paso 2(c)
Otra sugerencia especulativa proviene del hecho de que puede estar interesado solo en un solo coeficiente. Eso sería mucho más útil si los polinomios fueran dispersos, pero aun así puede valer la pena intentarlo en el caso denso. La idea sería iterar sobre el producto cartesiano de grados de monomios (usando IteratorOfCartesianProduct
), verificar para cada tupla si la suma de grados de monomios es igual al grado que le interesa, y si es así, sume el producto de los respectivos coeficientes a alguna variable acumulativa. El pseudocódigo para calcular p
el coeficiente -th en GAP podría verse así
degs:= < list of degrees of polynomials >
degranges := List( degs, i -> [1..i] ); # list of ranges
# for sparse polynomial, take the list of degrees of monomials instead of a range
coeff := 0;
iter:=IteratorOfCartesianProduct(degranges);
for t in iter do
# t is a tuple of degrees of monomials
if Sum(t) = p then
coeff := coeff + Product( List( [1..Length(t)], i ->
< coefficient for x^t[i] in the i-th polynomial >
fi;
od;
Dominik B.
Olexandr Konovalov
PolynomialByExtRep
o incluso PolynomialByExtRepNC si confía en los argumentos, consulte aquí . Entonces al menos no tienes que usarSum
e innermod
. Sin embargo, no estoy seguro de cuánta aceleración obtendrá, ya que espero que sea la multiplicación lo que lleva la mayor parte del tiempo, pero de todos modos esta sería una optimización que vale la pena. Esperamos saber si esto tendrá algún efecto, luego veamos más.Dominik B.
Dominik B.
Olexandr Konovalov
Olexandr Konovalov
Dominik B.
Dominik B.
Olexandr Konovalov
Olexandr Konovalov
ProductCoeffs
, tal vez eso podría ser más eficiente que usar iteradores, por favor, eche un vistazo.