mirror of
https://github.com/c-cube/sidekick.git
synced 2025-12-06 03:05:31 -05:00
Added .merlin (still may needs some work though). Fixed some warning of deprecated use of 'Pervasives.or'
806 lines
23 KiB
OCaml
806 lines
23 KiB
OCaml
(**************************************************************************)
|
|
(* *)
|
|
(* Cubicle *)
|
|
(* Combining model checking algorithms and SMT solvers *)
|
|
(* *)
|
|
(* Sylvain Conchon and Alain Mebsout *)
|
|
(* Universite Paris-Sud 11 *)
|
|
(* *)
|
|
(* Copyright 2011. This file is distributed under the terms of the *)
|
|
(* Apache Software License version 2.0 *)
|
|
(* *)
|
|
(**************************************************************************)
|
|
|
|
open Num
|
|
open Format
|
|
open Sig
|
|
|
|
let ale = Hstring.make "<="
|
|
let alt = Hstring.make "<"
|
|
let is_le n = Hstring.compare n ale = 0
|
|
let is_lt n = Hstring.compare n alt = 0
|
|
|
|
let (-@) l1 l2 = List.rev_append l1 l2
|
|
|
|
module L = Literal
|
|
module Sy = Symbols
|
|
|
|
exception NotConsistent of Literal.LT.Set.t
|
|
|
|
module type EXTENDED_Polynome = sig
|
|
include Polynome.T
|
|
val poly_of : r -> t
|
|
val alien_of : t -> r
|
|
end
|
|
|
|
module Make
|
|
(X : Sig.X)
|
|
(P : EXTENDED_Polynome with type r = X.r) = struct
|
|
|
|
module MP = Map.Make(P)
|
|
module SP = Set.Make(P)
|
|
module SX = Set.Make(struct type t = X.r include X end)
|
|
module MX = Map.Make(struct type t = X.r include X end)
|
|
|
|
type r = P.r
|
|
|
|
module LR = Literal.Make(struct type t = X.r include X end)
|
|
|
|
module Seq =
|
|
Set.Make
|
|
(struct
|
|
type t = r L.view * L.LT.t option * Explanation.t
|
|
let compare (a, _, _) (b, _, _) =
|
|
LR.compare (LR.make a) (LR.make b)
|
|
end)
|
|
|
|
module Inequation = struct
|
|
type t = {
|
|
ple0 : P.t;
|
|
is_le : bool;
|
|
dep : (Literal.LT.t * num * P.t * bool) list;
|
|
expl : Explanation.t
|
|
}
|
|
|
|
let print fmt ineq = fprintf fmt "%a %s 0" P.print ineq.ple0
|
|
(if ineq.is_le then "<=" else "<")
|
|
|
|
let create p1 p2 is_le a expl =
|
|
let p = P.add p1 (P.mult (P.create [] (Int (-1)) (P.type_info p1)) p2) in
|
|
{ ple0 = p; is_le = is_le; dep = [a, Int 1, p, is_le]; expl = expl }
|
|
|
|
let choose ineq = snd (P.choose ineq.ple0)
|
|
|
|
let find x ineq = P.find x ineq.ple0
|
|
|
|
let is_monomial ineq = P.is_monomial ineq.ple0
|
|
|
|
let pos_neg mx { ple0 = p } =
|
|
List.fold_left (fun m (c,x) ->
|
|
let cmp = compare_num c (Int 0) in
|
|
if cmp = 0 then m
|
|
else
|
|
let (pos, neg) = try MX.find x m with Not_found -> (0,0) in
|
|
if cmp > 0 then MX.add x (pos+1, neg) m
|
|
else MX.add x (pos, neg+1) m ) mx (fst (P.to_list p))
|
|
|
|
end
|
|
|
|
type t = {
|
|
inequations : (Literal.LT.t * Inequation.t) list ;
|
|
monomes: (Intervals.t * SX.t) MX.t;
|
|
polynomes : Intervals.t MP.t;
|
|
known_eqs : SX.t;
|
|
improved : SP.t;
|
|
}
|
|
|
|
module Debug = struct
|
|
|
|
let list_of_ineqs fmt = List.iter (fprintf fmt "%a " Inequation.print)
|
|
|
|
let assume a = ()
|
|
|
|
let cross x cpos cneg others ninqs = ()
|
|
|
|
let print_use fmt use =
|
|
SX.iter (fprintf fmt "%a, " X.print) use
|
|
|
|
let env env = ()
|
|
|
|
let implied_equalities l = ()
|
|
end
|
|
|
|
let empty _ = {
|
|
inequations = [] ;
|
|
monomes = MX.empty ;
|
|
polynomes = MP.empty ;
|
|
known_eqs = SX.empty ;
|
|
improved = SP.empty ;
|
|
}
|
|
|
|
let replace_inequation env x ineq =
|
|
{ env with
|
|
inequations = (x, ineq)::(List.remove_assoc x env.inequations) }
|
|
|
|
|
|
let up_improved env p oldi newi =
|
|
if Intervals.is_strict_smaller newi oldi then
|
|
{ env with improved = SP.add p env.improved }
|
|
else env
|
|
|
|
(*
|
|
let oldify_inequations env =
|
|
{ env with
|
|
inequations = env.inequations@env.new_inequations;
|
|
new_inequations = [] } *)
|
|
|
|
let mult_bornes_vars vars monomes ty=
|
|
List.fold_left
|
|
(fun ui (y,n) ->
|
|
let ui' = try
|
|
fst (MX.find y monomes)
|
|
with Not_found -> Intervals.undefined ty
|
|
in
|
|
Intervals.mult ui (Intervals.power n ui')
|
|
) (Intervals.point (Int 1) ty Explanation.empty) vars
|
|
|
|
|
|
let intervals_from_monomes env p =
|
|
let pl, v = P.to_list p in
|
|
List.fold_left
|
|
(fun i (a, x) ->
|
|
let i_x, _ = MX.find x env.monomes in
|
|
Intervals.add (Intervals.scale a i_x) i
|
|
) (Intervals.point v (P.type_info p) Explanation.empty) pl
|
|
|
|
let rec add_monome expl use_x env x =
|
|
try
|
|
let u, old_use_x = MX.find x env.monomes in
|
|
{ env with monomes = MX.add x (u, SX.union old_use_x use_x) env.monomes }
|
|
with Not_found ->
|
|
update_monome expl use_x env x
|
|
|
|
and init_monomes env p use_p expl =
|
|
List.fold_left
|
|
(fun env (_, x) -> add_monome expl use_p env x)
|
|
env (fst (P.to_list p))
|
|
|
|
and init_alien expl p (normal_p, c, d) ty use_x env =
|
|
let env = init_monomes env p use_x expl in
|
|
let i = intervals_from_monomes env p in
|
|
let i =
|
|
try
|
|
let old_i = MP.find normal_p env.polynomes in
|
|
let old_i = Intervals.scale d
|
|
(Intervals.add old_i (Intervals.point c ty Explanation.empty)) in
|
|
Intervals.intersect i old_i
|
|
with Not_found -> i
|
|
in
|
|
env, i
|
|
|
|
|
|
|
|
and update_monome expl use_x env x =
|
|
let ty = X.type_info x in
|
|
let ui, env =
|
|
match X.term_extract x with
|
|
| Some t ->
|
|
let use_x = SX.singleton x in
|
|
begin
|
|
match Term.view t with
|
|
| {Term.f = (Sy.Op Sy.Div); xs = [a; b]} ->
|
|
let pa = P.poly_of (fst (X.make a)) in
|
|
let pb = P.poly_of (fst (X.make b)) in
|
|
let (pa', ca, da) as npa = P.normal_form_pos pa in
|
|
let (pb', cb, db) as npb = P.normal_form_pos pb in
|
|
let env, ia = init_alien expl pa npa ty use_x env in
|
|
let env, ib = init_alien expl pb npb ty use_x env in
|
|
let ia, ib = match Intervals.doesnt_contain_0 ib with
|
|
| Yes ex when Num.compare_num ca cb = 0
|
|
&& P.compare pa' pb' = 0 ->
|
|
let expl = Explanation.union ex expl in
|
|
Intervals.point da ty expl, Intervals.point db ty expl
|
|
| _ -> ia, ib
|
|
in
|
|
Intervals.div ia ib, env
|
|
| _ -> Intervals.undefined ty, env
|
|
end
|
|
| _ -> Intervals.undefined ty, env
|
|
in
|
|
let u, use_x' =
|
|
try MX.find x env.monomes
|
|
with Not_found -> Intervals.undefined (X.type_info x), use_x in
|
|
let ui = Intervals.intersect ui u in
|
|
{ env with monomes = MX.add x (ui, (SX.union use_x use_x')) env.monomes }
|
|
|
|
and tighten_div x env expl = env
|
|
|
|
and tighten_non_lin x use_x env expl =
|
|
let env = tighten_div x env expl in
|
|
SX.fold
|
|
(fun x acc ->
|
|
let _, use = MX.find x acc.monomes in
|
|
update_monome expl use acc x)
|
|
use_x env
|
|
|
|
let update_monomes_from_poly p i polynomes monomes =
|
|
let lp, _ = P.to_list p in
|
|
let ty = P.type_info p in
|
|
List.fold_left (fun monomes (a,x) ->
|
|
let np = P.remove x p in
|
|
let (np,c,d) = P.normal_form_pos np in
|
|
try
|
|
let inp = MP.find np polynomes in
|
|
let new_ix =
|
|
Intervals.scale
|
|
((Int 1) // a)
|
|
(Intervals.add i
|
|
(Intervals.scale (minus_num d)
|
|
(Intervals.add inp
|
|
(Intervals.point c ty Explanation.empty)))) in
|
|
let old_ix, ux = MX.find x monomes in
|
|
let ix = Intervals.intersect old_ix new_ix in
|
|
MX.add x (ix, ux) monomes
|
|
with Not_found -> monomes)
|
|
monomes lp
|
|
|
|
let update_polynomes env expl =
|
|
let polynomes, monomes, improved = MP.fold
|
|
(fun p ip (polynomes, monomes, improved) ->
|
|
let new_i = intervals_from_monomes env p in
|
|
let i = Intervals.intersect new_i ip in
|
|
if Intervals.is_strict_smaller i ip then
|
|
let monomes = update_monomes_from_poly p i polynomes monomes in
|
|
let improved = SP.add p improved in
|
|
MP.add p i polynomes, monomes, improved
|
|
else polynomes, monomes, improved
|
|
) env.polynomes (env.polynomes, env.monomes, env.improved) in
|
|
{env with polynomes = polynomes; monomes = monomes ; improved = improved}
|
|
|
|
|
|
let find_one_eq x u =
|
|
match Intervals.is_point u with
|
|
| Some (v, ex) when X.type_info x <> Ty.Tint || is_integer_num v ->
|
|
let eq =
|
|
L.Eq (x,(P.alien_of (P.create [] v (X.type_info x)))) in
|
|
Some (eq, None, ex)
|
|
| _ -> None
|
|
|
|
let find_eq eqs x u env =
|
|
match find_one_eq x u with
|
|
| None -> eqs
|
|
| Some eq1 -> eq1::eqs
|
|
|
|
type ineq_status =
|
|
| Trivial_eq
|
|
| Trivial_ineq of num
|
|
| Bottom
|
|
| Monome of num * P.r * num
|
|
| Other
|
|
|
|
let ineq_status ({Inequation.ple0 = p ; is_le = is_le} as ineq) =
|
|
match Inequation.is_monomial ineq with
|
|
Some (a, x, v) -> Monome (a, x, v)
|
|
| None ->
|
|
if P.is_empty p then
|
|
let _, v = P.to_list p in
|
|
let c = compare_num v (Int 0) in
|
|
if c > 0 || (c >=0 && not is_le) then Bottom
|
|
else
|
|
if c = 0 && is_le then Trivial_eq
|
|
else Trivial_ineq v
|
|
else Other
|
|
|
|
(*let ineqs_from_dep dep borne_inf is_le =
|
|
List.map
|
|
(fun {poly_orig = p; coef = c} ->
|
|
let (m,v,ty) = P.mult_const minusone p in
|
|
(* quelle valeur pour le ?????? *)
|
|
{ ple0 = {poly = (m, v +/ (borne_inf // c), ty); le = is_le} ;
|
|
dep = []}
|
|
)dep*)
|
|
|
|
let mk_equality p =
|
|
let r1 = P.alien_of p in
|
|
let r2 = P.alien_of (P.create [] (Int 0) (P.type_info p)) in
|
|
L.Eq (r1, r2)
|
|
|
|
let fm_equalities env eqs { Inequation.ple0 = p; dep = dep; expl = ex } =
|
|
let inqs, eqs =
|
|
List.fold_left
|
|
(fun (inqs, eqs) (a, _, p, _) ->
|
|
List.remove_assoc a inqs, (mk_equality p, Some a, ex) :: eqs
|
|
) (env.inequations, eqs) dep
|
|
in
|
|
{ env with inequations = inqs }, eqs
|
|
|
|
let update_intervals env eqs expl (a, x, v) is_le =
|
|
let uints, use_x = MX.find x env.monomes in
|
|
let b = ((Int (-1)) */ v) // a in
|
|
let u =
|
|
if a >/ (Int 0) then
|
|
Intervals.new_borne_sup expl b is_le uints
|
|
else
|
|
Intervals.new_borne_inf expl b is_le uints in
|
|
let env = { env with monomes = MX.add x (u, use_x) env.monomes } in
|
|
let env = tighten_non_lin x use_x env expl in
|
|
env, (find_eq eqs x u env)
|
|
|
|
let update_ple0 env p0 is_le expl =
|
|
if P.is_empty p0 then env
|
|
else
|
|
let ty = P.type_info p0 in
|
|
let a, _ = P.choose p0 in
|
|
let p, change =
|
|
if a </ Int 0 then
|
|
P.mult (P.create [] (Int (-1)) ty) p0, true
|
|
else p0, false in
|
|
let p, c, _ = P.normal_form p in
|
|
let c = minus_num c in
|
|
let u =
|
|
if change then
|
|
Intervals.new_borne_inf expl c is_le (Intervals.undefined ty)
|
|
else
|
|
Intervals.new_borne_sup expl c is_le (Intervals.undefined ty) in
|
|
let u, pu =
|
|
try
|
|
let pu = MP.find p env.polynomes in
|
|
let i = Intervals.intersect u pu in
|
|
i, pu
|
|
with Not_found -> u, Intervals.undefined ty
|
|
in
|
|
let env =
|
|
if Intervals.is_strict_smaller u pu then
|
|
let polynomes = MP.add p u env.polynomes in
|
|
let monomes = update_monomes_from_poly p u polynomes env.monomes in
|
|
let improved = SP.add p env.improved in
|
|
{ env with
|
|
polynomes = polynomes;
|
|
monomes = monomes;
|
|
improved = improved }
|
|
else env
|
|
in
|
|
match P.to_list p0 with
|
|
| [a,x], v -> fst(update_intervals env [] expl (a, x, v) is_le)
|
|
| _ -> env
|
|
|
|
let add_inequations acc lin expl =
|
|
List.fold_left
|
|
(fun (env, eqs) ineq ->
|
|
(* let expl = List.fold_left
|
|
(fun expl (l,_,_,_) ->
|
|
Explanation.union (*Explanation.everything*)
|
|
(Explanation.singleton (Formula.mk_lit l))
|
|
expl
|
|
) expl ineq.Inequation.dep
|
|
in *)
|
|
let expl = Explanation.union ineq.Inequation.expl expl in
|
|
match ineq_status ineq with
|
|
| Bottom ->
|
|
raise (Exception.Inconsistent expl)
|
|
|
|
| Trivial_eq ->
|
|
fm_equalities env eqs ineq
|
|
|
|
| Trivial_ineq c ->
|
|
let n, pp =
|
|
List.fold_left
|
|
(fun ((n, pp) as acc) (_, _, p, is_le) ->
|
|
if is_le then acc else
|
|
match pp with
|
|
| Some _ -> n+1, None
|
|
| None when n=0 -> 1, Some p
|
|
| _ -> n+1, None) (0,None) ineq.Inequation.dep
|
|
in
|
|
let env =
|
|
List.fold_left
|
|
(fun env (_, coef, p, is_le) ->
|
|
let ty = P.type_info p in
|
|
let is_le =
|
|
match pp with
|
|
Some x -> P.compare x p = 0 | _ -> is_le && n=0
|
|
in
|
|
let p' = P.sub (P.create [] (c // coef) ty) p in
|
|
update_ple0 env p' is_le expl
|
|
) env ineq.Inequation.dep
|
|
in
|
|
env, eqs
|
|
|
|
| Monome (a, x, v) ->
|
|
let env, eqs =
|
|
update_intervals env eqs expl (a, x, v) ineq.Inequation.is_le
|
|
in
|
|
|
|
(*let env,eqs = update_bornes env eqs ((a,x),c) ineq.ple0.le in
|
|
let env,eqs = update_polynomes env eqs ineq in
|
|
env, pers_ineqs, eqs*)
|
|
env, eqs
|
|
|
|
| Other ->
|
|
env, eqs
|
|
(*t env,eqs = update_polynomes env eqs ineq in
|
|
env, pers_ineqs, eqs*)
|
|
|
|
|
|
) acc lin
|
|
|
|
let mult_list c =
|
|
List.map (fun (a, coef, p, is_le) -> (a, coef */ c, p, is_le))
|
|
|
|
let div_by_pgcd (a, b) ty =
|
|
try
|
|
if ty = Ty.Tint then
|
|
let p = Big_int.gcd_big_int (big_int_of_num a) (big_int_of_num b) in
|
|
let p = num_of_big_int p in
|
|
a // p, b // p
|
|
else a, b
|
|
with Failure "big_int_of_ratio" -> a, b
|
|
|
|
let cross x cpos cneg =
|
|
let rec cross_rec acc = function
|
|
| [] -> acc
|
|
| { Inequation.ple0 = p1; is_le = k1; dep = d1; expl = ex1 } :: l ->
|
|
let n1 = abs_num (P.find x p1) in
|
|
(* let ty = P.type_info p1 in *)
|
|
let acc =
|
|
List.fold_left
|
|
(fun acc {Inequation.ple0 = p2; is_le = k2; dep=d2; expl = ex2} ->
|
|
let n2 = abs_num (P.find x p2) in
|
|
(* let n1, n2 = div_by_pgcd (n1, n2) ty in *)
|
|
let p = P.add
|
|
(P.mult (P.create [] n2 (P.type_info p2)) p1)
|
|
(P.mult (P.create [] n1 (P.type_info p1)) p2) in
|
|
let d1 = mult_list n2 d1 in
|
|
let d2 = mult_list n1 d2 in
|
|
let ni =
|
|
{ Inequation.ple0 = p; is_le = k1&&k2; dep = d1 -@ d2;
|
|
expl = Explanation.union ex1 ex2 }
|
|
in
|
|
ni::acc
|
|
) acc cpos
|
|
in
|
|
cross_rec acc l
|
|
in
|
|
cross_rec [] cneg
|
|
|
|
let split x l =
|
|
let rec split_rec (cp, cn, co) ineq =
|
|
try
|
|
let a = Inequation.find x ineq in
|
|
if a >/ (Int 0) then ineq::cp, cn, co
|
|
else cp, ineq::cn, co
|
|
with Not_found -> cp, cn, ineq::co
|
|
in
|
|
List.fold_left split_rec ([], [], []) l
|
|
|
|
let length s = SX.fold (fun _ acc -> acc+1) s 0
|
|
|
|
let choose_var l =
|
|
let pos_neg = List.fold_left Inequation.pos_neg MX.empty l in
|
|
let xopt = MX.fold (fun x (pos, neg) acc ->
|
|
match acc with
|
|
| None -> Some (x, pos * neg)
|
|
| Some (y, c') ->
|
|
let c = pos * neg in
|
|
if c < c' then Some (x, c) else acc
|
|
) pos_neg None in
|
|
match xopt with
|
|
| Some (x, _) -> x
|
|
| None -> raise Not_found
|
|
|
|
let rec fourier ( (env, eqs) as acc) l expl =
|
|
match l with
|
|
| [] -> acc
|
|
| ineq :: l' ->
|
|
try
|
|
(* let x = Inequation.choose ineq in *)
|
|
let x = choose_var l in
|
|
let cpos, cneg, others = split x l in
|
|
let ninqs = cross x cpos cneg in
|
|
Debug.cross x cpos cneg others ninqs;
|
|
let acc = add_inequations acc cpos expl in
|
|
let acc = add_inequations acc cneg expl in
|
|
fourier acc (ninqs -@ others) expl
|
|
with Not_found -> add_inequations acc l expl
|
|
|
|
(*
|
|
let fm env eqs expl =
|
|
fourier (env, eqs)
|
|
(List.map snd env.inequations)
|
|
(List.map snd env.new_inequations) expl
|
|
*)
|
|
|
|
let fm env eqs expl =
|
|
fourier (env, eqs) (List.map snd env.inequations) expl
|
|
|
|
let is_num r =
|
|
let ty = X.type_info r in ty = Ty.Tint || ty = Ty.Treal
|
|
|
|
let add_disequality env eqs p expl =
|
|
let ty = P.type_info p in
|
|
match P.to_list p with
|
|
| ([], (Int 0)) ->
|
|
raise (Exception.Inconsistent expl)
|
|
| ([], v) ->
|
|
env, eqs
|
|
| ([a, x], v) ->
|
|
let b = (minus_num v) // a in
|
|
let i1 = Intervals.point b ty expl in
|
|
let i2, use2 =
|
|
try
|
|
MX.find x env.monomes
|
|
with Not_found -> Intervals.undefined ty, SX.empty
|
|
in
|
|
let i = Intervals.exclude i1 i2 in
|
|
let env ={ env with monomes = MX.add x (i,use2) env.monomes } in
|
|
let env = tighten_non_lin x use2 env expl in
|
|
env, find_eq eqs x i env
|
|
| _ ->
|
|
let a, _ = P.choose p in
|
|
let p = if a >=/ Int 0 then p
|
|
else P.mult (P.create [] (Int (-1)) ty) p in
|
|
let p, c, _ = P.normal_form p in
|
|
let i1 = Intervals.point (minus_num c) ty expl in
|
|
let i2 =
|
|
try
|
|
MP.find p env.polynomes
|
|
with Not_found -> Intervals.undefined ty
|
|
in
|
|
let i = Intervals.exclude i1 i2 in
|
|
let env =
|
|
if Intervals.is_strict_smaller i i2 then
|
|
let polynomes = MP.add p i env.polynomes in
|
|
let monomes = update_monomes_from_poly p i polynomes env.monomes
|
|
in
|
|
let improved = SP.add p env.improved in
|
|
{ env with
|
|
polynomes = polynomes;
|
|
monomes = monomes;
|
|
improved = improved}
|
|
else env
|
|
in
|
|
env, eqs
|
|
|
|
let add_equality env eqs p expl =
|
|
let ty = P.type_info p in
|
|
match P.to_list p with
|
|
| ([], Int 0) -> env, eqs
|
|
| ([], v) ->
|
|
raise (Exception.Inconsistent expl)
|
|
| ([a, x], v) ->
|
|
let b = (minus_num v) // a in
|
|
let i = Intervals.point b ty expl in
|
|
let i, use =
|
|
try
|
|
let i', use' = MX.find x env.monomes in
|
|
Intervals.intersect i i', use'
|
|
with Not_found -> i, SX.empty
|
|
in
|
|
let env = { env with monomes = MX.add x (i, use) env.monomes} in
|
|
let env = tighten_non_lin x use env expl in
|
|
env, find_eq eqs x i env
|
|
| _ ->
|
|
let a, _ = P.choose p in
|
|
let p = if a >=/ Int 0 then p
|
|
else P.mult (P.create [] (Int (-1)) ty) p in
|
|
let p, c, _ = P.normal_form p in
|
|
let i = Intervals.point (minus_num c) ty expl in
|
|
let i, ip =
|
|
try
|
|
let ip = MP.find p env.polynomes in
|
|
Intervals.intersect i ip, ip
|
|
with Not_found -> i, Intervals.undefined ty
|
|
in
|
|
let env =
|
|
if Intervals.is_strict_smaller i ip then
|
|
let polynomes = MP.add p i env.polynomes in
|
|
let monomes = update_monomes_from_poly p i polynomes env.monomes
|
|
in
|
|
let improved = SP.add p env.improved in
|
|
{ env with
|
|
polynomes = polynomes;
|
|
monomes = monomes;
|
|
improved = improved }
|
|
else env
|
|
in
|
|
let env =
|
|
{ env with
|
|
known_eqs = SX.add (P.alien_of p) env.known_eqs
|
|
} in
|
|
env, eqs
|
|
|
|
let normal_form a = match a with
|
|
| L.Builtin (false, n, [r1; r2]) when is_le n && X.type_info r1 = Ty.Tint ->
|
|
let pred_r1 = P.sub (P.poly_of r1) (P.create [] (Int 1) Ty.Tint) in
|
|
L.Builtin (true, n, [r2; P.alien_of pred_r1])
|
|
|
|
| L.Builtin (true, n, [r1; r2]) when
|
|
not (is_le n) && X.type_info r1 = Ty.Tint ->
|
|
let pred_r2 = P.sub (P.poly_of r2) (P.create [] (Int 1) Ty.Tint) in
|
|
L.Builtin (true, ale, [r1; P.alien_of pred_r2])
|
|
|
|
| L.Builtin (false, n, [r1; r2]) when is_le n ->
|
|
L.Builtin (true, alt, [r2; r1])
|
|
|
|
| L.Builtin (false, n, [r1; r2]) when is_lt n ->
|
|
L.Builtin (true, ale, [r2; r1])
|
|
|
|
| _ -> a
|
|
|
|
let remove_trivial_eqs eqs la =
|
|
let set_of l =
|
|
List.fold_left (fun s e -> Seq.add e s) Seq.empty l
|
|
in
|
|
Seq.elements (Seq.diff (set_of eqs) (set_of la))
|
|
|
|
|
|
let equalities_from_polynomes env eqs =
|
|
let known, eqs =
|
|
MP.fold
|
|
(fun p i (knw, eqs) ->
|
|
let xp = P.alien_of p in
|
|
if SX.mem xp knw then knw, eqs
|
|
else
|
|
match Intervals.is_point i with
|
|
| Some (num, ex) ->
|
|
let r2 = P.alien_of (P.create [] num (P.type_info p)) in
|
|
SX.add xp knw, (L.Eq(xp, r2), None, ex) :: eqs
|
|
| None -> knw, eqs
|
|
) env.polynomes (env.known_eqs, eqs)
|
|
in {env with known_eqs= known}, eqs
|
|
|
|
|
|
|
|
let equalities_from_monomes env eqs =
|
|
let known, eqs =
|
|
MX.fold
|
|
(fun x (i,_) (knw, eqs) ->
|
|
if SX.mem x knw then knw, eqs
|
|
else
|
|
match Intervals.is_point i with
|
|
| Some (num, ex) ->
|
|
let r2 = P.alien_of (P.create [] num (X.type_info x)) in
|
|
SX.add x knw, (L.Eq(x, r2), None, ex) :: eqs
|
|
| None -> knw, eqs
|
|
) env.monomes (env.known_eqs, eqs)
|
|
in {env with known_eqs= known}, eqs
|
|
|
|
let equalities_from_intervals env eqs =
|
|
let env, eqs = equalities_from_polynomes env eqs in
|
|
equalities_from_monomes env eqs
|
|
|
|
let assume env la =
|
|
let env = {env with improved = SP.empty} in
|
|
Debug.env env;
|
|
let env, eqs, new_ineqs, expl =
|
|
List.fold_left
|
|
(fun (env, eqs, new_ineqs, expl) (a, root, e) ->
|
|
let a = normal_form a in
|
|
let expl = Explanation.union e expl in
|
|
try
|
|
match a with
|
|
| L.Builtin(_, n, [r1;r2]) when is_le n || is_lt n ->
|
|
let root = match root with
|
|
| Some a -> a | None -> assert false in
|
|
let p1 = P.poly_of r1 in
|
|
let p2 = P.poly_of r2 in
|
|
let ineq = Inequation.create p1 p2 (is_le n) root expl in
|
|
let env =
|
|
init_monomes env ineq.Inequation.ple0 SX.empty expl in
|
|
let env =
|
|
update_ple0 env ineq.Inequation.ple0 (is_le n) expl in
|
|
let env = replace_inequation env root ineq in
|
|
env, eqs, true, expl
|
|
|
|
| L.Distinct (false, [r1; r2]) when is_num r1 && is_num r2 ->
|
|
let p = P.sub (P.poly_of r1) (P.poly_of r2) in
|
|
let env = init_monomes env p SX.empty expl in
|
|
let env, eqs = add_disequality env eqs p expl in
|
|
env, eqs, new_ineqs, expl
|
|
|
|
| L.Eq(r1, r2) when is_num r1 && is_num r2 ->
|
|
let p = P.sub (P.poly_of r1) (P.poly_of r2) in
|
|
let env = init_monomes env p SX.empty expl in
|
|
let env, eqs = add_equality env eqs p expl in
|
|
env, eqs, new_ineqs, expl
|
|
|
|
| _ -> (env, eqs, new_ineqs, expl)
|
|
|
|
with Intervals.NotConsistent expl ->
|
|
raise (Exception.Inconsistent expl)
|
|
)
|
|
(env, [], false, Explanation.empty) la
|
|
|
|
in
|
|
if new_ineqs then
|
|
if false then
|
|
();
|
|
try
|
|
(* we only call fm when new ineqs are assumed *)
|
|
let env, eqs = if new_ineqs then fm env eqs expl else env, eqs in
|
|
(* let env = oldify_inequations env in *)
|
|
let env = update_polynomes env expl in
|
|
let env, eqs = equalities_from_intervals env eqs in
|
|
Debug.env env;
|
|
let eqs = remove_trivial_eqs eqs la in
|
|
Debug.implied_equalities eqs;
|
|
let result =
|
|
List.fold_left
|
|
(fun r (a_sem, a_term, ex) ->
|
|
{ assume = (LSem(a_sem), ex) :: r.assume;
|
|
remove =
|
|
match a_term with
|
|
| None -> r.remove
|
|
| Some t -> (LTerm(t), ex)::r.remove
|
|
} ) { assume = []; remove = [] } eqs
|
|
in
|
|
env, result
|
|
|
|
with Intervals.NotConsistent expl ->
|
|
raise (Exception.Inconsistent expl)
|
|
|
|
let query env a_ex =
|
|
try
|
|
ignore(assume env [a_ex]);
|
|
No
|
|
with Exception.Inconsistent expl -> Yes expl
|
|
|
|
let case_split_polynomes env =
|
|
let o = MP.fold
|
|
(fun p i o ->
|
|
match Intervals.finite_size i with
|
|
| Some s when s >/ (Int 1) ->
|
|
begin
|
|
match o with
|
|
| Some (s', _, _, _) when s' <=/ s -> o
|
|
| _ ->
|
|
let n, ex = Intervals.borne_inf i in
|
|
Some (s, p, n, ex)
|
|
end
|
|
| _ -> o
|
|
) env.polynomes None in
|
|
match o with
|
|
| Some (s, p, n, ex) ->
|
|
let r1 = P.alien_of p in
|
|
let r2 = P.alien_of (P.create [] n (P.type_info p)) in
|
|
[L.Eq(r1, r2), ex, s]
|
|
| None ->
|
|
[]
|
|
|
|
let case_split_monomes env =
|
|
let o = MX.fold
|
|
(fun x (i,_) o ->
|
|
match Intervals.finite_size i with
|
|
| Some s when s >/ (Int 1) ->
|
|
begin
|
|
match o with
|
|
| Some (s', _, _, _) when s' <=/ s -> o
|
|
| _ ->
|
|
let n, ex = Intervals.borne_inf i in
|
|
Some (s, x, n, ex)
|
|
end
|
|
| _ -> o
|
|
) env.monomes None in
|
|
match o with
|
|
| Some (s,x,n,ex) ->
|
|
let ty = X.type_info x in
|
|
let r1 = x in
|
|
let r2 = P.alien_of (P.create [] n ty) in
|
|
[L.Eq(r1, r2), ex, s]
|
|
| None ->
|
|
[]
|
|
|
|
let case_split env =
|
|
match case_split_polynomes env with
|
|
| [] -> case_split_monomes env
|
|
| choices -> choices
|
|
|
|
let add env _ = env
|
|
|
|
let extract_improved env =
|
|
SP.fold
|
|
(fun p acc ->
|
|
MP.add p (MP.find p env.polynomes) acc)
|
|
env.improved MP.empty
|
|
|
|
end
|