@@ -7,6 +7,7 @@ open GoblintCil
77open TerminationPreprocessing
88open ListMatrix
99open SparseVector
10+ open GobApron
1011
1112(* * Contains all loop counter variables (varinfo) and maps them to their corresponding loop statement. *)
1213let loop_counters : stmt VarToStmt.t ref = ref VarToStmt. empty
@@ -61,9 +62,9 @@ module Matrix = ListMatrix (Rat) (SparseVector)
6162
6263module 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+
120131let 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
163213let 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. *)
328331let 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" , _ ->
0 commit comments