From ac414990321917aada7a93fc95879c88906feb02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bobot?= <francois.bobot@cea.fr> Date: Tue, 11 May 2021 15:39:17 +0200 Subject: [PATCH] Add a debugging message for each contradiction and a debugging flag --debug-flag contradiction --- src_colibri2/core/egraph.ml | 28 +++++++++------ src_colibri2/core/egraph.mli | 1 + src_colibri2/core/interp.ml | 4 +-- src_colibri2/theories/ADT/adt.ml | 38 ++++++++++++++++---- src_colibri2/theories/LRA/dom_interval.ml | 11 ++++-- src_colibri2/theories/LRA/dom_polynome.ml | 12 +++++-- src_colibri2/theories/LRA/fourier.ml | 6 +++- src_colibri2/theories/bool/equality.ml | 8 ++++- src_colibri2/theories/quantifier/uninterp.ml | 7 +++- 9 files changed, 89 insertions(+), 26 deletions(-) diff --git a/src_colibri2/core/egraph.ml b/src_colibri2/core/egraph.ml index 8cf416a78..ef1ac0677 100644 --- a/src_colibri2/core/egraph.ml +++ b/src_colibri2/core/egraph.ml @@ -31,6 +31,9 @@ let debug_few = Debug.register_info_flag ~desc:"for the core solver" "Egraph.few" +let print_decision = Colibri2_popop_lib.Debug.register_flag ~desc:"Print@ information@ about@ the@ decisions@ made" "decision" +let print_contradiction = Colibri2_popop_lib.Debug.register_flag ~desc:"Print@ information@ about@ the@ contradiction@ found" "contradiction" + let stats_set_dom = Debug.register_stats_int ~name:"Egraph.set_dom/merge" ~init:0 let stats_set_value = @@ -707,23 +710,31 @@ module Delayed = struct then (* already same value. Does that really happen? *) () - else + else begin + Debug.dprintf8 print_contradiction + "[Egraph] %a and %a are merged with conflicting values %a and %a" + Node.pp node0 Node.pp node0' Value.pp v Value.pp v'; raise Contradiction + end - let test_mergeable_values t node node' = + let check_mergeable_values t node node' = let old_s = Node.M.find_opt node t.env.value.values in let old_s' = Node.M.find_opt node' t.env.value.values in match old_s, old_s' with | None, None | Some _, None - | None, Some _ -> true + | None, Some _ -> () | Some v, Some v' -> if Value.equal v v' then (* already same value. Does that really happen? *) - true - else - false + () + else begin + Debug.dprintf8 print_contradiction + "[Egraph] %a and %a are merged with conflicting values %a and %a" + Node.pp node Node.pp node' Value.pp v Value.pp v'; + raise Contradiction + end let finalize_merge t node1_0 node2_0 inv = let node1 = find t node1_0 in @@ -812,8 +823,7 @@ module Delayed = struct let node1 = find t node1_0 in let node2 = find t node2_0 in if not (Node.equal node1 node2) then begin - if not (test_mergeable_values t node1 node2) then - raise Contradiction; + check_mergeable_values t node1 node2; let ((other_node0,_),(_,_)) = choose_repr t.env (node1_0,node1) (node2_0,node2) in let inv = not (Node.equal node1_0 other_node0) in @@ -1207,8 +1217,6 @@ let () = Exn_printer.register (fun fmt exn -> | exn -> raise exn ) -let print_decision = Colibri2_popop_lib.Debug.register_flag ~desc:"Print@ information@ about@ the@ decisions@ made" "decision" - type theory = t -> unit let theories = ref [] diff --git a/src_colibri2/core/egraph.mli b/src_colibri2/core/egraph.mli index 8c1b52fa8..9473dbe20 100644 --- a/src_colibri2/core/egraph.mli +++ b/src_colibri2/core/egraph.mli @@ -191,6 +191,7 @@ module Backtrackable: sig end val print_decision: Colibri2_popop_lib.Debug.flag +val print_contradiction: Colibri2_popop_lib.Debug.flag type theory = t -> unit diff --git a/src_colibri2/core/interp.ml b/src_colibri2/core/interp.ml index df46fe06f..7dc91cedb 100644 --- a/src_colibri2/core/interp.ml +++ b/src_colibri2/core/interp.ml @@ -205,8 +205,8 @@ let check_ground_terms d = if Option.is_none (Egraph.get_value d n) then raise (ArgOfGroundTermWithoutValueAfterModelFixing (g, n))); if not (check d g) then ( - Debug.dprintf2 debug "Interp: checking of %a failed" Ground.Term.pp - (Ground.sem g); + Debug.dprintf2 Egraph.print_contradiction + "Interp: checking of %a failed" Ground.Term.pp (Ground.sem g); Egraph.contradiction d)) module WTO = Colibri2_stdlib.Wto.Make (Node) diff --git a/src_colibri2/theories/ADT/adt.ml b/src_colibri2/theories/ADT/adt.ml index e60358194..cc054cd26 100644 --- a/src_colibri2/theories/ADT/adt.ml +++ b/src_colibri2/theories/ADT/adt.ml @@ -45,11 +45,16 @@ module D = struct let merged d1 d2 = Option.equal equal d1 d2 - let merge' d d1 d2 = + let merge' info d d1 d2 = match (d1, d2) with | Unk s1, Unk s2 -> let s = Case.S.inter s1 s2 in - if Case.S.is_empty s then Egraph.contradiction d else Unk s + if Case.S.is_empty s then ( + Debug.dprintf5 Egraph.print_contradiction + "[ADT] The intersection of %a and %a is empty %t" Field.S.pp s1 + Case.S.pp s2 info; + Egraph.contradiction d) + else Unk s | One { case = c1; fields = f1 }, One { case = c2; fields = f2 } -> if Case.equal c1 c2 then One @@ -62,15 +67,27 @@ module D = struct Some n1) f1 f2; } - else Egraph.contradiction d + else ( + Debug.dprintf5 Egraph.print_contradiction + "[ADT] case conflict between %a and %a %t" Case.pp c1 Case.pp c2 + info; + Egraph.contradiction d) | (One { case = c1; _ } as d1), Unk c2 | Unk c2, (One { case = c1; _ } as d1) -> - if Case.S.mem c1 c2 then d1 else Egraph.contradiction d + if Case.S.mem c1 c2 then d1 + else ( + Debug.dprintf5 Egraph.print_contradiction + "[ADT] case %a is not in %a %t" Case.pp c1 Case.S.pp c2 info; + Egraph.contradiction d) let merge d (d1, n1) (d2, n2) _ = let s = match (d1, d2) with - | Some d1, Some d2 -> merge' d d1 d2 + | Some d1, Some d2 -> + merge' + (fun fmt -> + Fmt.pf fmt "when merging %a and %a" Node.pp n1 Node.pp n2) + d d1 d2 | None, Some d1 | Some d1, None -> d1 | None, None -> assert false (* absurd: already merged *) @@ -85,7 +102,9 @@ let upd_dom d n d2 = match Egraph.get_dom d D.key n with | None -> Egraph.set_dom d D.key n d2 | Some d1 -> - let d' = D.merge' d d1 d2 in + let d' = + D.merge' (fun fmt -> Fmt.pf fmt "when updating %a" Node.pp n) d d1 d2 + in if not (D.equal d' d1) then Egraph.set_dom d D.key n d' let case_of_adt ty = @@ -189,7 +208,12 @@ let converter d (f : Ground.t) = if vr then D.Unk (Case.S.singleton case) else let s = Case.S.remove case (case_of_adt adt) in - if Case.S.is_empty s then Egraph.contradiction d else D.Unk s)); + if Case.S.is_empty s then ( + Debug.dprintf4 Egraph.print_contradiction + "[ADT] tester %a removed the only case %a of the type" Node.pp + r Case.pp case; + Egraph.contradiction d) + else D.Unk s)); wait.for_dom d D.key e (setb r (let+ ve = get e in diff --git a/src_colibri2/theories/LRA/dom_interval.ml b/src_colibri2/theories/LRA/dom_interval.ml index 9d36f7e3d..a905003d4 100644 --- a/src_colibri2/theories/LRA/dom_interval.ml +++ b/src_colibri2/theories/LRA/dom_interval.ml @@ -45,6 +45,11 @@ let () = DomKind.register(module struct | Some i1,_, Some i2,_ -> begin match D.inter i1 i2 with | None -> + Debug.dprintf8 Egraph.print_contradiction + "[LRA/Dom] The intersection of %a and %a is empty when merging %a and %a" + D.pp i1 D.pp i2 + Node.pp cl1 + Node.pp cl2; Egraph.contradiction d | Some i -> if not (D.equal i i1) then @@ -128,8 +133,10 @@ let upd_dom d n' v' = | Some old -> match D.inter old v' with | None -> - Debug.dprintf6 debug "[LRA] upd node = %a d = %a d' = %a" - Node.pp n' D.pp old D.pp v'; + Debug.dprintf6 Egraph.print_contradiction + "[LRA/Dom] The intersection of %a with %a is empty when updating %a" + D.pp old D.pp v' + Node.pp n'; Egraph.contradiction d | Some d' -> if not (D.equal old d') diff --git a/src_colibri2/theories/LRA/dom_polynome.ml b/src_colibri2/theories/LRA/dom_polynome.ml index a1ad365b6..d5058f51b 100644 --- a/src_colibri2/theories/LRA/dom_polynome.ml +++ b/src_colibri2/theories/LRA/dom_polynome.ml @@ -125,8 +125,12 @@ module Th = struct (** p = other *) add_itself d other p end - | Cst _ -> + | Cst c -> (* 0 = cst <> 0 *) + Debug.dprintf6 Egraph.print_contradiction + "[LRA/Poly] Found 0 = %a when merging %a and %a" + Q.pp c + Node.pp cl1 Node.pp cl2; Egraph.contradiction d | Var(q,x,p') -> (** diff = qx + p' *) @@ -156,8 +160,12 @@ module Th = struct Node.pp cl Polynome.pp p1 Polynome.pp p2 Polynome.pp diff; begin match Polynome.extract diff with | Zero -> () - | Cst _ -> + | Cst c -> (* 0 = cst <> 0 *) + Debug.dprintf4 Egraph.print_contradiction + "[LRA/Poly] Found 0 = %a when updating %a" + Q.pp c + Node.pp cl; Egraph.contradiction d | Var(q,x,p') -> (** diff = qx + p' *) diff --git a/src_colibri2/theories/LRA/fourier.ml b/src_colibri2/theories/LRA/fourier.ml index 046503fd8..4258775bb 100644 --- a/src_colibri2/theories/LRA/fourier.ml +++ b/src_colibri2/theories/LRA/fourier.ml @@ -137,7 +137,11 @@ let add_eq d eqs p bound origins = | Some p, _ when Q.sign p < 0 -> Debug.dprintf2 debug "[Fourier] discard %a" Ground.S.pp origins; eqs - | _ -> Egraph.contradiction d + | Some p, bound -> + Debug.dprintf4 Egraph.print_contradiction + "[LRA/Fourier] Found %a%a0" + Q.pp p Bound.pp bound; + Egraph.contradiction d let mk_eq d bound a b = let (!) n = diff --git a/src_colibri2/theories/bool/equality.ml b/src_colibri2/theories/bool/equality.ml index f77cf9d57..8afe5938c 100644 --- a/src_colibri2/theories/bool/equality.ml +++ b/src_colibri2/theories/bool/equality.ml @@ -79,6 +79,7 @@ module Dis : sig type t type elt val pp: t Format.printer + val pp_elt: elt Format.printer val empty: t val of_node: ThE.t -> elt val to_node: elt -> ThE.t @@ -93,6 +94,7 @@ end = struct type t = ThE.S.t type elt = ThE.t let empty = ThE.S.empty + let pp_elt = ThE.pp let pp fmt s = let aux fmt m = ThE.M.bindings m @@ -135,7 +137,11 @@ module D = struct | None, Some s -> Egraph.set_dom d dom cl1 s | Some s1, Some s2 -> - let s = Dis.test_disjoint (fun _ -> Egraph.contradiction d) s1 s2 in + let s = Dis.test_disjoint (fun c -> + Debug.dprintf6 Egraph.print_contradiction + "[Equality] The currently merged %a and %a are different since %a" + Node.pp cl1 Node.pp cl2 Dis.pp_elt c; + Egraph.contradiction d) s1 s2 in Egraph.set_dom d dom cl1 s; Egraph.set_dom d dom cl2 s diff --git a/src_colibri2/theories/quantifier/uninterp.ml b/src_colibri2/theories/quantifier/uninterp.ml index bd9e08df7..efa8d6704 100644 --- a/src_colibri2/theories/quantifier/uninterp.ml +++ b/src_colibri2/theories/quantifier/uninterp.ml @@ -311,7 +311,12 @@ module UFModel = struct let lv = IArray.map ~f:interp s.args in let v = interp (Ground.node g) in match find d s lv with - | Some v' -> if not (Value.equal v v') then Egraph.contradiction d + | Some v' -> + if not (Value.equal v v') then ( + Debug.dprintf8 Egraph.print_contradiction + "[Uninterp] The model of %a (%a) is %a and not %a" Ground.pp g + Ground.Term.pp s Value.pp v' Value.pp v; + Egraph.contradiction d) | None -> set d s lv v in let f d g = waiter.for_any_value d (Ground.node g) (check_or_update g) in -- GitLab