Library StridedIntervals

Numerical domain of Strided Intervals.
Reference: Gogul Balakrishnan. “WYSINWYX: what you see is not what you eXecute.” PhD thesis. Madison: University of Wisconsin, 2007.
Abstract values are triples (s, l, u) representing all integers i, s.t.
l ≤ i ≤ u ∧ i ≡ l (mod s).
It is supposed to precisely capture common families of addresses, e.g., contiguous cells in an array.
Since the congruence domain is not very precise on machine integers (moduli must be powers of two since any operation might overflow), this domain is strictly more precise than the reduced product of intervals and congruences on machine integers.
Moreover, it is more precise than the projection to machine integers of the reduced product of the congruence domain on Z and the interval domain on Z in case of overflows.


Local Coercion Z_of_N : N >-> Z.

Data type.
Not a dependent type. In particular the type does neither enforce that bounds are correctly ordered nor that the upper bound is tight. However, some operations assume it (they are otherwise unprecise). The operations that would be unsound do the appropriate checks.
Record strided_interval : Type :=
  { si_stride : N
  ; si_low_bound: Z
  ; si_up_bound : Z
  }.

Definition si_valid (s: strided_interval) : Prop :=
  s.(si_low_bound) s.(si_up_bound).

Definition si_reduced (s: strided_interval) : Prop :=
  (s.(si_low_bound) s.(si_up_bound) [ s.(si_stride) ])
(s.(si_low_bound) = s.(si_up_bound) s.(si_stride) = N0).

Definition si_LE (x y: strided_interval) : Prop :=
  y.(si_low_bound) x.(si_low_bound)
x.(si_up_bound) y.(si_up_bound)
( y.(si_stride) | x.(si_stride) )
( x.(si_low_bound) y.(si_low_bound) [y.(si_stride)] ).

Definition si_LE_dec (x y: strided_interval) : { si_LE x y } + { ¬ si_LE x y }.

Definition si_join (x y: strided_interval) : strided_interval :=
  {| si_stride := N.gcd (N.gcd x.(si_stride) y.(si_stride))
                        (Nabs_diff x.(si_low_bound) y.(si_low_bound))
   ; si_low_bound := Zmin x.(si_low_bound) y.(si_low_bound)
   ; si_up_bound := Zmax x.(si_up_bound) y.(si_up_bound)
  |}.

Program Definition si_meet (x y: strided_interval) : strided_interval+⊥ :=
  match congr_dec (N.gcd x.(si_stride) y.(si_stride)) x.(si_low_bound) y.(si_low_bound) return _ with
    | left H
      let A := Zmax x.(si_low_bound) y.(si_low_bound) in
      let B := Zmin x.(si_up_bound) y.(si_up_bound) in
      let m := N.lcm x.(si_stride) y.(si_stride) in
      if Z_zerop m
      then
        if Z_le_dec A B
        then NotBot {| si_stride := m; si_low_bound := A; si_up_bound := A |}
        else Bot
      else
        let (n, K) := rem_eqn_particular x.(si_low_bound) y.(si_low_bound)
                                         x.(si_stride) y.(si_stride) _ _ _
        in
        let l := A + ((n - A) mod m) in
        let u := B - ((B - n) mod m) in
        match Z_dec l u with
        | inleft (left LT) ⇒ NotBot {| si_stride := m; si_low_bound := l; si_up_bound := u |}
        | inleft (right GT) ⇒ Bot
        | inright EQNotBot {| si_stride := 0%N; si_low_bound := l; si_up_bound := u |}
        end
    | right _Bot
  end.

Lemma si_meet_valid x y :
  match si_meet x y with
  | NotBot zsi_valid z
  | BotTrue
  end.

Lemma si_meet_reduced x y :
  match si_meet x y with
  | NotBot zsi_reduced z
  | BotTrue
  end.

Definition si_size (x : strided_interval) : N :=
  match Z_le_dec x.(si_low_bound) x.(si_up_bound) with
  | left LE
    match x.(si_stride) with
    | N0 ⇒ 1%N
    | Npos sN_of_Z ((x.(si_up_bound) - x.(si_low_bound)) / (Zpos s) + 1)
    end
  | right GTN0
  end.

Section Gamma.
  Variable interp : int Z.
  Local Coercion interp : int >-> Z.
  Variables min max : Z.
  Hypothesis range : i : int, min i max.
  Hypothesis interpz : interp Int.zero = 0.
  Hypothesis interp_inj : x y : int, x y interp x interp y.

  Definition si_top : strided_interval :=
    {| si_stride := 1
     ; si_low_bound := min
     ; si_up_bound := max
    |}.

  Lemma si_top_reduced (H: min max) : si_reduced si_top.

  Instance si_gamma : gamma_op strided_interval int := fun x
    fun ix.(si_low_bound) i x.(si_up_bound)
            x.(si_low_bound) i [ x.(si_stride) ].

  Lemma si_gamma_monotone (x y: strided_interval) :
    si_LE x y si_gamma x si_gamma y.

  Lemma si_gamma_top (i: int) : si_gamma si_top i.

  Lemma si_join_sound (x y: strided_interval) :
    si_gamma x si_gamma y si_gamma (si_join x y).

  Definition si_widen (x y: strided_interval) : strided_interval :=
    match Interval.widen_heuristic (Interval.ITV x.(si_low_bound) x.(si_up_bound))
                                   (Interval.ITV y.(si_low_bound) y.(si_up_bound)) with
    | Interval.ITV a b
      if zeq a b
      then {| si_stride := N0; si_low_bound := a; si_up_bound := b |}
      else {| si_stride := 1%N; si_low_bound := a; si_up_bound := b |}
    end.

  Lemma si_widen_reduced x y :
    si_reduced (si_widen x y).

  Instance toString : ToString strided_interval :=
    { to_string i :=
      if si_LE_dec si_top i
      then "⊤"%string
      else
        match i.(si_stride) with
        | N0string_of_z i.(si_low_bound)
        | s
          (string_of_z (Z_of_N s)
          ++ "[" ++ string_of_z i.(si_low_bound) ++ "; "
          ++ string_of_z i.(si_up_bound) ++ "]")%string
        end
    }.

  Instance si_wlat : weak_lattice strided_interval :=
    {| leb x y := si_LE_dec x y
     ; top := si_top
     ; join := si_join
     ; widen := si_widen
    |}.
  Lemma si_adom : adom strided_interval int si_wlat si_gamma.

  Lemma si_meet_sound (x y: strided_interval) :
    si_gamma x si_gamma y match si_meet x y with NotBot zsi_gamma z | Bot end.

  Definition si_const (i: int) : strided_interval :=
    {| si_stride := 0%N; si_low_bound := i; si_up_bound := i |}.

  Lemma si_const_sound (i: int) : si_gamma (si_const i) i.

  Lemma si_const_valid i : si_valid (si_const i).

  Lemma si_const_reduced i : si_reduced (si_const i).

  Definition si_add (x y: strided_interval) : strided_interval :=
    let l := x.(si_low_bound) + y.(si_low_bound) in
    let u := x.(si_up_bound) + y.(si_up_bound) in
    if Z_le_dec min l
    then
      if Z_le_dec l max
      then
        if Z_le_dec u max
        then {| si_stride := N.gcd x.(si_stride) y.(si_stride)
              ; si_low_bound := l
              ; si_up_bound := u
             |}
        else si_top
      else
        {| si_stride := N.gcd x.(si_stride) y.(si_stride)
         ; si_low_bound := l - Int.modulus
         ; si_up_bound := u - Int.modulus
        |}
    else
      if Z_le_dec min u
      then si_top
      else
        {| si_stride := N.gcd x.(si_stride) y.(si_stride)
         ; si_low_bound := l + Int.modulus
         ; si_up_bound := u + Int.modulus
        |}.

  Lemma si_add_valid x y :
    si_valid x
    si_valid y
    si_valid (si_add x y).

  Lemma si_add_reduced (H: min max) x y :
    si_valid x
    si_valid y
    si_reduced x
    si_reduced y
    si_reduced (si_add x y).
  Hint Resolve congr_plus_compat.

  Definition si_is_in_itv (u v: int) (x: strided_interval) : bool :=
    
    Z_le_dec u x.(si_low_bound) && Z_le_dec x.(si_up_bound) v.

  Definition si_contains (i: int) (x: strided_interval) : bool :=
    match si_meet x (si_const i) with
    | Botfalse
    | NotBot _true
    end.

  Function si_concretize_aux (s: positive) (base: Z) (nb: Z) (acc: list Z) {measure Zabs_nat nb} : list Z :=
    let nb := nb - Zpos s in
    match nb with
    | Zpos _ | Z0si_concretize_aux s base nb (base + nb :: acc)
    | Zneg _acc
    end.

  Definition si_concretize (x: strided_interval) : list Z :=
    match Z_le_dec x.(si_low_bound) x.(si_up_bound) with
    | left LE
      match x.(si_stride) with
      | N0x.(si_low_bound) :: nil
      | Npos s
        si_concretize_aux s x.(si_low_bound) ((x.(si_up_bound) - x.(si_low_bound)) / Zpos s × Zpos s + Zpos s) nil
      end
    | right GTnil
    end.

  Lemma si_concretize_sound_aux :
     acc nb s base (i:int),
      nb 0 [Zpos s]
      In (i:Z) (si_concretize_aux s base nb acc)
      In (i:Z) acc (base i base + nb - Zpos s base i [Zpos s]).

  Lemma si_concretize_exact (x: strided_interval) :
     i : int, List.In (i:Z) (si_concretize x) γ x i.

End Gamma.

Signed SI
Instance ssi_wlat : weak_lattice strided_interval :=
  si_wlat Int.min_signed Int.max_signed.
Instance ssi_gamma : gamma_op strided_interval int :=
  si_gamma Int.signed.
Lemma ssi_adom : adom strided_interval int ssi_wlat ssi_gamma.

Definition ssi_top : strided_interval := si_top Int.min_signed Int.max_signed.

Definition ssi_neg (x: strided_interval) : strided_interval :=
  if zle x.(si_low_bound) Int.min_signed
  then if zeq x.(si_up_bound) Int.min_signed
       then si_const Int.signed (Int.repr Int.min_signed)
       else ssi_top
  else
    
    if congr_dec x.(si_stride) x.(si_low_bound) x.(si_up_bound)
    then {| si_stride := x.(si_stride)
          ; si_low_bound := - x.(si_up_bound)
          ; si_up_bound := - x.(si_low_bound)
         |}
    else ssi_top.

Lemma ssi_neg_sound (x: strided_interval) :
  lift_unop Int.neg (γ x) γ (ssi_neg x).

Lemma ssi_neg_valid x :
  si_valid x
  si_valid (ssi_neg x).

Lemma ssi_neg_reduced x :
  si_reduced x
  si_reduced (ssi_neg x).

Definition ssi_not (i: strided_interval) : strided_interval :=
  si_add Int.min_signed Int.max_signed (ssi_neg i) (si_const Int.signed Int.mone).

Lemma ssi_not_valid x :
  si_valid x si_valid (ssi_not x).

Lemma ssi_not_reduced x :
  si_valid x
  si_reduced x
  si_reduced (ssi_not x).

Definition ssi_sub (x y: strided_interval) : strided_interval :=
  si_add Int.min_signed Int.max_signed x (ssi_neg y).

Lemma ssi_sub_valid x y :
  si_valid x si_valid y si_valid (ssi_sub x y).

Lemma ssi_sub_reduced x y :
  si_valid x si_reduced x
  si_valid y si_reduced y
  si_reduced (ssi_sub x y).

Definition ssi_mul_l (x y: strided_interval) : strided_interval :=
  match x.(si_stride) with
  | N0
    let k : Z := x.(si_low_bound) in
    match k with
    | Z0si_const Int.signed Int.zero
    | Zpos k'
      let l : Z := k × y.(si_low_bound) in
      if Z_le_dec Int.min_signed l
      then let u : Z := k × y.(si_up_bound) in
           if Z_le_dec u Int.max_signed
           then {| si_stride := Npos k' × y.(si_stride)
                 ; si_low_bound := l
                 ; si_up_bound := u
                |}
           else ssi_top
      else ssi_top
    | Zneg k'
      let l : Z := k × y.(si_up_bound) in
      if Z_le_dec Int.min_signed l
      then let u : Z := k × y.(si_low_bound) in
           if Z_le_dec u Int.max_signed
           then
             
             if congr_dec y.(si_stride) y.(si_low_bound) y.(si_up_bound)
             then {| si_stride := Npos k' × y.(si_stride)
                   ; si_low_bound := l
                   ; si_up_bound := u
                  |}
             else ssi_top
           else ssi_top
      else ssi_top
    end
  | _ssi_top
  end.

Lemma ssi_mul_l_sound : x y,
  Eval_int_binop OpMul (γ x) (γ y) γ (ssi_mul_l x y).

Lemma ssi_mul_l_valid x y:
  si_valid y
  si_valid (ssi_mul_l x y).

Lemma ssi_mul_l_reduced x y:
  si_reduced y
  si_reduced (ssi_mul_l x y).

Definition ssi_mul x y :=
  match x.(si_stride) with
  | N0ssi_mul_l x y
  | _ssi_mul_l y x
  end.

Lemma ssi_mul_valid x y :
  si_valid x
  si_valid y
  si_valid (ssi_mul x y).

Lemma ssi_mul_reduced x y :
  si_reduced x
  si_reduced y
  si_reduced (ssi_mul x y).

Lemma ssi_mul_sound x y :
  Eval_int_binop OpMul (γ x) (γ y) γ (ssi_mul x y).

Definition ssi_shl (x y: strided_interval) : strided_interval :=
  match y.(si_stride) with
  | N0
    
    let y' := Int.shl Int.one (Int.repr y.(si_low_bound)) in
    ssi_mul_l (si_const Int.signed y') x
  | _
    print
      "Warning ssi: shl"
    ()
  end.

Lemma ssi_shl_sound x y :
  Eval_int_binop OpShl (γ x) (γ y) γ (ssi_shl x y).

Definition ssi_divs_r (x: strided_interval) (y: positive) : strided_interval :=
  let xs := Z.of_N x.(si_stride) in
  let y' := Z.pos y in
  {| si_stride := if Zdivides_dec y' xs
                  && (zeq (Z.sgn x.(si_low_bound)) (Z.sgn x.(si_up_bound))
                   || Zdivides_dec y' x.(si_low_bound))
                  then N.div x.(si_stride) (N.pos y)
                  else 1%N
   ; si_low_bound := x.(si_low_bound) ÷ y'
   ; si_up_bound := x.(si_up_bound) ÷ y'
  |}.

Lemma ssi_divs_r_valid x y :
  si_valid x
  si_valid (ssi_divs_r x y).

Lemma ssi_divs_r_sound x y i j :
  γ x i
  Int.signed j = Z.pos y
  γ (ssi_divs_r x y) (Int.divs i j).

Definition ssi_divs (x y: strided_interval) : strided_interval :=
  match y.(si_stride) with
  | N0
    match y.(si_low_bound) with
    | Z.pos pssi_divs_r x p
    | _ ⇒ ()
    end
  | _ ⇒ ()
  end.

Lemma ssi_divs_valid x y : si_valid x si_valid (ssi_divs x y).

Lemma ssi_divs_sound x y : lift_binop Int.divs (γ x) (γ y) γ (ssi_divs x y).

Definition ssi_shr_l (x: strided_interval) (y: Z) : strided_interval :=
  let m := Z.shiftr x.(si_low_bound) y in
  let M := Z.shiftr x.(si_up_bound) y in
  {| si_stride := if zeq m M then 0 else 1
   ; si_low_bound := m
   ; si_up_bound := M
  |}.

Lemma ssi_shr_l_sound x y i :
  0 y < Int.modulus
  γ x i
  γ (ssi_shr_l x y) (Int.shr i (Int.repr y)).

Definition ssi_shr (x y: strided_interval) : strided_interval :=
  match y.(si_stride) with
  | N0ssi_shr_l x (Int.unsigned (Int.repr y.(si_low_bound)))
  | _ ⇒ ()
  end.

Lemma ssi_shr_sound x y i j :
  γ x iγ y j
  γ (ssi_shr x y) (Int.shr i j).

Definition ssi_shru (x y: strided_interval) : strided_interval :=
  match y.(si_stride) with
  | N0
    let y' := Int.unsigned (Int.repr y.(si_low_bound)) in
    if Z_zerop y'
    then x
    else if znegb x.(si_low_bound)
         then let (m, M) := Interval.shru_top y' in
              {| si_stride := 1%N; si_low_bound := m; si_up_bound := M |}
         else ssi_shr_l x y'
  | _ ⇒ ()
  end.

Lemma ssi_shru_sound x y i j :
  γ x iγ y j
  γ (ssi_shru x y) (Int.shru i j).
  Opaque Interval.shru_top.
  Transparent Interval.shru_top.

Definition ssi_mods_r (x: strided_interval) (y: positive) : strided_interval :=
  if x.(si_stride)
  then
    let r := Z.rem x.(si_low_bound) (Zpos y) in
    {| si_stride := N0; si_low_bound := r; si_up_bound := r |}
  else
    if zle 0 x.(si_low_bound)
    then {| si_stride := 1%N; si_low_bound := 0; si_up_bound := Zpos y - 1 |}
    else print "Warning ssi: mods" ssi_top.

Lemma ssi_mods_r_sound x y i j:
  i γ(x)
  Int.signed j = Z.pos y
  γ (ssi_mods_r x y) (Int.mods i j).

Definition ssi_mods (x y: strided_interval) : strided_interval :=
  match y.(si_stride) with
  | N0
    match y.(si_low_bound) with
    | Z.pos pssi_mods_r x p
    | _ ⇒ ()
    end
  | _ ⇒ ()
  end.

Lemma ssi_mods_sound x y : lift_binop Int.mods (γ x) (γ y) γ (ssi_mods x y).

Definition ssi_and (x y: strided_interval) : strided_interval :=
  match y.(si_stride) with
  | N0
    match x.(si_stride) with
    | N0si_const Int.signed (Int.and (Int.repr x.(si_low_bound)) (Int.repr (y.(si_low_bound))))
    | _
      match y.(si_low_bound) with
      | Zneg _ ⇒ ()
      | Z0si_const Int.signed Int.zero
      | Zpos p
        {| si_stride := 1; si_low_bound := 0
         ; si_up_bound := two_power_pos (Pos.size p) - 1 |}
      end
    end
  | _
    print
      "Warning ssi: and"
    ()
  end.


Lemma ssi_and_valid (x y: strided_interval) :
  si_valid (ssi_and x y).

Lemma ssi_and_reduced (x y: strided_interval) :
  si_reduced (ssi_and x y).

Notation todo2 := (fun s _ _print ("TODO ssi: " ++ s)%string (NotBot top)).
Notation todobw1 := (fun s x _print ("TODO ssi: " ++ s)%string (NotBot x)).
Notation todobw2 := (fun s x y _print ("TODO ssi bw2:" ++ s)%string (NotBot x, NotBot y)).

Definition ssi_backward_add (x y res: strided_interval) :=
  (si_meet x (ssi_sub res y),
   si_meet y (ssi_sub res x)).

Definition ssi_backward_le (x y: strided_interval) :=
  (si_meet x {| si_stride := 1; si_low_bound := Int.min_signed; si_up_bound := y.(si_up_bound) |},
   si_meet {| si_stride := 1; si_low_bound := x.(si_low_bound); si_up_bound := Int.max_signed |} y).

Definition cast_usi (x: strided_interval) : bool :=
  match x.(si_low_bound) with
  | Zneg _false
  | _zle x.(si_up_bound) Int.max_unsigned
  end.

Lemma cast_usi_true x :
  cast_usi x = true
  0 x.(si_low_bound) x.(si_up_bound) Int.max_unsigned.

Lemma cast_usi_gamma x i :
  cast_usi x = true
  γ x i
  Int.signed i = Int.unsigned i.

Definition ssi_backward_leu (x y: strided_interval) :=
  if cast_usi x && cast_usi y
  then ssi_backward_le x y
  else (NotBot x, NotBot y).

Lemma ssi_backward_le_sound x y i j :
  si_gamma Int.signed x i
  si_gamma Int.signed y j
  Int.lt j i = false
  let '(u,v) := ssi_backward_le x y in
  γ u i γ v j.

Lemma ssi_backward_leu_sound x y i j :
  si_gamma Int.signed x i
  si_gamma Int.signed y j
  Int.ltu j i = false
  let '(u,v) := ssi_backward_leu x y in
  γ u i γ v j.

Reduced valid interval as a strided interval with stride 1.
Definition si_interval (l u: Z) : strided_interval+⊥ :=
  match Z_dec l u with
  | inleft (left LT) ⇒ NotBot {| si_stride := 1; si_low_bound := l; si_up_bound := u |}
  | inleft (right GT) ⇒ Bot
  | inright EQNotBot {| si_stride := 0; si_low_bound := l; si_up_bound := l |}
  end.

Definition ssi_backward_lt (x y: strided_interval) :=
  (botbind (si_meet x) (si_interval Int.min_signed (y.(si_up_bound) - 1)),
   botbind (si_meet y) (si_interval (x.(si_low_bound) + 1) Int.max_signed)).

Definition ssi_backward_ltu (x y: strided_interval) :=
  if cast_usi x && cast_usi y
  then ssi_backward_lt x y
  else (NotBot x, NotBot y).

Lemma ssi_backward_lt_sound x y i j :
  γ x i γ y j
  Int.lt i j = true
  let '(u,v) := ssi_backward_lt x y in
  γ u i γ v j.

Lemma ssi_backward_ltu_sound x y i j :
  γ x i γ y j
  Int.ltu i j = true
  let '(u,v) := ssi_backward_ltu x y in
  γ u i γ v j.

Definition ssi_backward_ne (x y: strided_interval) :=
  let (x1, y1) := ssi_backward_lt x y in
  let (y2, x2) := ssi_backward_lt y x in
  (x1 x2, y1 y2).

Lemma ssi_backward_ne_sound x y i j :
  γ x i γ y j
  Int.eq i j = false
  let '(u, v) := ssi_backward_ne x y in
  γ u i γ v j.
  Hint Resolve ssi_adom lift_bot.

Definition ssi_backward_cmp (c:comparison) (x y res: strided_interval) :=
  match res.(si_stride) with
  | N0
    if Z_zerop res.(si_low_bound)
    then
      
      match c with
      | Cnelet ab := si_meet x y in (ab, ab)
      | Cgtssi_backward_le x y
      | CltInterval.swap (ssi_backward_le y x)
      | Cgessi_backward_lt x y
      | CleInterval.swap (ssi_backward_lt y x)
      | Ceqssi_backward_ne x y
      end
    else
      if Z_eq_dec res.(si_low_bound) 1
      then
        
        match c with
        | Ceqlet ab := si_meet x y in (ab, ab)
        | Clessi_backward_le x y
        | CgeInterval.swap (ssi_backward_le y x)
        | Cltssi_backward_lt x y
        | CgtInterval.swap (ssi_backward_lt y x)
        | Cnessi_backward_ne x y
        end
      else (NotBot x, NotBot y)
  | _(NotBot x, NotBot y)
  end.

Definition ssi_backward_cmpu (c:comparison) (x y res: strided_interval) :=
  match res.(si_stride) with
  | N0
    if Z_zerop res.(si_low_bound)
    then
      
      match c with
      | Cnelet ab := si_meet x y in (ab, ab)
      | Cgtssi_backward_leu x y
      | CltInterval.swap (ssi_backward_leu y x)
      | Cgessi_backward_ltu x y
      | CleInterval.swap (ssi_backward_ltu y x)
      | Ceqssi_backward_ne x y
      end
    else
      if Z_eq_dec res.(si_low_bound) 1
      then
        
        match c with
        | Ceqlet ab := si_meet x y in (ab, ab)
        | Clessi_backward_leu x y
        | CgeInterval.swap (ssi_backward_leu y x)
        | Cltssi_backward_ltu x y
        | CgtInterval.swap (ssi_backward_ltu y x)
        | Cnessi_backward_ne x y
        end
      else (NotBot x, NotBot y)
  | _(NotBot x, NotBot y)
  end.

Lemma ssi_backward_cmp_sound c :
   x y z, i j,
    γ x i γ y j γ z (eval_int_binop (OpCmp c) i j)
    let '(u,v) := ssi_backward_cmp c x y z in
    γ u i γ v j.

Lemma ssi_backward_cmpu_sound c :
   x y z, i j,
    γ x i γ y j γ z (eval_int_binop (OpCmpu c) i j)
    let '(u,v) := ssi_backward_cmpu c x y z in
    γ u i γ v j.


Instance ssiToString : ToString strided_interval := toString Int.min_signed Int.max_signed.

Instance ssi_dom : ab_machine_int strided_interval :=
  {| as_int_adom := ssi_adom
   ; meet_int := si_meet
   ; size x := Just (si_size x)
   ; concretize x := Just (IntSet.of_list (List.map Int.repr (si_concretize x)))
   ; const_int := si_const Int.signed
   ; booleans := {| si_stride := 1%N; si_low_bound := 0; si_up_bound := 1 |}
   ; range_int x f := match f with
                  | SignedNotBot (Interval.ITV x.(si_low_bound) x.(si_up_bound))
                  | Unsignedtop
                  end
   ; forward_int_unop op x :=
       match op with
       | OpNegNotBot (ssi_neg x)
       | OpNotNotBot (ssi_not x)
       end
   ; forward_int_binop op x y :=
       match op with
       | OpAddNotBot (si_add Int.min_signed Int.max_signed x y)
       | OpSubNotBot (ssi_sub x y)
       | OpMulNotBot (ssi_mul x y)
       | OpAndNotBot (ssi_and x y)
       | OpDivsNotBot (ssi_divs x y)
       | OpModsNotBot (ssi_mods x y)
       | OpShlNotBot (ssi_shl x y)
       | OpShrNotBot (ssi_shr x y)
       | OpShruNotBot (ssi_shru x y)
       | _todo2 (to_string x ++ " " ++ to_string op ++ " " ++ to_string y)%string x y
       end
   ; is_in_itv := si_is_in_itv Int.signed
   ; backward_int_unop op :=
       match op with
       | _todobw1 (to_string op)
       end
   ; backward_int_binop op :=
       match op with
       | OpCmp cssi_backward_cmp c
       | OpCmpu cssi_backward_cmpu c
       | OpAddssi_backward_add
       | _todobw2 (to_string op)
       end
  |}.

Lemma ssi_is_in_itv_sound (u v: int) (x: strided_interval) :
  si_is_in_itv Int.signed u v x = true
   i, si_gamma Int.signed x i Int.lt v i = false Int.lt i u = false.

Lemma ssi_add_sound (x y: strided_interval) :
  lift_binop Int.add (γ x) (γ y) γ (si_add Int.min_signed Int.max_signed x y).

Lemma ssi_not_sound x : lift_unop Int.not (si_gamma Int.signed x) (si_gamma Int.signed (ssi_not x)).

Lemma ssi_sub_sound x y : lift_binop Int.sub (γ x) (γ y) γ (ssi_sub x y).

Lemma ssi_and_sound x y : lift_binop Int.and (γ x) (γ y) γ (ssi_and x y).

Lemma ssi_backward_add_sound :
   x y z i j,
    γ x i
    γ y j
    γ z (Int.add i j)
    let (u, v) := ssi_backward_add x y z in
    γ u i γ v j.

Instance ssi_num_dom_correct : ab_machine_int_correct ssi_dom.

Product of strided signed intervals and unsigned (non-strided) intervals.
Section SSIU.

  Require Import Intervals.
  Import DLib Interval.
  Definition reduc2unsigned (i: strided_interval) : itv :=
    let m := i.(si_low_bound) in
    let M := i.(si_up_bound) in
    if zle 0 m
    then ITV m M
    else if zlt M 0
         then ITV (m + Int.modulus) (M + Int.modulus)
         else utop.

  Definition reduc2signed (i: itv) : strided_interval :=
    match reduc2signed i with
    | ITV m M ⇒ {| si_stride := 1%N; si_low_bound := m; si_up_bound := M |}
    end.

  Lemma reduc2unsigned_correct: i v,
    si_gamma Int.signed i v
    ugamma (reduc2unsigned i) v.

  Lemma reduc2signed_correct: i v,
    ugamma i v
    si_gamma Int.signed (reduc2signed i) v.

  Instance ssiu_red : reduction strided_interval itv :=
  {| ρ := botbind2 (fun s u
       let s' := reduc2signed u in
       let u' := reduc2unsigned s in
       match si_meet s s', u u' with
         | Bot, _ | _, BotBot
         | NotBot a, NotBot bNotBot (a,b)
       end)
  |}.

  Lemma ssiu_red_correct : reduction_correct ssi_adom unsigned_itv_adom.
    Hint Resolve reduc2unsigned_correct reduc2signed_correct.

  Instance ssiu_dom : ab_machine_int _ :=
    @reduced_product_int _ _ ssi_dom UInterval.itvu_num ssiu_red.
  Instance ssiu_dom_correct : ab_machine_int_correct ssiu_dom :=
    reduced_product_int_correct ssi_num_dom_correct UInterval.itvu_num_correct ssiu_red_correct.

End SSIU.