¿Existe una formulación general para encontrar todas las raíces de un polinomio, especialmente las complejas, utilizando el Método de Newton-Raphson?
¡Buena respuesta! No sabía de algo así para raíces complejas.
¿Existe una formulación general para encontrar todas las raíces de un polinomio, especialmente las complejas, utilizando el Método de Newton-Raphson?
Sí, ¡existe tal método! Consulta el llamado "Cómo encontrar todas las raíces de polinomios complejos por el método de Newton", de Hubbard, Schliecher y Sutherland.
No solo hay un método sino que, debido a la estabilidad de los puntos fijos bajo la iteración de la función del método de Newton, hay un método muy bueno. De hecho, los autores señalan que fueron llevados a este tema en su estudio de medidas invariantes del mapeo de Henon y, en ese contexto, tuvieron una necesidad genuina de encontrar raíces de polinomios cuyo grado era de varios miles. Evidentemente, su método tuvo éxito donde las herramientas de software establecidas fallaron.
La idea básica es encontrar una colección de semillas iniciales distribuidas de tal manera que se garantice que, para cada raíz, hay al menos una de las semillas que converge a esa raíz. Este conjunto es bastante grande pero puedes detenerte cuando hayas encontrado todas las raíces. La multiplicidad de la raíz se puede determinar por la velocidad de convergencia.
He incluido una implementación en Mathematica a continuación llamada NewtonSolve
. Aquí tienes un ejemplo:
NewtonSolve[(z^3 - 1) (z - I)^3, z,
ErrorTolerance -> 10^-20] // Chop
(* Salida: {{2.34482*10^-8 + 1. I, 1}, {0. + 1. I, 3},
{-0.5 + 0.866025 I, 1}, {-0.5 - 0.866025 I, 1}}
*)
Nota que el comando devuelve una lista de pares {raíz, multiplicidad}
y que se identificó correctamente que $i$ tiene una multiplicidad de 3. Por supuesto, hay polinomios que desafiarán a cualquier buscador de raíces y no afirmo que este código sea de calidad de producción, pero sí ilustra las ideas.
Aquí tienes una imagen que ilustra aún más lo que está sucediendo con este ejemplo:
Los puntos verdes grandes son exactamente las raíces del polinomio, cada una dentro de su cuenca de atracción sombreada. La observación fundamental en el documento es que cada una de estas cuencas de atracción se extiende hasta el infinito. Como resultado, podemos elegir un anillo suficientemente grande de semillas iniciales para que cada cuenca de atracción contenga una de las semillas. El anillo para este polinomio en particular (de hecho, cualquier polinomio de grado seis con raíces en el disco unitario) se muestra como el anillo de puntos negros.
La función resuelve un ejemplo supuestamente difícil propuesto en los comentarios anteriores, con la multiplicidad correcta, en menos de un segundo:
NewtonSolve[(z - 1)^50, z] // Timing
(* Salida: {0.293804, {{1. + 0. I, 50}}} *)
Aquí está el código para NewtonSolve
:
Options[NewtonSolve] = {
NormalizationFactor -> Automatic,
ErrorTolerance -> $MachineEpsilon
};
NewtonSolve[poly_, var_,
opts___] := Module[
{p, z, nwt, cp, cpp,
coeffs, deg, maxRootRadius,
mult, sameRootQ, newRootQ,
maxIters, rootsSoFar, initPoints,
numInitPoints, rmPair, normFactor,
tol},
normFactor = NormalizationFactor /. {opts} /.
Options[NewtonSolve];
tol = ErrorTolerance /. {opts} /.
Options[NewtonSolve];
coeffs = CoefficientList[poly, var];
deg = Length[coeffs] - 1;
If[normFactor === Automatic,
maxRootRadius = Max[Abs[Drop[coeffs, -1]/Last[coeffs]]] + 1,
maxRootRadius = normFactor];
p[z_] = poly /. var -> maxRootRadius*z;
cp = Compile[{{z, _Complex}}, p[z]];
cpp = Compile[{{z, _Complex}}, Evaluate[p'[z]]];
nwt = Compile[{{z, _Complex}},
Evaluate[z - p[z]/p'[z]]];
mult[z0_Complex] := If[nwt[z0] == z0, 1,
mult[FixedPointList[nwt, z0, 1000]]];
mult[orbit_List] := Module[{f, div, diffs},
f[x_] := If[x != 1.0, 1/(x - 1)];
div[{a_, b_}] := If[b != 0, a/b];
diffs = Abs[(#[[2]] - #[[1]]) & /@
Partition[Drop[orbit, -1], 2, 1]];
statisticalMode[Round[f /@ (div /@
Partition[diffs, 2, 1])] + 1 /. Round[_] -> 0]];
sameRootQ[z1_, z2_, 1] := If[Abs[cp[z1]] >= Abs[cp[z2]],
Abs[z1 - z2] <= Abs[3 cp[z1]/cpp[z1]],
Abs[z2 - z1] <= Abs[3 cp[z2]/cpp[z2]]];
sameRootQ[z1_, z2_, mm_ /; mm > 1] := Abs[z1 - z2] < 100 tol;
newRootQ[z_, mm_] := Module[{justRootsSoFar, flag},
flag = True;
justRootsSoFar = First /@ Flatten[rootsSoFar];
Scan[If[sameRootQ[#, z, mm], Return[flag = False]] &,
justRootsSoFar];
flag];
maxIters =
Ceiling[(Log[1 + Sqrt[2]] - Log[tol])/(
Log[deg] - Log[deg - 1])];
rootsSoFar = {};
numRootsSoFar = 0;
initPoints = N[S[deg]];
numInitPoints = Length[initPoints];
i = 0;
While[i++ < numInitPoints && numRootsSoFar < deg,
orbit = NestWhileList[nwt, initPoints[[i]],
(Abs[cp[#1]] >= tol && #1 != #2) &, 2, maxIters];
nextRoot = Last[orbit];
If[(Abs[cp[nextRoot]] < tol || orbit[[-2]] == orbit[[-1]]),
m = mult[nextRoot];
If[m > 1,
nextRoot = FixedPoint[nwt, nextRoot, maxIters]];
If[newRootQ[nextRoot, m],
numRootsSoFar = numRootsSoFar + m;
rootsSoFar = {rootsSoFar, rmPair[nextRoot, m]}]]
];
Flatten[rootsSoFar] /. rmPair[r_, mm_] ->
{r*maxRootRadius, mm}
] /; (PolynomialQ[poly, var] &&
NumericQ[poly /. var :> Random[]]);
statisticalMode[list_] :=
Module[{c, mc, ms},
c = {Length[#], First[#]} & /@ Split[Sort[list]];
If[Length[c] === 1, Return[c[[1, 2]]]];
mc = Max[First[Transpose[c]]];
If[mc === 1, Return[{}]];
ms = Cases[c, {mc , val_} -> val];
If[Length[ms] == 1, ms[[1]], ms];
ms[[1]]] /; VectorQ[list] && (Length[list] > 0);
statisticalMode[{}] = 1;
ring[r_, d_] := With[{n = Ceiling[8.32547 d Log[d]]},
Flatten[Transpose[Partition[Table[r Exp[2 Pi I j/n],
{j, 0, n - 1}], Ceiling[n/d], Ceiling[n/d], 1, {{}}]]]];
S[d_] := With[{R = 1 + Sqrt[2], s = Ceiling[0.26632 Log[d]]},
Flatten[Table[ring[R (1 - 1/d)^((2 \[Nu] - 1)/(4 s)), d],
{\[Nu], 1, s}]]];
@user_of_math ¡Qué bien que te haya gustado! He añadido una pequeña explicación adicional con una imagen.
Tal como se ha señalado, el método de Newton-Raphson, al igual que la mayoría de otros métodos similares, convergen a una sola raíz aislada. Sin embargo, existen métodos para encontrar todas las raíces de un polinomio.
Uno que conozco, es crear la matriz compañera, y luego encontrar (numéricamente) los eigenvalores de esa matriz, que son precisamente las raíces de tu polinomio.
Si utilizas Matlab, esto es precisamente lo que hace la rutina 'roots'. Por experiencia personal con esa rutina, corre muy rápido tanto para polinomios de grados bajos como altos.
Si bien en general la respuesta es no, existe el método de Weierstrass, el cual se basa en el método de Newton multidimensional e intenta encontrar todas las raíces complejas. Al igual que el método de Newton, no se garantiza que tenga éxito y solo funciona bien cuando las raíces son simples.
El método de Weierstrass probablemente es lo más cercano a lo que estás buscando.
I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.
4 votos
El método de Newton-Raphson converge rápidamente a una raíz aislada de una ecuación o sistema de ecuaciones que involucran funciones suaves una vez que tenemos una aproximación suficientemente cercana a esa raíz. Desafortunadamente, estos "cuencas de atracción" a menudo tienen un patrón fractal, por lo que es imposible hacer una generalización amplia sobre cómo asegurarse de que estás lo suficientemente cerca. Vea la discusión aquí en los conjuntos de Julia.
0 votos
También hay una dificultad en saber cuándo una raíz tiene multiplicidad mayor que uno, o cuando dos raíces que tienen multiplicidad uno suceden estar muy cerca una de la otra.
0 votos
¿Quieres (todos) las raíces complejas de polinomios en una variable?
0 votos
Sí, quiero esto
0 votos
N-R nunca se utiliza por sí solo, en general: debe utilizarse en combinación con un método de enraizamiento, como la bisección.
0 votos
@user_of_math La pregunta se trata principalmente de raíces complejas.
0 votos
En resumen, no. Incluso cuando puede converger hacia una raíz, la convergencia puede ser arbitrariamente lenta, por lo que nunca puedes estar seguro de que estás cerca. Mira qué sucede con $(x-1)^{50}$ por ejemplo.
0 votos
He añadido la etiqueta de complex-dynamics ya que la solución a la que me he referido a continuación depende fundamentalmente de esa área de estudio.
0 votos
Utilice Método de Laguerre.
3 votos
@hardmath Los límites de las cuencas tienen una estructura fractal, pero las cuencas en sí son conjuntos abiertos y se extienden hasta el infinito de manera uniforme, por lo que es posible elegir un conjunto de semillas iniciales para asegurar que se capturen todas las raíces. Además, la multiplicidad de cada raíz se refleja en la tasa de convergencia hacia la raíz, aunque es cierto que esto es difícil de detectar para multiplicidades grandes. Todos los detalles están contenidos en el artículo vinculado en mi respuesta.
0 votos
@zibadawatimmy El comando
NewtonSolve
que describo a continuación encuentra las raíces de tu polinomio en 0.2 segundos.0 votos
@MarkMcClure: Mis comentarios iniciales precedieron la estrechez de la pregunta a ecuaciones polinómicas (en una variable). De hecho, las raíces múltiples pueden ser detectables por el MCD, dependiendo de si los coeficientes del polinomio son conocidos o si aparecen simplemente como una "caja negra" para su evaluación (función y derivada ya que se contemplan las iteraciones de Newton).
0 votos
@hardmath De hecho, ¡no sabía que la pregunta originalmente se refería a polinomios! Sin embargo, mi comentario parece adecuado, dadas el nuevo contexto.