
package MPFR.Floats.Balls is -- balls in a commutative Banach algebra with unit

  pragma Elaborate_Body;

  subtype Rad is LLFloat;

  type Ball is      -- ball around constant
    record
      C: Rep;       -- center
      R: Rad;       -- radius
    end record;

  --- auxiliary
  procedure NOP(Dummy: in out Ball);
  function ReturnTrue(Dummy: Ball) return Boolean;

  --- basic
  function Info(Dummy: Ball) return Scalar_Info;
  function IsSharp(S: Ball) return Boolean;
  function IsNumbers(S: Ball) return Boolean renames IsSharp;
  function IsZero(S: Ball) return Boolean;
  function "="(S1,S2: Ball) return Boolean;
  procedure SetZero(S: in out Ball);
  procedure SetSmallZero(S: in out Ball);
  function ReturnZero(Dummy: in Ball) return Ball;
  procedure Copy(S1: in Ball; S2: in out Ball);
  function Copy(S: Ball) return Ball;
  procedure Swap(S1,S2: in out Ball);

  --- sets
  function Center0(S: Ball) return Boolean;
  function Contains0(S: Ball) return Logical;
  function Contains(S1,S2: Ball) return Logical;
  procedure BallAt0(F: in Flt; S: in out Ball);
  function BallAt0(F: Flt) return Ball;
  procedure DiskAt0(F: in Flt; S: in out Ball) renames BallAt0;
  function DiskAt0(F: Flt) return Ball renames BallAt0;
  procedure ToErr(S: in out Ball);
  procedure ToErr(S1: in Ball; S2: in out Ball);
  function ToErr(S: Ball) return Ball;
  procedure Center(S: in out Ball);
  procedure Center(S1: in Ball; S2: in out Ball);
  function Center(S: Ball) return Ball;
  procedure CenterDisk(S: in out Ball) renames NOP;
  procedure CenterDisk(S1: in Ball; S2: in out Ball) renames Copy;
  function CenterDisk(S: Ball) return Ball renames Copy;
  procedure ModCenter(S: in out Ball);
  procedure ModCenter(S1: in Ball; S2: in out Ball);
  function ModCenter(S: Ball) return Ball;
  procedure ModNumbers(S: in out Ball) renames ModCenter;
  procedure ModNumbers(S1: in Ball; S2: in out Ball) renames ModCenter;
  function ModNumbers(S: Ball) return Ball renames ModCenter;
  procedure ErrMult(B: in Radius; S: in out Ball);
  procedure Union(S1: in Ball; S2: in out Ball);
  function Union(S1,S2: Ball) return Ball;
  procedure Intersection(S1: in Ball; S2: in out Ball; Empty: out Logical); -- an enclosure

  --- order
  function Sign(S: Ball) return Integer;
  function Compare(S1,S2: Ball) return Integer;
  function "<"(S1,S2: Ball) return Boolean;
  function "<="(S1,S2: Ball) return Boolean;
  function ">"(S1,S2: Ball) return Boolean;
  function ">="(S1,S2: Ball) return Boolean;
  procedure Min(S1: in Ball; S2: in out Ball);
  procedure Min(S1,S2: in Ball; S3: in out Ball);
  function Min(S1,S2: Ball) return Ball;
  procedure Max(S1: in Ball; S2: in out Ball);
  procedure Max(S1,S2: in Ball; S3: in out Ball);
  function Max(S1,S2: Ball) return Ball;
  function Inf(S: Ball) return Flt;
  function Sup(S: Ball) return Flt;

  --- addition and multiplication etc.
  procedure Neg(S: in out Ball);
  procedure Neg(S1: in Ball; S2: in out Ball);
  function "-"(S: Ball) return Ball;
  procedure Add(I: in Integer; S: in out Ball);
  procedure Add(S1: in Ball; S2: in out Ball);
  procedure Sum(S1,S2: in Ball; S3: in out Ball);
  function "+"(S1,S2: Ball) return Ball;
  procedure Sub(S1: in Ball; S2: in out Ball);
  procedure Diff(S1,S2: in Ball; S3: in out Ball);
  function "-"(S1,S2: Ball) return Ball;
  procedure Mult(R: in Flt; S,Tmp: in out Ball);
  procedure Mult(R: in Flt; S: in out Ball);
  procedure Prod(R: in Flt; S1: in Ball; S2: in out Ball);
  function "*"(R: Flt; S: Ball) return Ball;
  procedure AddProd(R: in Flt; S1: in Ball; S2,Tmp: in out Ball);
  procedure AddProd(R: in Flt; S1: in Ball; S2: in out Ball);
  procedure Mult(Q: in Rational; S: in out Ball);
  procedure Mult(S1: in Ball; S2: in out Ball);
  procedure Prod(S1,S2: in Ball; S3: in out Ball);
  function "*"(S1,S2: Ball) return Ball;
  procedure AddProd(S1,S2: in Ball; S3,Tmp: in out Ball);
  procedure AddProd(S1,S2: in Ball; S3: in out Ball);
  procedure SumProd(S1,S2,S3: in Ball; S4: in out Ball);
  procedure SubProd(S1,S2: in Ball; S3,Tmp: in out Ball);
  procedure Div(R: in Flt; S,Tmp: in out Ball);
  procedure Div(R: in Flt; S: in out Ball);
  procedure Quot(S1: in Ball; R: in Flt; S2: in out Ball);
  function "/"(S: Ball; R: Flt) return Ball;
  procedure Div(S1: in Ball; S2: in out Ball);
  procedure Quot(S1,S2: in Ball; S3: in out Ball);
  function "/"(S1,S2: Ball) return Ball;
  procedure Inv(S1: in Ball; S2: in out Ball);
  function Inv(S: Ball) return Ball;
  procedure IPower(I: in Integer; S1: in Ball; S2,Tmp: in out Ball);
  function "**"(S: Ball; I: Integer) return Ball;

  --- fun
  --- Sqrt, Root, Exp, Log, ArcCos, Cos, Sin are only for real numbers
  function IsReal(S: Ball) return Boolean renames ReturnTrue;
  procedure Adjoint(S: in out Ball) renames NOP;
  procedure Adjoint(S1: in Ball; S2: in out Ball) renames Copy;
  function Adjoint(S: Ball) return Ball renames Copy;
  procedure Norm(S1: in Ball; S2: in out Ball);
  function Norm(S: Ball) return Ball;
  function "abs"(S: Ball) return Ball renames Norm;
  function MaxNorm(S: Ball) return Radius;
  procedure Sqr(S: in out Ball);
  function Sqr(S: Ball) return Ball;
  procedure Sqrt(S1: in Ball; S2: in out Ball);
  function Sqrt(S: Ball) return Ball;
  procedure Root(K: Positive; S1: in Ball; S2: in out Ball);
  function Root(K: Positive; S: Ball) return Ball; --- uses MPFR
  procedure Exp(S1: in Ball; S2: in out Ball);
  function Exp(S: Ball) return Ball;               --- uses MPFR
  procedure Log(S1: in Ball; S2: in out Ball);
  function Log(S: Ball) return Ball;               --- uses MPFR
  procedure ArcCos(S1: in Ball; S2: in out Ball);
  function ArcCos(S: Ball) return Ball;            --- uses MPFR
  procedure ArcSin(S1: in Ball; S2: in out Ball);
  function ArcSin(S: Ball) return Ball;            --- uses MPFR
  procedure Cos(S1: in Ball; S2: in out Ball);
  function Cos(S: Ball) return Ball;               --- uses MPFR
  procedure Sin(S1: in Ball; S2: in out Ball);
  function Sin(S: Ball) return Ball;               --- uses MPFR
  procedure Simple_Random(S: in out Ball);
  function Pi return Ball;
  procedure QPower(Q: in Rational; S1: in Ball; S2: in out Ball);
  procedure Roots2(B,C: in Ball; U1,U2,V: in out Ball);
  procedure Roots3(B,C,D: in Ball; U0,U1,U2,V: in out Ball);

  --- conversion and i/o
  procedure Assign(I: in Integer; S: in out Ball);
  procedure Assign(Q: in Rational; S: in out Ball);
  procedure Assign(R: in Flt; S: in out Ball);
  function Scal(I: Integer) return Ball;
  function Scal(Q: Rational) return Ball;
  function Scal(R: Flt) return Ball;
  procedure Enclose(R1,R2: in Flt; S: in out Ball);
  function Enclose(R1,R2: Flt) return Ball;
  function Approx(S: Ball) return Flt;
  procedure Real_Part(Dummy: in out Ball) renames NOP;
  procedure Imag_Part(S: in out Ball) renames SetZero;
  procedure Eval0(S: in out Ball) renames NOP;
  procedure Show1(N: in String; S: in Ball; NewLine: in Boolean := True);
  procedure Show2(N: in String; S1,S2: in Ball; NewLine: in Boolean := True);
  procedure Put(F: in File_Type; S: in Ball; Decimal: in Boolean := False);
  procedure Get(F: in File_Type; S: in out Ball; Decimal: in Boolean := False);
  procedure Write(FileName: in String; S: in Ball; Decimal: in Boolean := False);
  procedure Read(FileName: in String; S: in out Ball; Decimal: in Boolean := False);

  procedure PutStd(S: in Ball; C,R: out LLFloat);
  procedure GetStd(C,R: in LLFloat; S: in out Ball);
  procedure PutNum(S: in Ball; R: in out Rep);
  procedure GetNum(R: in Rep; S: in out Ball);

  --- misc
  function Get_Precision(S: Ball) return Positive;
  procedure Proper_Rounding(Dummy: in Ball);
  procedure Proper_Rounding;
  procedure Free_Cache(Dummy: in Ball);
  procedure Put_Numeric(N: in Positive; S: in Ball);     --- primitive buffer
  procedure Get_Numeric(N: in Positive; S: in out Ball); --- primitive buffer

  Scalar_IsNumeric: constant Boolean := False;

private

  procedure Re_Format(P: in MP_Prec_T; V: in out MPFR_T);
  procedure Re_Format(V: in out MPFR_T);
  procedure Fix_Precision(V: in out MPFR_T; Rounded: out Int);
  function ULP_Weight(V: MPFR_T) return LLFloat;
  procedure SumErr(S1,S2: in MPFloat; S3: in out MPFloat; Err: out LLFloat);
  procedure DiffErr(S1,S2: in MPFloat; S3: in out MPFloat; Err: out LLFloat);

  procedure RBall(R1,R2: in Rep; S: in out Ball);
  procedure RSup(S: in Ball; R: in out Rep);
  function RSup(S: Ball) return Rep;
  procedure RInf(S: in Ball; R: in out Rep);
  function RInf(S: Ball) return Rep;

  Tiny:  constant Rad := Rad'Scaling(ROne,Flt'Machine_Emin);
  CZero: constant Rep := Scal(0);
  COne:  constant Rep := Scal(1);
  CInfo: constant Scalar_Info := Info(CZero);
  BZero: constant Ball := (CZero,RZero);

  BInfo: constant Scalar_Info := (RepType    => CInfo.RepType,
                                  IsStandard => CInfo.IsStandard,
                                  IsNumeric  => False,
                                  IsComplex  => False,
                                  NReps      => 1,
                                  RMode      => (Up,Strict));

  pragma Inline_Always (Re_Format,Fix_Precision,ULP_Weight);

end MPFR.Floats.Balls;
