Skip to content

Commit 36f9f2d

Browse files
Merge pull request #1754 from goblint/dimchange-tidyup
Dimchange tidyup
2 parents 9f07df1 + 95fc18c commit 36f9f2d

File tree

6 files changed

+105
-87
lines changed

6 files changed

+105
-87
lines changed

src/cdomains/affineEquality/arrayImplementation/arrayMatrix.ml

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -137,18 +137,18 @@ module ArrayMatrix: ArrayMatrixFunctor =
137137
let reduce_col_with m j =
138138
if not @@ is_empty m then
139139
(let r = ref (-1) in
140-
for i' = 0 to num_rows m - 1 do
141-
let rev_i' = num_rows m - i' - 1 in
142-
if !r < 0 && m.(rev_i').(j) <>: A.zero then r := rev_i';
143-
if !r <> rev_i' then
144-
let g = m.(rev_i').(j) in
140+
for i' = 0 to num_rows m - 1 do (* i' runs through all row indices *)
141+
let rev_i' = num_rows m - i' - 1 in (* rev_i' runs through all row indices in reverse order *)
142+
if !r < 0 && m.(rev_i').(j) <>: A.zero then r := rev_i'; (* if we found the j-column (non-zero element), store its row index in r *)
143+
if !r <> rev_i' then (* exclude the non-zero element's row from the transformation *)
144+
let g = m.(rev_i').(j) in (* only act if rev_i'/j element is non-zero*)
145145
if g <>: A.zero then
146-
let s = g /: m.(!r).(j) in
147-
for j' = 0 to num_cols m - 1 do
146+
let s = g /: m.(!r).(j) in (* determine the kill factor*)
147+
for j' = 0 to num_cols m - 1 do (* kill the rev_i' element, eintrailing a modification of the rest columns*)
148148
m.(rev_i').(j') <- m.(rev_i').(j') -: s *: m.(!r).(j')
149149
done
150150
done;
151-
if !r >= 0 then Array.fill m.(!r) 0 (num_cols m) A.zero)
151+
if !r >= 0 then Array.fill m.(!r) 0 (num_cols m) A.zero) (* kill row r *)
152152

153153
let reduce_col_with m j = timing_wrap "reduce_col_with" (reduce_col_with m) j
154154
let reduce_col m j =
@@ -165,16 +165,16 @@ module ArrayMatrix: ArrayMatrixFunctor =
165165

166166
let del_cols m cols =
167167
let n_c = Array.length cols in
168-
if n_c = 0 || is_empty m then m
168+
if n_c = 0 || is_empty m then m (* if #toberemoved=0, return m *)
169169
else
170170
let m_r, m_c = num_rows m, num_cols m in
171-
if m_c = n_c then empty () else
172-
let m' = Array.make_matrix m_r (m_c - n_c) A.zero in
173-
for i = 0 to m_r - 1 do
174-
let offset = ref 0 in
175-
for j = 0 to (m_c - n_c) - 1 do
171+
if m_c = n_c then empty () else (* if #cols = #toberemoved, return empty *)
172+
let m' = Array.make_matrix m_r (m_c - n_c) A.zero in (* else alloc smaller array m' *)
173+
for i = 0 to m_r - 1 do (* i iterates rows of m' *)
174+
let offset = ref 0 in (* offset keeps track of coloffset *)
175+
for j = 0 to (m_c - n_c) - 1 do (* j iterates cols of m' *)
176176
while !offset < n_c && !offset + j = cols.(!offset) do incr offset done;
177-
m'.(i).(j) <- m.(i).(j + !offset);
177+
m'.(i).(j) <- m.(i).(j + !offset); (* copy m to m' *)
178178
done
179179
done;
180180
m'

src/cdomains/affineEquality/sparseImplementation/listMatrix.ml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -186,17 +186,16 @@ module ListMatrix: SparseMatrixFunctor =
186186
let reduce_col m j =
187187
if is_empty m then m
188188
else
189-
let rec find_pivot idx entries = (* Finds non-zero element in column j and returns pair of row idx and the pivot value *)
189+
let rec find_pivot idx entries = (* Finds non-zero element in column j and returns pair of row idx, the pivot value and the row *)
190190
match entries with
191191
| [] -> None
192192
| row :: rest -> let value = V.nth row j in
193-
if value =: A.zero then find_pivot (idx - 1) rest else Some (idx, value)
193+
if value =: A.zero then find_pivot (idx - 1) rest else Some (idx, value, row)
194194
in
195195
match (find_pivot (num_rows m - 1) (List.rev m)) with
196196
| None -> m (* column is already filled with zeroes *)
197-
| Some (row_idx, pivot) ->
198-
let pivot_row = List.nth m row_idx in (* use the pivot row to reduce all entries in column j to zero, then "delete" the pivot row *)
199-
List.mapi (fun idx row ->
197+
| Some (row_idx, pivot,pivot_row) ->
198+
List.mapi (fun idx row -> (* use the pivot row to reduce all entries in column j to zero, then "delete" the pivot row *)
200199
if idx = row_idx then
201200
V.zero_vec (num_cols m)
202201
else

src/cdomains/apron/affineEqualityDenseDomain.apron.ml

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,14 @@ struct
3030
let dim_add ch m = timing_wrap "dim add" (dim_add ch) m
3131

3232

33-
let dim_remove (ch: Apron.Dim.change) m ~del =
33+
let dim_remove (ch: Apron.Dim.change) m =
3434
if Array.length ch.dim = 0 || is_empty m then
3535
m
3636
else (
37-
Array.modifyi (+) ch.dim;
38-
let m' = if not del then let m = copy m in Array.fold_left (fun y x -> reduce_col_with y x; y) m ch.dim else m in
37+
let m' = let m = copy m in Array.fold_left (fun y x -> reduce_col_with y x; y) m ch.dim in
3938
remove_zero_rows @@ del_cols m' ch.dim)
4039

41-
let dim_remove ch m ~del = timing_wrap "dim remove" (fun del -> dim_remove ch m ~del:del) del
40+
let dim_remove ch m = timing_wrap "dim remove" (dim_remove ch) m
4241
end
4342

4443
(** It defines the type t of the affine equality domain (a struct that contains an optional matrix and an apron environment) and provides the functions needed for handling variables (which are defined by RelationDomain.D2) such as add_vars remove_vars.
@@ -234,12 +233,11 @@ struct
234233
let meet t1 t2 =
235234
let sup_env = Environment.lce t1.env t2.env in
236235

237-
let t1, t2 = change_d t1 sup_env ~add:true ~del:false, change_d t2 sup_env ~add:true ~del:false in
236+
let t1, t2 = dimchange2_add t1 sup_env, dimchange2_add t2 sup_env in
238237
if is_bot t1 || is_bot t2 then
239238
bot ()
240239
else
241-
(* TODO: Why can I be sure that m1 && m2 are all Some here?
242-
Answer: because is_bot checks if t1.d is None and we checked is_bot before. *)
240+
(* Option.get, because is_bot checks if t1.d is None and we checked is_bot before. *)
243241
let m1, m2 = Option.get t1.d, Option.get t2.d in
244242
if is_top_env t1 then
245243
{d = Some (dim_add (Environment.dimchange t2.env sup_env) m2); env = sup_env}
@@ -448,22 +446,35 @@ struct
448446
if M.tracing then M.tracel "ops" "assign_var t:\n %s \n v: %a \n v': %a\n -> %s" (show t) Var.pretty v Var.pretty v' (show res);
449447
res
450448

451-
let assign_var_parallel t vv's =
449+
let assign_var_parallel t vv's = (* vv's is a list of pairs of lhs-variables and their rhs-values *)
452450
let assigned_vars = List.map fst vv's in
453-
let t = add_vars t assigned_vars in
454-
let primed_vars = List.init (List.length assigned_vars) (fun i -> Var.of_string (Int.to_string i ^"'")) in (* TODO: we use primed vars in analysis, conflict? *)
455-
let t_primed = add_vars t primed_vars in
451+
let t = add_vars t assigned_vars in (* introduce all lhs-variables to the relation data structure *)
452+
let primed_vars = List.init (* create a list with primed variables "i'" for each lhs-variable *)
453+
(List.length assigned_vars)
454+
(fun i -> Var.of_string (Int.to_string i ^"'"))
455+
in (* TODO: we use primed integers as var names, conflict? *)
456+
let t_primed = add_vars t primed_vars in (* introduce primed variables to the relation data structure *)
457+
(* sequence of assignments: i' = snd vv_i : *)
456458
let multi_t = List.fold_left2 (fun t' v_prime (_,v') -> assign_var t' v_prime v') t_primed primed_vars vv's in
457459
match multi_t.d with
458-
| Some m when not @@ is_top_env multi_t ->
459-
let replace_col m x y =
460+
| Some m when not @@ is_top_env multi_t -> (* SUBSTITUTE assigned_vars/primed_vars via OVERWRITE & ERASE *)
461+
let replace_col m x y = (* OVERWRITES column for var_y with column for var_x *)
460462
let dim_x, dim_y = Environment.dim_of_var multi_t.env x, Environment.dim_of_var multi_t.env y in
461463
let col_x = Matrix.get_col m dim_x in
462464
Matrix.set_col_with m col_x dim_y
463465
in
466+
let erase_cols m old_env to_erase = (* ERASES (i.e. entries are removed and column collapsed) from m all to_erase-columns *)
467+
let m = Matrix.copy m in
468+
let new_env = Environment.remove_vars old_env to_erase in
469+
let dimchange = Environment.dimchange2 old_env new_env in
470+
if Environment.equal old_env new_env then
471+
{d = Some m; env = new_env}
472+
else
473+
{ d = Some (Matrix.remove_zero_rows @@ Matrix.del_cols m (Option.get dimchange.remove).dim); env=new_env}
474+
in
464475
let m_cp = Matrix.copy m in
465-
let switched_m = List.fold_left2 replace_col m_cp primed_vars assigned_vars in
466-
let res = drop_vars {d = Some switched_m; env = multi_t.env} primed_vars ~del:true in
476+
let switched_m = List.fold_left2 replace_col m_cp primed_vars assigned_vars in (* OVERWRITE columns for assigned_vars with column for primed_vars *)
477+
let res = erase_cols switched_m multi_t.env primed_vars in (* ERASE column for primed_vars *)
467478
let x = Option.get res.d in
468479
if Matrix.normalize_with x then
469480
{d = Some x; env = res.env}

src/cdomains/apron/affineEqualityDomain.apron.ml

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,14 @@ struct
3030
let dim_add ch m = timing_wrap "dim add" (dim_add ch) m
3131

3232

33-
let dim_remove (ch: Apron.Dim.change) m ~del =
33+
let dim_remove (ch: Apron.Dim.change) m =
3434
if Array.length ch.dim = 0 || is_empty m then
3535
m
3636
else (
37-
Array.modifyi (+) ch.dim;
38-
let m' = if not del then Array.fold_left (fun y x -> reduce_col y x) m ch.dim else m in
37+
let m' = Array.fold_left (fun y x -> reduce_col y x) m ch.dim in
3938
remove_zero_rows @@ del_cols m' ch.dim)
4039

41-
let dim_remove ch m ~del = timing_wrap "dim remove" (fun del -> dim_remove ch m ~del:del) del
40+
let dim_remove ch m = timing_wrap "dim remove" (dim_remove ch) m
4241
end
4342

4443
(** It defines the type t of the affine equality domain (a struct that contains an optional matrix and an apron environment) and provides the functions needed for handling variables (which are defined by RelationDomain.D2) such as add_vars remove_vars.
@@ -235,12 +234,11 @@ struct
235234
let meet t1 t2 =
236235
let sup_env = Environment.lce t1.env t2.env in
237236

238-
let t1, t2 = change_d t1 sup_env ~add:true ~del:false, change_d t2 sup_env ~add:true ~del:false in
237+
let t1, t2 = dimchange2_add t1 sup_env, dimchange2_add t2 sup_env in
239238
if is_bot t1 || is_bot t2 then
240239
bot ()
241240
else
242-
(* TODO: Why can I be sure that m1 && m2 are all Some here?
243-
Answer: because is_bot checks if t1.d is None and we checked is_bot before. *)
241+
(* Option.get, because is_bot checks if t1.d is None and we checked is_bot before. *)
244242
let m1, m2 = Option.get t1.d, Option.get t2.d in
245243
if is_top_env t1 then
246244
{d = Some (dim_add (Environment.dimchange t2.env sup_env) m2); env = sup_env}
@@ -442,21 +440,33 @@ struct
442440
if M.tracing then M.tracel "ops" "assign_var t:\n %s \n v: %a \n v': %a\n -> %s" (show t) Var.pretty v Var.pretty v' (show res);
443441
res
444442

445-
let assign_var_parallel t vv's =
446-
let assigned_vars = List.map fst vv's in
447-
let t = add_vars t assigned_vars in
448-
let primed_vars = List.init (List.length assigned_vars) (fun i -> Var.of_string (Int.to_string i ^"'")) in (* TODO: we use primed vars in analysis, conflict? *)
449-
let t_primed = add_vars t primed_vars in
443+
let assign_var_parallel t vv's = (* vv's is a list of pairs of lhs-variables and their rhs-values *)
444+
let assigned_vars = List.map fst vv's in
445+
let t = add_vars t assigned_vars in (* introduce all lhs-variables to the relation data structure *)
446+
let primed_vars = List.init (* create a list with primed variables "i'" for each lhs-variable *)
447+
(List.length assigned_vars)
448+
(fun i -> Var.of_string (Int.to_string i ^"'"))
449+
in (* TODO: we use primed integers as var names, conflict? *)
450+
let t_primed = add_vars t primed_vars in (* introduce primed variables to the relation data structure *)
451+
(* sequence of assignments: i' = snd vv_i : *)
450452
let multi_t = List.fold_left2 (fun t' v_prime (_,v') -> assign_var t' v_prime v') t_primed primed_vars vv's in
451453
match multi_t.d with
452-
| Some m when not @@ is_top_env multi_t ->
453-
let replace_col m x y =
454+
| Some m when not @@ is_top_env multi_t -> (* SUBSTITUTE assigned_vars/primed_vars via OVERWRITE & ERASE *)
455+
let replace_col m x y = (* OVERWRITES column for var_y with column for var_x *)
454456
let dim_x, dim_y = Environment.dim_of_var multi_t.env x, Environment.dim_of_var multi_t.env y in
455457
let col_x = Matrix.get_col_upper_triangular m dim_x in
456458
Matrix.set_col m col_x dim_y
457459
in
458-
let switched_m = List.fold_left2 replace_col m primed_vars assigned_vars in
459-
let res = drop_vars {d = Some switched_m; env = multi_t.env} primed_vars ~del:true in
460+
let erase_cols m old_env to_erase = (* ERASES (i.e. entries are removed and column collapsed) from m all to_erase-columns *)
461+
let new_env = Environment.remove_vars old_env to_erase in
462+
let dimchange = Environment.dimchange2 old_env new_env in
463+
if Environment.equal old_env new_env then
464+
{d = Some m; env = new_env}
465+
else
466+
{ d = Some (Matrix.remove_zero_rows @@ Matrix.del_cols m (BatOption.get dimchange.remove).dim); env = new_env}
467+
in
468+
let switched_m = List.fold_left2 replace_col m primed_vars assigned_vars in (* OVERWRITE columns for assigned_vars with column for primed_vars *)
469+
let res = erase_cols switched_m multi_t.env primed_vars in (* ERASE column for primed_vars *)
460470
let x = Option.get res.d in
461471
(match Matrix.normalize x with
462472
| None -> bot ()

src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -178,14 +178,12 @@ module EqualitiesConjunction = struct
178178
if Array.length ch.dim = 0 || is_empty m then
179179
m
180180
else (
181-
let cpy = Array.copy ch.dim in
182-
Array.modifyi (+) cpy; (* this is a hack to restore the original https://antoinemine.github.io/Apron/doc/api/ocaml/Dim.html remove_dimensions semantics for dim_remove *)
183-
let m' = Array.fold_lefti (fun y i x -> forget_variable y (x)) m cpy in (* clear m' from relations concerning ch.dim *)
184-
modify_variables_in_domain m' cpy (-))
181+
let m' = Array.fold_lefti (fun y i x -> forget_variable y (x)) m ch.dim in (* clear m' from relations concerning ch.dim *)
182+
modify_variables_in_domain m' ch.dim (-))
185183

186184
let dim_remove ch m = Timing.wrap "dim remove" (fun m -> dim_remove ch m) m
187185

188-
let dim_remove ch m ~del = let res = dim_remove ch m in if M.tracing then
186+
let dim_remove ch m = let res = dim_remove ch m in if M.tracing then
189187
M.tracel "dim_remove" "dim remove at positions [%s] in { %s } -> { %s }"
190188
(Array.fold_right (fun i str -> (string_of_int i) ^ ", " ^ str) ch.dim "")
191189
(show (snd m))
@@ -443,8 +441,8 @@ struct
443441

444442
let meet t1 t2 =
445443
let sup_env = Environment.lce t1.env t2.env in
446-
let t1 = change_d t1 sup_env ~add:true ~del:false in
447-
let t2 = change_d t2 sup_env ~add:true ~del:false in
444+
let t1 = dimchange2_add t1 sup_env in
445+
let t2 = dimchange2_add t2 sup_env in
448446
match t1.d, t2.d with
449447
| Some d1', Some d2' ->
450448
EConj.IntMap.fold (fun lhs rhs map -> meet_with_one_conj map lhs rhs) (snd d2') t1 (* even on sparse d2, this will chose the relevant conjs to meet with*)
@@ -655,7 +653,7 @@ struct
655653
match multi_t.d with
656654
| Some arr when not @@ is_top multi_t ->
657655
let switched_arr = List.fold_left2 (fun multi_t assigned_var primed_var-> assign_var multi_t assigned_var primed_var) multi_t assigned_vars primed_vars in
658-
drop_vars switched_arr primed_vars ~del:true
656+
remove_vars switched_arr primed_vars
659657
| _ -> t
660658

661659
let assign_var_parallel t vv's =

0 commit comments

Comments
 (0)