module Rep_Proj_Base
  (* Basis for modules specifying to_rep/of_rep for all scalar types. *)
  type t
  type rep_type

  function to_rep t : rep_type
  function of_rep rep_type : t

  meta "model_projection" function to_rep

  val of_rep (x : rep_type) : t
    ensures  { to_rep (result) = x }

  val to_rep (x : t) : rep_type
    ensures  { to_rep (x) = result }

  predicate in_range (x : rep_type)

  axiom inversion_axiom :
    forall x : t [to_rep x].
      of_rep (to_rep x) = x

  axiom range_axiom :
    forall x : t [to_rep x]. in_range (to_rep x)
  meta "remove_unused:dependency" axiom range_axiom, function to_rep

end

module Discrete_Base
  (* The module that is used as basis for all discrete types. It
    contains the whole discrete theory, except the projections
    to_rep/of_rep and associated axioms. *)

  use "_gnatprove_standard".Main

  type rep_type

  function bool_eq (x : rep_type) (y : rep_type) : bool =
    if x = y then True else False

  val bool_eq (x : rep_type) (y : rep_type) : bool
  ensures { if x = y then result else not result }

  type t

  val function attr__ATTRIBUTE_IMAGE rep_type : __image

  predicate attr__ATTRIBUTE_VALUE__pre_check (x : __image)

  function attr__ATTRIBUTE_VALUE __image : rep_type

  val attr__ATTRIBUTE_VALUE_ (x : __image) : rep_type
    requires { attr__ATTRIBUTE_VALUE__pre_check x }
    ensures { result = attr__ATTRIBUTE_VALUE x }

  val function user_eq (x : t) (y : t) : bool

  val constant dummy : t
  meta "remove_unused:remove_constant" constant dummy

end

module Static_Discrete_Base
  (* The module that is used as basis for all "static" discrete types.
     It contains the whole discrete theory, except the projections
     to_rep/of_rep and associated axioms. "Static" here means that Why
     only sees a static version of the type, with constants for the
     bounds, even though this might correspond to dynamic types in
     Ada. *)

  clone export Discrete_Base

  function first : rep_type

  function last  : rep_type

  val check_not_last (n : rep_type) : rep_type
    requires { n <> last }
    ensures { result = n /\ n <> last}

  val check_not_first (n : rep_type) : rep_type
    requires { n <> first }
    ensures { result = n /\ n <> first}

  predicate in_range (x : rep_type)

  val range_check_ (n : rep_type) : rep_type
    requires { in_range n }
    ensures { result = n /\ in_range n}

  predicate dynamic_property (f l x : rep_type) = in_range x
end

module Static_Discrete
  use        int.Int

  clone export Static_Discrete_Base with
    type rep_type = int
end

module Rep_Proj_Int
  (* Specification of to_rep when rep_type = int; add coercion axiom. *)
  use        int.Int

  clone export Rep_Proj_Base with
    type rep_type = int

  axiom coerce_axiom :
    forall x : int [to_rep (of_rep x)].
      in_range x -> to_rep (of_rep x) = x
end

module Static_Modular_Base
  use        int.Int

  clone export Static_Discrete_Base

  function rep_to_int rep_type : int

  (* for conversions from int to bitvectors, we need to be able to do
     the range check directly in int. *)
  predicate in_range_int int

  val range_check_int_ (n : int) : int
    requires { in_range_int n }
    ensures { result = n /\ in_range_int n }

  predicate dynamic_property_int (f l x : int) = in_range_int x
end

module Rep_Proj_ltBVGen
  (* Basis for specification of to_rep when rep_type is a BV with
     modulus smaller than 2**(8/16/32/64); add coercion axiom and
     to_int spec. Used in parallel with Static_Modular_lt* *)
  clone export Rep_Proj_Base

  function urem rep_type rep_type : rep_type

  function attr__ATTRIBUTE_MODULUS : rep_type

  function rep_to_int rep_type : int

  predicate in_range_int int

  axiom coerce_axiom :
    forall x : rep_type [to_rep (of_rep x)].
      let y = urem x attr__ATTRIBUTE_MODULUS in
        in_range y -> to_rep (of_rep x) = y

  function to_int (x : t) : int = rep_to_int (to_rep x) (* used for modular indexed arrays cloning *)

  axiom range_int_axiom :
    forall x : t [to_int x]. in_range_int (to_int x)
  meta "remove_unused:dependency" axiom range_int_axiom, function to_int
end

module Rep_Proj_BVGen
  (* Basis for specification of to_rep when rep_type is a BV with
     modulus equal to 2**(8/16/32/64); add coercion axiom and
     to_int spec. Used in parallel with Static_Modular_* *)
  clone export Rep_Proj_Base

  function rep_to_int rep_type : int

  predicate in_range_int int

  axiom coerce_axiom :
    forall x : rep_type [to_rep (of_rep x)].
        in_range x -> to_rep (of_rep x) = x

  function to_int (x : t) : int = rep_to_int (to_rep x) (* used for modular indexed arrays cloning *)

  axiom range_int_axiom :
    forall x : t [to_int x]. in_range_int (to_int x)
  meta "remove_unused:dependency" axiom range_int_axiom, function to_int
end

(* ---- Modular with modulus lower or equal to 128 ---- *)

module Static_Modular_lt128
  use _gnatprove_standard.BV128 as BV128
  type rep_type = BV128.t

  function rep_to_int (x : rep_type) : int = BV128.t'int x

  clone export Static_Modular_Base with
    type rep_type = rep_type,
    function rep_to_int = rep_to_int

  function attr__ATTRIBUTE_MODULUS : rep_type
end

module Rep_Proj_ltBV128
  use _gnatprove_standard.BV128
  type rep_type = t

  function rep_to_int (x : rep_type) : int = t'int x

  clone export Rep_Proj_ltBVGen with
    type rep_type = rep_type,
    function rep_to_int = rep_to_int,
    function urem = urem

  (* need to specify modulus when cloning this *)
end

module Static_Modular_128
  use _gnatprove_standard.BV128 as BV128
  type rep_type = BV128.t

  function rep_to_int (x : rep_type) : int = BV128.t'int x

  clone export Static_Modular_Base with
    type rep_type = rep_type,
    function rep_to_int = rep_to_int
end

module Rep_Proj_BV128
  use _gnatprove_standard.BV128
  type rep_type = t

  function rep_to_int (x : rep_type) : int = t'int x

  clone export Rep_Proj_BVGen with
    type rep_type = rep_type,
    function rep_to_int = rep_to_int
end

(* ---- Modular with modulus lower or equal to 64 ---- *)

module Static_Modular_lt64
  use _gnatprove_standard.BV64 as BV64
  type rep_type = BV64.t

  function rep_to_int (x : rep_type) : int = BV64.t'int x

  clone export Static_Modular_Base with
    type rep_type = rep_type,
    function rep_to_int = rep_to_int

  function attr__ATTRIBUTE_MODULUS : rep_type
end

module Rep_Proj_ltBV64
  use _gnatprove_standard.BV64
  type rep_type = t

  function rep_to_int (x : rep_type) : int = t'int x

  clone export Rep_Proj_ltBVGen with
    type rep_type = rep_type,
    function rep_to_int = rep_to_int,
    function urem = urem

  (* need to specify modulus when cloning this *)
end

module Static_Modular_64
  use _gnatprove_standard.BV64 as BV64
  type rep_type = BV64.t

  function rep_to_int (x : rep_type) : int = BV64.t'int x

  clone export Static_Modular_Base with
    type rep_type = rep_type,
    function rep_to_int = rep_to_int
end

module Rep_Proj_BV64
  use _gnatprove_standard.BV64
  type rep_type = t

  function rep_to_int (x : rep_type) : int = t'int x

  clone export Rep_Proj_BVGen with
    type rep_type = rep_type,
    function rep_to_int = rep_to_int
end

(* ---- Modular with modulus lower or equal to 32 ---- *)

module Static_Modular_lt32
  use _gnatprove_standard.BV32 as BV32
  type rep_type = BV32.t

  function rep_to_int (x : rep_type) : int = BV32.t'int x

  clone export Static_Modular_Base with
    type rep_type = rep_type,
    function rep_to_int = rep_to_int

  function attr__ATTRIBUTE_MODULUS : rep_type
end

module Rep_Proj_ltBV32
  use  _gnatprove_standard.BV32
  type rep_type = t

  function rep_to_int (x : rep_type) : int = t'int x

  clone export Rep_Proj_ltBVGen with
    type rep_type = rep_type,
    function rep_to_int = rep_to_int,
    function urem = urem

  (* need to specify modulus when cloning this *)
end

module Static_Modular_32
  use _gnatprove_standard.BV32 as BV32
  type rep_type = BV32.t

  function rep_to_int (x : rep_type) : int = BV32.t'int x

  clone export Static_Modular_Base with
    type rep_type = rep_type,
    function rep_to_int = rep_to_int
end

module Rep_Proj_BV32
  use _gnatprove_standard.BV32
  type rep_type = t

  function rep_to_int (x : rep_type) : int = t'int x

  clone export Rep_Proj_BVGen with
    type rep_type = rep_type,
    function rep_to_int = rep_to_int
end

(* ---- Modular with modulus lower or equal to 16 ---- *)

module Static_Modular_lt16
  use _gnatprove_standard.BV16 as BV16
  type rep_type = BV16.t

  function rep_to_int (x : rep_type) : int = BV16.t'int x

  clone export Static_Modular_Base with
    type rep_type = rep_type,
    function rep_to_int = rep_to_int

  function attr__ATTRIBUTE_MODULUS : rep_type
end

module Rep_Proj_ltBV16
  use _gnatprove_standard.BV16
  type rep_type = t

  function rep_to_int (x : rep_type) : int = t'int x

  clone export Rep_Proj_ltBVGen with
    type rep_type = rep_type,
    function rep_to_int = rep_to_int,
    function urem = urem

  (* need to specify modulus when cloning this *)
end

module Static_Modular_16
  use _gnatprove_standard.BV16 as BV16
  type rep_type = BV16.t

  function rep_to_int (x : rep_type) : int = BV16.t'int x

  clone export Static_Modular_Base with
    type rep_type = rep_type,
    function rep_to_int = rep_to_int
end

module Rep_Proj_BV16
  use _gnatprove_standard.BV16
  type rep_type = t

  function rep_to_int (x : rep_type) : int = t'int x

  clone export Rep_Proj_BVGen with
    type rep_type = rep_type,
    function rep_to_int = rep_to_int
end

(* ---- Modular with modulus lower or equal to 8 ---- *)

module Static_Modular_lt8
  use _gnatprove_standard.BV8 as BV8
  type rep_type = BV8.t

  function rep_to_int (x : rep_type) : int = BV8.t'int x

  clone export Static_Modular_Base with
    type rep_type = rep_type,
    function rep_to_int = rep_to_int

  function attr__ATTRIBUTE_MODULUS : rep_type
end

module Rep_Proj_ltBV8
  use _gnatprove_standard.BV8
  type rep_type = t

  function rep_to_int (x : rep_type) : int = t'int x

  clone export Rep_Proj_ltBVGen with
    type rep_type = rep_type,
    function rep_to_int = rep_to_int,
    function urem = urem

  (* need to specify modulus when cloning this *)
end

module Static_Modular_8
  use _gnatprove_standard.BV8 as BV8
  type rep_type = BV8.t

  function rep_to_int (x : rep_type) : int = BV8.t'int x

  clone export Static_Modular_Base with
    type rep_type = rep_type,
    function rep_to_int = rep_to_int
end

module Rep_Proj_BV8
  use _gnatprove_standard.BV8
  type rep_type = t

  function rep_to_int (x : rep_type) : int = t'int x

  clone export Rep_Proj_BVGen with
    type rep_type = rep_type,
    function rep_to_int = rep_to_int
end

(* ---- Dynamic types ---- *)

module Dynamic_Discrete
  type rep_type
  type t

  (* To be instantiated with functions from the Ada base type *)
  function base_to_rep t : rep_type
  function base_of_rep rep_type : t

  meta "model_projection" function base_to_rep

  function to_rep (x : t) : rep_type = base_to_rep x
  function of_rep (x : rep_type) : t = base_of_rep x

  val to_rep (x : t) : rep_type
  ensures { result = base_to_rep x }
  val of_rep (x : rep_type) : t
  ensures { result = base_of_rep x }

  clone export Discrete_Base
      with type t = t,
      type rep_type = rep_type

  predicate dynamic_property (first last n : rep_type)

  val check_not_last (_ last n : rep_type) : rep_type
    requires { n <> last }
    ensures { result = n /\ n <> last }

  val check_not_first (first _ n : rep_type) : rep_type
    requires { n <> first }
    ensures { result = n /\ n <> first }

  val range_check_ (first last n : rep_type) : rep_type
    requires { dynamic_property first last n }
    ensures { result = n /\ dynamic_property first last n }
end

module Dynamic_Modular
  use int.Int

  clone export Dynamic_Discrete

  (* for conversions from int to bitvectors, we need to be able to
     check the dynamic property directly in int. *)
  predicate dynamic_property_int (first last n : int)

  val range_check_int_ (first last n : int) : int
    requires { dynamic_property_int first last n }
    ensures { result = n /\ dynamic_property_int first last n}
end

module Fixed_Point_Shared
  use int.Int

  (* We're using division to define the predicate pos_div_relation. The only
     values which we care about are for non-negative arguments, for which
     int.ComputerDivision and int.EuclideanDivision give the same result.
     Use the latter as it is directly bound to SMT-LIB "div" operator.
  *)
  use int.EuclideanDivision

  (* Helper predicate to define the result of operations on fixed-points.
     It is used with non-negative values for num and positive values for den.
     It expresses that res is either the result of the integer division
     num/den when exact, or one of the two closest integers.
  *)

  predicate pos_div_relation (res : int) (num : int) (den : int) =
    let exact = div num den in
    (* case 1: special case for zero *)
    if num = 0 then
      res = 0
    (* case 2: RM G.2.3(9,13) if the result is exact, that's it *)
    else if num = exact * den then
      res = exact
    (* case 3: RM G.2.3(10,14/3) if the result is not exact, that's one of
       the closest integers. *)
    else
      exact <= res <= exact + 1

  (* Helper predicate to define the result of conversion of fixed-points to
     integers.  Like pos_div_relation, it is used with non-negative values for
     num and positive values for den.  It expresses that res is either the
     result of the integer division num/den when exact, or the closest integer
     when rounding is needed, rounding away from zero in case of tie.
  *)

  predicate pos_div_relation_round_away (res : int) (num : int) (den : int) =
    let exact = div num den in
    (* case 1: special case for zero *)
    if num = 0 then
      res = 0
    (* case 2: RM G.2.3(9,13) if the result is exact, that's it *)
    else if num = exact * den then
      res = exact
    (* case 3: RM 4.6(33) if the result is not exact, that's the closest
       integer, rounded away from zero if exactly halfway between two
       integers. *)
    else
      let rest = num - exact * den in
      if 2 * rest >= den then
        res = exact + 1
      else
        res = exact

end

module Fixed_Point_Rep
  (* The module that is used to define a representative for fixed-point types.

     Multiplication and division are restricted in the following ways:
     - these operations between different fixed-point types and universal real
       are rejected.
     - these operations between fixed-point types are supported only when the
       smalls involved are compatible according to Ada RM G.2.3(21). This is
       handled in module Fixed_Point_Mult_Div
     - these operations between a fixed-point type and an integer are
       always supported and are defined in this module

    These restrictions enforce in particular that the result of all
    multiplication and division operations on fixed-points (with both fixed-point
    arguments, or an integer argument) is in the "perfect result set" as defined
    in Ada RM G.2.3: the result is either exact, or one of the two representable
    values that are closest to the exact result. This property is axiomatized
    below and in Fixed_Point_Mult_Div

    We use a type "__fixed" that is an alias of "int", to avoid confusion, for
    the internal integer representation of a fixed-point value. This type is
    used for performing all operations. In particular, addition, subtraction,
    comparisons, Succ and Pred are directly operating on this type. Literals
    are also expressed in this type. Multiplication and division are axiomatized
    to reflect the constraints of Ada RM G.2.3.
  *)

  use int.Int
  use real.RealInfix
  use real.FromInt
  use "_gnatprove_standard".Main
  use "_gnatprove_standard".Int_Division
  use Fixed_Point_Shared

  (* Numerator and denominator of the fractional "small" value of the
     corresponding fixed-point type. These are guaranteed to be positive
     whole numbers.

     The real value of a fixed-point number can be obtained by multiplying its
     integer representation by num_small and dividing it by den_small.
  *)

  function num_small : int
  function den_small : int

  (* multiplication between a fixed-point value and an integer *)

  function fxp_mult_int (x : __fixed) (y : int) : __fixed = x * y
  val fxp_mult_int (x : __fixed) (y : int) : __fixed
  ensures { result = fxp_mult_int x y }

  (* division between a fixed-point value and an integer
     case 1:
         If the divident is zero, then the result is zero.
     case 2:
         If both arguments are of the same sign, then the mathematical
         result is either exact, or between exact and exact+1, which are the
         possible results.

         for example:
              x =  5, y =  3, exact = 1, math = 1.666.., result in { 1, 2 }
              x = -5, y = -3, exact = 1, math = 1.666.., result in { 1, 2 }
     case 3:
         If arguments are of opposite signs, then the mathematical
         result is either exact, or between exact-1 and exact, which are the
         possible results.

         for example:
              x = -5, y =  3, exact = -1, math = -1.666.., result in { -2, -1 }
              x =  5, y = -3, exact = -1, math = -1.666.., result in { -2, -1 }
  *)

  function fxp_div_int (x : __fixed) (y : int) : __fixed

  val fxp_div_int_ (x : __fixed) (y : int) : __fixed
     requires { y <> 0 }
     ensures { result = fxp_div_int x y }

  axiom fxp_div_int_def :
    forall x : __fixed. forall y : int [fxp_div_int x y].
      if x = 0 then
        fxp_div_int x y = 0
      else if x > 0 /\ y > 0 then
        pos_div_relation (fxp_div_int x y) x y
      else if x < 0 /\ y < 0 then
        pos_div_relation (fxp_div_int x y) (-x) (-y)
      else if x < 0 /\ y > 0 then
        pos_div_relation (- (fxp_div_int x y)) (-x) y
      else if x > 0 /\ y < 0 then
        pos_div_relation (- (fxp_div_int x y)) x (-y)
      else (* y = 0 *)
        true
  meta "remove_unused:dependency" axiom fxp_div_int_def, function fxp_div_int

  (* conversion functions to int
     case 1:
         If the argument is zero, then the result is zero.
     case 2:
         If the argument is positive, then the mathematical result is either
         exact or exact+1, whichever is closest and rounding away from zero.

         for example, with small = 1/4:
              x = 5, exact = 1, math = 1.25, result = 1
     case 3:
         If the argument is negative, then the mathematical result is either
         exact or exact-1, whichever is closest and rounding away from zero.

         for example, with small = 1/4:
              x = -5, exact = -1, math = -1.25, result = -1
  *)

  val function to_int (x : __fixed) : int

  axiom to_int_def :
    forall x : __fixed [to_int x].
      if x = 0 then
        to_int x = 0
      else if x > 0 then
        pos_div_relation_round_away (to_int x) (x * num_small) den_small
      else (* x < 0 *)
        pos_div_relation_round_away (- (to_int x)) (-x * num_small) (den_small)
  meta "remove_unused:dependency" axiom to_int_def, function to_int

  (* conversion function from int
     case 1:
         If the argument is zero, then the result is zero.
     case 2:
         If the argument is positive, then the mathematical result is either
         exact, or between exact and exact+1, which are the possible results.

         for example, with small = 2:
              x = 5, exact = 2, math = 2.5, result in { 2, 3 }
     case 3:
         If the argument is negative, then the mathematical result is either
         exact, or between exact-1 and exact, which are the possible results.

         for example, with small = 2:
              x = -5, exact = -2, math = -2.5, result in { -3, -2 }
  *)

  val function of_int (x : int) : __fixed

  axiom of_int_def :
    forall x : __fixed [of_int x].
      if x = 0 then
        of_int x = 0
      else if x > 0 then
        pos_div_relation (of_int x) (x * den_small) num_small
      else (* x < 0 *)
        pos_div_relation (- (of_int x)) (-x * den_small) (num_small)
  meta "remove_unused:dependency" axiom of_int_def, function of_int

end

module Fixed_Point_Base
  (* The module that is used as basis of all fixed-point types. It does not
     contain operations on fixed point types which are stored in representative
     modules *)
  use int.Int
  use "_gnatprove_standard".Main

  type t

  val constant dummy : t
  meta "remove_unused:remove_constant" constant dummy

  val constant attr__ATTRIBUTE_IMAGE __fixed : __image

  predicate attr__ATTRIBUTE_VALUE__pre_check (x : __image)

  function attr__ATTRIBUTE_VALUE __image : __fixed

  val attr__ATTRIBUTE_VALUE_ (x : __image) : __fixed
    requires { attr__ATTRIBUTE_VALUE__pre_check x }
    ensures { result = attr__ATTRIBUTE_VALUE x }

  val function user_eq (x : t) (y : t) : bool
end

module Fixed_Point_Mult_Div
  (* The module that is used for multiplication and division between fixed-point
     types, with a fixed-point result. These operations between fixed-point
     types are supported only when the smalls involved are compatible according
     to Ada RM G.2.3(21).

     This enforces that the result is in the "perfect result set" as defined
     in Ada RM G.2.3: the result is either exact, or one of the two representable
     values that are closest to the exact result. This property is axiomatized
     below.

     Note that it may be the case that only one of multiplication/division is
     supported. In that case, we still defined them together here, but gnat2why
     will reject any use of an unsupported operation.
  *)

  use int.Int
  use "_gnatprove_standard".Main
  use Fixed_Point_Shared

  (* Numerator and denominator of the fractional "small" value of the
     corresponding fixed-point types. These are guaranteed to be positive
     whole numbers.

     There is a different pair num_small/den_small for every argument and for
     the result of the operation:
     - xxx_small_x for the first argument
     - xxx_small_y for the second argument
     - xxx_small_res for the result

     The real value of a fixed-point number can be obtained by multiplying its
     integer representation by num_small and dividing it by den_small.
  *)

  function num_small_x : __fixed
  function den_small_x : __fixed
  function num_small_y : __fixed
  function den_small_y : __fixed
  function num_small_res : __fixed
  function den_small_res : __fixed

  (* multiplication between two fixed-point values, where the arguments and
     result may have different values of small.

     case 1:
         If any argument is zero, the result is zero
     case 2:
         If both arguments are of the same sign, then the mathematical
         result is either exact, or between exact and exact+1, which are the
         possible results.

         for example, with small = 1/4:
              x =  5, y =  3, exact = 3, math = 3.75, result in { 3, 4 }
              x = -5, y = -3, exact = 3, math = 3.75, result in { 3, 4 }
     case 3:
         If arguments are of opposite signs, then the mathematical
         result is either exact, or between exact-1 and exact, which are the
         possible results.

         for example, with small = 1/4:
              x =  5, y = -3, exact = -3, math = -3.75, result in { -4, -3 }
              x = -5, y =  3, exact = -3, math = -3.75, result in { -4, -3 }
  *)

  val function fxp_mult (x : __fixed) (y : __fixed) : __fixed

  axiom fxp_mult_def :
    forall x : __fixed. forall y : __fixed [fxp_mult x y].
      if x = 0 \/ y = 0 then
        fxp_mult x y = 0
      else if (x > 0 /\ y > 0) \/ (x < 0 /\ y < 0) then
        pos_div_relation (fxp_mult x y)
          (x * y * num_small_x * num_small_y * den_small_res)
          (den_small_x * den_small_y * num_small_res)
      else (* (x < 0 /\ y > 0) \/ (x > 0 /\ y < 0) *)
        pos_div_relation (- (fxp_mult x y))
          (- (x * y * num_small_x * num_small_y * den_small_res))
          (den_small_x * den_small_y * num_small_res)
  meta "remove_unused:dependency" axiom fxp_mult_def, function fxp_mult

  (* division between two fixed-point values, where the arguments and result
     may have different values of small.

     case 1:
         If the dividand is zero, then the result is zero.
     case 2:
         If both arguments are of the same sign, then the mathematical
         result is either exact, or between exact and exact+1, which are the
         possible results.

         for example, with small = 1/4:
              x =  5, y =  3, exact = 6, math = 6.666.., result in { 6, 7 }
              x = -5, y = -3, exact = 6, math = 6.666.., result in { 6, 7 }
     case 3:
         If arguments are of opposite signs, then the mathematical
         result is either exact, or between exact-1 and exact, which are the
         possible results.

         for example, with small = 1/4:
              x = -5, y =  3, exact = -6, math = -6.666.., result in { -7, -6 }
              x =  5, y = -3, exact = -6, math = -6.666.., result in { -7, -6 }
  *)

  function fxp_div (x : __fixed) (y : __fixed) : __fixed

  val fxp_div_ (x : __fixed) (y : __fixed) : __fixed
     requires { y <> 0 }
     ensures { result = fxp_div x y }

  axiom fxp_div_def :
    forall x : __fixed. forall y : __fixed [fxp_div x y].
      if x = 0 then
        fxp_div x y = 0
      else if x > 0 /\ y > 0 then
        pos_div_relation (fxp_div x y)
          (x * num_small_x * den_small_y * den_small_res)
          (y * den_small_x * num_small_y * num_small_res)
      else if x < 0 /\ y < 0 then
        pos_div_relation (fxp_div x y)
          (-x * num_small_x * den_small_y * den_small_res)
          (-y * den_small_x * num_small_y * num_small_res)
      else if x < 0 /\ y > 0 then
        pos_div_relation (- (fxp_div x y))
          (-x * num_small_x * den_small_y * den_small_res)
          (y * den_small_x * num_small_y * num_small_res)
      else if x > 0 /\ y < 0 then
        pos_div_relation (- (fxp_div x y))
          (x * num_small_x * den_small_y * den_small_res)
          (-y * den_small_x * num_small_y * num_small_res)
      else (* y = 0 *)
        true
  meta "remove_unused:dependency" axiom fxp_div_def, function fxp_div
end

module Static_Fixed_Point
  (* The module that is used as basis for all "static" fixed-point types.
     "Static" here means that Why only sees a static version of the type,
     with constants for the bounds, even though this might correspond to
     dynamic types in Ada. *)

  use "_gnatprove_standard".Main
  use int.Int

  clone export Fixed_Point_Base

  function first : __fixed

  function last  : __fixed

  val check_not_last (n : __fixed) : __fixed
    requires { n <> last }
    ensures { result = n }

  val check_not_first (n : __fixed) : __fixed
    requires { n <> first }
    ensures { result = n }

  predicate in_range (x : __fixed)

  val range_check_ (n : __fixed) : __fixed
    requires { in_range n }
    ensures { result = n }

  predicate dynamic_property (f l x : __fixed) = in_range x
end

module Rep_Proj_Fixed
  (* Specification of to_rep when rep_type = __fixed; add coercion axiom. *)
  use "_gnatprove_standard".Main
  use int.Int

  clone export Rep_Proj_Base with
    type rep_type = __fixed

  axiom coerce_axiom :
    forall x : __fixed [to_rep (of_rep x)].
      in_range x -> to_rep (of_rep x) = x
end

module Dynamic_Fixed_Point
  (* The module that is used as basis for all "dynamic" fixed-point types.
     "Dynamic" here means that Why sees a dynamic version of the type, with
     references for the bounds, which correspond to some cases of dynamic
     types in Ada. *)

  use "_gnatprove_standard".Main
  use int.Int

  type t

  function base_to_rep t : __fixed
  function base_of_rep __fixed : t

  meta "model_projection" function base_to_rep

  function to_fixed (x : t) : __fixed = base_to_rep x
  function of_fixed (x : __fixed) : t = base_of_rep x

  clone export Fixed_Point_Base
      with type t = t

  predicate dynamic_property (first last n : __fixed)

  val check_not_last (_ last n : __fixed) : __fixed
    requires { n <> last }
    ensures { result = n }

  val check_not_first (first _ n : __fixed) : __fixed
    requires { n <> first }
    ensures { result = n }

  val range_check_ (first last n : __fixed) : __fixed
    requires { dynamic_property first last n }
    ensures { result = n /\ dynamic_property first last n}
end

module Floating_Point_Base
  (* The module that is used as basis for all floating-point types. *)

  use "_gnatprove_standard".Main

  type rep_type                 (* float32, float64 or float80 *)

  predicate eq rep_type rep_type
  predicate is_finite rep_type

  function bool_eq (x : rep_type) (y : rep_type) : bool =
    if eq x y then True else False
  val bool_eq (x : rep_type) (y : rep_type) : bool
    ensures { result = bool_eq x y }

  type t

  val function user_eq (x : t) (y : t) : bool

  val constant attr__ATTRIBUTE_IMAGE rep_type : __image

  predicate attr__ATTRIBUTE_VALUE__pre_check (x : __image)

  function attr__ATTRIBUTE_VALUE __image : rep_type

  val attr__ATTRIBUTE_VALUE_ (x : __image) : rep_type
    requires { attr__ATTRIBUTE_VALUE__pre_check x }
    ensures { result = attr__ATTRIBUTE_VALUE x }

  val constant dummy : t
  meta "remove_unused:remove_constant" constant dummy
end

module Static_Floating_Point
  (* The module that is used as basis for all "static" floating-point types. *)

  clone export Floating_Point_Base

  function first : rep_type

  function last  : rep_type

  val check_not_last (n : rep_type) : rep_type
    requires { n <> last }
    ensures { result = n }

  val check_not_first (n : rep_type) : rep_type
    requires { n <> first }
    ensures { result = n }

  predicate in_range (x : rep_type)

  val range_check_ (n : rep_type) : rep_type
    requires { in_range n }
    ensures { result = n /\ is_finite n }

  predicate dynamic_property (f l x : rep_type) = in_range x
end

module Static_Float32
  use ieee_float.Float32

  clone export Static_Floating_Point with
    type rep_type = t,
    predicate eq = eq,
    predicate is_finite = t'isFinite
end

module Rep_Proj_Float32
  (* Specification of to_rep when rep_type = float32; add coercion axiom *)
  use ieee_float.Float32

  clone export Rep_Proj_Base with
    type rep_type = t

  axiom coerce_axiom :
    forall x : Float32.t [to_rep (of_rep x)].
      in_range x -> to_rep (of_rep x) = x
end

module Static_Float64
  use ieee_float.Float64

  clone export Static_Floating_Point with
    type rep_type = t,
    predicate eq = eq,
    predicate is_finite = t'isFinite
end

module Rep_Proj_Float64
  (* Specification of to_rep when rep_type = float64; add coercion axiom *)
  use ieee_float.Float64

  clone export Rep_Proj_Base with
    type rep_type = t

  axiom coerce_axiom :
    forall x : Float64.t [to_rep (of_rep x)].
      in_range x -> to_rep (of_rep x) = x
end

module Static_Float80
  use ieee_float.Float80

  clone export Static_Floating_Point with
    type rep_type = t,
    predicate eq = eq,
    predicate is_finite = t'isFinite
end

module Rep_Proj_Float80
  (* Specification of to_rep when rep_type = float80; add coercion axiom *)
  use ieee_float.Float80

  clone export Rep_Proj_Base with
    type rep_type = t

  axiom coerce_axiom :
    forall x : Float80.t [to_rep (of_rep x)].
      in_range x -> to_rep (of_rep x) = x
end

module Dynamic_Floating_Point
  (* The module that is used as basis for all "dynamic" floating-point types. *)

  clone export Floating_Point_Base

  function base_to_rep t : rep_type
  function base_of_rep rep_type : t

  meta "model_projection" function base_to_rep

  val base_of_rep (x : rep_type) : t
    ensures  { base_to_rep (result) = x }

  function to_rep (x : t) : rep_type = base_to_rep x
  function of_rep (x : rep_type) : t = base_of_rep x

  val to_rep (x : t) : rep_type
  ensures { result = base_to_rep x }
  val of_rep (x : rep_type) : t
  ensures { result = base_of_rep x }

  predicate dynamic_property (first last n : rep_type)

  val check_not_last (_ last n : rep_type) : rep_type
    requires { n <> last }
    ensures { result = n }

  val check_not_first (first _ n : rep_type) : rep_type
    requires { n <> first }
    ensures { result = n }

  val range_check_ (first last n : rep_type) : rep_type
    requires { dynamic_property first last n }
    ensures { result = n /\ dynamic_property first last n }
end

(* The following modules are templates for unconstrained and constrained array
types. Only the one for one dimension is commented, the others are very similar *)

(* ??? TBD Index types of arrays are treated in a special way, but there is no
reason for that: something similar could be the basis for all
scalar types. To be done. *)

module Index_Type
  (* This is the module for an index type of an unconstrained array. first
  and last are always in the base type, but when first <= last, then they are
  actually in the index subtype. *)

  (* These are filled in for every instance of an index type *)
  type base
  type rep

  function  to_rep base : rep
  meta "model_projection" function to_rep
  predicate in_range_base rep
  predicate index_dynamic_property rep rep rep
  predicate index_le rep rep

  (* the bound type *)
  type t = {rec__first : base;
            rec__last  : base}

  (* first and last of an index *)
  let function first (x:t) : base = x.rec__first

  let function last (x:t) : base = x.rec__last

  (* constructing and deconstructing the index *)
  val function mk rep rep : t

  axiom mk_def :
    forall f l : rep [mk f l].
      in_range_base f ->
      in_range_base l ->
      (to_rep (first (mk f l)) = f /\
        to_rep (last (mk f l)) = l)
  meta "remove_unused:dependency" axiom mk_def, function mk

  (* The range check that is required by conversion to an unconstrained array.
     See RM 3.6.2(4-6) and 4.6(38) *)
  predicate dynamic_property (range_first : rep) (range_last : rep) (low : rep) (high : rep) =
    in_range_base low /\ in_range_base high /\
       (index_le low high -> (index_dynamic_property range_first range_last low /\ index_dynamic_property range_first range_last high))
end

module Array_Comparison_Axiom
  use int.Int

  (* These declarations have to be filled in by gnat2why for each
  discrete 1 dimension array type *)
  type component_type
  type rep_type
  type map

  clone _gnatprove_standard.Array__Index as Index

  predicate rep_lt rep_type rep_type
  predicate rep_gt rep_type rep_type

  function to_rep component_type : rep_type
  meta "model_projection" function to_rep

  function get map Index.t : component_type
  function bool_eq map Index.t Index.t map Index.t Index.t : bool

  val function lcp map Index.t Index.t map Index.t Index.t : Index.t
  (* Compute the last index of the longest common prefix between 2 arrays.
     To preserve soundness and not assume the existence of an index smaller
     than the first index of any arrays, it is only defined if a and b have
     at least an element in common. *)
  meta "encoding:lskept" function lcp

  axiom lcp_def :
    forall a b : map.
    forall a_first a_last b_first b_last : Index.t [lcp a a_first a_last b b_first b_last].
      (* Conditions of applications:
           a and b are non empty, and a (a_first) = b (b_first) *)
      Index.le a_first a_last /\ Index.le b_first b_last /\
      to_rep (get a a_first) = to_rep (get b b_first) ->
      (* Use lcp to find the last index of the longest common prefix
         in a and b *)
      let a_i = lcp a a_first a_last b b_first b_last in
      let b_i = lcp b b_first b_last a a_first a_last in
      (* a_i - a_first = b_i - b_first *)
      Index.sub a_i a_first = Index.sub b_i b_first /\
      (* a_first <= a_i <= a_last *)
      Index.le a_first a_i /\ Index.le a_i a_last /\
      (* b_first <= b_i <= b_last *)
      Index.le b_first b_i /\ Index.le b_i b_last /\
      (* a (a_first .. a_i) = b (b_first .. b_i) *)
      bool_eq a a_first a_i b b_first b_i = True /\
      (* It is the longest prefix, ie either we have reached the end of a or b,
         or the next elements in a and b are not equal. *)
      (a_i = a_last \/ b_i = b_last \/
        (Index.lt a_i a_last /\ Index.lt b_i b_last /\
         to_rep (get a (Index.add a_i Index.one)) <>
         to_rep (get b (Index.add b_i Index.one))))
  meta "remove_unused:dependency" axiom lcp_def, function lcp

  val function compare map Index.t Index.t map Index.t Index.t : int
  meta "encoding:lskept" function compare

  axiom compare_def_eq :
    forall a b : map.
    forall a_first a_last b_first b_last : Index.t [compare a a_first a_last b b_first b_last].
      (compare a a_first a_last b b_first b_last = 0 <->
          bool_eq a a_first a_last b b_first b_last = True)
  meta "remove_unused:dependency" axiom compare_def_eq, function compare

  axiom compare_def_lt :
    forall a b : map.
    forall a_first a_last b_first b_last : Index.t [compare a a_first a_last b b_first b_last].
      (compare a a_first a_last b b_first b_last < 0 <->
       (* b is non empty and ... *)
       (Index.le b_first b_last /\
         (* a is empty or ... *)
         (Index.lt a_last a_first \/
          (* a is non empty and ... *)
          Index.le a_first a_last /\
           (* a (a_first) < b (b_first) or ... *)
           (rep_lt (to_rep (get a a_first)) (to_rep (get b b_first)) \/
            (* a (a_first) = b (b_first) and ... *)
            (to_rep (get a a_first) = to_rep (get b b_first) /\
              (* Use lcp to find the last index of the longest common prefix
                 in a and b. *)
              (let a_i = lcp a a_first a_last b b_first b_last in
               let b_i = lcp b b_first b_last a a_first a_last in
                  (* b_i is not the last element of b and ... *)
                  Index.lt b_i b_last /\
                  (* a_i is the last element of a or ... *)
                    (a_i = a_last \/
                    (* the next element of a is smaller than the next element
                         of b. *)
                      Index.lt a_i a_last /\
                         rep_lt (to_rep (get a (Index.add a_i Index.one)))
                                (to_rep (get b (Index.add b_i Index.one))))))))))
  meta "remove_unused:dependency" axiom compare_def_lt, function compare

  axiom compare_def_gt :
    forall a b : map.
    forall a_first a_last b_first b_last : Index.t [compare a a_first a_last b b_first b_last].
      (compare a a_first a_last b b_first b_last > 0 <->
        (* a is non empty and ... *)
        (Index.le a_first a_last /\
        (* b is empty or ... *)
        (Index.lt b_last b_first \/
          (* b is non empty and ... *)
          Index.le b_first b_last /\
           (* a (a_first) > b (b_first) or ... *)
           (rep_gt (to_rep (get a a_first)) (to_rep (get b b_first)) \/
            (* a (a_first) = b (b_first) and ... *)
            (to_rep (get a a_first) = to_rep (get b b_first) /\
              (* Use lcp to find the last index of the longest common prefix
                 in a and b. *)
              (let a_i = lcp a a_first a_last b b_first b_last in
               let b_i = lcp b b_first b_last a a_first a_last in
                  (* a_i is not the last element of a and ... *)
                  Index.lt a_i a_last /\
                     (* b_i is the last element of b or ... *)
                     (b_i = b_last \/
                     (* the next element of a is bigger than the next element
                         of b. *)
                      Index.lt b_i b_last /\
                         rep_gt (to_rep (get a (Index.add a_i Index.one)))
                                (to_rep (get b (Index.add b_i Index.one))))))))))
  meta "remove_unused:dependency" axiom compare_def_gt, function compare
end

module Array_Int_Rep_Comparison_Axiom
  use int.Int

  clone export Array_Comparison_Axiom with
  type rep_type = int,
  predicate rep_lt = (<),
  predicate rep_gt = (>)
end

module Array_BV8_Rep_Comparison_Axiom
  use bv.BV8

  clone export Array_Comparison_Axiom with
  type rep_type = t,
  predicate rep_lt = ult,
  predicate rep_gt = ugt
end

module Array_BV16_Rep_Comparison_Axiom
  use bv.BV16

  clone export Array_Comparison_Axiom with
  type rep_type = t,
  predicate rep_lt = ult,
  predicate rep_gt = ugt
end

module Array_BV32_Rep_Comparison_Axiom
  use bv.BV32

  clone export Array_Comparison_Axiom with
  type rep_type = t,
  predicate rep_lt = ult,
  predicate rep_gt = ugt
end

module Array_BV64_Rep_Comparison_Axiom
  use bv.BV64

  clone export Array_Comparison_Axiom with
  type rep_type = t,
  predicate rep_lt = ult,
  predicate rep_gt = ugt
end

module Array_BV128_Rep_Comparison_Axiom
  use bv.BV128

  clone export Array_Comparison_Axiom with
  type rep_type = t,
  predicate rep_lt = ult,
  predicate rep_gt = ugt
end

module Array_Generic_Op_Axiom
  type component_type
  type map

  clone _gnatprove_standard.Array__Index as Index

  function get map Index.t : component_type

  function to_bool component_type : bool
  function of_bool bool : component_type
  function base_op bool bool : bool

  function array_op map Index.t Index.t map Index.t Index.t : map

  axiom op_def:
   forall a b : map.
   forall a_first a_last b_first b_last : Index.t.
   forall i : Index.t [get (array_op a a_first a_last b b_first b_last) i].
     (Index.le a_first i /\ Index.le i a_last) ->
     get (array_op a a_first a_last b b_first b_last) i =
            of_bool (base_op (to_bool (get a i)) (to_bool (get b (Index.add (Index.sub i a_first) b_first))))
  meta "remove_unused:dependency" axiom op_def, function array_op
end

module Array_Logical_Op_Generic_Axioms
  use bool.Bool as Bool

  (* These declarations have to be filled in by gnat2why for each
       boolean 1 dimension array type *)
   type component_type
   function to_bool component_type : bool
   function of_bool bool : component_type

   type map

   clone _gnatprove_standard.Array__Index as Index

   function get map Index.t : component_type

   function xorb map Index.t Index.t map Index.t Index.t : map
   meta "encoding:lskept" function xorb
   function andb map Index.t Index.t map Index.t Index.t : map
   meta "encoding:lskept" function andb
   function orb  map Index.t Index.t map Index.t Index.t : map
   meta "encoding:lskept" function orb
   function notb map Index.t Index.t : map
   meta "encoding:lskept" function notb

   clone Array_Generic_Op_Axiom as Or_Axiom with
     type component_type = component_type,
     type map = map,
     type Index.t = Index.t,
     predicate Index.le = Index.le,
     predicate Index.lt = Index.lt,
     predicate Index.gt = Index.gt,
     function Index.add = Index.add,
     function Index.sub = Index.sub,
     function Index.one = Index.one,
     function get = get,
     function to_bool = to_bool,
     function of_bool = of_bool,
     function array_op = orb,
     function base_op = Bool.orb

   clone Array_Generic_Op_Axiom as And_Axiom with
     type component_type = component_type,
     type map = map,
     type Index.t = Index.t,
     predicate Index.le = Index.le,
     predicate Index.lt = Index.lt,
     predicate Index.gt = Index.gt,
     function Index.add = Index.add,
     function Index.sub = Index.sub,
     function Index.one = Index.one,
     function get = get,
     function to_bool = to_bool,
     function of_bool = of_bool,
     function array_op = andb,
     function base_op = Bool.andb

   clone Array_Generic_Op_Axiom as Xor_Axiom with
     type component_type = component_type,
     type map = map,
     type Index.t = Index.t,
     predicate Index.le = Index.le,
     predicate Index.lt = Index.lt,
     predicate Index.gt = Index.gt,
     function Index.add = Index.add,
     function Index.sub = Index.sub,
     function Index.one = Index.one,
     function get = get,
     function to_bool = to_bool,
     function of_bool = of_bool,
     function array_op = xorb,
     function base_op = Bool.xorb

   axiom notb_def:
    forall a : map.
    forall a_first a_last : Index.t.
    forall i : Index.t [get (notb a a_first a_last) i].
      (Index.le a_first i /\ Index.le i a_last) ->
      get (notb a a_first a_last) i =
             of_bool (Bool.notb (to_bool (get a i)))
  meta "remove_unused:dependency" axiom notb_def, function notb

   val xorb (a : map) (af : Index.t) (al : Index.t) (b : map) (bf : Index.t) (bl : Index.t) : map
   ensures { result = xorb a af al b bf bl }

   val andb (a : map) (af : Index.t) (al : Index.t) (b : map) (bf : Index.t) (bl : Index.t) : map
   ensures { result = andb a af al b bf bl }

   val orb (a : map) (af : Index.t) (al : Index.t) (b : map) (bf : Index.t) (bl : Index.t) : map
   ensures { result = orb a af al b bf bl }

   val notb (a : map) (af : Index.t) (al : Index.t) : map
   ensures { result = notb a af al }
end

module Standard_Array_Logical_Op_Axioms
  use bool.Bool

  function bool_id (b : bool) : bool = b

  clone export Array_Logical_Op_Generic_Axioms with
     type component_type = bool,
     function to_bool = bool_id,
     function of_bool = bool_id
end

module Subtype_Array_Logical_Op_Axioms
  use int.Int
  use "_gnatprove_standard".Boolean as Boolean

   type component_type
   function to_int component_type : int
   function of_int int : component_type

  function to_bool (x : component_type) : bool = Boolean.of_int (to_int (x))
  function of_bool (x : bool) : component_type = of_int (Boolean.to_int (x))

  clone export Array_Logical_Op_Generic_Axioms with
     type component_type = component_type,
     function to_bool = to_bool,
     function of_bool = of_bool
end

module Unconstr_Array
  (* The module to be cloned for an unconstrained array of dimension 1 *)

  (* These declarations have to be filled in by gnat2why for each
  unconstrained array type *)
  type map

  type index_base_type
  type index_rep_type

  function to_rep index_base_type : index_rep_type
  function rep_to_int index_rep_type : int

  meta "model_projection" function to_rep

  predicate in_range_base index_rep_type
  predicate index_dynamic_property index_rep_type index_rep_type index_rep_type
  predicate index_rep_le index_rep_type index_rep_type

  function array_bool_eq map index_rep_type index_rep_type map index_rep_type index_rep_type : bool

  clone Index_Type as I1 with
    type      base          = index_base_type,
    type      rep           = index_rep_type,
    function  to_rep        = to_rep,
    predicate index_le      = index_rep_le,
    predicate in_range_base = in_range_base,
    predicate index_dynamic_property = index_dynamic_property

  (* An unconstrained array comes with its bounds *)
  type __t [@syntax:array:elts] =
    { elts [@syntax:getter:elts] [@model_trace:] : map; rt : I1.t }

  let function to_array [@rewrite:to_array] (a : __t) : map = a.elts

  let function of_array [@rewrite:of_array] (a : map) (f l : index_rep_type) : __t =
    { elts = a; rt = I1.mk f l }

  use int.Int

  function first [@name:First] [@model_trace:'First] [@rewrite:first] (a : __t) : index_rep_type = to_rep (I1.first a.rt)
  val first (a : __t) : index_rep_type
  ensures { result = first a }

  function last [@name:Last] [@model_trace:'Last] [@rewrite:last] (a : __t) : index_rep_type = to_rep (I1.last a.rt)
  val last (a : __t) : index_rep_type
  ensures { result = last a }

  function length (a : __t) : int =
    if index_rep_le (first a) (last a) then
      rep_to_int (last a) - rep_to_int (first a) + 1 else 0
  val length (a : __t) : int
  ensures { result = length a }

  predicate dynamic_property (range_first range_last f1 l1 : index_rep_type) =
    I1.dynamic_property range_first range_last f1 l1

  val constant value__size : int

  val constant object__size : int

  val constant component__size : int

  val constant alignment : int

  axiom value__size_axiom :
    value__size >= 0
  meta "remove_unused:dependency" axiom value__size_axiom, function value__size

  axiom object__size_axiom :
    object__size >= 0
  meta "remove_unused:dependency" axiom object__size_axiom, function object__size

  axiom component__size_axiom :
    component__size >= 0
  meta "remove_unused:dependency" axiom component__size_axiom, function component__size

  axiom alignment_axiom :
    alignment >= 0
  meta "remove_unused:dependency" axiom alignment_axiom, function alignment

  function bool_eq (x : __t) (y : __t) : bool =
    array_bool_eq
      x.elts (to_rep (I1.first x.rt)) (to_rep (I1.last x.rt))
      y.elts (to_rep (I1.first y.rt)) (to_rep (I1.last y.rt))

  val bool_eq (x : __t) (y : __t) : bool
  ensures { result =  bool_eq x y }

  val function user_eq (x : __t) (y : __t) : bool

  val constant dummy : __t
  meta "remove_unused:remove_constant" constant dummy
end

module Unconstr_Array_2
  (* The module to be cloned for an unconstrained array of dimension 1 *)

  type map

  type index_base_type
  type index_rep_type

  function to_rep index_base_type : index_rep_type
  function rep_to_int index_rep_type : int

  meta "model_projection" function to_rep

  predicate in_range_base index_rep_type
  predicate index_dynamic_property index_rep_type index_rep_type index_rep_type
  predicate index_rep_le index_rep_type index_rep_type

  type index_base_type_2
  type index_rep_type_2

  function to_rep_2 index_base_type_2 : index_rep_type_2
  function rep_to_int_2 index_rep_type_2 : int

  meta "model_projection" function to_rep_2

  predicate in_range_base_2 index_rep_type_2
  predicate index_dynamic_property_2 index_rep_type_2 index_rep_type_2 index_rep_type_2
  predicate index_rep_le_2 index_rep_type_2 index_rep_type_2

  function array_bool_eq map index_rep_type index_rep_type index_rep_type_2 index_rep_type_2 map index_rep_type index_rep_type index_rep_type_2 index_rep_type_2 : bool

  clone Index_Type as I1 with
    type      base          = index_base_type,
    type      rep           = index_rep_type,
    function  to_rep        = to_rep,
    predicate index_le      = index_rep_le,
    predicate in_range_base = in_range_base,
    predicate index_dynamic_property = index_dynamic_property

  clone Index_Type as I2 with
    type      base          = index_base_type_2,
    type      rep           = index_rep_type_2,
    function  to_rep        = to_rep_2,
    predicate index_le      = index_rep_le_2,
    predicate in_range_base = in_range_base_2,
    predicate index_dynamic_property = index_dynamic_property_2

  type __t =
    { elts [@model_trace:] : map;
      rt : I1.t;
      rt_2 : I2.t
    }

  let function to_array (a : __t) : map =
    a.elts

  let function of_array (a : map)
    (f l : index_rep_type) (f2 l2 : index_rep_type_2) : __t =
    { elts = a;
      rt = I1.mk f l;
      rt_2 = I2.mk f2 l2 }

  use int.Int

  function first [@model_trace:'First (1)] (a : __t) : index_rep_type = to_rep (I1.first a.rt)
  val first (a : __t) : index_rep_type
  ensures { result = first a }

  function last [@model_trace:'Last (1)] (a : __t) : index_rep_type = to_rep (I1.last a.rt)
  val last (a : __t) : index_rep_type
  ensures { result = last a }

  function length (a : __t) : int =
    if index_rep_le (first a) (last a) then
      rep_to_int (last a) - rep_to_int (first a) + 1 else 0
  val length (a : __t) : int
  ensures { result = length a }

  function first_2 [@model_trace:'First (2)]  (a : __t) : index_rep_type_2 = to_rep_2 (I2.first a.rt_2)
  val first_2 (a : __t) : index_rep_type_2
  ensures { result = first_2 a }

  function last_2 [@model_trace:'Last (2)] (a : __t) : index_rep_type_2 = to_rep_2 (I2.last a.rt_2)
  val last_2 (a : __t) : index_rep_type_2
  ensures { result = last_2 a }

  function length_2 (a : __t) : int =
    if index_rep_le_2 (first_2 a) (last_2 a) then
      rep_to_int_2 (last_2 a) - rep_to_int_2 (first_2 a) + 1 else 0
  val length_2 (a : __t) : int
  ensures { result = length_2 a }

  predicate dynamic_property (range_first1 range_last1 f1 l1 : index_rep_type)
                             (range_first2 range_last2 f2 l2 : index_rep_type_2) =
    I1.dynamic_property range_first1 range_last1 f1 l1 /\ I2.dynamic_property range_first2 range_last2 f2 l2

  val function value__size : int

  val constant object__size : int

  val constant component__size : int

  val constant alignment : int

  axiom value__size_axiom :
    value__size >= 0
  meta "remove_unused:dependency" axiom value__size_axiom, function value__size

  axiom object__size_axiom :
    object__size >= 0
  meta "remove_unused:dependency" axiom object__size_axiom, function object__size

  axiom component__size_axiom :
    component__size >= 0
  meta "remove_unused:dependency" axiom component__size_axiom, function component__size

  axiom alignment_axiom:
    alignment >= 0
  meta "remove_unused:dependency" axiom alignment_axiom, function alignment

  function bool_eq (x : __t) (y : __t) : bool =
    array_bool_eq
      x.elts (to_rep (I1.first x.rt)) (to_rep (I1.last x.rt))
             (to_rep_2 (I2.first x.rt_2)) (to_rep_2 (I2.last x.rt_2))
      y.elts (to_rep (I1.first y.rt)) (to_rep (I1.last y.rt))
             (to_rep_2 (I2.first y.rt_2)) (to_rep_2 (I2.last y.rt_2))

  val bool_eq (x : __t) (y : __t) : bool
  ensures { result =  bool_eq x y }

  val function user_eq (x : __t) (y : __t) : bool

  val constant dummy : __t
  meta "remove_unused:remove_constant" constant dummy
end

module Unconstr_Array_3
  (* The module to be cloned for an unconstrained array of dimension 1 *)

  type map

  type index_base_type
  type index_rep_type

  function to_rep index_base_type : index_rep_type
  function rep_to_int index_rep_type : int

  meta "model_projection" function to_rep

  predicate in_range_base index_rep_type
  predicate index_dynamic_property index_rep_type index_rep_type index_rep_type
  predicate index_rep_le index_rep_type index_rep_type

  type index_base_type_2
  type index_rep_type_2

  function to_rep_2 index_base_type_2 : index_rep_type_2
  function rep_to_int_2 index_rep_type_2 : int

  meta "model_projection" function to_rep_2

  predicate in_range_base_2 index_rep_type_2
  predicate index_dynamic_property_2 index_rep_type_2 index_rep_type_2 index_rep_type_2
  predicate index_rep_le_2 index_rep_type_2 index_rep_type_2

  type index_base_type_3
  type index_rep_type_3

  function to_rep_3 index_base_type_3 : index_rep_type_3
  function rep_to_int_3 index_rep_type_3 : int

  meta "model_projection" function to_rep_3

  predicate in_range_base_3 index_rep_type_3
  predicate index_dynamic_property_3 index_rep_type_3 index_rep_type_3 index_rep_type_3
  predicate index_rep_le_3 index_rep_type_3 index_rep_type_3

  function array_bool_eq map index_rep_type index_rep_type index_rep_type_2 index_rep_type_2 index_rep_type_3 index_rep_type_3 map index_rep_type index_rep_type index_rep_type_2 index_rep_type_2 index_rep_type_3 index_rep_type_3 : bool

  clone Index_Type as I1 with
    type      base          = index_base_type,
    type      rep           = index_rep_type,
    function  to_rep        = to_rep,
    predicate index_le      = index_rep_le,
    predicate in_range_base = in_range_base,
    predicate index_dynamic_property = index_dynamic_property

  clone Index_Type as I2 with
    type      base          = index_base_type_2,
    type      rep           = index_rep_type_2,
    function  to_rep        = to_rep_2,
    predicate index_le      = index_rep_le_2,
    predicate in_range_base = in_range_base_2,
    predicate index_dynamic_property = index_dynamic_property_2

  clone Index_Type as I3 with
    type      base          = index_base_type_3,
    type      rep           = index_rep_type_3,
    function  to_rep        = to_rep_3,
    predicate index_le      = index_rep_le_3,
    predicate in_range_base = in_range_base_3,
    predicate index_dynamic_property = index_dynamic_property_3

  type __t =
    { elts [@model_trace:] : map;
      rt   : I1.t;
      rt_2 : I2.t;
      rt_3 : I3.t
    }

  let function to_array (a : __t) : map =
    a.elts

  let function of_array (a : map)
    (f l : index_rep_type) (f2 l2 : index_rep_type_2) (f3 l3 : index_rep_type_3) : __t =
    { elts = a;
      rt = I1.mk f l;
      rt_2 = I2.mk f2 l2;
      rt_3 = I3.mk f3 l3
    }

  use int.Int

  function first [@model_trace:'First (1)]  (a : __t) : index_rep_type = to_rep (I1.first a.rt)
  val first (a : __t) : index_rep_type
  ensures { result = first a }

  function last [@model_trace:'Last (1)] (a : __t) : index_rep_type = to_rep (I1.last a.rt)
  val last (a : __t) : index_rep_type
  ensures { result = last a }

  function length (a : __t) : int =
    if index_rep_le (first a) (last a) then
      rep_to_int (last a) - rep_to_int (first a) + 1 else 0
  val length (a : __t) : int
  ensures { result = length a }

  function first_2 [@model_trace:'First (2)] (a : __t) : index_rep_type_2 = to_rep_2 (I2.first a.rt_2)
  val first_2 (a : __t) : index_rep_type_2
  ensures { result = first_2 a }

  function last_2 [@model_trace:'Last (2)] (a : __t) : index_rep_type_2 = to_rep_2 (I2.last a.rt_2)
  val last_2 (a : __t) : index_rep_type_2
  ensures { result = last_2 a }

  function length_2 (a : __t) : int =
    if index_rep_le_2 (first_2 a) (last_2 a) then
      rep_to_int_2 (last_2 a) - rep_to_int_2 (first_2 a) + 1 else 0
  val length_2 (a : __t) : int
  ensures { result = length_2 a }

  function first_3 [@model_trace:'First (3)] (a : __t) : index_rep_type_3 = to_rep_3 (I3.first a.rt_3)
  val first_3 (a : __t) : index_rep_type_3
  ensures { result = first_3 a }

  function last_3 [@model_trace:'Last (3)] (a : __t) : index_rep_type_3 = to_rep_3 (I3.last a.rt_3)
  val last_3 (a : __t) : index_rep_type_3
  ensures { result = last_3 a }

  function length_3 (a : __t) : int =
    if index_rep_le_3 (first_3 a) (last_3 a) then
      rep_to_int_3 (last_3 a) - rep_to_int_3 (first_3 a) + 1 else 0
  val length_3 (a : __t) : int
  ensures { result = length_3 a }

  predicate dynamic_property (range_first1 range_last1 f1 l1 : index_rep_type)
                             (range_first2 range_last2 f2 l2 : index_rep_type_2)
                             (range_first3 range_last3 f3 l3 : index_rep_type_3) =
    I1.dynamic_property range_first1 range_last1 f1 l1 /\
    I2.dynamic_property range_first2 range_last2 f2 l2 /\
    I3.dynamic_property range_first3 range_last3 f3 l3

  val constant value__size : int

  val constant object__size : int

  val constant component__size : int

  val constant alignment : int

  axiom value__size_axiom :
    value__size >= 0
  meta "remove_unused:dependency" axiom value__size_axiom, function value__size

  axiom object__size_axiom :
    object__size >= 0
  meta "remove_unused:dependency" axiom object__size_axiom, function object__size

  axiom component__size_axiom :
    component__size >= 0
  meta "remove_unused:dependency" axiom component__size_axiom, function component__size

  axiom alignment_axiom :
    alignment >= 0
  meta "remove_unused:dependency" axiom alignment_axiom, function alignment

  function bool_eq (x : __t) (y : __t) : bool =
    array_bool_eq
      x.elts (to_rep (I1.first x.rt))   (to_rep (I1.last x.rt))
             (to_rep_2 (I2.first x.rt_2)) (to_rep_2 (I2.last x.rt_2))
             (to_rep_3 (I3.first x.rt_3)) (to_rep_3 (I3.last x.rt_3))
      y.elts (to_rep (I1.first y.rt))   (to_rep (I1.last y.rt))
             (to_rep_2 (I2.first y.rt_2)) (to_rep_2 (I2.last y.rt_2))
             (to_rep_3 (I3.first y.rt_3)) (to_rep_3 (I3.last y.rt_3))

  val bool_eq (x : __t) (y : __t) : bool
  ensures { result =  bool_eq x y }

  val function user_eq (x : __t) (y : __t) : bool

  val constant dummy : __t
  meta "remove_unused:remove_constant" constant dummy
end

module Unconstr_Array_4
  (* The module to be cloned for an unconstrained array of dimension 1 *)

  type map

  type index_base_type
  type index_rep_type

  function to_rep index_base_type : index_rep_type
  function rep_to_int index_rep_type : int

  meta "model_projection" function to_rep

  predicate in_range_base index_rep_type
  predicate index_dynamic_property index_rep_type index_rep_type index_rep_type
  predicate index_rep_le index_rep_type index_rep_type

  type index_base_type_2
  type index_rep_type_2

  function to_rep_2 index_base_type_2 : index_rep_type_2
  function rep_to_int_2 index_rep_type_2 : int

  meta "model_projection" function to_rep_2

  predicate in_range_base_2 index_rep_type_2
  predicate index_dynamic_property_2 index_rep_type_2 index_rep_type_2 index_rep_type_2
  predicate index_rep_le_2 index_rep_type_2 index_rep_type_2

  type index_base_type_3
  type index_rep_type_3

  function to_rep_3 index_base_type_3 : index_rep_type_3
  function rep_to_int_3 index_rep_type_3 : int

  meta "model_projection" function to_rep_3

  predicate in_range_base_3 index_rep_type_3
  predicate index_dynamic_property_3 index_rep_type_3 index_rep_type_3 index_rep_type_3
  predicate index_rep_le_3 index_rep_type_3 index_rep_type_3

  type index_base_type_4
  type index_rep_type_4

  function to_rep_4 index_base_type_4 : index_rep_type_4
  function rep_to_int_4 index_rep_type_4 : int

  meta "model_projection" function to_rep_4

  predicate in_range_base_4 index_rep_type_4
  predicate index_dynamic_property_4 index_rep_type_4 index_rep_type_4 index_rep_type_4
  predicate index_rep_le_4 index_rep_type_4 index_rep_type_4

  function array_bool_eq map index_rep_type index_rep_type index_rep_type_2 index_rep_type_2 index_rep_type_3 index_rep_type_3 index_rep_type_4 index_rep_type_4 map index_rep_type index_rep_type index_rep_type_2 index_rep_type_2 index_rep_type_3 index_rep_type_3 index_rep_type_4 index_rep_type_4 : bool

  clone Index_Type as I1 with
    type      base          = index_base_type,
    type      rep           = index_rep_type,
    function  to_rep        = to_rep,
    predicate index_le      = index_rep_le,
    predicate in_range_base = in_range_base,
    predicate index_dynamic_property = index_dynamic_property

  clone Index_Type as I2 with
    type      base          = index_base_type_2,
    type      rep           = index_rep_type_2,
    function  to_rep        = to_rep_2,
    predicate index_le      = index_rep_le_2,
    predicate in_range_base = in_range_base_2,
    predicate index_dynamic_property = index_dynamic_property_2

  clone Index_Type as I3 with
    type      base          = index_base_type_3,
    type      rep           = index_rep_type_3,
    function  to_rep        = to_rep_3,
    predicate index_le      = index_rep_le_3,
    predicate in_range_base = in_range_base_3,
    predicate index_dynamic_property = index_dynamic_property_3

  clone Index_Type as I4 with
    type      base          = index_base_type_4,
    type      rep           = index_rep_type_4,
    function  to_rep        = to_rep_4,
    predicate index_le      = index_rep_le_4,
    predicate in_range_base = in_range_base_4,
    predicate index_dynamic_property = index_dynamic_property_4

  type __t =
    { elts [@model_trace:] : map;
      rt   : I1.t;
      rt_2 : I2.t;
      rt_3 : I3.t;
      rt_4 : I4.t
    }

  let function to_array (a : __t) : map =
    a.elts

  let function of_array (a : map)
    (f l : index_rep_type)
    (f2 l2 : index_rep_type_2)
    (f3 l3 : index_rep_type_3)
    (f4 l4 : index_rep_type_4) : __t =
    { elts = a;
      rt = I1.mk f l;
      rt_2 = I2.mk f2 l2;
      rt_3 = I3.mk f3 l3;
      rt_4 = I4.mk f4 l4
    }

  use int.Int

  function first [@model_trace:'First (1)] (a : __t) : index_rep_type = to_rep (I1.first a.rt)
  val first (a : __t) : index_rep_type
  ensures { result = first a }

  function last [@model_trace:'Last (1)] (a : __t) : index_rep_type = to_rep (I1.last a.rt)
  val last (a : __t) : index_rep_type
  ensures { result = last a }

  function length (a : __t) : int =
    if index_rep_le (first a) (last a) then
      rep_to_int (last a) - rep_to_int (first a) + 1 else 0
  val length (a : __t) : int
  ensures { result = length a }

  function first_2 [@model_trace:'First (2)] (a : __t) : index_rep_type_2 = to_rep_2 (I2.first a.rt_2)
  val first_2 (a : __t) : index_rep_type_2
  ensures { result = first_2 a }

  function last_2 [@model_trace:'Last (2)] (a : __t) : index_rep_type_2 = to_rep_2 (I2.last a.rt_2)
  val last_2 (a : __t) : index_rep_type_2
  ensures { result = last_2 a }

  function length_2 (a : __t) : int =
    if index_rep_le_2 (first_2 a) (last_2 a) then
      rep_to_int_2 (last_2 a) - rep_to_int_2 (first_2 a) + 1 else 0
  val length_2 (a : __t) : int
  ensures { result = length_2 a }

  function first_3 [@model_trace:'First (3)] (a : __t) : index_rep_type_3 = to_rep_3 (I3.first a.rt_3)
  val first_3 (a : __t) : index_rep_type_3
  ensures { result = first_3 a }

  function last_3 [@model_trace:'Last (3)] (a : __t) : index_rep_type_3 = to_rep_3 (I3.last a.rt_3)
  val last_3 (a : __t) : index_rep_type_3
  ensures { result = last_3 a }

  function length_3 (a : __t) : int =
    if index_rep_le_3 (first_3 a) (last_3 a) then
      rep_to_int_3 (last_3 a) - rep_to_int_3 (first_3 a) + 1 else 0
  val length_3 (a : __t) : int
  ensures { result = length_3 a }

  function first_4 [@model_trace:'First (4)] (a : __t) : index_rep_type_4 = to_rep_4 (I4.first a.rt_4)
  val first_4 (a : __t) : index_rep_type_4
  ensures { result = first_4 a }

  function last_4 [@model_trace:'Last (4)] (a : __t) : index_rep_type_4 = to_rep_4 (I4.last a.rt_4)
  val last_4 (a : __t) : index_rep_type_4
  ensures { result = last_4 a }

  function length_4 (a : __t) : int =
    if index_rep_le_4 (first_4 a) (last_4 a) then
      rep_to_int_4 (last_4 a) - rep_to_int_4 (first_4 a) + 1 else 0
  val length_4 (a : __t) : int
  ensures { result = length_4 a }

  predicate dynamic_property (range_first1 range_last1 f1 l1 : index_rep_type)
                             (range_first2 range_last2 f2 l2 : index_rep_type_2)
                             (range_first3 range_last3 f3 l3 : index_rep_type_3)
                             (range_first4 range_last4 f4 l4 : index_rep_type_4) =
    I1.dynamic_property range_first1 range_last1 f1 l1 /\
    I2.dynamic_property range_first2 range_last2 f2 l2 /\
    I3.dynamic_property range_first3 range_last3 f3 l3 /\
    I4.dynamic_property range_first4 range_last4 f4 l4

  val constant value__size : int

  val constant object__size : int

  val constant component__size : int

  val constant alignment : int

  axiom value__size_axiom :
    value__size >= 0
  meta "remove_unused:dependency" axiom value__size_axiom, function value__size

  axiom object__size_axiom :
    object__size >= 0
  meta "remove_unused:dependency" axiom object__size_axiom, function object__size

  axiom component__size_axiom :
    component__size >= 0
  meta "remove_unused:dependency" axiom component__size_axiom, function component__size

  axiom alignment_axiom :
    alignment >= 0
  meta "remove_unused:dependency" axiom alignment_axiom, function alignment

  function bool_eq (x : __t) (y : __t) : bool =
    array_bool_eq
      x.elts (to_rep (I1.first x.rt))   (to_rep (I1.last x.rt))
             (to_rep_2 (I2.first x.rt_2)) (to_rep_2 (I2.last x.rt_2))
             (to_rep_3 (I3.first x.rt_3)) (to_rep_3 (I3.last x.rt_3))
             (to_rep_4 (I4.first x.rt_4)) (to_rep_4 (I4.last x.rt_4))
      y.elts (to_rep (I1.first y.rt))   (to_rep (I1.last y.rt))
             (to_rep_2 (I2.first y.rt_2)) (to_rep_2 (I2.last y.rt_2))
             (to_rep_3 (I3.first y.rt_3)) (to_rep_3 (I3.last y.rt_3))
             (to_rep_4 (I4.first y.rt_4)) (to_rep_4 (I4.last y.rt_4))

  val bool_eq (x : __t) (y : __t) : bool
  ensures { result =  bool_eq x y }

  val function user_eq (x : __t) (y : __t) : bool

  val constant dummy : __t
  meta "remove_unused:remove_constant" constant dummy
end

module Constr_Array
  type index_rep_type
  type map

  function first : index_rep_type
  function last  : index_rep_type

  function array_bool_eq map index_rep_type index_rep_type map index_rep_type index_rep_type : bool

  type __t = map

  val constant dummy : __t
  meta "remove_unused:remove_constant" constant dummy

  val constant value__size : int

  val constant object__size : int

  val constant component__size : int

  val constant alignment : int

  use int.Int

  axiom value__size_axiom :
    value__size >= 0
  meta "remove_unused:dependency" axiom value__size_axiom, function value__size

  axiom object__size_axiom :
    object__size >= 0
  meta "remove_unused:dependency" axiom object__size_axiom, function object__size

  axiom component__size_axiom :
    component__size >= 0
  meta "remove_unused:dependency" axiom component__size_axiom, function component__size

  axiom alignment_axiom :
    alignment >= 0
  meta "remove_unused:dependency" axiom alignment_axiom, function alignment

  function bool_eq (x : __t) (y : __t) : bool =
    array_bool_eq x first last
                  y first last

  val bool_eq (x : __t) (y : __t) : bool
  ensures { result =  bool_eq x y }

  val function user_eq (x : __t) (y : __t) : bool
end

module Constr_Array_2
  type index_rep_type
  type index_rep_type_2
  type map

  function first : index_rep_type
  function last  : index_rep_type

  function first_2 : index_rep_type_2
  function last_2  : index_rep_type_2

  function array_bool_eq map index_rep_type index_rep_type index_rep_type_2 index_rep_type_2 map index_rep_type index_rep_type index_rep_type_2 index_rep_type_2 : bool

  type __t = map

  val constant dummy : __t
  meta "remove_unused:remove_constant" constant dummy

  val constant value__size : int

  val constant object__size : int

  val constant component__size : int

  val constant alignment : int

  use int.Int

  axiom value__size_axiom :
    value__size >= 0
  meta "remove_unused:dependency" axiom value__size_axiom, function value__size

  axiom object__size_axiom :
    object__size >= 0
  meta "remove_unused:dependency" axiom object__size_axiom, function object__size

  axiom component__size_axiom :
    component__size >= 0
  meta "remove_unused:dependency" axiom component__size_axiom, function component__size

  axiom alignment_axiom :
    alignment >= 0
  meta "remove_unused:dependency" axiom alignment_axiom, function alignment

  function bool_eq (x : __t) (y : __t) : bool =
    array_bool_eq x first last first_2 last_2
                  y first last first_2 last_2

  val bool_eq (x : __t) (y : __t) : bool
  ensures { result =  bool_eq x y }

  val function user_eq (x : __t) (y : __t) : bool
end

module Constr_Array_3
  type index_rep_type
  type index_rep_type_2
  type index_rep_type_3
  type map

  function first : index_rep_type
  function last  : index_rep_type

  function first_2 : index_rep_type_2
  function last_2  : index_rep_type_2

  function first_3 : index_rep_type_3
  function last_3  : index_rep_type_3

  function array_bool_eq map index_rep_type index_rep_type index_rep_type_2 index_rep_type_2 index_rep_type_3 index_rep_type_3 map index_rep_type index_rep_type index_rep_type_2 index_rep_type_2 index_rep_type_3 index_rep_type_3 : bool

  type __t = map

  val constant dummy : __t
  meta "remove_unused:remove_constant" constant dummy

  val constant value__size : int

  val constant object__size : int

  val constant component__size : int

  val constant alignment : int

  use int.Int

  axiom value__size_axiom :
    value__size >= 0
  meta "remove_unused:dependency" axiom value__size_axiom, function value__size

  axiom object__size_axiom :
    object__size >= 0
  meta "remove_unused:dependency" axiom object__size_axiom, function object__size

  axiom component__size_axiom :
    component__size >= 0
  meta "remove_unused:dependency" axiom component__size_axiom, function component__size

  axiom alignment_axiom :
    alignment >= 0
  meta "remove_unused:dependency" axiom alignment_axiom, function alignment

  function bool_eq (x : __t) (y : __t) : bool =
    array_bool_eq x first last first_2 last_2 first_3 last_3
                  y first last first_2 last_2 first_3 last_3

  val bool_eq (x : __t) (y : __t) : bool
  ensures { result =  bool_eq x y }

  val function user_eq (x : __t) (y : __t) : bool
end

module Constr_Array_4
  type index_rep_type
  type index_rep_type_2
  type index_rep_type_3
  type index_rep_type_4
  type map

  function first : index_rep_type
  function last  : index_rep_type

  function first_2 : index_rep_type_2
  function last_2  : index_rep_type_2

  function first_3 : index_rep_type_3
  function last_3  : index_rep_type_3

  function first_4 : index_rep_type_4
  function last_4  : index_rep_type_4

  function array_bool_eq map index_rep_type index_rep_type index_rep_type_2 index_rep_type_2 index_rep_type_3 index_rep_type_3 index_rep_type_4 index_rep_type_4 map index_rep_type index_rep_type index_rep_type_2 index_rep_type_2 index_rep_type_3 index_rep_type_3 index_rep_type_4 index_rep_type_4 : bool

  type __t = map

  val constant dummy : __t
  meta "remove_unused:remove_constant" constant dummy

  val constant value__size : int

  val constant object__size : int

  val constant component__size : int

  val constant alignment : int

  use int.Int

  axiom value__size_axiom :
    value__size >= 0
  meta "remove_unused:dependency" axiom value__size_axiom, function value__size

  axiom object__size_axiom :
    object__size >= 0
  meta "remove_unused:dependency" axiom object__size_axiom, function object__size

  axiom component__size_axiom :
    component__size >= 0
  meta "remove_unused:dependency" axiom component__size_axiom, function component__size

  axiom alignment_axiom :
    alignment >= 0
  meta "remove_unused:dependency" axiom alignment_axiom, function alignment

  function bool_eq (x : __t) (y : __t) : bool =
    array_bool_eq x first last first_2 last_2 first_3 last_3 first_4 last_4
                  y first last first_2 last_2 first_3 last_3 first_4 last_4

  val bool_eq (x : __t) (y : __t) : bool
  ensures { result =  bool_eq x y }

  val function user_eq (x : __t) (y : __t) : bool
end

(* Module defining a bijection between an abstract type abstr_ty and a concrete
   type comp_ty. *)

module Incomplete_type
  type abstr_ty
  type comp_ty

  val function __open (x : abstr_ty) : comp_ty
  val function __close (x : comp_ty) : abstr_ty

  axiom close_open:
    forall x : abstr_ty [__open x]. __close (__open x) = x
  meta "remove_unused:dependency" axiom close_open, function __open

  axiom open_close:
    forall x : comp_ty [__close x]. __open (__close x) = x
  meta "remove_unused:dependency" axiom open_close, function __close
end

(* Module for the pledge of a local borrower. Morally, a pledge is a predicate
   representing the link between the borrowed value and the borrower. We do
   not use Why3 lambdas to avoid introducing polymorphism. Instead, we represent
   a pledge as a two parameter map with a function get to query whether the
   relation holds between the borrowed value and the borrower. *)

module Pledge
  type borrower
  type borrowed

  type __pledge_ty

  type __pledge_ty__ref = { mutable __pledge_ty__content[@model_trace:] : __pledge_ty }

  val function __pledge_get __pledge_ty borrowed borrower : bool
end
