theory Misc
  use real.RealInfix
  use real.Abs
  use real.ExpLog
  use int.Int

  (* Exp and log estimates, proved by dReal but not the other provers *)
  goal exp_limit : forall x : real. abs x <=. 25. -> exp x <=. 72004899338.
  goal log_limit : -. log (1. -. 0x1p-39) +. abs(log (1. -. 0x1p-39) *. 0x1p-36) <=. 0x1p-38

  let function exp_limit_fun (x:real)
    requires { abs x <=. 25. }
    ensures { exp x <=. 72004899338. }
  = ()

  use real.FromInt
  use int.Abs as AbsInt
  (* FromInt is not supported *)
  goal exp_limit_from_int_KO : forall x : int. AbsInt.abs x <= 25 -> exp (from_int x) <=. 72004899338.
  (* from_int 3 is simplified by 3. at the printer level *)
  goal from_int : from_int 3 <=. 4.

  use real.MinMax
  goal min_max_test : min 3. 4. >. max 1. 2.

  (* Square *)
  use real.Square
  (* Unfotunately not proved by dReal *)
  goal sqr_sqrt_KO : forall x. 0. <=. x -> sqr (sqrt x) = x
  goal sqr_sqrt_no_forall_KO : sqr (sqrt 3.) = 3.

  goal sqrt2_estimate : 1.41421356237 <=. sqrt 2. <=. 1.41421356238

  use real.PowerReal
  (* These are proved by dReal but not by CVC4/5, Alt-Ergo or Z3 *)
  goal power : forall x. pow x 2. <=. 9. -> abs x <=. 3.
  goal power2: forall x:real. x >. 2.5 -> (pow x 3.0) *. 2.0 >. 20.0

  (* This is not proved by dReal nor by any other prover *)
  goal sqr_sqrt2_KO : forall x. 0. <=. x -> pow (sqrt x) 2. = x

  (* This works because this reduces to true at the printer level *)
  goal huge_power : pow 5. 100. <=. 7.8886091e69

  (* Trigonometry *)
  use real.Trigonometry
  (* Basic axioms/lemmas, proved by dReal *)
  goal Pythagorean_identity : forall x:real. sqr (cos x) +. sqr (sin x) = 1.0
  goal Cos_le_one: forall x:real. abs (cos x) <=. 1.0
  goal Sin_le_one: forall x:real. abs (sin x) <=. 1.0
  goal Cos_sum: forall x y:real. cos (x+.y) = cos x *. cos y -. sin x *. sin y
  goal Sin_sum: forall x y:real. sin (x+.y) = sin x *. cos y +. cos x *. sin y
end

theory Quantifiers
  use int.Int
  function g (x : int) : int
  axiom g_pos : forall z. g z >= 0
  goal g2 : g 3 >= 0

  function h (x : int) : int
  axiom h_pos : forall x. x >= 0 -> h x >= 0
  goal g3: forall x. h (g x) >= 0
end

theory P
  use real.Real

  goal x_mul_x_pos :
    forall x:real. x * x >= 0.0

  function sqr (x:real) : real = x * x

  goal sqr_pos :
    forall x:real. sqr x >= 0.0
end

theory P2
  use real.Real
  use real.Square

  goal sqr_pos :
    forall x:real. sqr x >= 0.0
end

theory P3
  use real.Real
  use real.Trigonometry

  (* unprovable without cos-constant.ax, which causes failures for more interesting goals *)
  goal cos_bound :
    forall x:real. -1.0 <= cos x <= 1.0

  goal cos_bound_harder :
    forall x:real. -0.7 <= x <= 0.7 -> 0.7 <= cos x <= 1.0


  use real.Abs

  goal MethodErrorOK: forall x:real. abs x <= 0x1p-5 ->
    abs (1.0 - 0.5 * (x * x) - cos x) <= 0x1p-24

  goal MethodErrorWrong: forall x:real. abs x <= 0x1p-5 ->
    abs (1.0 - 0.5 * (x * x) - cos x) <= 0x1p-25
end


theory Power
  use real.RealInfix
  use real.PowerReal

  (* Here we check that we don't prove false assertions *)
  goal G_KO: false
  goal G1_KO: forall x:real. x >. 2.0 -> (pow x 3.0) *. 2.0 >. 20.0
  goal G2_KO: forall x:real. x >. 2.0 -> x >. 5.0
end


theory PolyPaverExamples
  use real.Real
  use real.ExpLog

  goal g1_KO: forall a b : real.
    -10.0 <= a <= 10.0 ->
    -10.0 <= b <= 10.0 ->
    b > a + 0.1 ->
    exp a - exp b > (b-a) * exp ((a + b) / 2.0)
end

theory TestBigConstantElimination
  use ieee_float.Float64
  use real.RealInfix
  use real.Abs
  use real.ExpLog
  use int.Int

  (*
    Real constants that are too big or too small cause dReal to crash on a call
    to strtod
    As long as this is not fixed, these constants are removed by the
    transformation "eliminate_big_constants"
  *)
  constant r1:real
  constant r2:real
  constant r3:real
  constant r4:real
  (* These are removed *)
  axiom H1 : r1 = 0x1p1023
  axiom H2 : r2 = 0x1p-1024
  (* These are kept *)
  axiom H3 : r3 = 0x1p1022
  axiom H4 : r4 = 0x1p-1023

  goal g1 : forall x : real. abs x <=. 25. -> exp x <=. 72004899338.

  (*
    Int constants that are too big cause dReal to prove false.
    As long as this is not fixed, these constants are removed by the
    transformation "eliminate_big_constants"
  *)
  constant i1:int
  constant i2:int
  (* i1 is removed *)
  axiom H5 : i1 = 0x80000000
  (* i2 is kept *)
  axiom H6 : i2 = 0x7FFFFFFF
  goal G2_KO : false
end
