Fixed points of folded polynomial systems, part 2

$$ \newcommand{\bint}{\displaystyle{\int\hspace{-10.4pt}\Large\mathit{8}}} \newcommand{\res}{\displaystyle{\text{Res}}} \newcommand{Log}{\text{Log}} \newcommand{Arg}{\text{Arg}} \newcommand{pLog}{\text{pLog}} $$

Readers are encouraged to read Fixed points of folded polynomial systems, part 1 first.

  1. Background:

  2. In the first part of this section, we studied fixed points of a folded system $$ F^{((n))}(z,w)=\underbrace{F(F(F(\cdots F))\cdots)}_{\text{n times}} $$ where $$ \begin{equation} F(z,w)=\left\{\begin{array}{l} 1-1/4 w+z^2 \\ z \end{array} \right\} \end{equation} $$ or equivalently the roots of $V_n(z,w)=F^{((n))}-\{z,w\}$. And we found the time to compute the fixed points of $F^{((10))}$ using $\texttt{NSolve}$ was about $6.5$ hours on a $4.5$ GHz quad-core Intel Zeon machine. And based on the trend of computing $F^{((7))}$ through $F^{((10))}$, estimated the time to compute $F^{((11))}$ to be about $2.5$ days and about $25$ days for $F^{((12))}$. We also developed a method to blanket-search a region in the $\{z,w=z\}$ plane using Netwon's method and Mathematica's $\texttt{FindRoot}$ function to compute cycle-$10$ roots but this approach produced a small number of roots for the test cases studied and would quickly become computationally expensive if the region were more finely partitioned. Clearly we would like a more efficient means of computing the fixed points to higher folded polynomial systems.

    One reason for the low number of cycle-10 roots found by the blanket-search Newton iteration was the choice of seeds. Recall, a root is given by two numbers $\{p,q\}\in \mathbb{C}$. And the seeds were of the form $\{a,a\}$. However in general a root $\{p,q\}$ may be far-removed from any $\{a,a\}$ seed. For example, take the cycle-10 root $\{1.54409 -0.00374401 I,-1.59651-0.0411066 I\}$. A seed $\{a,a\}$ closest to this root would lie in a neighborhood of $\{0,0\}$, a distance of about $1.5$ from the root. And with the method used for the search, too far-removed from the root and so missed by the algorithm. Now, it is known a basin plot for a Newton iteration is often fractal which means there are many basins of attraction for reach root, but it is well-known the closer the seed is to the root, the greater chance the seed will lie in a basin of attraction for the root and so lead to a convergent sequence under Newton iteration. What we would like therefore, is to find a set of seeds that are as close to the roots as possible and thus increase the probability and therefore the number of seeds converging to a root.

  3. Better seeds

  4. Using system (1) above, suppose we plot, for the set of cycle-$n$ roots $\big\{\{z_1,w_1\},\{z_2,w_2\},\cdots,\{z_k,w_k\}\big\}$, the points $\big\{\{Re(z_1),Im(z_1)\},\{Re(z_2),Im(z_2)\},\cdots,\{Re(z_k),Im(z_k)\}\big\}$ for cycles $5$ through $10$. We obtain the plots shown in Figure 1. And in this particular example, similar plots are obtained for the $w$-terms.

    There is an obvious trend in the figures: the roots appear to increasingly populate a well-defined constrained region. In particular, consider the plots for cycle-$9$ and cycle-$10$. Suppose for each cycle-$10$ root, we compute the nearest cycle-$9$ root and create a bar-chart of the minimum distance for each of the cycle-$10$ roots. The results are shown in Figure 2.

    So that if we used the cycle-$9$ roots as seeds for the cycle-$10$ iteration, the maximum difference between a seed and the nearest root would be about $0.12$ and in most other cases, much less than this. How might that affect a Newton iteration of $V_{10}$ using as seeds the roots of $V_{9}$? And more importantly, could we use this to improve the estimated time of $2.5$ days to compute $V_{11}$ roots using $V_{10}$ roots as seeds? And of higher-folded systems?

  5. Finding roots of $V_n(z,w)$ with $V_{n-1}(z,w)$ seeds, Case 1:

  6. Recall in Part 1 we computed the roots of $V_9$ to $25$ digits of accuracy using $\texttt{NSolve}$. We would like to use these roots as seeds to compute the roots of $V_{10}$. The following code implements $\texttt{FindRoot}$ with default settings to compute the roots of $V_{10}$ using $V_9$ roots as seeds.

    Mathematica code 1

    cycleNum = 10;
    theV[z_, w_] = Nest[vectorF, {z, w}, cycleNum] - {z, w};
    newSeeds=cycle9Roots;
    
    PrintTemporary["Analyzing seed ", Dynamic@theIndex, "/", totalPoints];
    
    timing1 = AbsoluteTiming[
      iterationRecords = ParallelTable[
         If[Mod[rootNum, 100] == 0,
          theIndex = rootNum;
          ];
         theSeed = newSeeds[[rootNum]];
         Quiet[
          Check[
            {z, w} /. 
            FindRoot[theV[z, w], {{z, theSeed[[1]]}, {w, theSeed[[2]]}}],
              {"NaN", "NaN"},
              {FindRoot::lstol, (* insufficient decrease in merit function *)
               FindRoot::jsing,  (* Jacobian is singular *)
               FindRoot::cvmit,  (* maximum iterations reached without achieving desired accuracy *)
               FindRoot::sszero  (*step size has become less than tolerance of precision goal *)
            }],
            {FindRoot::lstol, FindRoot::jsing, FindRoot::cvmit,FindRoot::sszero}],
         {rootNum, 1, Length@theSeedList}];
      ]
     
    

    Mathematica output 1

    Total divergent seeds: 22
    Total roots found: 490
    Root precision: MachinePrecision
    Root accuracy: 15.6983
    Total time: 0.915275
    

    The code took about a second to find 490 roots with a default precision of 16 digits. Note only $22$ seeds did not converge to a root. The divergent seeds generated $\texttt{FindRoot::lstol}$ and $\texttt{FindRoot::cvmit}$ errors indicating insufficient working precision to achieve the default accuracy of $16$ digits using the default maximum number of iterations at $100$. If we now attempt to create folded root lists, the process of folding such low precision roots $10$ times through $F(z,w)$ reduces the precision down to $10$ which is below machine precision. An attempt to generate a cycle report of the resulting lists produces extremely poor results: $$ \begin{array}{c} \begin{array}{|c|c|c|c|} \hline \text{Cycle Type} & \text{Size} &\text{Roots Found} & \text{Difference} \\ \hline 1 & 2 & 261 & -259\\ 2 & 2 & 8 & -6\\ 5 & 30 & 154 & -124\\ 10 & 990 & 4499 & -3509\\ \hline \end{array} \\ \text{Table 1: Computed Cycles of $F^{((10))}$, Case 1} \\ \end{array} $$

    The problem with this case of course is the lack of sufficient working precision and illustrates the need to fine-tune the $\texttt{FindRoot}$ algorithm.

  7. Roots of $V_n(z,w)$, Case 2:

  8. Next consider iterating $V_{10}$ with greater working precision and larger iteration limit. In the code below we set the precision of the seeds to a working precision of $100$ digits and increase the maximum number of iterations to $500$:

    Mathematica code 2

      workingPrecision=100;
      maxIterations=500;
      theSeedList = SetPrecision[theCurrentRoots, workingPrecision];
      
      timing1 = AbsoluteTiming[
       iterationRecords = ParallelTable[
          If[Mod[rootNum, 100] == 0,
           theIndex = rootNum;
           ];
          theSeed = theSeedList[[rootNum]];
          Quiet[
           Check[ {z, w} /. 
             FindRoot[theV[z, w], {{z, theSeed[[1]]}, {w, theSeed[[2]]}},
              WorkingPrecision -> workingPrecision, 
              MaxIterations -> maxIterations],
            {"NaN", "NaN"}, {FindRoot::lstol, FindRoot::jsing, 
             FindRoot::cvmit}], {FindRoot::lstol, FindRoot::jsing, 
            FindRoot::cvmit}],
          {rootNum, 1, Length@theSeedList}];
       ];
    
    

    Mathematica output 2

    Total divergent seeds: 2
    Total roots found: 510
    Root precision: 100.
    Root accuracy: 99.7437
    Total time: 3.23674
    

    Note with a higher precision and increasing the maximum number of iterations reduced the number of divergent seeds to two. And more importantly, the roots were computed to an accuracy of of $99$ digits. Now when we fold the roots and compute the cycle report we obtain: $$ \begin{array}{c} \begin{array}{|c|c|c|c|} \hline \text{Cycle Type} & \text{Size} &\text{Roots Found} & \text{Difference} \\ \hline 1 & 2 & 2 & 0\\ 2 & 2 & 2 & 0\\ 5 & 30 & 30 & 0\\ 10 & 990 & 970 & 20\\ \hline \end{array} \\ \text{Table 2: Computed Cycles of $F^{((10))}$, Case 2} \\ \end{array} $$

    So by increasing the precision and maximum iterations, and including the post-processing time to delete duplicate roots, fold the roots, and compute the cycle report, we were able to find all but $20$ roots of $V_{10}$ in about $4$ seconds using the cycle-$9$ roots as seeds.

  9. Improving Newton's method, Case 3: Step size control

  10. A good step-size control of Newton's method will prevent oscillations about a root or escapes from the root. One method which can avoid these two possibilities is "Line search" method. In this method, the direction of a step is given by Newton's iteration but the size of the step is altered by internally solving a particular minimization problem which improves convergence. Background on this method can be found at the following Mathematica site: Unconstrained optimization: Step Control

    The following code employs an explicit step-control method to search for the cycle-$10$ roots. Values for $\texttt{DecreaseFactor}$ and $\texttt{MaxRelativeStepSize}$ were determined heuristically.

    Mathematica code 3

      workingPrecision=100;
      maxIterations=500;
      theSeedList = SetPrecision[theCurrentRoots, workingPrecision];
      
       timing1 = AbsoluteTiming[
       iterationRecords = ParallelTable[
          If[Mod[rootNum, 100] == 0,
           theIndex = rootNum;
           ];
          theSeed = theSeedList[[rootNum]];
          Quiet[
           Check[ {z, w} /. 
             FindRoot[theV[z, w], {{z, theSeed[[1]]}, {w, theSeed[[2]]}}, 
              Method -> {"Newton", 
                "StepControl" -> {"LineSearch", 
                  "CurvatureFactor" -> Automatic, 
                  "DecreaseFactor" -> 1/10000, 
                  "MaxRelativeStepSize" -> 1/2, Method -> Automatic}}, 
              WorkingPrecision -> workingPrecision, 
              MaxIterations -> maxIterations], {"NaN", 
             "NaN"}, {FindRoot::lstol, FindRoot::jsing, 
             FindRoot::cvmit}], {FindRoot::lstol, FindRoot::jsing, 
            FindRoot::cvmit}],
          {rootNum, 1, Length@theSeedList}];
       ];
    

    Mathematica output 3

    Total divergent seeds: 2
    Total roots found: 510
    Root precision: 100.
    Root accuracy: 99.7437
    Total time: 3.04331
    

    And in this case all roots were computed in about $4$ seconds. Note in particular the number of convergent seeds was the same as Case 2: $510$. However, in this case, there were seeds which converged to different roots than that of Case 2 and by folding these different roots, contributed the missing $20$ roots identified in Case 3. $$ \begin{array}{c} \begin{array}{|c|c|c|c|} \hline \text{Cycle Type} & \text{Size} &\text{Roots Found} & \text{Difference} \\ \hline 1 & 2 & 2 & 0\\ 2 & 2 & 2 & 0\\ 5 & 30 & 30 & 0\\ 10 & 990 & 990 & 0\\ \hline \end{array} \\ \text{Table 3: Final cycle report for roots of $V_{10}$} \\ \end{array} $$

    So given the $33$ minutes to compute the cycle-$9$ roots reported in Part 1, only $4$ seconds of computation was needed to compute the cycle-$10$ roots. In Part 3, we use the techniques above and other methods to compute roots to higher-folded systems.

No comments:

Post a Comment

Blog Archive