Skip to content

Commit 2709525

Browse files
Alexander MazurAlexander Mazur
authored andcommitted
Made another query instead of invariant
1 parent 211b3e8 commit 2709525

18 files changed

Lines changed: 209 additions & 99 deletions

dune-project

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ Goblint includes analyses for assertions, overflows, deadlocks, etc and can be e
6969
conf-gcc ; ensures opam-repository CI installs real gcc from homebrew on MacOS
7070
domain-local-await
7171
domain_shims
72+
ocplib-simplex
7273
)
7374
(depopts
7475
apron

goblint.opam

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ depends: [
7171
"conf-gcc"
7272
"domain-local-await"
7373
"domain_shims"
74+
"ocplib-simplex"
7475
]
7576
depopts: ["apron" "z3" "domainslib"]
7677
conflicts: [

goblint.opam.locked

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ depends: [
8484
"ocaml-variants" {= "4.14.2+options"}
8585
"ocamlbuild" {= "0.14.3"}
8686
"ocamlfind" {= "1.9.8"}
87+
"ocplib-simplex" {= "0.5.1"}
8788
"odoc" {= "3.0.0" & with-doc}
8889
"odoc-parser" {= "3.0.0" & with-doc}
8990
"ordering" {= "3.19.1"}

src/analyses/apron/relationAnalysis.apron.ml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ struct
7676
if VH.mem v_ins v then
7777
VH.find v_ins v
7878
else
79-
let v_in = Cilfacade.create_var @@ makeVarinfo false (v.vname ^ "#in") v.vtype in (* temporary local g#in for global g *)
79+
let v_in = Cilfacade.create_var @@ makeVarinfo false (v.vname ^ "#in") v.vtype in (* temporary local g#in for global g *)
8080
v_in.vattr <- v.vattr; (* preserve goblint_relation_track attribute *)
8181
VH.replace v_ins v v_in;
8282
v_in
@@ -613,7 +613,7 @@ struct
613613
if (one_var || GobApron.Lincons1.num_vars lincons1 >= 2) && (exact || Apron.Lincons1.get_typ lincons1 <> EQ) then
614614
RD.cil_exp_of_lincons1 lincons1
615615
|> Option.map e_inv
616-
(*|> Option.filter (InvariantCil.exp_is_suitable ~scope)*)
616+
|> Option.filter (InvariantCil.exp_is_suitable ~scope)
617617
else
618618
None
619619
)
@@ -628,6 +628,8 @@ struct
628628
else
629629
Invariant.none
630630

631+
let query_my_invariant man = MyInvariant.of_lincons1_set (RD.invariant_set man.local.rel)
632+
631633
let query man (type a) (q: a Queries.t): a Queries.result =
632634
let open Queries in
633635
let st = man.local in
@@ -652,6 +654,7 @@ struct
652654
| Queries.InvariantGlobal g ->
653655
let g: V.t = Obj.obj g in
654656
query_invariant_global man g
657+
| Queries.MyInvariant _ -> query_my_invariant man
655658
| _ -> Result.top q
656659

657660

src/analyses/loopTermination.ml

Lines changed: 82 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ open GoblintCil
77
open TerminationPreprocessing
88
open ListMatrix
99
open SparseVector
10+
open GobApron
1011

1112
(** Contains all loop counter variables (varinfo) and maps them to their corresponding loop statement. *)
1213
let loop_counters : stmt VarToStmt.t ref = ref VarToStmt.empty
@@ -61,9 +62,9 @@ module Matrix = ListMatrix (Rat) (SparseVector)
6162

6263
module SparseVec = SparseVector (Rat)
6364

64-
module VarSet = Set.Make(String)
65+
module StringSet = Set.Make (String)
6566

66-
let string_of_constraints (constraints: Invariant.t) =
67+
let string_of_invariant (constraints: Invariant.t) =
6768
match constraints with
6869
| `Top -> "Top"
6970
| `Bot -> "Bot"
@@ -80,12 +81,12 @@ let exp_list_of_constraints (constraints : Invariant.t) =
8081
| BinOp (Ge, e1, e2, t) -> (BinOp (Le, e2, e1, t)) :: acc
8182
| BinOp (Eq, e1, e2, t) -> (BinOp (Le, e1, e2, t)) :: (BinOp (Le, e2, e1, t)) :: acc
8283
| BinOp (Ne, _, _, _) -> acc
83-
| _ -> failwith "Found something else, help me" in
84+
| _ -> failwith "Found something else" in
8485
let cs =
8586
cs |> Invariant.Exp.process |> List.map Invariant.Exp.to_cil |> List.fold_left to_leq []
8687
in
8788
if M.tracing then
88-
(M.trace "termination" "Constraints: %s" (string_of_constraints constraints);
89+
(M.trace "termination" "Constraints: %s" (string_of_invariant constraints);
8990
M.trace "termination" "Number of constraints after conversion to Leq list: %i" (List.length cs));
9091
cs
9192

@@ -98,15 +99,12 @@ let coeff_in_exp vname e =
9899
| c, None | None, c -> c)
99100
| BinOp (MinusA, e1, e2, _) ->
100101
failwith "found a Minus"
101-
(*(match find_coeff v e1, find_coeff v e2 with
102-
| Some c1, Some c2 -> failwith "This shouldn't happen"
103-
| c, None -> c
104-
| None, Some c -> Some (Rat.mult Rat.m_one c))*)
105102
| BinOp (Mult, Const (CInt (c, _, _)), Lval (Var v, _), _) -> if v.vname = vname then Some (c |> cilint_to_int |> Rat.of_int) else None
106103
| BinOp (Mult, _, _, _) -> failwith "found another Mult"
107104
| Const (CInt (c, _, _)) -> None
108105
| Lval (Var v, _) -> if v.vname = vname then Some Rat.one else None
109-
| _ -> failwith "found something else"
106+
| BinOp (Mod, _, _, _) -> None
107+
| _ -> failwith "found something unexpected"
110108
in
111109
match e with
112110
| BinOp (Le, e1, e2, _) ->
@@ -117,6 +115,19 @@ let coeff_in_exp vname e =
117115
| None, Some c -> Rat.neg c)
118116
| _ -> failwith "This shouldn't happen"
119117

118+
let get_var vname env =
119+
let vars, _ = Environment.vars env in
120+
Array.find_map (fun v -> if Var.to_string v = vname then Some v else None) vars
121+
122+
let coeff_in_lincons1 vname (e: Lincons1.t) =
123+
match get_var vname e.env with
124+
| None -> Rat.zero
125+
| Some v ->
126+
match Lincons1.get_coeff e v with
127+
| Interval _ -> failwith "Lincons1 coeff is an interval, this shouldn't happen"
128+
| Scalar s ->
129+
s |> SharedFunctions.int_of_scalar |> Option.get |> Z.to_int |> Rat.of_int |> Rat.minus (* negate the coefficient because of SUPEQ typ *)
130+
120131
let const_in_exp e =
121132
let rec inner = function
122133
| BinOp (PlusA, e1, e2, _) ->
@@ -126,6 +137,7 @@ let const_in_exp e =
126137
| c, None | None, c -> c)
127138
| Const (CInt (c, _, _)) -> if Z.compare c Z.zero = 0 then None else Some (c |> cilint_to_int |> Rat.of_int)
128139
| BinOp (Mult, _, _, _) -> None
140+
| BinOp (Mod, _, _, _) -> None
129141
| Lval (Var v, _) -> None
130142
| _ -> failwith "found something else"
131143
in
@@ -138,27 +150,65 @@ let const_in_exp e =
138150
| None, Some c -> c)
139151
| _ -> failwith "This shouldn't happen"
140152

141-
let transposed_matrices_of_exp_list (cs : exp list) =
153+
let const_in_lincons1 (e: Lincons1.t) =
154+
match Lincons1.get_cst e with
155+
| Interval _ -> failwith "Lincons1 coeff is an interval, this shouldn't happen"
156+
| Scalar s ->
157+
match e.lincons0.typ with
158+
| SUPEQ -> s |> SharedFunctions.int_of_scalar |> Option.get |> Z.to_int |> Rat.of_int (* don't negate here because cst is on the correct side *)
159+
| _ -> failwith "wrong typ"
160+
161+
let transposed_matrices_of_exp_list id (cs : exp list) =
142162
let rec vars_from_exp acc = function
143-
| BinOp (_, e1, e2, _) -> VarSet.union (vars_from_exp acc e1) (vars_from_exp acc e2)
163+
| BinOp (_, e1, e2, _) -> StringSet.union (vars_from_exp acc e1) (vars_from_exp acc e2)
144164
| UnOp (_, e, _) -> vars_from_exp acc e
145165
| Lval (Var v, _) ->
146-
let len = String.length v.vname in
147-
if String.starts_with ~prefix:"old_" v.vname then
148-
VarSet.add (String.sub v.vname 4 (len - 4)) acc
149-
else
150-
VarSet.add v.vname acc
166+
(match String.split_on_char '_' v.vname with
167+
| "id"::_::"old"::_ -> acc (* TODO: maybe I'm forgetting too much here, could keep old_vars with the correct id *)
168+
| _ -> StringSet.add v.vname acc)
151169
| CastE _ -> failwith "Encountered cast"
152170
| Question _ -> failwith "Encountered question"
153171
| _ -> acc
154172
in
155-
let vars = cs |> List.fold_left vars_from_exp VarSet.empty |> VarSet.elements in
156-
let old_vars = List.map (String.cat "old_") vars in
173+
let vars = cs |> List.fold_left vars_from_exp StringSet.empty |> StringSet.elements in
174+
let old_vars = List.map (String.cat @@ "id_" ^ id ^ "_old_") vars in
175+
(* TODO: could this result in invalid expressions where some terms are missing? *)
157176
let atr = List.fold_left (fun m v -> cs |> List.map (coeff_in_exp v) |> SparseVec.of_list |> Matrix.append_row m) (Matrix.empty ()) old_vars in
158177
let a'tr = List.fold_left (fun m v -> cs |> List.map (coeff_in_exp v) |> SparseVec.of_list |> Matrix.append_row m) (Matrix.empty ()) vars in
159178
let b = cs |> List.map const_in_exp |> SparseVec.of_list in
160179
atr, a'tr, b
161180

181+
let transposed_matrices_of_lincons1set id (cs : Lincons1Set.t) =
182+
let to_supeq_set e a =
183+
match Lincons1.get_typ e with
184+
| SUPEQ -> Lincons1Set.add e a
185+
| EQ ->
186+
let pos_e = Lincons1.make (Lincons1.get_linexpr1 e) SUPEQ in
187+
let neg_e = Lincons1.make (Linexpr1.neg (Lincons1.get_linexpr1 e)) SUPEQ in
188+
a |> Lincons1Set.add pos_e |> Lincons1Set.add neg_e
189+
| _ -> failwith "Wrong typ in Lincons1Set"
190+
in
191+
let c = Lincons1Set.find_first (Fun.const true) cs in
192+
let remove_old v =
193+
match v |> Var.to_string |> String.split_on_char '_' with
194+
| "id"::_::"old"::_ -> false (* TODO: maybe I'm forgetting too much here, could keep old_vars with the correct id *)
195+
| _ -> true
196+
in
197+
let vars, _ = Environment.vars c.env in
198+
let vars = vars |> Array.to_list |> List.filter remove_old in
199+
let cs = Lincons1Set.fold to_supeq_set cs Lincons1Set.empty in
200+
let atr = List.fold_left
201+
(fun m v -> cs |> Lincons1Set.elements |>
202+
List.map (coeff_in_lincons1 (Printf.sprintf "id_%s_old_%s" id (Var.to_string v))) |> SparseVec.of_list |> Matrix.append_row m) (Matrix.empty ()) vars in
203+
let a'tr = List.fold_left (fun m v -> cs |> Lincons1Set.elements |> List.map (coeff_in_lincons1 (Var.to_string v)) |> SparseVec.of_list |> Matrix.append_row m) (Matrix.empty ()) vars in
204+
let b = cs |> Lincons1Set.elements |> List.map const_in_lincons1 |> SparseVec.of_list in
205+
atr, a'tr, b
206+
207+
let string_of_my_invariant (constraints : MyInvariant.t) =
208+
match constraints with
209+
| `Top -> "Top"
210+
| `Bot -> "Bot"
211+
| `Lifted cs -> cs |> Lincons1Set.elements |> List.map Lincons1.show |> String.concat "; "
162212

163213
let termination_provable a_transposed a'_transposed b =
164214
let num_constraints = Matrix.num_cols a_transposed in
@@ -277,53 +327,6 @@ let termination_provable a_transposed a'_transposed b =
277327
| SAT -> true
278328
| UNK -> failwith "Simplex returned UNK, this shouldn't happen"
279329

280-
let test_termination_provable () =
281-
let zero = Rat.zero in
282-
let one = Rat.one in
283-
let two = Rat.of_int 2 in
284-
let m_one = Rat.m_one in
285-
let m_two = Rat.of_int (-2) in
286-
287-
(* From regression test 52: *)
288-
(*let a_transposed = Matrix.append_row (Matrix.append_row (Matrix.append_row (Matrix.append_row (Matrix.empty ())
289-
(SparseVec.of_list [m_one; zero; zero; zero; m_one; zero; zero; zero; zero; zero; one; m_one; zero; zero])) (*i*)
290-
(SparseVec.of_list [zero; zero; zero; one; one; zero; zero; zero; one; one; zero; zero; one; m_one])) (*j*)
291-
(SparseVec.of_list [zero; m_one; zero; zero; zero; zero; zero; zero; zero; zero; zero; zero; zero; zero])) (*nat*)
292-
(SparseVec.of_list [zero; zero; m_one; zero; zero; zero; zero; zero; zero; zero; zero; zero; zero; zero]) (*pos*)
293-
in
294-
let a'_transposed = Matrix.append_row (Matrix.append_row (Matrix.append_row (Matrix.append_row (Matrix.empty ())
295-
(SparseVec.of_list [zero; zero; zero; zero; zero; zero; zero; zero; zero; m_one; m_one; one; zero; zero])) (*i'*)
296-
(SparseVec.of_list [zero; zero; zero; zero; zero; m_one; zero; zero; m_one; zero; zero; zero; m_one; one])) (*j'*)
297-
(SparseVec.of_list [zero; zero; zero; zero; zero; zero; m_one; zero; zero; m_one; m_one; one; zero; zero])) (*nat'*)
298-
(SparseVec.of_list [zero; zero; zero; zero; zero; zero; zero; m_one; zero; zero; zero; zero; one; m_one]) (*pos'*)
299-
in
300-
let b = SparseVec.of_list [Rat.of_int 2147483647; zero; m_one; Rat.of_int 2147483646; m_one;
301-
Rat.of_int 2147483647; zero; m_one; m_one; m_one;
302-
zero; zero; zero; zero]*)
303-
304-
(* From regression test 53: *)
305-
(*let a_transposed = Matrix.append_row (Matrix.append_row (Matrix.empty ())
306-
(SparseVec.of_list [zero; m_one; zero; zero; zero; m_one; one; zero; zero])) (*x1*)
307-
(SparseVec.of_list [m_one; zero; zero; zero; zero; zero; zero; m_one; one]) (*x2*)
308-
in
309-
let a'_transposed = Matrix.append_row (Matrix.append_row (Matrix.empty ())
310-
(SparseVec.of_list [zero; zero; m_one; zero; one; two; m_two; zero; zero])) (*x1'*)
311-
(SparseVec.of_list [zero; zero; zero; m_one; zero; zero; zero; one; m_one]) (*x2'*)
312-
in
313-
let b = SparseVec.of_list [zero; m_two; m_one; m_one; Rat.of_int 1073741823;
314-
zero; two; one; m_one]*)
315-
316-
(* From regression test 53, simplified: *)
317-
let a_transposed = Matrix.append_row (Matrix.empty ())
318-
(SparseVec.of_list [m_one; zero; m_one; one]) (*x1*)
319-
in
320-
let a'_transposed = Matrix.append_row (Matrix.empty ())
321-
(SparseVec.of_list [zero; one; two; m_two]) (*x1'*)
322-
in
323-
let b = SparseVec.of_list [m_one; Rat.of_int 1073741823; zero; two]
324-
in
325-
termination_provable a_transposed a'_transposed b
326-
327330
(** Checks whether a variable can be bounded. *)
328331
let ask_bound man varinfo =
329332
let open IntDomain.IntDomTuple in
@@ -378,10 +381,21 @@ struct
378381
end
379382
| None ->
380383
(*failwith "Encountered a call to __goblint_bounded with an unknown loop counter variable."*)
381-
let atr, a'tr, b = man.ask (Queries.Invariant Invariant.default_context) |> exp_list_of_constraints |> transposed_matrices_of_exp_list in
384+
let loop_id = loop_counter.vname |> String.split_on_char '_' |> (function _::id::_ -> id | _ -> "-1")
385+
in
386+
(*let atr, a'tr, b = man.ask (Queries.Invariant Invariant.default_context) |> exp_list_of_constraints |> transposed_matrices_of_exp_list loop_id in*)
387+
388+
let my_inv = man.ask (Queries.MyInvariant MyInvariant.default_context) in
389+
let lincons1set =
390+
match my_inv with
391+
| `Lifted cs -> cs
392+
| `Top | `Bot -> Lincons1Set.empty
393+
in
394+
let atr, a'tr, b = transposed_matrices_of_lincons1set loop_id lincons1set in
395+
382396
let term_provable = termination_provable atr a'tr b in
383-
if term_provable then (M.success ~category:Termination "Loop terminates")
384-
else (M.warn ~category:Termination "The program might not terminate! (Loop analysis)")
397+
if term_provable then ((*if GobConfig.get_bool "dbg.termination-bounds" then*) M.success ~category:Termination "Loop terminates")
398+
else (M.warn ~category:Termination "The program might not terminate!")
385399

386400
end
387401
| "__goblint_bounded", _ ->

src/cdomain/value/domains/invariant.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ struct
6262
end
6363

6464

65-
(** Lift {!ExpLat} such that join/meet folds don't introduce excessive [|| 0|] or [&& 1] expressions. *)
65+
(** Lift {!ExpLat} such that join/meet folds don't introduce excessive [|| 0] or [&& 1] expressions. *)
6666

6767
module N =
6868
struct

src/cdomains/apron/affineEqualityDenseDomain.apron.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,8 @@ struct
596596
in
597597
BatOption.map_default invariant [] t.d
598598

599+
let invariant_set _ = failwith "not needed here"
600+
599601
let cil_exp_of_lincons1 = Convert.cil_exp_of_lincons1
600602

601603
let env t = t.env

src/cdomains/apron/affineEqualityDomain.apron.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,8 @@ struct
547547
in
548548
BatOption.map_default invariant [] t.d
549549

550+
let invariant_set _ = failwith "not needed here"
551+
550552
let cil_exp_of_lincons1 = Convert.cil_exp_of_lincons1
551553

552554
let env t = t.env

src/cdomains/apron/apronDomain.apron.ml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -555,7 +555,7 @@ struct
555555
let to_lincons_set d =
556556
Lincons1Set.of_earray (A.to_lincons_array Man.mgr d)
557557

558-
let invariant d =
558+
let invariant_set d =
559559
(* Would like to minimize to get rid of multi-var constraints directly derived from one-var constraints,
560560
but not implemented in Apron at all: https://github.com/antoinemine/apron/issues/44 *)
561561
(* let d = A.copy Man.mgr d in
@@ -572,9 +572,15 @@ struct
572572
lcd
573573

574574
let invariant d =
575-
invariant d
575+
let res =
576+
invariant_set d
576577
|> (if Oct.manager_is_oct Man.mgr then Lincons1Set.simplify else Fun.id)
577578
|> Lincons1Set.elements (* TODO: remove list conversion? *)
579+
in
580+
if M.tracing then
581+
(M.trace "termination" "RD.invariant: (%s)" (res |> List.map Lincons1.show |> String.concat ", "));
582+
res
583+
578584
end
579585

580586
(** With heterogeneous environments. *)

src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,8 @@ struct
813813
in
814814
BatOption.get t.d |> fun (_,map) -> EConj.IntMap.fold (fun lhs rhs list -> get_const list lhs rhs) map []
815815

816+
let invariant_set _ = failwith "not needed here"
817+
816818
let cil_exp_of_lincons1 = Convert.cil_exp_of_lincons1
817819

818820
let env t = t.env

0 commit comments

Comments
 (0)