package dedukti
An implementation of The Lambda-Pi Modulo Theory
Install
Dune Dependency
Authors
Maintainers
Sources
v2.7.tar.gz
sha512=97171b48dd96043d84587581d72edb442f63e7b5ac1695771aa1c3c9074739e15bc7d17678fedb7062acbf403a0bf323d97485c31b92376b80c63b5c2300ee3c
sha256=5e1b6a859dfa1eb2098947a99c7d11ee450f750d96da1720f4834e1505d1096c
doc/src/dedukti.kernel/srcheck.ml.html
Source file srcheck.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 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
open Basic open Term module SS = Exsubst.ExSubst let d_SR = Debug.register_flag "SR Checking" let srfuel = ref 1 (* Check whether two pairs of terms are unifiable (one way or the other) *) let cstr_eq ((n1, t1, u1) : cstr) ((n2, t2, u2) : cstr) = let t1', u1' = (Subst.shift n2 t1, Subst.shift n2 u1) in let t2', u2' = (Subst.shift n1 t2, Subst.shift n1 u2) in (term_eq t1' t2' && term_eq u1' u2') || (term_eq t1' u2' && term_eq u1' t2') module SRChecker (R : Reduction.S) = struct type lhs_typing_cstr = { subst : SS.t; unsolved : cstr list; unsatisf : cstr list; } let pp_lhs_typing_cstr fmt {subst; unsolved; unsatisf} = Format.fprintf fmt "TypingConstraint:@.{@.%a@.[%a]@.[%a]@.}" (SS.pp (fun _ -> mk_ident "")) subst (pp_list ", " pp_cstr) unsolved (pp_list ", " pp_cstr) unsatisf let empty : lhs_typing_cstr = {subst = SS.identity; unsolved = []; unsatisf = []} let get_subst c = c.subst let get_unsat c = match c.unsatisf with [] -> None | c :: _ -> Some c let snf sg c depth = let rec aux fuel t = let t1, flag = SS.apply' c.subst depth t in let t2 = R.snf sg t1 in if flag && fuel <> 0 then aux (fuel - 1) t2 else t2 in aux !srfuel let whnf sg c depth = let rec aux fuel t = let t1, flag = SS.apply' c.subst depth t in let t2 = R.whnf sg t1 in if flag && fuel <> 0 then aux (fuel - 1) t2 else t2 in aux !srfuel (* Syntactical match against all unsolved equations *) let term_eq_under_cstr (eq_cstr : cstr list) : term -> term -> bool = let rec aux = function | [] -> true | (n, t1, t2) :: tl -> ( List.exists (cstr_eq (n, t1, t2)) eq_cstr || match (t1, t2) with | App (h1, a1, l1), App (h2, a2, l2) -> List.length l1 = List.length l2 && aux ((n, h1, h2) :: (n, a1, a2) :: List.map2 (fun x y -> (n, x, y)) l1 l2 @ tl) | Lam (_, _, _, t1), Lam (_, _, _, t2) -> aux ((n + 1, t1, t2) :: tl) | Pi (_, _, a1, b1), Pi (_, _, a2, b2) -> aux ((n, a1, a2) :: (n + 1, b1, b2) :: tl) | _ -> term_eq t1 t2 && aux tl) in fun t1 t2 -> aux [(0, t1, t2)] let convertible (sg : Signature.t) (c : lhs_typing_cstr) (depth : int) (ty_inf : term) (ty_exp : term) : bool = R.are_convertible sg ty_inf ty_exp || match (SS.is_identity c.subst, c.unsolved) with | true, [] -> false | true, _ -> term_eq_under_cstr c.unsolved (R.snf sg ty_inf) (R.snf sg ty_exp) | false, _ -> let snf_ty_inf = snf sg c depth ty_inf in let snf_ty_exp = snf sg c depth ty_exp in R.are_convertible sg snf_ty_inf snf_ty_exp || c.unsolved <> [] && term_eq_under_cstr c.unsolved snf_ty_inf snf_ty_exp (* **** PSEUDO UNIFICATION ********************** *) let rec add_to_list q acc l1 l2 = match (l1, l2) with | [], [] -> Some acc | h1 :: t1, h2 :: t2 -> add_to_list q ((q, h1, h2) :: acc) t1 t2 | _, _ -> None let unshift_reduce sg q t = try Some (Subst.unshift q t) with Subst.UnshiftExn -> ( try Some (Subst.unshift q (R.snf sg t)) with Subst.UnshiftExn -> None) (** Under [d] lambdas, checks whether term [te] *must* contain an occurence of any variable that satisfies the given predicate [p], *even when substituted or reduced*. This check make no assumption on the rewrite system or possible substitution - any definable symbol are "safe" as they may reduce to a term where no variable occur - any applied meta variable (DB index > [d]) are "safe" as they may be substituted and reduce to a term where no variable occur Raises VarSurelyOccurs if the term [te] *surely* contains an occurence of one of the [vars]. *) let sure_occur_check sg (d : int) (p : int -> bool) (te : term) : bool = let exception VarSurelyOccurs in let rec aux = function | [] -> () | (k, t) :: tl -> ( (* k counts the number of local lambda abstractions *) match t with | Kind | Type _ | Const _ -> aux tl | Pi (_, _, a, b) -> aux ((k, a) :: (k + 1, b) :: tl) | Lam (_, _, None, b) -> aux ((k + 1, b) :: tl) | Lam (_, _, Some a, b) -> aux ((k, a) :: (k + 1, b) :: tl) | DB (_, _, n) -> if n >= k && p (n - k) then raise VarSurelyOccurs else aux tl | App (f, a, args) -> ( match f with | DB (_, _, n) -> if n >= k && p (n - k) then raise VarSurelyOccurs else if n >= k + d (* a matching variable *) then aux tl else aux (((k, a) :: List.map (fun t -> (k, t)) args) @ tl) | Const (l, cst) when Signature.is_injective sg l cst -> aux (((k, a) :: List.map (fun t -> (k, t)) args) @ tl) | _ -> aux tl (* Default case encompasses: - Meta variables: DB(_,_,n) with n >= k + d - Definable symbols - Lambdas (FIXME: when can this happen ?) - Illegal applications *))) in try aux [(0, te)]; false with VarSurelyOccurs -> true (** Under [d] lambdas, gather all free variables that are *surely* contained in term [te]. That is to say term [te] will contain an occurence of these variables *even when substituted or reduced*. This check make no assumption on the rewrite system or possible substitutions - applied definable symbols *surely* contain no variable as they may reduce to terms where their arguments are erased - applied meta variable (DB index > [d]) *surely* contain no variable as they may be substituted and reduce to a term where their arguments are erased Sets the indices of *surely* contained variables to [true] in the [vars] boolean array which is expected to be of size (at least) [d]. *) let gather_free_vars (d : int) (terms : term list) : bool array = let vars = Array.make d false in let rec aux = function | [] -> () | (k, t) :: tl -> ( (* k counts the number of local lambda abstractions *) match t with | DB (_, _, n) -> if n >= k && n < k + d then vars.(n - k) <- true; aux tl | Pi (_, _, a, b) -> aux ((k, a) :: (k + 1, b) :: tl) | Lam (_, _, None, b) -> aux ((k + 1, b) :: tl) | Lam (_, _, Some a, b) -> aux ((k, a) :: (k + 1, b) :: tl) | App (f, a, args) -> aux (((k, f) :: (k, a) :: List.map (fun t -> (k, t)) args) @ tl) | _ -> aux tl) in aux (List.map (fun t -> (0, t)) terms); vars let try_solve q args t = try let dbs = List.map (function DB (_, _, n) -> n | _ -> raise Matching.NotUnifiable) args in let arity = List.length dbs in let var = Dtree. {arity; depth = q; vars = dbs; mapping = mapping_of_vars q arity dbs} in let sol = Matching.solve_miller var t in Some (Term.add_n_lambdas arity sol) with Matching.NotUnifiable -> None let rec pseudo_u sg flag (s : lhs_typing_cstr) : cstr list -> bool * lhs_typing_cstr = function | [] -> (flag, s) | (q, t1, t2) :: lst -> ( let t1' = whnf sg s q t1 in let t2' = whnf sg s q t2 in Debug.(debug d_SR) "Processing: %a = %a" pp_term t1' pp_term t2'; let dropped () = pseudo_u sg flag s lst in let unsolved () = pseudo_u sg flag {s with unsolved = (q, t1', t2') :: s.unsolved} lst in let unsatisf () = pseudo_u sg true {s with unsatisf = (q, t1', t2') :: s.unsolved} lst in let subst db ar te = pseudo_u sg true {s with subst = SS.add s.subst db ar te} lst in if term_eq t1' t2' then dropped () else match (t1', t2') with | Kind, Kind | Type _, Type _ -> assert false (* Equal terms *) | DB (_, _, n), DB (_, _, n') when n = n' -> assert false (* Equal terms *) | _, Kind | Kind, _ | _, Type _ | Type _, _ -> unsatisf () | Pi (_, _, a, b), Pi (_, _, a', b') -> pseudo_u sg true s ((q, a, a') :: (q + 1, b, b') :: lst) | Lam (_, _, _, b), Lam (_, _, _, b') -> pseudo_u sg true s ((q + 1, b, b') :: lst) (* Potentially eta-equivalent terms *) | Lam (_, i, _, b), a when !Reduction.eta -> let b' = mk_App (Subst.shift 1 a) (mk_DB dloc i 0) [] in pseudo_u sg true s ((q + 1, b, b') :: lst) | a, Lam (_, i, _, b) when !Reduction.eta -> let b' = mk_App (Subst.shift 1 a) (mk_DB dloc i 0) [] in pseudo_u sg true s ((q + 1, b, b') :: lst) (* A definable symbol is only be convertible with closed terms *) | Const (l, cst), t when not (Signature.is_injective sg l cst) -> if sure_occur_check sg q (fun k -> k <= q) t then unsatisf () else unsolved () | t, Const (l, cst) when not (Signature.is_injective sg l cst) -> if sure_occur_check sg q (fun k -> k <= q) t then unsatisf () else unsolved () (* X = Y : map either X to Y or Y to X *) | DB (l1, x1, n1), DB (l2, x2, n2) when n1 >= q && n2 >= q -> let n, t = if n1 < n2 then (n1, mk_DB l2 x2 (n2 - q)) else (n2, mk_DB l1 x1 (n1 - q)) in subst (n - q) 0 t (* X = t : 1) make sure that t is possibly closed and without occurence of X 2) if by chance t already is so, then map X to t 3) otherwise drop the constraint *) | DB (_, _, n), t when n >= q -> ( if sure_occur_check sg q (fun k -> k < q || k = n) t then unsatisf () else match unshift_reduce sg q t with | None -> unsolved () | Some ut -> let n' = n - q in if Subst.occurs n' ut then let t' = R.snf sg ut in if Subst.occurs n' t' then unsatisf () else subst n' 0 t' else subst n' 0 ut) | t, DB (_, _, n) when n >= q -> ( if sure_occur_check sg q (fun k -> k < q || k = n) t then unsatisf () else match unshift_reduce sg q t with | None -> unsolved () | Some ut -> let n' = n - q in if Subst.occurs n' ut then let t' = R.snf sg ut in if Subst.occurs n' t' then unsatisf () else subst n' 0 t' else subst n' 0 ut) (* f t1 ... tn / X t1 ... tn = u 1) Gather all free variables in t1 ... tn 2) Make sure u only relies on these variables *) | App (DB (_, _, n), a, args), t when n >= q -> ( let occs = gather_free_vars q (a :: args) in if sure_occur_check sg q (fun k -> k < q && not occs.(k)) t then unsatisf () else match try_solve q (a :: args) t with | None -> unsolved () | Some ut -> let n' = n - q in let t' = if Subst.occurs n' ut then ut else R.snf sg ut in if Subst.occurs n' t' then unsolved () (* X = t[X] cannot be turned into a (extended-)substitution *) else subst n' (1 + List.length args) t') | t, App (DB (_, _, n), a, args) when n >= q -> ( let occs = gather_free_vars q (a :: args) in if sure_occur_check sg q (fun k -> k < q && not occs.(k)) t then unsatisf () else match try_solve q (a :: args) t with | None -> unsolved () | Some ut -> let n' = n - q in let t' = if Subst.occurs n' ut then ut else R.snf sg ut in if Subst.occurs n' t' then unsolved () (* X = t[X] cannot be turned into a (extended-)substitution *) else subst n' (1 + List.length args) t') | App (Const (l, cst), a, args), t when not (Signature.is_injective sg l cst) -> let occs = gather_free_vars q (a :: args) in if sure_occur_check sg q (fun k -> k < q && not occs.(k)) t then unsatisf () else unsolved () | t, App (Const (l, cst), a, args) when not (Signature.is_injective sg l cst) -> let occs = gather_free_vars q (a :: args) in if sure_occur_check sg q (fun k -> k < q && not occs.(k)) t then unsatisf () else unsolved () | App (f, a, args), App (f', a', args') -> ( (* f = Kind | Type | DB n when n<q | Pi _ * | Const name when (is_static name) *) match add_to_list q lst args args' with | None -> unsatisf () (* Different number of arguments. *) | Some lst2 -> pseudo_u sg true s ((q, f, f') :: (q, a, a') :: lst2)) | _, _ -> unsatisf ()) let compile_cstr (sg : Signature.t) (cstr : cstr list) : lhs_typing_cstr = (* Successively runs pseudo_u to apply solved constraints to the remaining unsolved constraints in the hope to deduce more constraints in solved form *) let rec process_solver fuel sol = match pseudo_u sg false {sol with unsolved = []} sol.unsolved with | false, s -> s (* When pseudo_u did nothing *) | true, sol' -> if fuel = 0 then sol' else process_solver (fuel - 1) {sol' with subst = SS.mk_idempotent sol'.subst} in (* TODO: this function is given some fuel. In practice 1 is enough for all tests. We should write a test to force a second reentry in the loop. *) process_solver !srfuel {subst = SS.identity; unsolved = cstr; unsatisf = []} let optimize sg c = (* Substitutes are put in SNF *) { c with unsolved = List.map (fun (n, t, u) -> (n, R.snf sg t, R.snf sg u)) c.unsolved; } end
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>