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 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
|
/* Hierarchy Builder: algebraic hierarchies made easy
This software is released under the terms of the MIT license */
% This file contains additions to elpi or coq-elpi standard library
% elpi:if version < 2.0.0
kind triple type -> type -> type -> type.
type triple A -> B -> C -> triple A B C.
pred triple_1 i:triple A B C, o:A.
triple_1 (triple A _ _) A.
pred triple_2 i:triple A B C, o:B.
triple_2 (triple _ B _) B.
pred triple_3 i:triple A B C, o:C.
triple_3 (triple _ _ C) C.
% elpi:endif
namespace std {
pred nlist i:int, i:A, o: list A.
nlist N X L :- std.map {std.iota N} (_\ y\ y = X) L.
pred list-diff i:list A, i:list A, o:list A.
list-diff X [] X.
list-diff L [D|DS] R :-
std.filter L (x\ not(x = D)) L1,
list-diff L1 DS R.
pred list-uniq i:list A, o:list A.
pred list-uniq.seen i:A.
list-uniq [] [].
list-uniq [X|XS] YS :- list-uniq.seen X, !, list-uniq XS YS.
list-uniq [X|XS] [X|YS] :- list-uniq.seen X => list-uniq XS YS.
pred list-eq-set i:list A, i:list A.
list-eq-set L1 L2 :- list-diff L1 L2 [], list-diff L2 L1 [].
pred partition i:list A, i:(A -> prop), o:list A, o:list A.
partition [] _ [] [].
partition [X|XS] P [X|YS] ZS :- P X, !, partition XS P YS ZS.
partition [X|XS] P YS [X|ZS] :- partition XS P YS ZS.
pred under.do! i:((A -> prop) -> A -> prop), i:list prop.
under.do! Then LP :- Then (_\ std.do! LP) _.
pred map-triple i:(A -> A1 -> prop), i:(B -> B1 -> prop), i:(C -> C1 -> prop), i:triple A B C, o:triple A1 B1 C1.
map-triple F G H (triple X Y Z) (triple X1 Y1 Z1) :- F X X1, G Y Y1, H Z Z1.
pred sort.split i:list A, o:list A, o:list A.
sort.split [] [] [] :- !.
sort.split [X] [X] [] :- !.
sort.split [X,Y|TL] [X|L1] [Y|L2] :- sort.split TL L1 L2.
pred sort.merge i:(A -> A -> prop), i:list A, i:list A, o:list A.
sort.merge _ [] L L :- !.
sort.merge _ L [] L :- !.
sort.merge Rel [X1|L1] [X2|L2] [X1|M] :- Rel X1 X2, !,
sort.merge Rel L1 [X2|L2] M.
sort.merge Rel [X1|L1] [X2|L2] [X2|M] :-
sort.merge Rel [X1|L1] L2 M.
pred sort i:list A, i:(A -> A -> prop), o:list A.
sort [] _ [] :- !.
sort [X] _ [X] :- !.
sort L Rel M :-
sort.split L L1 L2, sort L1 Rel S1, sort L2 Rel S2, sort.merge Rel S1 S2 M.
pred bubblesort i:list A, i:(A -> A -> prop), o:list A.
bubblesort [] _ [] :- !.
bubblesort [X] _ [X] :- !.
bubblesort [X,Y|TL] Rel [X|Rest1] :- Rel X Y, !, bubblesort [Y|TL] Rel Rest1.
bubblesort [X,Y|TL] Rel [Y|Rest1] :- bubblesort [X|TL] Rel Rest1.
% TODO: pred toposort i:(A -> A -> prop), i:list A, o:list A.
% pred edge? i:int, i:int.
% toposort edge? [1,2,3,4] TopoList
pred topovisit i: list (pair A A), i: A, i: list A, i: list A, o: list A, o: list A.
topovisit _ X VS PS VS PS :- std.mem PS X, !.
topovisit _ X VS _ _ _ :- std.mem VS X, !, halt "cycle detected.".
topovisit ES X VS PS VS' [X|PS'] :-
toporec ES {std.map {std.filter ES (e\ fst e X)} snd} [X|VS] PS VS' PS'.
pred toporec i: list (pair A A), i: list A, i: list A, i: list A, o: list A, o: list A.
toporec _ [] VS PS VS PS.
toporec ES [X|XS] VS PS VS'' PS'' :-
topovisit ES X VS PS VS' PS', toporec ES XS VS' PS' VS'' PS''.
pred toposort i: list (pair A A), i: list A, o: list A.
toposort ES XS XS'' :-
toporec ES XS [] [] _ XS',
std.filter XS' (std.mem XS) XS''.
namespace gref {
pred topovisit i: coq.gref.map coq.gref.set, i: classname, i: coq.gref.set, i: list classname, i: coq.gref.set, o: coq.gref.set, o: list classname, o: coq.gref.set.
topovisit _ X VS PS PSS VS PS PSS :- coq.gref.set.mem X PSS, !.
topovisit _ X VS _ _ _ _ _ :- coq.gref.set.mem X VS, !, halt "cycle detected.".
topovisit ES X VS PS PSS VS' [X|PS'] PSS'' :-
(coq.gref.map.find X ES M ; coq.gref.set.empty M),
toporec ES {coq.gref.set.elements M} {coq.gref.set.add X VS} PS PSS VS' PS' PSS',
coq.gref.set.add X PSS' PSS''.
pred toporec i: coq.gref.map coq.gref.set, i: list classname, i: coq.gref.set, i: list classname, i: coq.gref.set, o: coq.gref.set, o: list classname, o: coq.gref.set.
toporec _ [] VS PS PSS VS PS PSS.
toporec ES [X|XS] VS PS PSS VS'' PS'' PSS'' :-
topovisit ES X VS PS PSS VS' PS' PSS', toporec ES XS VS' PS' PSS' VS'' PS'' PSS''.
pred add-to-neighbours i:coq.gref.set, i:pair gref gref, i:coq.gref.map coq.gref.set, o:coq.gref.map coq.gref.set.
add-to-neighbours VS (pr _ V) A A :- not(coq.gref.set.mem V VS), !.
add-to-neighbours _ (pr K V) A A1 :- coq.gref.map.find K A L, !, coq.gref.map.add K {coq.gref.set.add V L} A A1.
add-to-neighbours _ (pr K V) A A1 :- coq.gref.map.add K {coq.gref.set.add V {coq.gref.set.empty} } A A1.
pred toposort i:list (pair gref gref), i:list gref, o:list gref.
toposort ES XS XS'' :- !, std.do! [
std.fold XS {coq.gref.set.empty} coq.gref.set.add VS,
std.fold ES {coq.gref.map.empty} (add-to-neighbours VS) EM,
toporec EM XS {coq.gref.set.empty} [] {coq.gref.set.empty} _ XS'' _
].
}
pred time-do! i:list prop.
time-do! [].
time-do! [P|PS] :-
std.time P Time, !,
if (constant P C _) true (C = P),
coq.say Time ">>" C,
time-do! PS.
}
namespace compat {
% TODO: replace with std.map-filter when coq-elpi > 1.9.2
pred map-filter i:list A, i:(A -> B -> prop), o:list B.
map-filter [] _ [].
map-filter [X|XS] F [Y|YS] :- F X Y, !, map-filter XS F YS.
map-filter [_|XS] F YS :- map-filter XS F YS.
}
pred print-ctx.
print-ctx :- declare_constraint print-ctx [].
constraint print-ctx mixin-src {
rule \ (G ?- print-ctx) | (coq.say "The context is:" G).
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
pred coq.term-is-gref? i:term, o:gref.
coq.term-is-gref? (global GR) GR :- !.
coq.term-is-gref? (pglobal GR _) GR :- !.
coq.term-is-gref? (app [Hd|_]) GR :- !, coq.term-is-gref? Hd GR.
coq.term-is-gref? (let _ _ T x\x) GR :- !, coq.term-is-gref? T GR.
pred coq.prod-tgt->gref i:term, o:gref.
coq.prod-tgt->gref T GR :- whd1 T T1, !, coq.prod-tgt->gref T1 GR.
coq.prod-tgt->gref (prod N Src Tgt) GR :- !, @pi-decl N Src x\ coq.prod-tgt->gref (Tgt x) GR.
coq.prod-tgt->gref End GR :- coq.term->gref End GR.
% TODO: move to coq-elpi proper / move to coq.pp in coq-elpi >= 1.9
pred coq.indt-decl->string i:indt-decl, o:string.
coq.indt-decl->string (parameter ID _ Ty D) S :-
coq.id->name ID Name,
(@pi-decl Name Ty x\ coq.indt-decl->string (D x) S1),
S is "Parameter" ^ ID ^ " : " ^ {coq.term->string Ty} ^ "\n" ^ S1.
coq.indt-decl->string (inductive _ _ _ _) "NYI".
coq.indt-decl->string (record ID Ty KID RD) S :-
coq.record-decl->string RD S1,
S is ID ^ " : " ^ {coq.term->string Ty} ^ " := " ^ KID ^ " {\n" ^ S1 ^ "}".
pred coq.record-decl->string i:record-decl, o:string.
coq.record-decl->string end-record "".
coq.record-decl->string (field _ ID Ty D) S :-
coq.id->name ID Name,
(@pi-decl Name Ty x\ coq.record-decl->string (D x) S1),
S is " " ^ ID ^ " : " ^ {coq.term->string Ty} ^ ";\n" ^ S1.
pred coq.ground-indt-decl? i:indt-decl.
coq.ground-indt-decl? (parameter ID _ Ty D) :-
ground_term Ty,
coq.id->name ID Name, (@pi-decl Name Ty x\ coq.ground-indt-decl? (D x)).
coq.ground-indt-decl? (inductive _ _ _ _).
coq.ground-indt-decl? (record _ Ty _ RD) :-
ground_term Ty,
coq.ground-record-decl? RD.
pred coq.ground-record-decl? i:record-decl.
coq.ground-record-decl? end-record.
coq.ground-record-decl? (field _ ID Ty D) :-
ground_term Ty,
coq.id->name ID Name, (@pi-decl Name Ty x\ coq.ground-record-decl? (D x)).
% TODO: remove when coq-elpi > 1.9.3
pred copy-indt-decl i:indt-decl, o:indt-decl.
copy-indt-decl (parameter ID I Ty D) (parameter ID I Ty1 D1) :-
copy Ty Ty1,
@pi-parameter ID Ty1 x\ copy-indt-decl (D x) (D1 x).
copy-indt-decl (inductive ID CO A D) (inductive ID CO A1 D1) :-
copy-arity A A1,
coq.id->name ID N, coq.arity->term A1 T, @pi-decl N T i\ std.map (D i) copy-constructor (D1 i).
% @pi-inductive ID A1 i\ std.map (D i) copy-constructor (D1 i). % requires Coq-Elpi 1.9.x
copy-indt-decl (record ID T IDK F) (record ID T1 IDK F1) :-
copy T T1,
copy-fields F F1.
pred copy-fields i:record-decl, o:record-decl.
copy-fields end-record end-record.
copy-fields (field Att ID T F) (field Att ID T1 F1) :-
copy T T1,
@pi-parameter ID T1 x\ copy-fields (F x) (F1 x).
pred copy-constructor i:indc-decl, o:indc-decl.
copy-constructor (constructor ID A) (constructor ID A1) :- copy-arity A A1.
% TODO: move to coq-elpi proper
pred coq.gref.list->set i:list gref, o:coq.gref.set.
coq.gref.list->set L S :-
std.fold L {coq.gref.set.empty} coq.gref.set.add S.
% [coq.abstract-indt-decl Section I AbsI] abstracts I over the Section variables
% which becomes parameter nodes of the indt-decl type
pred coq.abstract-indt-decl i:list constant, i:indt-decl, o:indt-decl.
coq.abstract-indt-decl [] X X1 :- copy-indt-decl X X1.
coq.abstract-indt-decl [C|CS] X (parameter ID explicit Ty1 X1) :-
coq.gref->id (const C) ID,
coq.env.typeof (const C) Ty,
copy Ty Ty1,
@pi-parameter ID Ty x\
(copy (global (const C)) x :- !) =>
coq.abstract-indt-decl CS X (X1 x).
% [coq.abstract-const-decl Section I AbsI] abstracts I over the Section variables
% which becomes fun nodes
pred coq.abstract-const-decl i:list constant, i:pair term term, o:pair term term.
coq.abstract-const-decl [] (pr X Y) (pr X1 Y1) :- copy X X1, copy Y Y1.
coq.abstract-const-decl [C|CS] X (pr (fun Name Ty1 X1) (prod Name Ty1 X2)) :-
coq.gref->id (const C) ID,
coq.id->name ID Name,
coq.env.typeof (const C) Ty,
copy Ty Ty1,
@pi-parameter ID Ty x\
(copy (global (const C)) x :- !) =>
coq.abstract-const-decl CS X (pr (X1 x) (X2 x)).
% [coq.copy-clauses-for-unfold CS CL] generates clauses for the copy predicate
% to unfold all constants in CS
pred coq.copy-clauses-for-unfold i:list constant, o:list prop.
coq.copy-clauses-for-unfold [] [].
coq.copy-clauses-for-unfold [C|CS] [ClauseApp,Clause|L] :-
coq.env.const C (some B) _,
ClauseApp = (pi B1 Args Args1 B2 Args2 R\
copy (app[global (const C)|Args]) R :- !,
copy B B1,
std.map Args copy Args1,
hd-beta B1 Args1 B2 Args2,
unwind B2 Args2 R),
Clause = (pi B1\
copy (global (const C)) B1 :- !, copy B B1),
coq.copy-clauses-for-unfold CS L.
% like fold-map, needed for coq-elpi < 1.9
pred coq.fold-map i:term, i:A, o:term, o:A.
coq.fold-map X A Y A :- name X, !, X = Y, !. % avoid loading "coq.fold-map x A x A" at binders
coq.fold-map (global _ as C) A C A :- !.
coq.fold-map (sort _ as C) A C A :- !.
coq.fold-map (fun N T F) A (fun N T1 F1) A2 :- !,
coq.fold-map T A T1 A1, pi x\ coq.fold-map (F x) A1 (F1 x) A2.
coq.fold-map (let N T B F) A (let N T1 B1 F1) A3 :- !,
coq.fold-map T A T1 A1, coq.fold-map B A1 B1 A2, pi x\ coq.fold-map (F x) A2 (F1 x) A3.
coq.fold-map (prod N T F) A (prod N T1 F1) A2 :- !,
coq.fold-map T A T1 A1, (pi x\ coq.fold-map (F x) A1 (F1 x) A2).
coq.fold-map (app L) A (app L1) A1 :- !, std.fold-map L A coq.fold-map L1 A1.
coq.fold-map (fix N Rno Ty F) A (fix N Rno Ty1 F1) A2 :- !,
coq.fold-map Ty A Ty1 A1, pi x\ coq.fold-map (F x) A1 (F1 x) A2.
coq.fold-map (match T Rty B) A (match T1 Rty1 B1) A3 :- !,
coq.fold-map T A T1 A1, coq.fold-map Rty A1 Rty1 A2, std.fold-map B A2 coq.fold-map B1 A3.
coq.fold-map (primitive _ as C) A C A :- !.
coq.fold-map (uvar M L as X) A W A1 :- var X, !, std.fold-map L A coq.fold-map L1 A1, coq.mk-app-uvar M L1 W.
% when used in CHR rules
coq.fold-map (uvar X L) A (uvar X L1) A1 :- std.fold-map L A coq.fold-map L1 A1.
pred cs-pattern->term i:cs-pattern, o:term.
cs-pattern->term (cs-gref GR) T :- coq.env.global GR T.
cs-pattern->term (cs-sort prop) (sort prop).
cs-pattern->term (cs-sort sprop) (sort sprop).
cs-pattern->term (cs-sort _) T :- coq.elaborate-skeleton {{ Type }} _ T ok.
cs-pattern->term cs-prod T :- coq.elaborate-skeleton (prod `x` Ty_ x\ Bo_ x) _ T ok.
pred term->cs-pattern i:term, o:cs-pattern.
term->cs-pattern (prod _ _ _) cs-prod.
term->cs-pattern (sort U) (cs-sort U).
term->cs-pattern T (cs-gref GR) :- coq.term->gref T GR.
term->cs-pattern T _ :- coq.error T "HB database: is not a valid canonical key".
% this one is in utils, maybe cs-pattern->name is not stdpp material
pred gref->modname-label i:gref, i:int, i:string, o:string.
pred cs-pattern->name i:cs-pattern, o:string.
cs-pattern->name cs-prod "prod".
cs-pattern->name (cs-sort _) "sort".
cs-pattern->name cs-default "default".
cs-pattern->name (cs-gref GR) Name :- gref->modname-label GR 1 "_" Name.
% ---------------------------------------------------------------------
% kit for closing a term by abstracting evars with lambdas
% we use constraints to attach to holes a number
% and replace them by a special node, to later be bound
% via a lambda
namespace abstract-holes {
% we add a new constructor to terms to represent terms to be abstracted
type abs int -> term.
% bind back abstracted subterms
pred bind i:int, i:int, i:term, o:term.
bind I M T T1 :- M > I, !,
T1 = {{ fun x => lp:(B x) }},
N is I + 1,
pi x\ % we allocate the fresh symbol for (abs M)
(copy (abs N) x :- !) => % we schedule the replacement (abs M) -> x
bind N M T (B x).
bind M M T T1 :- copy T T1. % we perform all the replacements
% for a term with M holes, returns a term with M variables to fill these holes
% the clause see is only generated for a term if it hasn't been seen before
% the term might need to be typechecked first or main generates extra holes for the
% type of the parameters
pred main i:term, o:term.
main T1 T3 :- std.do! [
% we put (abs N) in place of each occurrence of the same hole
(pi T Ty N N' M \ fold-map T N (abs M) M :- var T, not (seen? T _), !, coq.typecheck T Ty ok, fold-map Ty N _ N', M is N' + 1, seen! T M) =>
(pi T N M \ fold-map T N (abs M) N :- var T, seen? T M, !) =>
fold-map T1 0 T2 M,
% we abstract M holes (M abs nodes)
bind 0 M T2 T3,
% cleanup constraint store
purge-seen!,
].
% all constraints are also on _ so that they share
% a variable with the constraint to purge the store
% we query if the hole was seen before, and if so
% we fetch its number
pred seen? i:term, o:int.
seen? X Y :- declare_constraint (seen? X Y) [X,_].
% we declare it is now seen and label it with a number
pred seen! i:term, i:int.
seen! X Y :- declare_constraint (seen! X Y) [X,_].
% to empty the store
pred purge-seen!.
purge-seen! :- declare_constraint purge-seen! [_].
constraint seen? seen! purge-seen! {
% a succesful query, give the label back via M
rule (seen! X N) \ (seen? X M) <=> (M = N).
% an unsuccesful query
rule \ (seen? X _) <=> false.
rule purge-seen! \ (seen! _ _).
rule \ purge-seen!.
}
}
|