Estoy tratando de escribir una función que toma los coeficientes enteros de dos polinomios y devuelve los coeficientes de un polinomio que tiene una raíz para cada forma en que se puede multiplicar un par de raíces del par de polinomios de entrada.
La aplicación que tenía en mente es la representación exacta de números algebraicos. En lugar de almacenar un número dado $x$ como un flotador o un símbolo, almacenaría los coeficientes de un polinomio que tiene $x$ como raíz. Operar con números almacenados de esa manera, sin perder precisión, requiere operar con las raíces sin calcularlas realmente.
(Tengo claro que esta estrategia de representación tiene graves defectos, tanto en términos de eficiencia como de multiplicidad de soluciones, pero sigo queriendo resolver el problema).
Ejemplo
Supongamos que las listas de coeficientes de los polinomios de entrada son [1,0,-1] y [1,5,6]. Es decir, la entrada es el polinomio $x^2 - 1$ y el polinomio $x^2 + 5x + 6$ . Tienen raíces $-1,+1$ y $-2,-3$ respectivamente. Por lo tanto, el polinomio de salida debe tener raíces $-1 \cdot -2,-1 \cdot -3,1 \cdot -2,1 \cdot -3 = -3,-2,2,3$ y es igual a $(x-3)(x-2)(x+2)(x+3)$ que es $x^4 - 13x^2 + 36$ y así la salida es [1,0,-13,0,36].
Parcialmente resuelto
He trabajado en el problema, y he conseguido factorizar los efectos de los polinomios de entrada en piezas separadas (eso creo, al menos). Me llevaría demasiado tiempo explicar cómo llegué a donde estoy... basta con decir que fue muy ad-hoc.
La siguiente función parece calcular lo que quiero, y es casi independiente de las raíces:
var decreasings = DecreasingSequencesOfSize(
length: poly1.Degree,
total: indexOfOutputCoefficient,
max: poly2.Degree);
var outputCoefficient =
(from coefRepeatSequence in decreasings
let coefs2Factor =
coefRepeatSequence
.Select(e => coefs2[e])
.Product()
let coefs1Factor = F(coefRepeatSequence, roots1, coefs1)
select coefs2Factor*coefs1Factor
).Sum();
private static BigInteger F(IReadOnlyList<int> d, IReadOnlyList<BigInteger> roots, IReadOnlyList<BigInteger> coefs) {
return (from p in d.DistinctPermutations()
select p.Select((e, i) => BigInteger.Pow(roots[i], e)).Product()
).Sum();
}
Lo siento si no ha quedado del todo claro. He reducido el código todo lo posible.
He aquí una formulación alternativa de F, como función recursiva:
private static BigInteger F2(IReadOnlyList<int> d, IReadOnlyList<BigInteger> roots) {
var zeroes = d.Count(e => e == 0);
if (zeroes == d.Count) return 1;
var min = d.Min();
if (min > 0) {
var mecs = d.Where(e => e > 0).Select(e => e - min).ToArray();
return BigInteger.Pow(roots.Product(), min) * F2(mecs, roots);
}
var decs = d.Where(e => e > 0).ToArray();
return (from x in roots.Choose(d.Count - zeroes)
select F2(decs, x)
).Sum();
}
Como puedes ver, la única dependencia de las raíces es para calcular la función F. Parece que siempre se puede reducir a una expresión en términos de los coeficientes... Puedo hacerlo a mano para polinomios de grado pequeño, y puedo tropezar para reducirlo para los más grandes, pero no veo el patrón todavía...
Question
Así que...
- ¿Está ya resuelto este problema?
- ¿Hay alguna técnica que deba conocer y que pueda ayudar?
- ¿Me estoy perdiendo algo obvio?
Actualización
He utilizado la solución de Jyrki y la he puesto en práctica. Puedes encontrar el código en mi Repo de github de PolyNumber .