File : funs2-num.adb


with Messages;
use Messages;

package body Funs2.Num is

  function NumInv(F: Fun) return Fun is
    Iter: constant Integer := 15;
    Eps: constant Radius := 5.0E-16;
    Err: Rep;
    G,H: Fun;
  begin
    G.A := F.A;
    G.E := F.E;
    if IsZero(F.Q) then
      G.P := NumInv(F.P);
      G.Q := TayZero;
    else
      Prod(F.P,F.P,G.P);
      Prod(F.Q,F.Q,G.Q);
      Mult(CoordT2(F.A),G.Q);
      G.Q := NumInv(G.P-G.Q);
      G.P := F.P*G.Q;
      G.Q := -F.Q*G.Q;
    end if;
    for I in 1 .. Iter loop    -- now iterate G -> (2-FG)G
      Prod(F,G,H);
      AddConst(-ScalOne,H);
      Err := Sup(Norm(H));
      AddConst(-ScalOne,H);
      Mult(H,G);
      Neg(G);
      if Err<Eps then return G; end if;
    end loop;
    Show("Funs2.Num.NumInv: precision only",Err,1);
    return G;
  end NumInv;

  procedure NumInv(L: in out Flop) is
    H: Fun;
  begin
    H := L(1)*Reflect(L(1))-L(2)*Reflect(L(2));
    H := NumInv(H);
    L(1) := H*Reflect(L(1));
    L(2) := -H*L(2);
  end NumInv;

  procedure VApprox(D: in Domain; V: out Fun) is
  begin
    if not VHave then
      Read("vapprox.data",VSave);
      VHave := True;
    end if;
    if VSave.A /= D.A then
      if Verbosity>2 then Show2("converting ",VSave.A,D.A); end if;
      ChangeVar(D.A,VSave);
    end if;
    V := VSave;
    SetRho(D.R,V);
  end VApprox;

  procedure NumCompZero(F,G: in Fun; R: in RadPair; V: in out Fun) is
--- solves G(x,V)+F(V,W)=0 by Newton's method
--- V can be zero but needs valid V.A
--- using also VApprox if initial V is zero or inaccurate
    OldVerbosity: constant Natural := Verbosity;
    TmpVerbosity: constant Natural := IMin(2,Verbosity);
    Iter: constant Integer := 30;
    N:    constant Integer := 4;
    Eps1: constant Radius  := 1.0E-05;
    Eps2: constant Radius  := 1.0E-08;
    Eps3: constant Radius  := 1.0E-15;
    DV:   constant Domain  := (V.A,R);
    Skip: Boolean := False;
    Err: Rep;
    FX,FY,GX,GY,FGV: Fun;
    L: Flop;
  begin
    TraceEnter("Funs.Num.NumCompZero");
    Show("Computing approx V",3);
    Verbosity := TmpVerbosity;           --- too many domain violations
    SetRho(R,V);
    if not IsZero(V) then
      FGV := CompY(V,G)+CompVW(V,F);
      Err := Sup(Norm(FGV));
      Skip := Err<Eps1;
    end if;
    if not Skip then VApprox(DV,V); end if;
    for I in 1 .. Iter loop
      if not Skip then
        FGV := CompY(V,G)+CompVW(V,F);
        Err := Sup(Norm(FGV));
      end if;
      Skip := False;
      if Err>Eps2 or else (I mod N)=1 then
        Der(R,F,FX,FY);
        Der(R,G,GX,GY);
        L(1) := CompY(V,GY)+CompVW(V,FX);
        L(2) := -CompVW(V,FY);
        NumInv(L);
      end if;
      V := V-L*FGV;
      exit when Err<Eps3;
    end loop;
    if Err>Eps3 then
      Show("Funs2.Num.NumCompZero: precision only",Err,1);
    end if;
    Verbosity := OldVerbosity;
    TraceLeave;
  end NumCompZero;

  procedure NumCompZeroD(F,G: in Fun; R: RadPair; V: in out Fun) is
--- NumCompZero for derivatives
    FX,GY,H: Fun;
  begin
    Der(Rho(F),F,FX,H);
    Der(Rho(G),G,H,GY);
    NumCompZero(FX,GY,R,V);
  end NumCompZeroD;

  function GuessRho(F: Fun) return RadPair is
    D0: constant Integer := PDeg/5;
    D1: constant Integer := PDeg-D0;
  begin
    return Min(GuessRho(D0,D1,F.P),GuessRho(D0,D1,F.Q));
  end GuessRho;

  procedure RhoInfo(N: in String; F: in Fun; Rn: in RadPair) is
    Rh: constant RadPair := Rho(F);
    Rg: constant RadPair := GuessRho(F);
  begin
    Show1(N,F.A);
    Show(N & " guess radii ",Rg(1),Rg(2));
    Show(N & "  have radii ",Rh(1),Rh(2));
    Show(N & "  need radii ",Rn(1),Rn(2));
    Show(N & " need / have ",Rn(1)/Rh(1),Rn(2)/Rh(2));
    New_Line;
  end RhoInfo;

end Funs2.Num;