[inferbo] More physical equalities for Bounds

Reviewed By: skcho

Differential Revision: D13176079

fbshipit-source-id: e09ebd176
master
Mehdi Bouaziz 6 years ago committed by Facebook Github Bot
parent 03d3a85f45
commit bdbf39aaa3

@ -41,6 +41,8 @@ module SymLinear = struct
let le : t -> t -> bool =
fun x y ->
phys_equal x y
||
let le_one_pair s v1_opt v2_opt =
let v1 = NonZeroInt.opt_to_big_int v1_opt in
let v2 = NonZeroInt.opt_to_big_int v2_opt in
@ -82,13 +84,15 @@ module SymLinear = struct
let plus : t -> t -> t =
fun x y ->
let plus_coeff _ c1 c2 = NonZeroInt.plus c1 c2 in
M.union plus_coeff x y
PhysEqual.optim2 x y ~res:(M.union plus_coeff x y)
let mult_const : NonZeroInt.t -> t -> t = fun n x -> M.map (NonZeroInt.( * ) n) x
let mult_const : NonZeroInt.t -> t -> t =
fun n x -> if NonZeroInt.is_one n then x else M.map (NonZeroInt.( * ) n) x
let exact_div_const_exn : t -> NonZeroInt.t -> t =
fun x n -> M.map (fun c -> NonZeroInt.exact_div_exn c n) x
fun x n -> if NonZeroInt.is_one n then x else M.map (fun c -> NonZeroInt.exact_div_exn c n) x
(* Returns a symbol when the map contains only one symbol s with a
@ -445,8 +449,8 @@ module Bound = struct
PInf
| PInf ->
MInf
| Linear (c, x) ->
Linear (Z.neg c, SymLinear.neg x)
| Linear (c, x) as b ->
if Z.(equal c zero) && SymLinear.is_zero x then b else Linear (Z.neg c, SymLinear.neg x)
| MinMax (c, sign, min_max, d, x) ->
mk_MinMax (Z.neg c, Sign.neg sign, min_max, d, x)
@ -619,9 +623,15 @@ module Bound = struct
overapprox_min original_b1 b2
let underapprox_max b1 b2 = neg (overapprox_min (neg b1) (neg b2))
let underapprox_max b1 b2 =
let res = neg (overapprox_min (neg b1) (neg b2)) in
if equal res b1 then b1 else if equal res b2 then b2 else res
let overapprox_max b1 b2 =
let res = neg (underapprox_min (neg b1) (neg b2)) in
if equal res b1 then b1 else if equal res b2 then b2 else res
let overapprox_max b1 b2 = neg (underapprox_min (neg b1) (neg b2))
let approx_max = function
| Symb.BoundEnd.LowerBound ->
@ -678,19 +688,18 @@ module Bound = struct
let plus_common : f:(t -> t -> t) -> t -> t -> t =
fun ~f x y ->
match (x, y) with
| _, _ when is_zero x ->
y
| _, _ when is_zero y ->
x
| Linear (c1, x1), Linear (c2, x2) ->
Linear (Z.(c1 + c2), SymLinear.plus x1 x2)
| MinMax (c1, sign, min_max, d1, x1), Linear (c2, x2)
| Linear (c2, x2), MinMax (c1, sign, min_max, d1, x1)
when SymLinear.is_zero x2 ->
mk_MinMax (Z.(c1 + c2), sign, min_max, d1, x1)
| _ ->
f x y
if is_zero x then y
else if is_zero y then x
else
match (x, y) with
| Linear (c1, x1), Linear (c2, x2) ->
Linear (Z.(c1 + c2), SymLinear.plus x1 x2)
| MinMax (c1, sign, min_max, d1, x1), Linear (c2, x2)
| Linear (c2, x2), MinMax (c1, sign, min_max, d1, x1)
when SymLinear.is_zero x2 ->
mk_MinMax (Z.(c1 + c2), sign, min_max, d1, x1)
| _ ->
f x y
let plus_l : t -> t -> t =
@ -723,25 +732,27 @@ module Bound = struct
let mult_const : Symb.BoundEnd.t -> NonZeroInt.t -> t -> t =
fun bound_end n x ->
match x with
| MInf ->
if NonZeroInt.is_positive n then MInf else PInf
| PInf ->
if NonZeroInt.is_positive n then PInf else MInf
| Linear (c, x') ->
Linear (Z.(c * (n :> Z.t)), SymLinear.mult_const n x')
| MinMax _ -> (
let int_bound =
let bound_end' =
if NonZeroInt.is_positive n then bound_end else Symb.BoundEnd.neg bound_end
if NonZeroInt.is_one n then x
else
match x with
| MInf ->
if NonZeroInt.is_positive n then MInf else PInf
| PInf ->
if NonZeroInt.is_positive n then PInf else MInf
| Linear (c, x') ->
Linear (Z.(c * (n :> Z.t)), SymLinear.mult_const n x')
| MinMax _ -> (
let int_bound =
let bound_end' =
if NonZeroInt.is_positive n then bound_end else Symb.BoundEnd.neg bound_end
in
big_int_of_minmax bound_end' x
in
big_int_of_minmax bound_end' x
in
match int_bound with
| Some i ->
of_big_int Z.(i * (n :> Z.t))
| None ->
of_bound_end bound_end )
match int_bound with
| Some i ->
of_big_int Z.(i * (n :> Z.t))
| None ->
of_bound_end bound_end )
let mult_const_l = mult_const Symb.BoundEnd.LowerBound
@ -760,30 +771,32 @@ module Bound = struct
let div_const : Symb.BoundEnd.t -> t -> NonZeroInt.t -> t option =
fun bound_end x n ->
match x with
| MInf ->
Some (if NonZeroInt.is_positive n then MInf else PInf)
| PInf ->
Some (if NonZeroInt.is_positive n then PInf else MInf)
| Linear (c, x') when SymLinear.is_zero x' ->
Some (Linear (Z.(c / (n :> Z.t)), SymLinear.zero))
| Linear (c, x') when NonZeroInt.is_multiple c n -> (
match SymLinear.exact_div_const_exn x' n with
| x'' ->
Some (Linear (Z.(c / (n :> Z.t)), x''))
| exception NonZeroInt.DivisionNotExact ->
None )
| MinMax _ ->
let c =
match bound_end with
| Symb.BoundEnd.LowerBound ->
underapprox_minmax_div_const x n
| Symb.BoundEnd.UpperBound ->
overapprox_minmax_div_const x n
in
Option.map c ~f:of_big_int
| _ ->
None
if NonZeroInt.is_one n then Some x
else
match x with
| MInf ->
Some (if NonZeroInt.is_positive n then MInf else PInf)
| PInf ->
Some (if NonZeroInt.is_positive n then PInf else MInf)
| Linear (c, x') when SymLinear.is_zero x' ->
Some (Linear (Z.(c / (n :> Z.t)), SymLinear.zero))
| Linear (c, x') when NonZeroInt.is_multiple c n -> (
match SymLinear.exact_div_const_exn x' n with
| x'' ->
Some (Linear (Z.(c / (n :> Z.t)), x''))
| exception NonZeroInt.DivisionNotExact ->
None )
| MinMax _ ->
let c =
match bound_end with
| Symb.BoundEnd.LowerBound ->
underapprox_minmax_div_const x n
| Symb.BoundEnd.UpperBound ->
overapprox_minmax_div_const x n
in
Option.map c ~f:of_big_int
| _ ->
None
let div_const_l = div_const Symb.BoundEnd.LowerBound
@ -803,110 +816,110 @@ module Bound = struct
let is_not_infty : t -> bool = function MInf | PInf -> false | _ -> true
let lift1 : (t -> t) -> t bottom_lifted -> t bottom_lifted =
fun f x -> match x with Bottom -> Bottom | NonBottom x -> NonBottom (f x)
let lift2 : (t -> t -> t) -> t bottom_lifted -> t bottom_lifted -> t bottom_lifted =
fun f x y ->
match (x, y) with
| Bottom, _ | _, Bottom ->
Bottom
| NonBottom x, NonBottom y ->
NonBottom (f x y)
(** Substitutes ALL symbols in [x] with respect to [eval_sym]. Under/over-Approximate as good as possible according to [subst_pos]. *)
let subst : subst_pos:Symb.BoundEnd.t -> t -> eval_sym -> t bottom_lifted =
fun ~subst_pos x eval_sym ->
let get s =
match eval_sym s with
| NonBottom x when Symb.Symbol.is_unsigned s ->
NonBottom (approx_max subst_pos x zero)
| x ->
x
let lift1 : (t -> t) -> t bottom_lifted -> t bottom_lifted =
fun f x -> match x with Bottom -> Bottom | NonBottom x -> NonBottom (f x)
in
let get_mult_const s coeff =
if NonZeroInt.is_one coeff then get s
else if NonZeroInt.is_minus_one coeff then get s |> lift1 neg
else
match eval_sym s with
| Bottom -> (
(* For unsigned symbols, we can over/under-approximate with zero depending on [subst_pos] and the sign of the coefficient. *)
match (Symb.Symbol.is_unsigned s, subst_pos, NonZeroInt.is_positive coeff) with
| true, Symb.BoundEnd.LowerBound, true | true, Symb.BoundEnd.UpperBound, false ->
NonBottom zero
| _ ->
Bottom )
| NonBottom x ->
let x = mult_const subst_pos coeff x in
if Symb.Symbol.is_unsigned s then NonBottom (approx_max subst_pos x zero)
else NonBottom x
let lift2 : (t -> t -> t) -> t bottom_lifted -> t bottom_lifted -> t bottom_lifted =
fun f x y ->
match (x, y) with
| Bottom, _ | _, Bottom ->
Bottom
| NonBottom x, NonBottom y ->
NonBottom (f x y)
in
match x with
| MInf | PInf ->
NonBottom x
| Linear (c, se) ->
SymLinear.fold se
~init:(NonBottom (of_big_int c))
~f:(fun acc s coeff -> lift2 (plus subst_pos) acc (get_mult_const s coeff))
| MinMax (c, sign, min_max, d, s) -> (
match get s with
| Bottom ->
Option.value_map (big_int_of_minmax subst_pos x) ~default:Bottom ~f:(fun i ->
NonBottom (of_big_int i) )
| NonBottom x' ->
let res =
match (sign, min_max, x') with
| Plus, Min, MInf | Minus, Max, PInf ->
MInf
| Plus, Max, PInf | Minus, Min, MInf ->
PInf
| sign, Min, PInf | sign, Max, MInf ->
of_big_int (Sign.eval_big_int sign c d)
| _, _, Linear (c2, se) -> (
if SymLinear.is_zero se then
of_big_int (Sign.eval_big_int sign c (MinMax.eval_big_int min_max d c2))
else if SymLinear.is_one_symbol se then
mk_MinMax
( Sign.eval_big_int sign c c2
, sign
, min_max
, Z.(d - c2)
, SymLinear.get_one_symbol se )
else if SymLinear.is_mone_symbol se then
mk_MinMax
( Sign.eval_big_int sign c c2
, Sign.neg sign
, MinMax.neg min_max
, Z.(c2 - d)
, SymLinear.get_mone_symbol se )
else
match big_int_of_minmax subst_pos x with
| Some i ->
of_big_int i
| None ->
of_bound_end subst_pos )
| _, _, MinMax (c2, sign2, min_max2, d2, s2) -> (
match (min_max, sign2, min_max2) with
| Min, Plus, Min | Max, Plus, Max ->
let c' = Sign.eval_big_int sign c c2 in
let d' = MinMax.eval_big_int min_max Z.(d - c2) d2 in
mk_MinMax (c', sign, min_max, d', s2)
| Min, Minus, Max | Max, Minus, Min ->
let c' = Sign.eval_big_int sign c c2 in
let d' = MinMax.eval_big_int min_max2 Z.(c2 - d) d2 in
mk_MinMax (c', Sign.neg sign, min_max2, d', s2)
| _ ->
let bound_end =
match sign with Plus -> subst_pos | Minus -> Symb.BoundEnd.neg subst_pos
in
of_big_int
(Sign.eval_big_int sign c
(MinMax.eval_big_int min_max d
(big_int_of_minmax bound_end x' |> Option.value ~default:d))) )
in
NonBottom res )
fun ~subst_pos x eval_sym ->
let get s =
match eval_sym s with
| NonBottom x when Symb.Symbol.is_unsigned s ->
NonBottom (approx_max subst_pos x zero)
| x ->
x
in
let get_mult_const s coeff =
if NonZeroInt.is_one coeff then get s
else if NonZeroInt.is_minus_one coeff then get s |> lift1 neg
else
match eval_sym s with
| Bottom -> (
(* For unsigned symbols, we can over/under-approximate with zero depending on [subst_pos] and the sign of the coefficient. *)
match (Symb.Symbol.is_unsigned s, subst_pos, NonZeroInt.is_positive coeff) with
| true, Symb.BoundEnd.LowerBound, true | true, Symb.BoundEnd.UpperBound, false ->
NonBottom zero
| _ ->
Bottom )
| NonBottom x ->
let x = mult_const subst_pos coeff x in
if Symb.Symbol.is_unsigned s then NonBottom (approx_max subst_pos x zero)
else NonBottom x
in
match x with
| MInf | PInf ->
NonBottom x
| Linear (c, se) ->
if SymLinear.is_empty se then NonBottom x
else
SymLinear.fold se
~init:(NonBottom (of_big_int c))
~f:(fun acc s coeff -> lift2 (plus subst_pos) acc (get_mult_const s coeff))
| MinMax (c, sign, min_max, d, s) -> (
match get s with
| Bottom ->
Option.value_map (big_int_of_minmax subst_pos x) ~default:Bottom ~f:(fun i ->
NonBottom (of_big_int i) )
| NonBottom x' ->
let res =
match (sign, min_max, x') with
| Plus, Min, MInf | Minus, Max, PInf ->
MInf
| Plus, Max, PInf | Minus, Min, MInf ->
PInf
| sign, Min, PInf | sign, Max, MInf ->
of_big_int (Sign.eval_big_int sign c d)
| _, _, Linear (c2, se) -> (
if SymLinear.is_zero se then
of_big_int (Sign.eval_big_int sign c (MinMax.eval_big_int min_max d c2))
else if SymLinear.is_one_symbol se then
mk_MinMax
( Sign.eval_big_int sign c c2
, sign
, min_max
, Z.(d - c2)
, SymLinear.get_one_symbol se )
else if SymLinear.is_mone_symbol se then
mk_MinMax
( Sign.eval_big_int sign c c2
, Sign.neg sign
, MinMax.neg min_max
, Z.(c2 - d)
, SymLinear.get_mone_symbol se )
else
match big_int_of_minmax subst_pos x with
| Some i ->
of_big_int i
| None ->
of_bound_end subst_pos )
| _, _, MinMax (c2, sign2, min_max2, d2, s2) -> (
match (min_max, sign2, min_max2) with
| Min, Plus, Min | Max, Plus, Max ->
let c' = Sign.eval_big_int sign c c2 in
let d' = MinMax.eval_big_int min_max Z.(d - c2) d2 in
mk_MinMax (c', sign, min_max, d', s2)
| Min, Minus, Max | Max, Minus, Min ->
let c' = Sign.eval_big_int sign c c2 in
let d' = MinMax.eval_big_int min_max2 Z.(c2 - d) d2 in
mk_MinMax (c', Sign.neg sign, min_max2, d', s2)
| _ ->
let bound_end =
match sign with Plus -> subst_pos | Minus -> Symb.BoundEnd.neg subst_pos
in
of_big_int
(Sign.eval_big_int sign c
(MinMax.eval_big_int min_max d
(big_int_of_minmax bound_end x' |> Option.value ~default:d))) )
in
NonBottom res )
let subst_lb x eval_sym = subst ~subst_pos:Symb.BoundEnd.LowerBound x eval_sym

Loading…
Cancel
Save