Skip to content

Commit 61caba2

Browse files
implemented different rref_vec that doesn't use normalize
1 parent b15b9d2 commit 61caba2

File tree

8 files changed

+7101
-22
lines changed

8 files changed

+7101
-22
lines changed

array.txt

Lines changed: 2150 additions & 0 deletions
Large diffs are not rendered by default.

list.txt

Lines changed: 2318 additions & 0 deletions
Large diffs are not rendered by default.

rref_vec.txt

Lines changed: 1256 additions & 0 deletions
Large diffs are not rendered by default.

sparse.txt

Lines changed: 1294 additions & 0 deletions
Large diffs are not rendered by default.

src/cdomains/affineEquality/arrayImplementation/arrayVector.ml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,4 +132,7 @@ module ArrayVector: AbstractVector =
132132
let starting_from_nth n v =
133133
failwith "TODO / deprecated"
134134

135+
let find_first_non_zero v =
136+
failwith "TODO"
137+
135138
end

src/cdomains/affineEquality/sparseImplementation/listMatrix.ml

Lines changed: 72 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,11 @@ module ListMatrix: AbstractMatrix =
4444
let cols = Array.to_list cols in
4545
let sorted_cols = List.sort Stdlib.compare cols in
4646
let rec count_sorted_occ acc cols last count =
47-
match cols with
48-
| [] -> if count > 0 then (last, count) :: acc else acc
49-
| x :: xs when x = last -> count_sorted_occ acc xs x (count + 1)
50-
| x :: xs -> let acc = if count > 0 then (last, count) :: acc else acc in
51-
count_sorted_occ acc xs x 1
47+
match cols with
48+
| [] -> if count > 0 then (last, count) :: acc else acc
49+
| x :: xs when x = last -> count_sorted_occ acc xs x (count + 1)
50+
| x :: xs -> let acc = if count > 0 then (last, count) :: acc else acc in
51+
count_sorted_occ acc xs x 1
5252
in
5353
let occ_cols = List.rev @@ count_sorted_occ [] sorted_cols 0 0 in
5454
let () = Printf.printf "After add_empty_columns m:\n%s\n" (show (List.map (fun row -> V.insert_zero_at_indices row occ_cols (List.length cols)) m)) in
@@ -116,7 +116,7 @@ module ListMatrix: AbstractMatrix =
116116
V.zero_vec (num_cols m)
117117
else
118118
let row_value = V.nth row j in
119-
if row_value = A.zero then row
119+
if row_value =: A.zero then row
120120
else (let s = row_value /: pivot in
121121
sub_scaled_row row pivot_row s)
122122
) m)) in
@@ -137,12 +137,11 @@ module ListMatrix: AbstractMatrix =
137137
if pivot_element = A.zero then m
138138
else List.mapi (fun idx row ->
139139
let row_value = V.nth row j in
140-
if row_value = A.zero then row
140+
if row_value =: A.zero then row
141141
else (let s = row_value /: pivot_element in
142142
V.map2_f_preserves_zero (fun x y -> x -: s *: y) row v)
143143
) m
144144

145-
146145
let del_col m j =
147146
if num_cols m = 1 then empty ()
148147
else
@@ -237,17 +236,68 @@ module ListMatrix: AbstractMatrix =
237236
let () = Printf.printf "After normalizing we have m:\n%s" (show m') in
238237
if affeq_rows_are_valid m' then Some m' else None (* TODO: We can check this for each row, using the helper function row_is_invalid *)
239238

239+
(* This function return a tuple of row index and pivot position (column) in m *)
240+
(* TODO: maybe we could use a Hashmap instead of a list? *)
241+
let get_pivot_positions (m : t) : (int * int) list =
242+
List.rev @@ List.fold_lefti (
243+
fun acc i row -> match V.find_first_non_zero row with
244+
| None -> acc
245+
| Some (pivot_col, _) -> (i, pivot_col) :: acc
246+
) [] m
247+
248+
(* Inserts the vector v with pivot at piv_idx at the correct position in m. m has to be in rref form. *)
249+
let insert_v_according_to_piv m v piv_idx pivot_positions =
250+
match List.find_opt (fun (row_idx, piv_col) -> piv_col > piv_idx) pivot_positions with
251+
| None -> append_row m v
252+
| Some (row_idx, _) -> let (before, after) = List.split_at row_idx m in
253+
before @ (v :: after)
254+
255+
let rref_vec (m : t) (v : V.t) : t option =
256+
let () = Printf.printf "Before rref_vec we have m:\n%sv: %s\n" (show m) (V.show v) in
257+
if is_empty m then (* In this case, v is normalized and returned *)
258+
match V.find_first_non_zero v with
259+
| None -> let () = Printf.printf "After rref_vec there is no normalization\n " in None
260+
| Some (_, value) ->
261+
let normalized_v = V.map_f_preserves_zero (fun x -> x /: value) v in
262+
let res = init_with_vec normalized_v in
263+
let () = Printf.printf "After rref_vec we have m:\n%s\n" (show res) in
264+
Some res
265+
else (* We try to normalize v and check if a contradiction arises. If not, we insert v at the appropriate place in m (depending on the pivot) *)
266+
let pivot_positions = get_pivot_positions m in
267+
let () = Printf.printf "pivot positions are: %s\n\n" (List.fold_right (fun (row, piv) s -> "(" ^ (Int.to_string row) ^ "," ^ (Int.to_string piv) ^ ")" ^ s) pivot_positions "") in
268+
let v_after_elim = List.fold_left (
269+
fun acc (row_idx, pivot_position) ->
270+
let v_at_piv = V.nth acc pivot_position in
271+
if v_at_piv =: A.zero then
272+
acc
273+
else
274+
let piv_row = List.nth m row_idx in
275+
sub_scaled_row acc piv_row v_at_piv
276+
) v pivot_positions
277+
in
278+
match V.find_first_non_zero v_after_elim with (* now we check for contradictions and finally insert v *)
279+
| None -> let () = Printf.printf "After rref_vec we have m:\n%s\n" (show m) in
280+
Some m (* v is zero vector and was therefore already covered by zero *)
281+
| Some (idx, value) ->
282+
if idx = (num_cols m - 1) then
283+
let () = Printf.printf "After rref_vec there is no normalization\n " in None
284+
else
285+
let normalized_v = V.map_f_preserves_zero (fun x -> x /: value) v_after_elim in
286+
let res = insert_v_according_to_piv m normalized_v idx pivot_positions in
287+
let () = Printf.printf "After rref_vec we have m:\n%s\n" (show res) in
288+
Some res
289+
240290

241291
(*This function yields the same result as appending vector v to m and normalizing it afterwards would. However, it is usually faster than performing those ops manually.*)
242292
(*m must be in rref form and contain the same num of cols as v*)
243293
(*If m is empty then v is simply normalized and returned*)
244294
(* TODO: OPTIMIZE! *)
245-
let rref_vec m v =
295+
(*let rref_vec m v =
246296
let () = Printf.printf "Before rref_vec we have m:\n%sv: %s\n" (show m) (V.show v) in
247297
match normalize @@ append_matrices m (init_with_vec v) with
248298
| Some res -> let () = Printf.printf "After rref_vec, before removing zero rows, we have m:\n%s\n" (show res) in
249299
Some (remove_zero_rows res)
250-
| None -> let () = Printf.printf "After rref_vec there is no normalization\n " in None
300+
| None -> let () = Printf.printf "After rref_vec there is no normalization\n " in None*)
251301

252302
(*Similar to rref_vec_with but takes two matrices instead.*)
253303
(*ToDo Could become inefficient for large matrices since pivot_elements are always recalculated + many row additions*)
@@ -280,18 +330,18 @@ module ListMatrix: AbstractMatrix =
280330
in
281331
let () = Printf.printf "Is m1 covered by m2?\n m1:\n%sm2:\n%s" (show m1) (show m2) in
282332
if num_rows m1 > num_rows m2 then false else
283-
let rec is_covered_by_helper m1 m2 =
284-
match m1 with
285-
| [] -> true
286-
| v1::vs1 ->
287-
let first_non_zero = V.findi_val_opt ((<>:) A.zero) v1 in
288-
match first_non_zero with
289-
| None -> true (* vs1 must also be zero-vectors because of rref *)
290-
| Some (idx, _) ->
291-
let linearly_indep = is_linearly_independent_rref v1 m2 in
292-
if linearly_indep then false else is_covered_by_helper vs1 m2
293-
in is_covered_by_helper m1 m2
294-
333+
let rec is_covered_by_helper m1 m2 =
334+
match m1 with
335+
| [] -> true
336+
| v1::vs1 ->
337+
let first_non_zero = V.findi_val_opt ((<>:) A.zero) v1 in
338+
match first_non_zero with
339+
| None -> true (* vs1 must also be zero-vectors because of rref *)
340+
| Some (idx, _) ->
341+
let linearly_indep = is_linearly_independent_rref v1 m2 in
342+
if linearly_indep then false else is_covered_by_helper vs1 m2
343+
in is_covered_by_helper m1 m2
344+
295345
let is_covered_by m1 m2 = Timing.wrap "is_covered_by" (is_covered_by m1) m2
296346

297347
let find_opt f m =

src/cdomains/affineEquality/sparseImplementation/sparseVector.ml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,12 @@ module SparseVector: AbstractVector =
203203
else find_zero_or_val xs idx
204204
in find_zero_or_val v.entries (-1)
205205

206+
let find_first_non_zero v =
207+
if v.entries = [] then None
208+
else Some (List.hd v.entries)
209+
210+
let find_first_non_zero v = Timing.wrap "find_first_non_zero" (find_first_non_zero) v
211+
206212
let map f v =
207213
of_list (List.map f (to_list v))
208214

src/cdomains/affineEquality/vector.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ sig
4949
(* Returns optional tuple of position and value which was found*)
5050
val findi_val_opt: (num -> bool) -> t -> (int * num) Option.t
5151

52+
val find_first_non_zero : t -> (int * num) option
53+
5254
val find_opt: (num -> bool) -> t -> num Option.t
5355

5456
val map: (num -> num) -> t -> t

0 commit comments

Comments
 (0)