File : fouriers-ops.adb
with Messages, Reps.Ops;
use Messages;
pragma Elaborate_All (Messages, Reps.Ops);
package body Fouriers.Ops is
use Components_Ops;
Small: constant Rep := Half**10;
ScalTwo: constant Scalar := Scal(Two);
ScalHalf: constant Scalar := Scal(Half);
OnePlus: constant Scalar := Widen(ScalOne); --- used in norms
HalfPlus: constant Scalar := Widen(ScalHalf); --- used in norms
function IMin(I1,I2: Integer) return Integer renames Integer'Min;
function IMax(I1,I2: Integer) return Integer renames Integer'Max;
function Deg(P: Taylor) return Degree renames Components.Deg; --- want to inline it
pragma Inline (Imin,Imax,Deg);
function DmaxCount return Integer is
D: Integer := 0;
begin
for M in Freq1 loop
for N in Nmin(M) .. Nmax(M) loop
D := D+Dmax(M,N)+1;
end loop;
end loop;
return D;
end DmaxCount;
function ErrCount return Integer is
C: Integer;
begin
C := (Pdeg+1)*NumErrs(Lmax,Wmax);
for M in Freq1 loop
for N in Nmin(M) .. Nmax(M) loop
if Dmax(M,N) >= 0 then C := C+1; end if;
end loop;
end loop;
return C;
end ErrCount;
function InRange(M,N: Integer; K: Natural := 0; D: Degrees := Dmax) return Boolean is
begin
return M in Freq1 and then N in Freq2 and then K<=D(M,N);
end InRange;
procedure Component(K: Natural; H1: in Fourier; H2: out Fourier) is
E,S: Scalar;
begin
H2.P := H1.P;
H2.J := H1.J;
H2.R := H1.R;
SetZero(H2.C(0,0));
S := ScalZero;
for M in Freq1 loop
for N in Nmin(M,H1.J) .. Nmax(M) loop
ComponentSplit(K,H1.C(M,N),H2.C(M,N),E);
if not H1.P then
S := S+E*NormFactor(H1.R.Q,M,N,True);
end if;
end loop;
end loop;
if Trunc then return; end if;
if H1.P then
ResetErrComp(H2);
return;
end if;
for I in FreqE loop
ComponentSplit(K,H1.E(I),H2.E(I),E);
S := S+E;
end loop;
AddErrComp(Abs(S),H2.E(0));
end Component;
procedure SetComponent(M: in Freq1; N: in Freq2; K: in Natural; S: in Scalar; H: in out Fourier) is
--- allowing K's larger than Dmax(M,N)
begin
if InRange(M,N) and (H.J=0 or else M /= 0 or else N /= 0 or else S=ScalZero) then
SetComponent(K,S,H.C(M,N));
if K<Dho or else Err0(S) then return; end if;
H.P := False; -- S may depend on p
else
Message("Fouriers.Ops.SetComponent",Index_Error);
end if;
end SetComponent;
procedure AddComponent(M: in Freq1; N: in Freq2; K: in Natural; S: in Scalar; H: in out Fourier) is
begin
if InRange(M,N) and (H.J=0 or else M /= 0 or else N /= 0 or else S=ScalZero) then
AddComponent(K,S,H.C(M,N));
if K<Dho or else Err0(S) then return; end if;
H.P := False; -- S may depend on p
else
Message("Fouriers.Ops.AddComponent",Index_Error);
end if;
end AddComponent;
procedure SetErrComp(I: in FreqE; K: in Natural; S: in Scalar; H: in out Fourier) is
begin
if Trunc then return; end if;
if K <= Pdeg then
SetComponent(K,Ball(S),H.E(I));
if S /= ScalZero then H.P := False; end if;
else
Message("Fouriers.Ops.SetErrComp",Index_Error);
end if;
end SetErrComp;
procedure AddErrComp(I: in FreqE; P: in Taylor; H: in out Fourier) is
begin
if Trunc or else Deg(P)<0 then return; end if;
MultAdd(Ball(One),P,H.E(I));
H.P := False;
end AddErrComp;
procedure AddBall(S: in Scalar; H: in out Fourier) is
begin
if Trunc or else S=ScalZero then return; end if;
AddErrComp(Abs(S),H.E(0));
H.P := False;
end AddBall;
procedure Copy(H1: in Fourier; H2: out Fourier) is
begin
H2.P := H1.P;
H2.J := H1.J;
H2.R := H1.R;
for M in Freq1 loop
for N in Nmin(M) .. Nmax(M) loop
Copy(H1.C(M,N),H2.C(M,N));
end loop;
end loop;
if Trunc then return; end if;
for I in FreqE loop
Copy(H1.E(I),H2.E(I));
end loop;
end Copy;
procedure ZeroConstant(H: in out Fourier) is
begin
if Dho>0 then
SetComponent(0,0,0,ScalZero,H);
else
ResetCenter(H.C(0,0),0,0);
end if;
end ZeroConstant;
procedure ErrConvert(H: in Fourier; P: out Taylor) is
Dn: Integer;
begin
SetZero(P);
if Trunc then return; end if;
for I in reverse FreqE loop
MultAdd(Ball(One),H.E(I),P);
end loop;
for M in Freq1 loop
EffDeg(M,H,Dn);
for N in Nmin(M,H.J) .. Dn loop
MultAdd(Ball(NormFactor(H.R.Q,M,N)),H.C(M,N),P);
end loop;
end loop;
end ErrConvert;
procedure QDegConvert(L,W: in Positive; H: in out Fourier) is
Lt: constant Positive := Imin(L,Lmax);
Wt: constant Positive := Imin(W,Wmax);
D: Integer;
begin
for M in Freq1 loop
for N in Nmin(M) .. Nmax(M) loop
Cleanup(H.C(M,N));
if Kcut(M,N,Lt,Wt)<0 and then Deg(H.C(M,N)) >= 0 then
if not Trunc then
MultAdd(Ball(NormFactor(H.R.Q,M,N)),H.C(M,N),H.E(Ierr(M,N)));
H.P := False;
end if;
SetZero(H.C(M,N));
end if;
end loop;
end loop;
if H.P then return; end if;
D := NumErrs(Lt,Wt);
for I in D+1 .. SizeE loop
Add(H.E(I),H.E(D));
SetZero(H.E(I));
end loop;
end QDegConvert;
function Coeff(M,N: Integer; K: Natural; H: Fourier) return Scalar is
C: Scalar := ScalZero;
begin
if H.P then
if InRange(M,N) then
C := Component(K,H.C(M,N));
end if;
else
for I in 0 .. Ierr(M,N) loop
C := C+Coeff(H.R.P,K,H.E(I));
end loop;
C := Ball(C/NormFactor(H.R.Q,M,N));
if InRange(M,N) then
C := C+Coeff(H.R.P,K,H.C(M,N));
end if;
end if;
return C;
end Coeff;
procedure UpdateSavedFactors(R: in Radius) is
Fm,Fn,Pm,Pmn: Scalar;
begin
if R=SavedFactors.R then return; end if;
SavedFactors.R := R;
Fn := Exp((-R)*InvGold);
Fm := Exp(Scal(R)); --- start nonnegative m's
Pm := ScalOne;
for M in 0 .. SizeE1 loop
Pmn := Pm;
for N in FreqE2 loop
SavedFactors.C(M,N) := HalfPlus*(Pmn+Inv(Pmn));
Pmn := Pmn*Fn;
end loop;
Pm := Pm*Fm;
end loop;
Fm := Inv(Fm); --- now negative m's
Pm := Fm;
for M in reverse -SizeE1 .. -1 loop
Pmn := Pm;
for N in FreqE2 loop
SavedFactors.C(M,N) := HalfPlus*(Pmn+Inv(Pmn));
Pmn := Pmn*Fn;
end loop;
Pm := Pm*Fm;
end loop;
end UpdateSavedFactors;
function NormFactor(R: Radius; M,N: Integer; Update: in Boolean := False) return Scalar is
begin
if N<0 then
return NormFactor(R,-M,-N,Update);
elsif R=SavedFactors.R then
if M in FreqE1 and then N in FreqE2 then
return SavedFactors.C(M,N);
end if;
elsif Update then
UpdateSavedFactors(R);
end if;
return OnePlus*Cosh(R*(Scal(M)+Rep(-N)*InvGold));
end NormFactor;
function Norm(R: Weights; H: Fourier) return Scalar is
E: Scalar := ScalZero;
begin
if not H.P then
for I in reverse FreqE loop
E := E+Norm(R.P,H.E(I));
end loop;
end if;
if R.Q=SavedFactors.R then
for M in Freq1 loop
for N in Nmin(M,H.J) .. Nmax(M) loop
E := E+SavedFactors.C(M,N)*Norm(R.P,H.C(M,N));
end loop;
end loop;
return E;
end if;
declare
Fm,Fn,Pm,Pmn: Scalar;
begin
Fn := Exp((-R.Q)*InvGold);
Fm := Exp(Scal(R.Q)); ---- start nonnegative m's
Pm := ScalOne;
for M in 0 .. Size1 loop
Pmn := Pm;
for N in 0 .. Nmax(M) loop
E := E+HalfPlus*(Pmn+Inv(Pmn))*Norm(R.P,H.C(M,N));
Pmn := Pmn*Fn;
end loop;
Pm := Pm*Fm;
end loop;
Fm := Inv(Fm); ---- now negative m's
Pm := Fm;
for M in reverse -Size1 .. -1 loop
Pmn := Pm*Fn;
for N in 1 .. Nmax(M) loop
E := E+HalfPlus*(Pmn+Inv(Pmn))*Norm(R.P,H.C(M,N));
Pmn := Pmn*Fn;
end loop;
Pm := Pm*Fm;
end loop;
end;
return E;
end Norm;
function Norm(H: Fourier) return Scalar is
begin
return Norm(H.R,H);
end Norm;
function Val(Z: Scalar; H: Fourier) return Scalar is
S: Scalar := ScalZero;
begin
if H.J=1 then return ScalZero; end if;
if not H.P then
for I in reverse FreqE loop
S := S+Val(H.R.P,Ball(Z),H.E(I));
end loop;
end if;
for M in Freq1 loop
for N in Nmin(M) .. Nmax(M) loop
S:=S+Val(H.R.P,Z,H.C(M,N));
end loop;
end loop;
return S;
end Val;
function ValQ0(H: Fourier) return Taylor is
P: Taylor;
begin
SetZero(P);
if H.J=1 then return P; end if;
if not H.P then
for I in reverse FreqE loop
MultAdd(Ball(One),H.E(I),P);
end loop;
end if;
for M in Freq1 loop
for N in Nmin(M) .. Nmax(M) loop
Add(H.C(M,N),P);
end loop;
end loop;
return P;
end ValQ0;
procedure Neg(H1: in Fourier; H2: out Fourier) is
begin
H2.P := H1.P;
H2.J := H1.J;
H2.R := H1.R;
for M in Freq1 loop
for N in Nmin(M) .. Nmax(M) loop
Neg(H1.C(M,N),H2.C(M,N));
end loop;
end loop;
if Trunc then return; end if;
for I in FreqE loop
Copy(H1.E(I),H2.E(I));
end loop;
end Neg;
function "-"(H: Fourier) return Fourier is
Ht: Fourier;
begin
Neg(H,Ht);
return Ht;
end "-";
procedure Mult(S: in Scalar; H: in out Fourier) is
begin
if S = ScalZero then
SetZero(H.J,H.R,H);
return;
end if;
H.P := H.P and Err0(S); -- S may depend on p
for M in Freq1 loop
for N in Nmin(M,H.J) .. Nmax(M) loop
Mult(S,H.C(M,N));
end loop;
end loop;
if H.P then return; end if;
for I in FreqE loop
Mult(Abs(S),H.E(I));
end loop;
end Mult;
procedure Prod(S: in Scalar; H1: in Fourier; H2: out Fourier) is
begin
if S = ScalZero then
SetZero(H1.J,H1.R,H2);
return;
end if;
H2.P := H1.P and Err0(S); -- S may depend on p
H2.J := H1.J;
H2.R := H1.R;
for M in Freq1 loop
for N in Nmin(M) .. Nmax(M) loop
Prod(S,H1.C(M,N),H2.C(M,N));
end loop;
end loop;
if Trunc then return; end if;
if H1.P then
ResetErrComp(H2);
return;
end if;
for I in FreqE loop
Prod(Abs(S),H1.E(I),H2.E(I));
end loop;
end Prod;
function "*"(S: Scalar; H: Fourier) return Fourier is
Ht: Fourier;
begin
Prod(S,H,Ht);
return Ht;
end "*";
procedure Add(H1: in Fourier; H2: in out Fourier) is
begin
if H1.J /= H2.J then
Message("Fouriers.Ops.Add",Parity_Error);
end if;
H2.R := Min(H1.R,H2.R);
for M in Freq1 loop
for N in Nmin(M,H1.J) .. Nmax(M) loop
Add(H1.C(M,N),H2.C(M,N));
end loop;
end loop;
if H1.P then return; end if;
H2.P := Trunc;
for I in FreqE loop
Add(H1.E(I),H2.E(I));
end loop;
end Add;
procedure Sum(H1,H2: in Fourier; H3: out Fourier) is
begin
if H1.J /= H2.J then
Message("Fouriers.Ops.Sum",Parity_Error);
end if;
H3.P := H1.P and H2.P;
H3.J := H1.J;
H3.R := Min(H1.R,H2.R);
for M in Freq1 loop
for N in Nmin(M) .. Nmax(M) loop
Sum(H1.C(M,N),H2.C(M,N),H3.C(M,N));
end loop;
end loop;
if Trunc then return; end if;
if H3.P then
ResetErrComp(H3);
return;
end if;
for I in FreqE loop
Sum(H1.E(I),H2.E(I),H3.E(I));
end loop;
end Sum;
function "+"(H1,H2: Fourier) return Fourier is
Hr: Fourier;
begin
Sum(H1,H2,Hr);
return Hr;
end "+";
procedure Sub(H1: in Fourier; H2: in out Fourier) is
begin
if H1.J /= H2.J then
Message("Fouriers.Ops.Sub",Parity_Error);
end if;
H2.R := Min(H1.R,H2.R);
for M in Freq1 loop
for N in Nmin(M,H1.J) .. Nmax(M) loop
Sub(H1.C(M,N),H2.C(M,N));
end loop;
end loop;
if H1.P then return; end if;
H2.P := Trunc;
for I in FreqE loop
Add(H1.E(I),H2.E(I));
end loop;
end Sub;
procedure Diff(H1,H2: in Fourier; H3: out Fourier) is
begin
if H1.J /= H2.J then
Message("Fouriers.Ops.Diff",Parity_Error);
end if;
H3.P := H1.P and H2.P;
H3.J := H1.J;
H3.R := Min(H1.R,H2.R);
for M in Freq1 loop
for N in Nmin(M) .. Nmax(M) loop
Diff(H1.C(M,N),H2.C(M,N),H3.C(M,N));
end loop;
end loop;
if Trunc then return; end if;
if H3.P then
ResetErrComp(H3);
return;
end if;
for I in FreqE loop
Sum(H1.E(I),H2.E(I),H3.E(I));
end loop;
end Diff;
function "-"(H1,H2: Fourier) return Fourier is
Hr: Fourier;
begin
Diff(H1,H2,Hr);
return Hr;
end "-";
procedure MultAdd(S: in Scalar; H1: in Fourier; H2: in out Fourier) is
begin
if S=ScalZero then return; end if;
if H1.J /= H2.J then
Message("Fouriers.Ops.MultAdd",Parity_Error);
end if;
H2.P := Err0(S) and H1.P and H2.P; -- S may depend on p
H2.R := Min(H1.R,H2.R);
for M in Freq1 loop
for N in Nmin(M,H1.J) .. Nmax(M) loop
MultAdd(S,H1.C(M,N),H2.C(M,N));
end loop;
end loop;
if H1.P then return; end if;
for I in FreqE loop
MultAdd(Abs(S),H1.E(I),H2.E(I));
end loop;
end MultAdd;
procedure Iminus(L: in Degrees; H: in out Fourier) is
begin
for M in Freq1 loop
for N in Nmin(M,H.J) .. Nmax(M) loop
if L(M,N)<0 then
SetZero(H.C(M,N));
else
ResetComponent(H.C(M,N),L(M,N)+1);
end if;
end loop;
end loop;
end Iminus;
function Iminus(L: Degrees; H: Fourier) return Fourier is
Hr: Fourier;
begin
Copy(H,Hr);
Iminus(L,Hr);
return Hr;
end Iminus;
procedure Iplus(L: in Degrees; H: in out Fourier) is
begin
for M in Freq1 loop
for N in Nmin(M,1) .. Nmax(M) loop
if H.P then
ResetComponent(H.C(M,N),0,L(M,N));
else
ResetComponent(H.C(M,N),0,Imin(Dho-1,L(M,N)));
ResetCenter(H.C(M,N),Imin(Dho-1,L(M,N))+1,L(M,N));
end if;
end loop;
end loop;
end Iplus;
function Iplus(L: Degrees; H: Fourier) return Fourier is
Hr: Fourier;
begin
Copy(H,Hr);
Iplus(L,Hr);
return Hr;
end Iplus;
procedure Normalize(M,N: in Integer; M3,N3: out Integer; Flip: out Boolean) is
begin
if N<0 or else (N=0 and then M<0) then
M3 := -M; N3 := -N; Flip := True;
else
M3 := M; N3 := N; Flip := False;
end if;
end Normalize;
pragma Inline (Normalize);
procedure MultAdd(S: in Scalar; M,N: in Integer; P1: in Taylor; H2: in Fourier; H3: in out Fourier; D: in Degrees := Dmax; Monom1: in Boolean := False) is
J1: constant Parity := (H2.J+H3.J) mod 2;
Flip: Boolean;
M1,M3,N1,N3,I1: Integer;
Cp,Cm1,Cm2,F: Scalar;
begin
Normalize(M,N,M1,N1,Flip); --- (M,N) need not be inrange
if Flip and then J1=1 then
Cp := (-Half)*S;
else
Cp := Half*S;
end if;
Cm1 := Cp;
Cm2 := Cp;
if J1 < H2.J then
Cm1 := -Cp;
elsif J1 > H2.J then
Cm2 := -Cp;
elsif J1 = 1 then
Cp := -Cp;
end if;
if not Trunc then
if Min(H2.R,H3.R) /= H3.R then
Message("Fouriers.Ops.MultAdd",Domain_Violation);
end if;
H3.P := False;
UpdateSavedFactors(H3.R.Q);
end if;
for M2 in Freq1 loop
for N2 in Nmin(M2,H2.J) .. Nmax(M2) loop
if Deg(H2.C(M2,N2))>=0 then
Normalize(M1+M2,N1+N2,M3,N3,Flip);
if InRange(M3,N3) then --- frequency sum
MultAdd(H3.R.P,Cp,P1,H2.C(M2,N2),H3.C(M3,N3),D(M3,N3),Monom1);
elsif not Trunc then
F := Ball(Cp*SavedFactors.C(M3,N3));
MultAdd(H3.R.P,F,P1,H2.C(M2,N2),H3.E(Ierr(M3,N3)),Pdeg,Monom1);
end if;
Normalize(M1-M2,N1-N2,M3,N3,Flip);
if InRange(M3,N3) then --- frequency difference
if not Flip then --- 1st minus 2nd frequency
MultAdd(H3.R.P,Cm1,P1,H2.C(M2,N2),H3.C(M3,N3),D(M3,N3),Monom1);
else --- 2nd minus 1st frequency
MultAdd(H3.R.P,Cm2,P1,H2.C(M2,N2),H3.C(M3,N3),D(M3,N3),Monom1);
end if;
elsif not Trunc then
F := Ball(Cp*SavedFactors.C(M3,N3));
MultAdd(H3.R.P,F,P1,H2.C(M2,N2),H3.E(Ierr(M3,N3)),Pdeg,Monom1);
end if;
end if;
end loop;
end loop;
if H3.J=1 then
SetZero(H3.C(0,0));
end if;
if H2.P then return; end if;
if M1=0 and then N1=0 then I1 := -1; else I1 := Ierr(M1,N1); end if;
F := Ball(S*SavedFactors.C(M1,N1));
for I2 in FreqE loop
MultAdd(H3.R.P,F,P1,H2.E(I2),H3.E(Imax(0,I2-I1-1)),Pdeg,Monom1); --- add coeffs*errors
end loop;
end MultAdd;
procedure MultAdd(S: in Scalar; H1,H2: in Fourier; H3: in out Fourier; D: in Degrees := Dmax) is
I2: Integer;
F: Scalar;
begin
if not Trunc then
if Min(Min(H1.R,H2.R),H3.R) /= H3.R then
Message("Fouriers.Ops.MultAdd",Domain_Violation);
end if;
UpdateSavedFactors(H3.R.Q);
end if;
for M in Freq1 loop
for N in Nmin(M,H1.J) .. Nmax(M) loop
if Deg(H1.C(M,N))>=0 then
MultAdd(S,M,N,H1.C(M,N),H2,H3,D); --- includes coeffs*errors
end if;
end loop;
end loop;
if H1.P then return; end if;
UpdateSavedFactors(H3.R.Q);
for M in Freq1 loop
for N in Nmin(M,H2.J) .. Nmax(M) loop
if M=0 and then N=0 then I2 := -1; else I2 := Ierr(M,N); end if;
F := Ball(S*SavedFactors.C(M,N));
for I1 in FreqE loop
MultAdd(H3.R.P,F,H1.E(I1),H2.C(M,N),H3.E(Imax(0,I1-I2-1)),Pdeg); --- add errors*coeffs
end loop;
end loop;
end loop;
if H2.P then return; end if;
declare
E1,E2: Taylor;
begin
SetZero(E1);
SetZero(E2);
for I in reverse FreqE loop
Add(H1.E(I),E1);
Add(H2.E(I),E2);
end loop;
MultAdd(H3.R.P,Abs(S),E1,E2,H3.E(0),Pdeg); --- add errors*errors
end;
end MultAdd;
procedure Mult(H1: in Fourier; H2: in out Fourier) is
Ht: Fourier;
begin
Copy(H2,Ht);
SetZero((H1.J+Ht.J) mod 2,Min(H1.R,Ht.R),H2);
MultAdd(ScalOne,H1,Ht,H2);
end Mult;
procedure Prod(R: in Weights; S: in Scalar; H1,H2: in Fourier; H3: out Fourier; D: in Degrees := Dmax) is
begin
SetZero((H1.J+H2.J) mod 2,R,H3);
MultAdd(S,H1,H2,H3,D);
end Prod;
procedure Prod(R: in Weights; H1,H2: in Fourier; H3: out Fourier; D: in Degrees := Dmax) is
begin
SetZero((H1.J+H2.J) mod 2,R,H3);
MultAdd(ScalOne,H1,H2,H3,D);
end Prod;
function "*"(H1,H2: Fourier) return Fourier is
Hr: Fourier;
begin
SetZero((H1.J+H2.J) mod 2,Min(H1.R,H2.R),Hr);
MultAdd(ScalOne,H1,H2,Hr);
return Hr;
end "*";
procedure Powers(R: in Weights; H: in Fourier; Hp: in FouVecPtr) is
I: Integer;
begin
if not (H.P or else Min(R,H.R)=R) then
Message("Fouriers.Ops.Powers",Domain_Violation);
end if;
Copy(H,Hp(1));
Hp(1).R := R;
I := 1;
for K in 2 .. Hp'Last loop
Prod(R,Hp(I),Hp(K-I),Hp(K));
if I+I=K then I := K; end if;
end loop;
end Powers;
procedure Comp(IsPoly: in Boolean; R: in Radius; P: in Taylor; Hp: in FouVecPtr; Hr: out Fourier; D: in Power := Dho) is
--- Hp(K) is assumed to be the K-th power of Hp(1)
S,C,E: Scalar;
Pe: Taylor;
begin
-- TraceEnter("Comp");
SetZero(0,Hp(1).R,Hr);
if Deg(P)<0 then
-- TraceLeave;
return;
end if;
if Hp(1).J /= 0 then
Message("Fouriers.Ops.Comp",Not_Implemented);
end if;
if IsPoly then
for K in reverse 1 .. Deg(P) loop
MultAdd(Component(K,P),Hp(K),Hr);
end loop;
AddComponent(0,Component(0,P),Hr.C(0,0));
-- TraceLeave;
return;
end if;
S := Norm(Hp(1));
if Sup(S)>R then
Message("Fouriers.Ops.Comp",Domain_Violation);
end if;
for K in reverse Imax(D,1) .. Deg(P) loop
Split(Component(K,P),C,E);
MultAdd(C,Hp(K),Hr);
ErrConvert(Hp(K),Pe);
MultAdd(E,Pe,Hr.E(0));
end loop;
for K in reverse 1 .. D-1 loop
MultAdd(Component(K,P),Hp(K),Hr);
end loop;
if D=0 then
Split(Component(0,P),C,E);
AddComponent(0,C,Hr.C(0,0));
AddErrComp(E,Hr.E(0));
else
AddComponent(0,Component(0,P),Hr.C(0,0));
end if;
AddErrComp(ErrComp(P),Hr.E(0));
-- TraceLeave;
end Comp;
procedure Inv(R: in Weights; H1: in Fourier; H2: in out Fourier) is
--- just adds ball around approximate inverse H2
begin
if Trunc then return; end if;
declare
Ea,Eb,Ec,Ed: Scalar;
Ht: Fourier;
begin
Prod(R,H1,H2,Ht);
AddComponent(0,0,0,-ScalOne,Ht);
Ea := Norm(Ht);
Eb := Norm(R,H1);
Ec := Norm(R,H2)*Ea;
Ed := Two*(Ea+Eb*Ec);
if Sup(Ed)>Half or Sup(Ed+Two*Eb*Ec)>=One then
Message("Fouriers.Ops.Inv",Domain_Violation); --- to stop, use Domain_Error
end if;
H2.P := False;
AddErrComp(Ec*Inv(ScalOne-Ed),H2.E(0));
end;
end Inv;
procedure Scale(S: in Scalar; H1: in Fourier; H2: out Fourier) is
begin
H2.P := H1.P; -- S is constant
H2.J := H1.J;
H2.R := H1.R;
H2.R.P := Inf(Scal(H2.R.P)/Abs(S));
for M in Freq1 loop
for N in Nmin(M) .. Nmax(M) loop
Scale(S,H1.C(M,N),H2.C(M,N));
end loop;
end loop;
if Trunc then return; end if;
if H1.P then
ResetErrComp(H2);
return;
end if;
for I in FreqE loop
Scale(Abs(S),H1.E(I),H2.E(I));
end loop;
end Scale;
procedure Scale(S: in Scalar; H: in out Fourier) is
begin
H.R.P := Inf(Scal(H.R.P)/Abs(S));
for M in Freq1 loop
for N in Nmin(M,H.J) .. Nmax(M) loop
Scale(S,H.C(M,N));
end loop;
end loop;
if H.P then return; end if;
for I in FreqE loop
Scale(Abs(S),H.E(I));
end loop;
end Scale;
function Scale(S: Scalar; H: Fourier) return Fourier is
Hr: Fourier;
begin
Scale(S,H,Hr);
return Hr;
end Scale;
procedure ScaleRem1(Eps: in Scalar; H1: in Fourier; H2: out Fourier) is
begin
SetZero(H1.J,H1.R,H2);
H2.P := H1.P; -- Eps is a constant
for M in Freq1 loop
for N in Nmin(M,H1.J) .. Nmax(M) loop
ScaleRem1(Eps,H1.C(M,N),H2.C(M,N),H1.P);
end loop;
end loop;
end ScaleRem1;
procedure ScaleRem2(Eps: in Scalar; H1: in Fourier; H2: out Fourier) is
begin
SetZero(H1.J,H1.R,H2);
H2.P := H1.P; -- Eps is a constant
for M in Freq1 loop
for N in Nmin(M,H1.J) .. Nmax(M) loop
ScaleRem2(Eps,H1.C(M,N),H2.C(M,N),H1.P);
end loop;
end loop;
end ScaleRem2;
procedure OmegaDq(R2: in Radius; H1: in Fourier; H2: out Fourier) is
S: Scalar;
begin
H2.P := H1.P;
H2.J := 1-H1.J;
H2.R.Q := R2;
H2.R.P := H1.R.P;
for M in Freq1 loop
for N in Nmin(M,1) .. Nmax(M) loop
if H1.J = 0 then
Prod(Scal(-M)+Rep(N)*InvGold,H1.C(M,N),H2.C(M,N));
else
Prod(Scal(M)+Rep(-N)*InvGold,H1.C(M,N),H2.C(M,N));
end if;
end loop;
end loop;
SetZero(H2.C(0,0));
if Trunc then return; end if;
if H1.P then
ResetErrComp(H2);
return;
end if; -- not really used beyond this
if R2>=H1.R.Q then
Message("Fouriers.Ops.OmegaDq",Domain_Violation);
end if;
S := GammaMax(Scal(R2)/H1.R.Q,ScalZero,ScalZero);
S := S/(Exp(ScalOne)*(Scal(H1.R.Q)-Scal(R2)));
for I in FreqE loop
Prod(Abs(S),H1.E(I),H2.E(I));
end loop;
end OmegaDq;
procedure Der3(R3: in Radius; H1: in Fourier; H2: out Fourier) is
Mt: Integer;
Ft: Scalar;
begin
H2.P := H1.P;
H2.J := H1.J;
H2.R := H1.R;
for M in Freq1 loop
for N in Nmin(M) .. Nmax(M) loop
Der(H1.R.P,R3,H1.C(M,N),H2.C(M,N),H1.P);
end loop;
end loop;
H2.R.P := R3;
if Trunc then return; end if;
if H1.P then
ResetErrComp(H2);
end if;
Fmax1(Scal(R3)/H1.R.P,Mt,Ft);
Ft := Ft/R3;
for I in FreqE loop
Prod(Ft,H1.E(I),H2.E(I));
end loop;
end Der3;
function Der3(R3: Radius; H: Fourier) return Fourier is
Hr: Fourier;
begin
Der3(R3,H,Hr);
return Hr;
end Der3;
function DerVal3(Z: Scalar; H: Fourier) return Scalar is
Hd: Fourier;
begin
if H.J=1 then return ScalZero; end if;
Der3(SupAbs(Z),H,Hd);
return Val(Z,Hd);
end DerVal3;
procedure Gradient(R: in Weights; H: in Fourier; Hdq,Hdp: out Fourier) is
begin
OmegaDq(R.Q,H,Hdq);
Der3(R.P,H,Hdp);
end Gradient;
function DerDer3(H: Fourier) return Fourier is
Hr: Fourier;
begin
Copy(H,Hr);
for M in Freq1 loop
for N in Nmin(M) .. Nmax(M) loop
DerDer(Hr.C(M,N),Hr.P);
end loop;
end loop;
return Hr;
end DerDer3;
procedure Comp3(H: in Fourier; Hp3: in FouVecPtr; Hr: out Fourier) is
--- Hp3(K) is assumed to be the K-th power of Hp3(1)
R: Weights;
Hk: Fourier;
begin
TraceEnter("Comp3");
if Hp3(1).J /= 0 then
Message("Fouriers.Ops.Comp3",Not_Implemented);
end if;
R.Q := Radius'Min(H.R.Q,Hp3(1).R.Q);
R.P := Hp3(1).R.P;
SetZero(H.J,R,Hr);
if not H.P then
R.P := Sup(Norm(R,Hp3(1)));
if R.P>H.R.P then
Message("Fouriers.Ops.Comp3",Domain_Violation);
end if;
end if;
for K in reverse 1 .. Pdeg loop
Component(K,H,Hk);
MultAdd(ScalOne,Hk,Hp3(K),Hr);
end loop;
Component(0,H,Hk);
Add(Hk,Hr);
TraceLeave;
end Comp3;
procedure Comp3(H,H3: in Fourier; Hr: out Fourier) is
Hp3: FouVecPtr := new FouVec(1 .. Pdeg);
begin
Powers((Radius'Min(H.R.Q,H3.R.Q),H3.R.P),H3,Hp3);
Comp3(H,Hp3,Hr);
end Comp3;
procedure Comp3(H3: in Fourier; H: in out Fourier) is
Hr: Fourier;
Hp3: FouVecPtr := new FouVec(1 .. Pdeg);
begin
Powers((Radius'Min(H.R.Q,H3.R.Q),H3.R.P),H3,Hp3);
Comp3(H,Hp3,Hr);
Copy(Hr,H);
end Comp3;
function Comp3(H,H3: Fourier) return Fourier is
Hr: Fourier;
Hp3: FouVecPtr := new FouVec(1 .. Pdeg);
begin
Powers((Radius'Min(H.R.Q,H3.R.Q),H3.R.P),H3,Hp3);
Comp3(H,Hp3,Hr);
return Hr;
end Comp3;
procedure Comp3(H3: in Fourier; H: in FouVecPtr) is
Hr: Fourier;
Hp3: FouVecPtr := new FouVec(1 .. Pdeg);
begin
Powers((Radius'Min(H(1).R.Q,H3.R.Q),H3.R.P),H3,Hp3);
for L in H'Range loop
Comp3(H(L),Hp3,Hr);
Copy(Hr,H(L));
end loop;
end Comp3;
procedure CosSin(H: in Fourier; Hw1,Hw2,Hc,Hs: out Fourier) is
--- uses Hw1 and Hw2 as workspace only
Iter: constant Integer := 6;
Small: constant Rep := Half;
K: Natural := 0;
S,E,Ec,Es: Scalar;
begin
E := Norm(H);
while Sup(E)>Small loop
K := K+1;
E := Half*E;
end loop;
SetZero(0,H.R,Hc);
AddComponent(0,0,0,ScalOne,Hc);
S := Scal(Half**K);
Prod(S,H,Hs);
Copy(Hs,Hw1);
Ec := E**(2*Iter+1);
for I in 1 .. Iter loop -- Taylor polynomials
Prod(H.R,S,H,Hw1,Hw2);
Mult(Inv(Scal(-2*I)),Hw2);
Add(Hw2,Hc);
Prod(H.R,S,H,Hw2,Hw1);
Mult(Inv(Scal(2*I+1)),Hw1);
Add(Hw1,Hs);
Ec := Ec/Rep(2*I*(2*I+1));
end loop;
if not Trunc then
Ec := E*Ec/Rep(2*Iter+2);
Es := E*Ec/Rep(2*Iter+3);
Ec := Ec/(ScalOne-Sqr(E)/Rep((2*Iter+3)*(2*Iter+4)));
AddErrComp(Ec,Hc.E(0)); -- Remainder for Cos(H)
Es := Es/(ScalOne-Sqr(E)/Rep((2*Iter+4)*(2*Iter+5)));
AddErrComp(Es,Hs.E(0)); -- Remainder for Sin(H)
Hc.P := False;
Hs.P := False;
end if;
for I in 1 .. K loop -- double angle formula, K times
Prod(H.R,Hs,Hs,Hw1);
Prod(H.R,Hs,Hc,Hw2);
Prod(ScalTwo,Hw2,Hs);
Prod(H.R,Hc,Hc,Hw2); -- could avoid one multiplication
Diff(Hw2,Hw1,Hc);
end loop;
end CosSin;
procedure GammaGuessX(Err: in Radius; S,T,X0: in Rep; XL,XR: out Rep) is
--- Guess where Gamma takes its maximum value
use Reps.Ops;
Esx,Ex,XM,YL,YM,YR: Rep;
function DGammaSign(X: Rep) return Rep is
begin
Esx := Exp(-Two*S*X);
Ex:= Exp(-Two*X);
return Two*Ex*(One+Esx)/(One+Ex)-(T+Two*S)*Esx-T;
end DGammaSign;
begin
XR := X0;
YR := DGammaSign(XR);
if YR<=Zero then
XL := X0;
return;
end if;
while YR>Zero loop
XL := XR;
YL := YR;
XR := XL+One;
YR := DGammaSign(XR);
end loop;
while XR-XL>Err loop
XM := Half*(XL+XR);
YM := DGammaSign(XM);
if YM>Zero then
XL := XM;
YL := YM;
elsif YM<Zero then
XR := XM;
YR := YM;
else
XL := XM;
XR := XM;
return;
end if;
end loop;
end GammaGuessX;
function Gamma(S,T,X: Scalar) return Scalar is
begin
return Exp(-T*X)*(ScalOne+Exp((-Two)*S*X))/(ScalOne+Exp((-Two)*X));
end Gamma;
function GammaMax(S,T,X0: Scalar) return Scalar is
Err: constant Radius := 1.0E-6;
Eps: constant Radius := 1.0E-5;
XL,XR: Rep;
XM,Esx,Ex: Scalar;
function DGammaSign(X: Scalar) return Scalar is
begin
Esx := Exp((-Two)*S*X);
Ex:= Exp((-Two)*X);
return Two*Ex*(ScalOne+Esx)/(ScalOne+Ex)-(T+Two*S)*Esx-T;
end DGammaSign;
begin
if Inf(T)<Zero then
Message("RG_Ops.GammaMax",Parameter_Error);
end if;
if Sup(DGammaSign(X0))<Zero then
return Gamma(S,T,X0);
end if;
GammaGuessX(Err,Approx(S),Approx(T),Approx(X0),XL,XR);
XM := Scal(Half*(XR+XL))+Ball(Half*(XR-XL)+Eps);
if not Trunc and then (Inf(DGammaSign(Scal(Inf(XM))))<Zero or Sup(DGammaSign(Scal(Sup(XM))))>Zero) then
Message("RG_Ops.GammaMax",Parameter_Error);
end if;
return Gamma(S,T,XM);
end GammaMax;
procedure EffDeg(M: in Integer; H: in Fourier; Dn: out Integer) is
begin
for N in reverse Nmin(M,H.J) .. Nmax(M) loop
if not IsZero(H.C(M,N)) then
Dn := N;
return;
end if;
end loop;
Dn := -1;
end EffDeg;
procedure EffDeg(H: in Fourier; Dm: out Integer) is
begin
Dm := -1;
for M in Freq1 loop
for N in Nmin(M,H.J) .. Nmax(M) loop
if not IsZero(H.C(M,N)) then
Dm := Imax(Abs(M),Dm);
end if;
end loop;
end loop;
end EffDeg;
procedure IncCS(R: in Weights; Hc1,Hs1: in Fourier; Hwc,Hws: out Fourier; Hc2,Hs2: in out Fourier) is
--- make Hc2 := cos(H2+H1), Hs2 := sin(H2+H1)
--- from Hc1=cos(H1), Hs1=sin(H1), Hc2=cos(H2), Hs2=sin(H2)
--- uses Hwc and Hws as workspace only
begin
Copy(Hc2,Hwc);
Copy(Hs2,Hws);
Prod(R,Hc1,Hws,Hs2);
MultAdd(ScalOne,Hs1,Hwc,Hs2);
Prod(R,Hc1,Hwc,Hc2);
Multadd(-ScalOne,Hs1,Hws,Hc2);
end IncCS;
procedure UHatEtc(Hq: in Fourier; Rp,R: in Weights; SigHat,UHat: out Scalar) is
B: Weights;
begin
B.Q := Sup(Norm(R,Hq));
B.P := R.P;
SigHat := Scal(Rp.Q)-R.Q*InvGold-B.Q*InvGold;
if Inf(Rp.P*Sqr(Gold))<B.P then
Message("Fouriers.Ops.UHatEtc",Domain_Violation);
end if;
UHat := GammaMax(R.Q*InvGold/Rp.Q,SigHat/Rp.Q,ScalZero);
end UHatEtc;
procedure CompOmegaTmu0(R: in Weights; H,Hq: in Fourier; Hr: out Fourier; DoErr: in Boolean := True) is
S0: constant Scalar := -Gold-ScalOne; -- same as -Gold^2
S2: constant Scalar := -Sqr(InvGold); -- same as -1/Gold^2
Dm,Dn: Integer;
M: Freq1;
S1,SigHat,UHat: Scalar;
P: Taylor;
Hw1,Hw2,Hc1,Hs1,Hc2,Hs2,Hmc,Hms,Hmnc,Hmns: Fourier;
begin
TraceEnter("CompOmegaTmu0");
if Hq.J /= 1 then
Message("Fouriers.Ops.CompOmegaTmu0",Not_Implemented);
end if;
SetZero(H.J,R,Hr);
if DoErr and not H.P then -- could be improved with more info on H
for I in FreqE loop
Add(H.E(I),Hr.E(0));
end loop;
UHatEtc(Hq,H.R,R,SigHat,UHat); -- domains get checked here
Scale(Abs(S2),Hr.E(0));
Mult(UHat*Abs(S0),Hr.E(0));
end if;
EffDeg(H,Dm); -- looks only at H.C
if Dm<0 then
TraceLeave;
return;
end if;
S1 := Rep(2*H.J-1)*S0;
CosSin((-InvGold)*Hq,Hw1,Hw2,Hc1,Hs1);
CosSin(Sqr(InvGold)*Hq,Hw1,Hw2,Hc2,Hs2);
SetZero(0,R,Hmc);
SetComponent(0,0,0,ScalOne,Hmc);
SetZero(1,R,Hms);
for Mabs in 0 .. Dm loop
if Mabs>0 then
IncCS(R,Hc1,Hs1,Hw1,Hw2,Hmc,Hms);
end if;
for I in 0 .. 1 loop
M := (2*I-1)*Mabs;
Hms := -Hms;
if M<0 or else I=1 then
Copy(Hmc,Hmnc);
Copy(Hms,Hmns);
EffDeg(M,H,Dn);
for N in Nmin(M,H.J) .. Dn loop
if N > 0 then
IncCS(R,Hc2,Hs2,Hw1,Hw2,Hmnc,Hmns);
end if;
Scale(S2,H.C(M,N),P);
MultAdd(S0,N,M+N,P,Hmnc,Hr);
MultAdd(S1,N,M+N,P,Hmns,Hr);
end loop;
end if;
end loop;
end loop;
TraceLeave;
end CompOmegaTmu0;
procedure CompOmegaTmu0(R: in Weights; H: in FouVecPtr; Hq: in Fourier; Hr: in FouVecPtr; DoErr: in Boolean := True) is
--- R.P does not enter directly
Lf: constant Positive := Imin(H'Last,Hr'Last);
S0: constant Scalar := -Gold-ScalOne; -- same as -Gold^2
S2: constant Scalar := Gold-ScalTwo; -- same as -1/Gold^2
Dt,Dm,Dn: Integer;
M: Freq1;
S1,SigHat,UHat: Scalar;
P: Taylor;
Hw1,Hw2,Hc1,Hs1,Hc2,Hs2,Hmc,Hms,Hmnc,Hmns: Fourier;
begin
TraceEnter("CompOmegaTmu0");
if Hq.J /= 1 then
Message("Fouriers.Ops.CompOmegaTmu0",Not_Implemented);
end if;
for L in 1 .. Lf loop
SetZero(H(L).J,R,Hr(L));
if DoErr and not H(L).P then -- can be improved with more info on H
for I in FreqE loop
Add(H(L).E(I),Hr(L).E(0));
end loop;
UHatEtc(Hq,H(L).R,R,SigHat,UHat);
Scale(Abs(S2),Hr(L).E(0));
Mult(UHat*Abs(S0),Hr(L).E(0));
end if;
end loop;
Dm := -1;
for L in 1 .. Lf loop
EffDeg(H(L),Dt); -- looks only at H(L).C
Dm := IMax(Dm,Dt);
end loop;
if Dm<0 then
TraceLeave;
return;
end if;
CosSin((-InvGold)*Hq,Hw1,Hw2,Hc1,Hs1);
CosSin(Sqr(InvGold)*Hq,Hw1,Hw2,Hc2,Hs2);
SetZero(0,R,Hmc);
SetComponent(0,0,0,ScalOne,Hmc);
SetZero(1,R,Hms);
for Mabs in 0 .. Dm loop
if Mabs>0 then
IncCS(R,Hc1,Hs1,Hw1,Hw2,Hmc,Hms);
end if;
for I in 0 .. 1 loop
M := (2*I-1)*Mabs;
Hms := -Hms;
if M<0 or else I=1 then
Copy(Hmc,Hmnc);
Copy(Hms,Hmns);
Dn := -1;
for L in 1 .. Lf loop
EffDeg(M,H(L),Dt);
Dn := IMax(Dn,Dt);
end loop;
for N in Nmin(M) .. Dn loop
if N > 0 then
IncCS(R,Hc2,Hs2,Hw1,Hw2,Hmnc,Hmns);
end if;
for L in 1 .. Lf loop
Scale(S2,H(L).C(M,N),P);
S1 := Scal(2*H(L).J-1)*S0;
MultAdd(S0,N,M+N,P,Hmnc,Hr(L));
MultAdd(S1,N,M+N,P,Hmns,Hr(L));
end loop;
end loop;
end if;
end loop;
end loop;
TraceLeave;
end CompOmegaTmu0;
procedure CompOmega3(H1,H2: in Fourier; Hq,Hp: in Fourier; H3,H4: out Fourier) is
--- p-domains get checked in Comp
Rg: constant Weights := Min(Hq.R,Hp.R);
D1,D2,Dm,Dn: Integer;
M: Freq1;
S: Radius;
P: Taylor;
Hw1,Hw2,Hc1,Hs1,Hc2,Hs2,Hmc,Hms,Hmnc,Hmns: Fourier;
Hpp: FouVecPtr := new FouVec(1 .. Pdeg);
begin
TraceEnter("CompOmega3 fff");
if (Hq.J /= 1) or (Hp.J /= 0) then
Message("Fouriers.Ops.CompOmega3",Not_Implemented);
end if;
SetZero(H1.J,Rg,H3);
SetZero(H2.J,Rg,H4);
Powers(Rg,Hp,Hpp);
S := Sup(Scal(Rg.Q)+Norm(Rg,Hq));
if not H1.P then
if H1.R.Q<S then
Message("Fouriers.Ops.CompOmega3",Domain_Violation);
end if;
SetZero(P);
for I in FreqE loop
Add(H1.E(I),P);
end loop;
Mult(Ball(One),P);
Comp(False,H1.R.P,P,Hpp,Hw1,0); -- non-coherent addition
Hw1.J := H1.J; -- since P has parity of H1
MultAdd(GammaMax(Scal(Rg.Q)/H1.R.Q,ScalZero,ScalZero),Hw1,H3);
end if;
if not H2.P then
if H2.R.Q<S then
Message("Fouriers.Ops.CompOmega3",Domain_Violation);
end if;
SetZero(P);
for I in FreqE loop
Add(H2.E(I),P);
end loop;
Mult(Ball(One),P);
Comp(False,H2.R.P,P,Hpp,Hw2,0); -- non-coherent addition
Hw2.J := H2.J; -- since P has parity of H2
MultAdd(GammaMax(Scal(Rg.Q)/H2.R.Q,ScalZero,ScalZero),Hw2,H4);
end if;
EffDeg(H1,D1);
EffDeg(H2,D2);
Dm := Imax(D1,D2);
if Dm<0 then
TraceLeave;
return;
end if;
CosSin(Hq,Hw1,Hw2,Hc1,Hs1);
CosSin((-InvGold)*Hq,Hw1,Hw2,Hc2,Hs2);
SetZero(0,Rg,Hmc);
SetComponent(0,0,0,ScalOne,Hmc);
SetZero(1,Rg,Hms);
for Mabs in 0 .. Dm loop
if Mabs>0 then
IncCS(Rg,Hc1,Hs1,Hw1,Hw2,Hmc,Hms);
end if;
for I in 0 .. 1 loop
M := (2*I-1)*Mabs;
Hms := -Hms;
if M<0 or else I=1 then
Hmnc := Hmc;
Hmns := Hms;
EffDeg(M,H1,D1);
EffDeg(M,H2,D2);
Dn := Imax(D1,D2);
for N in Nmin(M) .. Dn loop
if N>0 then
IncCS(Rg,Hc2,Hs2,Hw1,Hw2,Hmnc,Hmns);
end if;
SetZero(P);
SetComponent(0,ScalOne,P);
SetZero(H1.J,Rg,Hw1);
MultAdd(ScalOne,M,N,P,Hmnc,Hw1);
MultAdd(Scal(2*H1.J-1),M,N,P,Hmns,Hw1);
Comp(H1.P,H1.R.P,H1.C(M,N),Hpp,Hw2);
MultAdd(ScalOne,Hw1,Hw2,H3);
SetZero(H2.J,Rg,Hw1);
MultAdd(ScalOne,M,N,P,Hmnc,Hw1);
MultAdd(Scal(2*H2.J-1),M,N,P,Hmns,Hw1);
Comp(H2.P,H2.R.P,H2.C(M,N),Hpp,Hw2);
MultAdd(ScalOne,Hw1,Hw2,H4);
end loop;
end if;
end loop;
end loop;
TraceLeave;
end CompOmega3;
procedure ZxDer3(H1: in Fourier; H2: out Fourier) is
begin
H2.P := H1.P;
H2.J := H1.J;
H2.R := H1.R;
for M in Freq1 loop
for N in Nmin(M) .. Nmax(M) loop
ZxDer(H1.C(M,N),H2.C(M,N),H1.P);
end loop;
end loop;
if Trunc then return; end if;
ResetErrComp(H2);
end ZxDer3;
procedure DqDot(S1,S2: in Scalar; H: in out Fourier) is
begin
if not H.P then
Message("Fouriers.Ops.DqDot",Not_Implemented);
end if;
H.J := 1-H.J;
for M in Freq1 loop
for N in Nmin(M,1) .. Nmax(M) loop
if H.J = 0 then
Mult(Rep(-M)*S1+Rep(-N)*S2,H.C(M,N));
else
Mult(Rep(M)*S1+Rep(N)*S2,H.C(M,N));
end if;
end loop;
end loop;
SetZero(H.C(0,0));
end DqDot;
procedure Gig(Sig: in Rep; H: in out Fourier) is
-- Sig defines a cutoff a la Iminus, unless H.P
begin
if not IsZero(H.C(0,0)) then
Message("Fouriers.Ops.Gig",Domain_Violation);
end if;
for M in Freq1 loop
for N in Nmin(M,1) .. Nmax(M) loop
if Deg(H.C(M,N))>=0 then
Mult((Scal(M)+Rep(-N)*InvGold)/(Rep(M)*InvGold+Scal(N)),H.C(M,N));
end if;
end loop;
end loop;
SetZero(H.C(0,0));
if H.P then return; end if;
for I in FreqE loop
Mult(ScalOne/Sig,H.E(I)); -- operator_norm <= 1/Sig
end loop;
end Gig;
procedure Gig(Sig: in Rep; H1: in Fourier; H2: out Fourier) is
-- Sig defines a cutoff a la Iminus, unless H1.P
begin
if not IsZero(H1.C(0,0)) then
Message("Fouriers.Ops.Gig",Domain_Violation);
end if;
H2.P := H1.P;
H2.J := H1.J;
H2.R := H1.R;
for M in Freq1 loop
for N in Nmin(M,1) .. Nmax(M) loop
if Deg(H1.C(M,N))>=0 then
Prod((Scal(M)+Rep(-N)*InvGold)/(Rep(M)*InvGold+Scal(N)),H1.C(M,N),H2.C(M,N));
else
SetZero(H2.C(M,N));
end if;
end loop;
end loop;
SetZero(H2.C(0,0));
if Trunc then return; end if;
if H1.P then
ResetErrComp(H2);
return;
end if;
for I in FreqE loop
Prod(ScalOne/Sig,H1.E(I),H2.E(I)); -- operator_norm <= 1/Sig
end loop;
end Gig;
function Gig(Sig: in Rep; H: Fourier) return Fourier is
Hr: Fourier;
begin
Gig(Sig,H,Hr);
return Hr;
end Gig;
procedure Dig(Kap: in Rep; H: in out Fourier) is
-- Kap defines a cutoff a la Iminus, unless H.P
KapInv: constant Radius := SupAbs(ScalOne/Kap);
begin
if not IsZero(H.C(0,0)) then
Message("Fouriers.Ops.Dig",Domain_Violation);
end if;
if H.J /= 0 then
Message("Fouriers.Ops.Dig",Not_Implemented);
end if;
H.J := 1;
for M in Freq1 loop
for N in Nmin(M,1) .. Nmax(M) loop
DerMult(H.R.P,KapInv,Inv(Rep(M)*InvGold+Scal(N)),H.C(M,N),H.P);
end loop;
end loop;
SetZero(H.C(0,0));
if H.P then return; end if;
for I in FreqE loop
DerMult(H.R.P,KapInv,ScalOne/Kap,H.E(I));
end loop;
end Dig;
procedure Dig(Kap: in Rep; H1: in Fourier; H2: out Fourier) is
-- Kap defines a cutoff a la Iminus, unless H1.P
KapInv: constant Radius := SupAbs(ScalOne/Kap);
begin
if not IsZero(H1.C(0,0)) then
Message("Fouriers.Ops.Dig",Domain_Violation);
end if;
if H1.J /= 0 then
Message("Fouriers.Ops.Dig",Not_Implemented);
end if;
H2.P := H1.P;
H2.J := 1;
H2.R := H1.R;
for M in Freq1 loop
for N in Nmin(M,1) .. Nmax(M) loop
DerProd(H1.R.P,KapInv,Inv(Rep(M)*InvGold+Scal(N)),H1.C(M,N),H2.C(M,N),H1.P);
end loop;
end loop;
SetZero(H2.C(0,0));
if Trunc then return; end if;
if H1.P then
ResetErrComp(H2);
return;
end if;
for I in FreqE loop
DerProd(H1.R.P,KapInv,ScalOne/Kap,H1.E(I),H2.E(I));
end loop;
end Dig;
function Dig(Kap: in Rep; H: Fourier) return Fourier is
Hr: Fourier;
begin
Dig(Kap,H,Hr);
return Hr;
end Dig;
--- sobolev stuff
procedure SetComponent(M: in Freq1; N: in Freq2; S: in Scalar; H: in out Sobolev) is
begin
if InRange(M,N) and (H.J=0 or else M /= 0 or else N /= 0 or else S=ScalZero) then
H.C(M,N) := S;
else
Message("Fouriers.Ops.SetComponent",Index_Error);
end if;
end SetComponent;
procedure AddComponent(M: in Freq1; N: in Freq2; S: in Scalar; H: in out Sobolev) is
begin
if InRange(M,N) and (H.J=0 or else M /= 0 or else N /= 0 or else S=ScalZero) then
H.C(M,N) := H.C(M,N)+S;
else
Message("Fouriers.Ops.AddComponent",Index_Error);
end if;
end AddComponent;
procedure AddErrComp(I: in FreqE; S: in Scalar; H: in out Sobolev) is
begin
if Trunc then return; end if;
H.E(I) := H.E(I)+Abs(S);
end AddErrComp;
procedure AddBall(S: in Scalar; H: in out Sobolev) is
begin
if Trunc or else S=ScalZero then return; end if;
H.E(0) := H.E(0)+Abs(S);
end AddBall;
function Coeff(M,N: Integer; H: Sobolev) return Scalar is
C: Scalar := ScalZero;
begin
if not Trunc then
for I in 0 .. Ierr(M,N) loop
C := C+H.E(I);
end loop;
C := Ball(C/NormFactor2(H.R,M,N));
end if;
if InRange(M,N) then
C := C+H.C(M,N);
end if;
return C;
end Coeff;
procedure ZeroConstant(H: in out Sobolev) is
begin
H.C(0,0) := ScalZero;
end ZeroConstant;
procedure UpdateSavedFactors2(R: in Radius) is
begin
if R=SavedFactors2.R then return; end if;
SavedFactors2.R := R;
for M in FreqE1 loop
for N in FreqE2 loop
SavedFactors2.C(M,N) := OnePlus*Exp(R*Log(ScalOne+Abs(Scal(M)+Rep(-N)*InvGold)));
end loop;
end loop;
end UpdateSavedFactors2;
function NormFactor2(R: Radius; M,N: Integer; Update: in Boolean := False) return Scalar is
begin
if N<0 then
return NormFactor2(R,-M,-N,Update);
elsif R=SavedFactors2.R then
if M in FreqE1 and then N in FreqE2 then
return SavedFactors2.C(M,N);
end if;
elsif Update then
UpdateSavedFactors2(R);
end if;
return OnePlus*Exp(R*Log(ScalOne+Abs(Scal(M)+Rep(-N)*InvGold)));
end NormFactor2;
function Norm(R: Radius; H: Sobolev) return Scalar is
E: Scalar := ScalZero;
begin
if not Trunc then
for I in FreqE loop
E := E+H.E(I);
end loop;
end if;
if R=SavedFactors2.R then
for M in Freq1 loop
for N in Nmin(M,H.J) .. Nmax(M) loop
E := E+SavedFactors2.C(M,N)*Abs(H.C(M,N));
end loop;
end loop;
else
for M in Freq1 loop
for N in Nmin(M,H.J) .. Nmax(M) loop
E := E+OnePlus*Exp(R*Log(ScalOne+Abs(Scal(M)+Rep(-N)*InvGold)))*Abs(H.C(M,N));
end loop;
end loop;
end if;
return E;
end Norm;
function Norm(H: Sobolev) return Scalar is
begin
return Norm(H.R,H);
end Norm;
procedure Neg(H1: in Sobolev; H2: out Sobolev) is
begin
H2.J := H1.J;
H2.R := H1.R;
for M in Freq1 loop
for N in Nmin(M) .. Nmax(M) loop
H2.C(M,N) := -H1.C(M,N);
end loop;
end loop;
if Trunc then return; end if;
H2.E := H1.E;
end Neg;
function "-"(H: Sobolev) return Sobolev is
Ht: Sobolev;
begin
Neg(H,Ht);
return Ht;
end "-";
procedure Mult(S: in Scalar; H: in out Sobolev) is
begin
for M in Freq1 loop
for N in Nmin(M) .. Nmax(M) loop
H.C(M,N) := S*H.C(M,N);
end loop;
end loop;
if Trunc then return; end if;
for I in FreqE loop
H.E(I) := Abs(S)*H.E(I);
end loop;
end Mult;
procedure Prod(S: in Scalar; H1: in Sobolev; H2: out Sobolev) is
begin
H2.J := H1.J;
H2.R := H1.R;
for M in Freq1 loop
for N in Nmin(M) .. Nmax(M) loop
H2.C(M,N) := S*H1.C(M,N);
end loop;
end loop;
if Trunc then return; end if;
for I in FreqE loop
H2.E(I) := Abs(S)*H1.E(I);
end loop;
end Prod;
function "*"(S: Scalar; H: Sobolev) return Sobolev is
Ht: Sobolev;
begin
Prod(S,H,Ht);
return Ht;
end "*";
procedure Add(H1: in Sobolev; H2: in out Sobolev) is
begin
if H1.J /= H2.J then
Message("Fouriers.Ops.Add",Parity_Error);
end if;
H2.R := Radius'Min(H1.R,H2.R);
for M in Freq1 loop
for N in Nmin(M) .. Nmax(M) loop
H2.C(M,N) := H2.C(M,N)+H1.C(M,N);
end loop;
end loop;
if Trunc then return; end if;
for I in FreqE loop
H2.E(I) := H2.E(I)+H1.E(I);
end loop;
end Add;
procedure Sum(H1,H2: in Sobolev; H3: out Sobolev) is
begin
if H1.J /= H2.J then
Message("Fouriers.Ops.Sum",Parity_Error);
end if;
H3.J := H1.J;
H3.R := Radius'Min(H1.R,H2.R);
for M in Freq1 loop
for N in Nmin(M) .. Nmax(M) loop
H3.C(M,N) := H1.C(M,N)+H2.C(M,N);
end loop;
end loop;
if Trunc then return; end if;
for I in FreqE loop
H3.E(I) := H1.E(I)+H2.E(I);
end loop;
end Sum;
function "+"(H1,H2: Sobolev) return Sobolev is
Hr: Sobolev;
begin
Sum(H1,H2,Hr);
return Hr;
end "+";
procedure Sub(H1: in Sobolev; H2: in out Sobolev) is
begin
if H1.J /= H2.J then
Message("Fouriers.Ops.Sub",Parity_Error);
end if;
H2.R := Radius'Min(H1.R,H2.R);
for M in Freq1 loop
for N in Nmin(M) .. Nmax(M) loop
H2.C(M,N) := H2.C(M,N)-H1.C(M,N);
end loop;
end loop;
if Trunc then return; end if;
for I in FreqE loop
H2.E(I) := H2.E(I)+H1.E(I);
end loop;
end Sub;
procedure Diff(H1,H2: in Sobolev; H3: out Sobolev) is
begin
if H1.J /= H2.J then
Message("Fouriers.Ops.Diff",Parity_Error);
end if;
H3.J := H1.J;
H3.R := Radius'Min(H1.R,H2.R);
for M in Freq1 loop
for N in Nmin(M) .. Nmax(M) loop
H3.C(M,N) := H1.C(M,N)-H2.C(M,N);
end loop;
end loop;
if Trunc then return; end if;
for I in FreqE loop
H3.E(I) := H1.E(I)+H2.E(I);
end loop;
end Diff;
function "-"(H1,H2: Sobolev) return Sobolev is
Hr: Sobolev;
begin
Diff(H1,H2,Hr);
return Hr;
end "-";
procedure MultAdd(S: in Scalar; H1: in Sobolev; H2: in out Sobolev) is
begin
if S=ScalZero then return; end if;
if H1.J /= H2.J then
Message("Fouriers.Ops.MultAdd",Parity_Error);
end if;
H2.R := Radius'Min(H1.R,H2.R);
for M in Freq1 loop
for N in Nmin(M) .. Nmax(M) loop
H2.C(M,N) := H2.C(M,N)+S*H1.C(M,N);
end loop;
end loop;
if Trunc then return; end if;
for I in FreqE loop
H2.E(I) := H2.E(I)+Abs(S)*H1.E(I);
end loop;
end MultAdd;
procedure MultAdd(S1: in Scalar; M,N: in Integer; H2: in Sobolev; H3: in out Sobolev) is
J1: constant Parity := (H2.J+H3.J) mod 2;
Flip: Boolean;
M1,M3,N1,N3,I1,I3: Integer;
Cp,Cm1,Cm2,F: Scalar;
begin
if S1=ScalZero then return; end if;
Normalize(M,N,M1,N1,Flip); --- (M,N) need not be inrange
if Flip and then J1=1 then
Cp := (-Half)*S1;
else
Cp := Half*S1;
end if;
Cm1 := Cp;
Cm2 := Cp;
if J1 < H2.J then
Cm1 := -Cp;
elsif J1 > H2.J then
Cm2 := -Cp;
elsif J1 = 1 then
Cp := -Cp;
end if;
if not Trunc then
if H3.R > H2.R then
Message("Fouriers.Ops.MultAdd",Domain_Violation);
end if;
UpdateSavedFactors2(H3.R);
end if;
for M2 in Freq1 loop
for N2 in Nmin(M2,H2.J) .. Nmax(M2) loop
if H2.C(M2,N2) /= ScalZero then
Normalize(M1+M2,N1+N2,M3,N3,Flip);
if InRange(M3,N3) then --- frequency sum
H3.C(M3,N3) := H3.C(M3,N3)+Cp*H2.C(M2,N2);
elsif not Trunc then
I3 := Ierr(M3,N3);
H3.E(I3) := H3.E(I3)+Abs(Cp*H2.C(M2,N2))*SavedFactors2.C(M3,N3);
end if;
Normalize(M1-M2,N1-N2,M3,N3,Flip);
if InRange(M3,N3) then --- frequency difference
if not Flip then --- 1st minus 2nd frequency
H3.C(M3,N3) := H3.C(M3,N3)+Cm1*H2.C(M2,N2);
else --- 2nd minus 1st frequency
H3.C(M3,N3) := H3.C(M3,N3)+Cm2*H2.C(M2,N2);
end if;
elsif not Trunc then
I3 := Ierr(M3,N3);
H3.E(I3) := H3.E(I3)+Abs(Cp*H2.C(M2,N2))*SavedFactors2.C(M3,N3);
end if;
end if;
end loop;
end loop;
if H3.J=1 then
H3.C(0,0) := ScalZero;
end if;
if Trunc then return; end if;
if M1=0 and then N1=0 then I1 := -1; else I1 := Ierr(M1,N1); end if;
F := Abs(S1)*SavedFactors2.C(M1,N1);
for I2 in FreqE loop
I3 := Imax(0,I2-I1-1);
H3.E(I3) := H3.E(I3)+F*H2.E(I2); --- add coeff*errors
end loop;
end MultAdd;
procedure MultAdd(S: in Scalar; H1,H2: in Sobolev; H3: in out Sobolev) is
I2,I3: Integer;
F: Scalar;
E1,E2: Scalar := ScalZero;
begin
if not Trunc then
if (H3.R > H1.R) or (H3.R > H2.R) then
Message("Fouriers.Ops.MultAdd",Domain_Violation);
end if;
UpdateSavedFactors2(H3.R);
end if;
for M in Freq1 loop
for N in Nmin(M,H1.J) .. Nmax(M) loop
if H1.C(M,N) /= ScalZero then
MultAdd(S*H1.C(M,N),M,N,H2,H3); --- includes coeffs*errors
end if;
end loop;
end loop;
if Trunc then return; end if;
UpdateSavedFactors2(H3.R);
for M in Freq1 loop
for N in Nmin(M,H2.J) .. Nmax(M) loop
if M=0 and then N=0 then I2 := -1; else I2 := Ierr(M,N); end if;
F := Abs(S*H2.C(M,N))*SavedFactors2.C(M,N);
for I1 in FreqE loop
I3 := Imax(0,I1-I2-1);
H3.E(I3) := H3.E(I3)+H1.E(I1)*F; --- add errors*coeffs
end loop;
end loop;
end loop;
for I in reverse FreqE loop
E1 := E1+H1.E(I);
E2 := E2+H2.E(I);
end loop;
H3.E(0) := H3.E(0)+Abs(S)*E1*E2; --- add errors*errors
end MultAdd;
procedure Mult(H1: in Sobolev; H2: in out Sobolev) is
Ht: Sobolev;
begin
Ht := H2;
SetZero((H1.J+Ht.J) mod 2,Radius'Min(H1.R,Ht.R),H2);
MultAdd(ScalOne,H1,Ht,H2);
end Mult;
procedure Prod(S: in Scalar; H1,H2: in Sobolev; H3: out Sobolev) is
begin
SetZero((H1.J+H2.J) mod 2,Radius'Min(H1.R,H2.R),H3);
MultAdd(S,H1,H2,H3);
end Prod;
procedure Prod(H1,H2: in Sobolev; H3: out Sobolev) is
begin
SetZero((H1.J+H2.J) mod 2,Radius'Min(H1.R,H2.R),H3);
MultAdd(ScalOne,H1,H2,H3);
end Prod;
function "*"(H1,H2: Sobolev) return Sobolev is
Hr: Sobolev;
begin
SetZero((H1.J+H2.J) mod 2,Radius'Min(H1.R,H2.R),Hr);
MultAdd(ScalOne,H1,H2,Hr);
return Hr;
end "*";
procedure Powers(H: in Sobolev; Hp: in SobVecPtr) is
I: Integer;
begin
if H.J /= 0 then
Message("Fouriers.Ops.Powers", Parity_Error);
end if;
Hp(1) := H;
I := 1;
for K in 2 .. Hp'Last loop
Prod(Hp(I),Hp(K-I),Hp(K));
if I+I=K then I := K; end if;
end loop;
end Powers;
procedure Comp(IsPoly: in Boolean; R: in Radius; P: in Taylor; Hp: in SobVecPtr; Hr: out Sobolev) is
--- Hp(K) is assumed to be the K-th power of Hp(1)
S,C,E: Scalar;
begin
-- TraceEnter("Comp");
SetZero(0,Hp(1).R,Hr);
if Deg(P)<0 then
-- TraceLeave;
return;
end if;
if Hp(1).J /= 0 then
Message("Fouriers.Ops.Comp",Not_Implemented);
end if;
if IsPoly then
for K in reverse 1 .. Deg(P) loop
MultAdd(Component(K,P),Hp(K),Hr);
end loop;
Hr.C(0,0) := Hr.C(0,0)+Component(0,P);
-- TraceLeave;
return;
end if;
S := Norm(Hp(1));
if Sup(S)>R then
Message("Fouriers.Ops.Comp",Domain_Violation);
end if;
for K in reverse Imax(Dho,1) .. Deg(P) loop
Split(Component(K,P),C,E);
MultAdd(C,Hp(K),Hr);
Hr.E(0) := Hr.E(0)+SupAbs(E)*(S**K);
end loop;
for K in reverse 1 .. Dho-1 loop
MultAdd(Component(K,P),Hp(K),Hr);
end loop;
if Dho=0 then
Split(Component(0,P),C,E);
Hr.C(0,0) := Hr.C(0,0)+C;
Hr.E(0) := Hr.E(0)+Abs(E);
else
Hr.C(0,0) := Hr.C(0,0)+Component(0,P);
end if;
Hr.E(0) := Hr.E(0)+ErrComp(P);
-- TraceLeave;
end Comp;
procedure CompTinv(H1: in Sobolev; H2: out Sobolev) is
-- errors->errors estimate not optimal
M2,N2,I2: Integer;
Flip: Boolean;
begin
SetZero(H1.J,H1.R,H2);
for M1 in Freq1 loop
for N1 in Nmin(M1,H1.J) .. Nmax(M1) loop
Normalize(N1-M1,M1,M2,N2,Flip);
if InRange(M2,N2) then
if Flip and then H1.J=1 then
H2.C(M2,N2) := -H1.C(M1,N1);
else
H2.C(M2,N2) := H1.C(M1,N1);
end if;
elsif not Trunc then
I2 := Ierr(M2,N2);
H2.E(I2) := H2.E(I2)+Abs(H1.C(M1,N1))*NormFactor2(H1.R,M2,N2);
end if;
end loop;
end loop;
if Trunc then return; end if;
for I1 in FreqE loop
I2 :=IntCeiling(Rep(I1)*InvGold);
H2.E(I2) := Gold*H1.E(I1);
end loop;
end CompTinv;
procedure CosSin(H: in Sobolev; Hw1,Hw2,Hc,Hs: out Sobolev) is
--- uses Hw1 and Hw2 as workspace only
Iter: constant Integer := 6;
Small: constant Rep := Half;
K: Natural := 0;
S,E,Ec,Es: Scalar;
begin
E := Norm(H);
while Sup(E)>Small loop
K := K+1;
E := Half*E;
end loop;
SetZero(0,H.R,Hc);
Hc.C(0,0) := Hc.C(0,0)+ScalOne;
S := Scal(Half**K);
Prod(S,H,Hs);
Hw1 := Hs;
Ec := E**(2*Iter+1);
for I in 1 .. Iter loop -- Taylor polynomials
Prod(S,H,Hw1,Hw2);
Mult(Inv(Scal(-2*I)),Hw2);
Add(Hw2,Hc);
Prod(S,H,Hw2,Hw1);
Mult(Inv(Scal(2*I+1)),Hw1);
Add(Hw1,Hs);
Ec := Ec/Rep(2*I*(2*I+1));
end loop;
if not Trunc then
Ec := E*Ec/Rep(2*Iter+2);
Es := E*Ec/Rep(2*Iter+3);
Ec := Ec/(ScalOne-Sqr(E)/Rep((2*Iter+3)*(2*Iter+4)));
Hc.E(0) := Hc.E(0)+Ec; -- Remainder for Cos(H)
Es := Es/(ScalOne-Sqr(E)/Rep((2*Iter+4)*(2*Iter+5)));
Hs.E(0) := Hs.E(0)+Es; -- Remainder for Sin(H)
end if;
for I in 1 .. K loop -- double angle formula, K times
Prod(Hs,Hs,Hw1);
Prod(Hs,Hc,Hw2);
Prod(ScalTwo,Hw2,Hs);
Prod(Hc,Hc,Hw2); -- could avoid one multiplication
Diff(Hw2,Hw1,Hc);
end loop;
end CosSin;
procedure BetaGuessX(Err: in Radius; S,Rq,R: in Rep; XL,XR: out Rep) is
--- Guess where Beta takes its maximum value
use Reps.Ops;
F: constant Rep := 1.2;
X0,XM,YL,YM,YR: Rep;
function DBetaSign(X: Rep) return Rep is
begin
return (S+R/(One+X))*Cosh(Rq*X)-Rq*Sinh(Rq*X);
end DBetaSign;
begin
X0 := Log((Rq+S)/(Rq-S))/(Two*Rq); -- minimizer when R=0
XR := X0;
YR := DBetaSign(XR);
while YR>Zero loop
XR := XR*F;
YR := DBetaSign(XR);
end loop;
XL := X0;
YL := DBetaSign(XL);
while YL<Zero loop
XL := XL/F;
YL := DBetaSign(XL);
end loop;
while XR-XL>Err loop
XM := Half*(XL+XR);
YM := DBetaSign(XM);
if YM>Zero then
XL := XM;
YL := YM;
elsif YM<Zero then
XR := XM;
YR := YM;
else
XL := XM;
XR := XM;
return;
end if;
end loop;
end BetaGuessX;
function Beta(Rq,R: Rep; S,T: Scalar) return Scalar is
begin
return Exp(R*Log(ScalOne+T)+S*T)/Cosh(Rq*T);
end Beta;
function BetaMax(Rq,R: Rep; S: Scalar) return Scalar is
Err: constant Radius := 1.0E-5;
Eps: constant Radius := 1.0E-4;
XL,XR: Rep;
XM: Scalar;
function DBetaSign(X: Scalar) return Scalar is
begin
return (S+R*Inv(ScalOne+X))*Cosh(Rq*X)-Rq*Sinh(Rq*X);
end DBetaSign;
begin
if Sup(S) >= Rq then
Message("RG_Ops.BetaMax 1",Parameter_Error);
end if;
BetaGuessX(Err,Approx(S),Rq,R,XL,XR);
XM := Scal(Half*(XR+XL))+Ball(Half*(XR-XL)+Eps);
if not Trunc and then (Inf(DBetaSign(Scal(Inf(XM))))<Zero or Sup(DBetaSign(Scal(Sup(XM))))>Zero) then
Message("RG_Ops.BetaMax 2",Parameter_Error);
end if;
return Beta(Rq,R,S,XM);
end BetaMax;
procedure IncCS(Hc1,Hs1: in Sobolev; Hwc,Hws: out Sobolev; Hc2,Hs2: in out Sobolev) is
--- make Hc2 := cos(H2+H1), Hs2 := sin(H2+H1)
--- from Hc1=cos(H1), Hs1=sin(H1), Hc2=cos(H2), Hs2=sin(H2)
--- uses Hwc and Hws as workspace only
begin
Hwc := Hc2;
Hws := Hs2;
Prod(Hc1,Hws,Hs2);
MultAdd(ScalOne,Hs1,Hwc,Hs2);
Prod(Hc1,Hwc,Hc2);
Multadd(-ScalOne,Hs1,Hws,Hc2);
end IncCS;
procedure CompOmega3(H1,H2: in Fourier; Gq,Gp: in Sobolev; G1,G2: out Sobolev) is
--- domains get checked in Comp and BetaMax
Rg: constant Radius := Radius'Min(Gq.R,Gp.R);
D1,D2,Dm,Dn: Integer;
M: Freq1;
S: Radius;
Gw1,Gw2,Gc1,Gs1,Gc2,Gs2,Gmc,Gms,Gmnc,Gmns: Sobolev;
Gpp: SobVecPtr := new SobVec(1 .. Pdeg);
begin
TraceEnter("CompOmega3 fss");
if (Gq.J /= 1) or (Gp.J /= 0) then
Message("Fouriers.Ops.CompOmega3",Not_Implemented);
end if;
SetZero(H1.J,Rg,G1);
SetZero(H2.J,Rg,G2);
S := Sup(Norm(Rg,Gq));
if not H1.P then
for I in FreqE loop
G1.E(0) := G1.E(0)+Norm(S,H1.E(I));
end loop;
G1.E(0) := G1.E(0)*BetaMax(H1.R.Q,Rg,Scal(S));
end if;
if not H2.P then
for I in FreqE loop
G2.E(0) := G2.E(0)+Norm(S,H2.E(I));
end loop;
G2.E(0) := G2.E(0)*BetaMax(H2.R.Q,Rg,Scal(S));
end if;
EffDeg(H1,D1);
EffDeg(H2,D2);
Dm := Imax(D1,D2);
if Dm<0 then
TraceLeave;
return;
end if;
CosSin(Gq,Gw1,Gw2,Gc1,Gs1);
CosSin((-InvGold)*Gq,Gw1,Gw2,Gc2,Gs2);
SetZero(0,Rg,Gmc);
Gmc.C(0,0) := ScalOne;
SetZero(1,Rg,Gms);
Powers(Gp,Gpp);
for Mabs in 0 .. Dm loop
if Mabs>0 then
IncCS(Gc1,Gs1,Gw1,Gw2,Gmc,Gms);
end if;
for I in 0 .. 1 loop
M := (2*I-1)*Mabs;
Gms := -Gms;
if M<0 or else I=1 then
Gmnc := Gmc;
Gmns := Gms;
EffDeg(M,H1,D1);
EffDeg(M,H2,D2);
Dn := Imax(D1,D2);
for N in Nmin(M) .. Dn loop
if N>0 then
IncCS(Gc2,Gs2,Gw1,Gw2,Gmnc,Gmns);
end if;
SetZero(H1.J,Rg,Gw1);
MultAdd(ScalOne,M,N,Gmnc,Gw1);
MultAdd(Scal(2*H1.J-1),M,N,Gmns,Gw1);
Comp(H1.P,H1.R.P,H1.C(M,N),Gpp,Gw2);
MultAdd(ScalOne,Gw1,Gw2,G1);
SetZero(H2.J,Rg,Gw1);
MultAdd(ScalOne,M,N,Gmnc,Gw1);
MultAdd(Scal(2*H2.J-1),M,N,Gmns,Gw1);
Comp(H2.P,H2.R.P,H2.C(M,N),Gpp,Gw2);
MultAdd(ScalOne,Gw1,Gw2,G2);
end loop;
end if;
end loop;
end loop;
TraceLeave;
end CompOmega3;
----- procedures that are implemented only numerically
procedure NumInv(Err: in Radius; H1: in Fourier; H2: out Fourier) is
--- iterate h2 -> h2*[2-h1*h2]
S,E: Scalar;
Hw1,Hw2: Fourier;
begin
if not Trunc then
Message("Fouriers.Ops.NumInv",Numeric_Only);
end if;
S := Component(0,0,0,H1);
if S /= ScalZero then
Prod(-Inv(Sqr(S)),H1,H2);
AddComponent(0,0,0,ScalTwo/S,H2);
for I in 1 .. 30 loop
Prod(H1.R,H1,H2,Hw1);
AddComponent(0,0,0,-ScalOne,Hw1);
E := Norm(H1.R,Hw1);
AddComponent(0,0,0,-ScalOne,Hw1);
Prod(H1.R,H2,Hw1,Hw2);
Neg(Hw2,H2);
if Sup(E) <= Err then
return;
end if;
end loop;
Message("Fouriers.Ops.NumInv",Giving_Up);
else
Message("Fouriers.Ops.NumInv",Division_By_Zero);
end if;
end NumInv;
function NumInv(Err: Radius; H: Fourier) return Fourier is
Hr: Fourier;
begin
NumInv(Err,H,Hr);
return Hr;
end NumInv;
procedure NumInvComp3(Err: in Radius; H1,H2: in Fourier; H3: out Fourier) is
--- iterate h3 -> h3-[h2(..,h3)-h1]/(D_3 h2)(..,h3)
R: Weights;
E: Scalar;
H,Hd,Hd2,Hd3: Fourier;
begin
TraceEnter("NumInvComp3");
if not Trunc then
Message("Fouriers.Ops.NumInvComp3",Numeric_Only);
end if;
if H1.J /= H2.J then
Message("Fouriers.Ops.NumInvComp3",Not_Implemented);
end if;
R := Min(H1.R,H2.R); -- arbitrary
SetZero(0,R,H3);
InvComp(R.P,Err,H1.C(0,0),H2.C(0,0),H3.C(0,0));
Der3(R.P,H2,H);
NumInv(Err,H,Hd2); -- need not be that precise
for I in 1 .. 20 loop
Comp3(H2,H3,H);
Sub(H1,H);
Comp3(Hd2,H3,Hd);
Prod(R,H,Hd,Hd3);
Sub(Hd3,H3);
E := Norm(R,Hd3);
if Sup(E) <= Err then
TraceLeave;
return;
end if;
end loop;
Message("Fouriers.Ops.NumInvComp3",Giving_Up);
TraceLeave;
end NumInvComp3;
procedure NumFixComp3(Err: in Radius; H: in Fourier; Hz: out Fourier) is
H1,H2: Fourier;
begin
Copy(H,H2);
AddComponent(0,0,1,ScalOne,H2);
SetZero(0,H.R,H1);
SetComponent(0,0,1,ScalOne,H1);
NumInvComp3(Err,H1,H2,Hz);
-- AddComponent(0,0,1,-ScalOne,Hz); -- originally last line
Comp3(H,Hz,H1); -- only for contractions
Neg(H1,Hz); -- only for contractions
end NumFixComp3;
function NumFixComp3(Err: Radius; H: Fourier) return Fourier is
Hz: Fourier;
begin
NumFixComp3(Err,H,Hz);
return Hz;
end NumFixComp3;
procedure NumInvAplus1(Err: in Radius; L: in Degrees; Hdq,Hdp,F: in Fourier; Psi: out Fourier) is
--- solve (I-)[A+1]Psi=(I-)F by iteration Psi -> (I-)[F-A(Psi)]
--- where A(Psi)=Hdp*Gig(Psi)-Hdq*Dig(Psi)
Iter: constant Integer := 50;
I: Integer := 1;
E: Scalar;
D: Degrees(Freq1,Freq2);
Psid,Psit: Fourier;
begin
if not Trunc then
Message("Fouriers.Ops.NumInvAplus1",Numeric_Only);
end if;
for M in Freq1 loop
for N in Nmin(M) .. Nmax(M) loop
D(M,N) := Imin(L(M,N),Dmax(M,N));
end loop;
end loop;
Copy(F,Psit);
Iminus(L,Psit); -- start with Psit := (I-)F
loop
Copy(F,Psi);
Dig(Small,Psit,Psid);
MultAdd(ScalOne,Hdq,Psid,Psi,D); -- add (I-)*Hdq*Dig(Psit)
Gig(Small,Psit,Psid);
MultAdd(-ScalOne,Hdp,Psid,Psi,D); -- subtract (I-)*Hdp*Gig(Psit)
E := Norm(Psi-Psit);
exit when I=Iter or Sup(E)<Err;
Copy(Psi,Psit);
I := I+1;
end loop;
if I=Iter then
Message("RG_Ops.NumInvAplus1",Giving_Up);
end if;
Show("NumInvAplus1: ",I,False);
Show(" |Psi-Psit| =",Sup(E));
end NumInvAplus1;
function NumInvAplus1(Err: Radius; L: Degrees; Hdq,Hdp,F: Fourier) return Fourier is
Psi: Fourier;
begin
NumInvAplus1(Err,L,Hdq,Hdp,F,Psi);
return Psi;
end NumInvAplus1;
end Fouriers.Ops;