Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Page
Library
Module
Module type
Parameter
Class
Class type
Source
matrix.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
module Make (Literal : Literal.S) = struct module LiteralPair = struct type t = Literal.t * Literal.t let compare (x0, y0) (x1, y1) = match Literal.compare x0 x1 with 0 -> Literal.compare y0 y1 | c -> c end module MatrixMap = Map.Make (LiteralPair) module LiteralMap = Map.Make (Literal) type 'a m = 'a MatrixMap.t module Make_SR (K : Algebra.Semiring_S) = struct module Vector = Vector.Make (Literal) module Vector_SR = Vector.Make_SR (K) let k_is_zero = K.(equal zero) let none_to_zero x = Option.value x ~default:K.zero let is_good_entry v1 v2 k = Literal.equal v1 v2 || not (k_is_zero k) (** We make sure the diagonal is never empty on the support of a matrix *) type t = K.t m let zero' = MatrixMap.empty let zero support = List.fold_left (fun acc s -> MatrixMap.add (s, s) K.zero acc) zero' support let for_all f = MatrixMap.for_all (fun (a, b) -> f a b) let is_zero = for_all (fun _ _ -> k_is_zero) let one support = List.fold_left (fun acc s -> MatrixMap.add (s, s) K.one acc) zero' support let diagonal vect = Vector.fold (fun s k acc -> MatrixMap.add (s, s) k acc) vect zero' let get_entry v1 v2 m = none_to_zero (MatrixMap.find_opt (v1, v2) m) let set_entry v1 v2 k = if is_good_entry v1 v2 k then MatrixMap.add (v1, v2) k else MatrixMap.remove (v1, v2) let singleton v1 v2 k = MatrixMap.singleton (v1, v1) K.zero |> MatrixMap.add (v2, v2) K.zero |> set_entry v1 v2 k let remove v1 v2 = MatrixMap.remove (v1, v2) let merge f = let g (v1, v2) x y = match f v1 v2 x y with | None -> if Literal.equal v1 v2 then Some K.zero else None | Some s -> if is_good_entry v1 v2 s then Some s else None in MatrixMap.merge g (** We keep the matrix as sparse as possible, while keeping the diagonal non-empty *) let union f = let g (v1, v2) x y = match f v1 v2 x y with | None -> if Literal.equal v1 v2 then Some K.zero else None | Some s -> if is_good_entry v1 v2 s then Some s else None in MatrixMap.union g let equal m1 m2 = let p = MatrixMap.merge (fun _ r1 r2 -> match (r1, r2) with | (None, None) -> None | (Some r, None) | (None, Some r) -> Some (r, K.zero) | (Some r1, Some r2) -> Some (r1, r2)) m1 m2 in MatrixMap.for_all (fun _ (a, b) -> K.equal a b) p let neq m1 m2 = not (equal m1 m2) let iter f = MatrixMap.iter (fun (v1, v2) -> f v1 v2) let fold f = MatrixMap.fold (fun (v1, v2) -> f v1 v2) let filter f = MatrixMap.filter (fun (v1, v2) -> f v1 v2) let bindings = MatrixMap.bindings let remove_zero_coeff = filter is_good_entry let map f m = MatrixMap.map f m |> remove_zero_coeff let mapi f m = MatrixMap.mapi (fun (v1, v2) -> f v1 v2) m |> remove_zero_coeff let get_support mat = fold (fun a b _ acc -> if Literal.equal a b then a :: acc else acc) mat [] let get_line var mat = MatrixMap.to_seq (filter (fun a _ _ -> Literal.equal a var) mat) |> Seq.map (fun ((_, b), c) -> (b, c)) |> LiteralMap.of_seq |> Vector.of_map |> Vector.union (fun _ _ x -> Some x) (Vector_SR.zero (get_support mat)) let get_column var mat = MatrixMap.to_seq (filter (fun _ b _ -> Literal.equal b var) mat) |> Seq.map (fun ((a, _), c) -> (a, c)) |> LiteralMap.of_seq |> Vector.of_map |> Vector.union (fun _ _ x -> Some x) (Vector_SR.zero (get_support mat)) let add = union (fun _ _ a b -> Some (K.add a b)) let mul m1 m2 = let support_m1 = get_support m1 in let support_m2 = get_support m2 in let aux y acc x = let rf = Vector_SR.mul_dot (get_line x m1) (get_column y m2) in if (not (Literal.equal x y)) && k_is_zero rf then acc else MatrixMap.add (x, y) rf acc in let aux2 acc2 y = List.fold_left (aux y) acc2 support_m1 in List.fold_left aux2 zero' support_m2 let pow mat k = let module St = struct include String let to_string x = x end in let module M = Monomial.Make (St) in let module SMap = Map.Make (St) in let var = "m" in let mono = M.singleton var k in (* We use [Monomial]'s fast exponentiation because why not *) let (res, _) = M.apply (module struct type t = K.t m let one = one (get_support mat) let mul = mul let equal = equal let to_string _ = "" end) mono (SMap.singleton var mat) in res let mul_vect m v = Vector.mapi (fun var _ -> Vector_SR.mul_dot (get_line var m) v) v let is_nilpotent mat = pow mat (List.length (get_support mat)) |> equal zero' let to_string mat : string = (* It is a sparse matrix, only print the non-zero entries *) String.concat "\n" (List.map (fun ((v1, v2), rf) -> Printf.sprintf "( %s ; %s ) := %s" (Literal.to_string v1) (Literal.to_string v2) (K.to_string rf)) (bindings mat)) module Infix = struct let ( + ) = add let ( * ) = mul let ( *^ ) = pow let ( *> ) = mul_vect let ( = ) = equal let ( <> ) = neq end end module Make_R (K : Algebra.Ring_S) = struct include Make_SR (K) let neg = map K.neg let sub m1 m2 = add m1 (neg m2) module Infix = struct include Infix let ( ~- ) = neg let ( - ) = sub end end let make_semiring (type a) (module K : Algebra.Semiring_S with type t = a) l = (module struct include Make_SR (K) let zero = zero l let one = one l end : Algebra.Semiring_S with type t = a m) let make_ring (type a) (module K : Algebra.Ring_S with type t = a) l = (module struct include Make_R (K) let zero = zero l let one = one l end : Algebra.Ring_S with type t = a m) end