-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfo_match.ml
170 lines (159 loc) · 6.71 KB
/
fo_match.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
(* ========================================================================= *)
(* *)
(* First-order matching and nets. *)
(* *)
(* (c) Copyright, Vincent Aravantinos, 2012-2013 *)
(* Analysis and Design of Dependable Systems *)
(* fortiss GmbH, Munich, Germany *)
(* *)
(* Formerly: Hardware Verification Group, *)
(* Concordia University *)
(* *)
(* Contact: <[email protected]> *)
(* *)
(* ========================================================================= *)
(* ------------------------------------------------------------------------- *)
(* First-order matching of terms. *)
(* *)
(* Same note as in [drule.ml]: *)
(* in the event of spillover patterns, this may return false results; *)
(* but there's usually an implicit check outside that the match worked *)
(* anyway. A test could be put in (see if any "env" variables are left in *)
(* the term after abstracting out the pattern instances) but it'd be slower. *)
(* ------------------------------------------------------------------------- *)
let fo_term_match lcs p t =
let fail () = failwith "fo_term_match" in
let rec self bnds (tenv,tyenv as env) p t =
match p,t with
|Comb(p1,p2),Annot.Comb_(t1,t2,_) -> self bnds (self bnds env p1 t1) p2 t2
|Abs(v,p),Annot.Abs_(v',t,_) ->
let tyenv' = type_match (type_of v) (Annot.type_of v') tyenv in
self ((v',v)::bnds) (tenv,tyenv') p t
|Const(n,ty),Annot.Const_(n',ty',_) ->
if n <> n' then fail ()
else
let tyenv' = type_match ty ty' tyenv in
tenv,tyenv'
|Var(n,ty) as v,t ->
(* Is [v] bound? *)
(try if Annot.equal t (rev_assoc v bnds) then env else fail ()
(* No *)
with Failure _ ->
if mem v lcs
then
match t with
|Annot.Var_(n',ty') when n' = n & ty' = ty -> env
|_ -> fail ()
else
let tyenv' = type_match ty (Annot.type_of t) tyenv in
let t' = try Some (rev_assoc v tenv) with Failure _ -> None in
match t' with
|Some t' -> if t = t' then tenv,tyenv' else fail ()
|None -> (t,v)::tenv,tyenv')
|_ -> fail ()
in
let tenv,tyenv = self [] ([],[]) p (Annot.of_term t) in
let inst = inst tyenv in
List.rev_map (fun t,v -> Annot.to_term t,inst v) tenv,tyenv;;
let GEN_PART_MATCH_ALL =
let rec match_bvs t1 t2 acc =
try let v1,b1 = dest_abs t1
and v2,b2 = dest_abs t2 in
let n1 = fst(dest_var v1) and n2 = fst(dest_var v2) in
let newacc = if n1 = n2 then acc else insert (n1,n2) acc in
match_bvs b1 b2 newacc
with Failure _ -> try
let l1,r1 = dest_comb t1
and l2,r2 = dest_comb t2 in
match_bvs l1 l2 (match_bvs r1 r2 acc)
with Failure _ -> acc
in
fun partfn th ->
let sth = SPEC_ALL th in
let bod = concl sth in
let pbod = partfn bod in
let lcs = intersect (frees (concl th)) (freesl(hyp th)) in
let fvs = subtract (subtract (frees bod) (frees pbod)) lcs in
fun tm ->
let bvms = match_bvs tm pbod [] in
let abod = deep_alpha bvms bod in
let ath = EQ_MP (ALPHA bod abod) sth in
let insts,tyinsts = fo_term_match lcs (partfn abod) tm in
let eth = INSTANTIATE_ALL ([],insts,tyinsts) (GENL fvs ath) in
let fth = itlist (fun v th -> snd(SPEC_VAR th)) fvs eth in
let tm' = partfn (concl fth) in
if Pervasives.compare tm' tm = 0 then fth else
try SUBS[ALPHA tm' tm] fth
with Failure _ -> failwith "PART_MATCH: Sanity check failure";;
let exists_subterm p t =
try ignore (find_term p t);true with Failure _ -> false;;
module Fo_nets =
struct
type term_label =
|Vnet of int
|Lcnet of string * int
|Cnet of string * int
|Lnet of int
type 'a t = Netnode of (term_label * 'a t) list * 'a list
let empty_net = Netnode([],[])
let enter =
let label_to_store lcs t =
let op,args = strip_comb t in
let nargs = length args in
match op with
|Const(n,_) -> Cnet(n,nargs),args
|Abs(v,b) ->
let b' = if mem v lcs then vsubst [genvar(type_of v),v] b else b in
Lnet nargs,b'::args
|Var(n,_) when mem op lcs -> Lcnet(n,nargs),args
|Var(_,_) -> Vnet nargs,args
|_ -> assert false
in
let rec net_update lcs elem (Netnode(edges,tips)) = function
|[] -> Netnode(edges,elem::tips)
|t::rts ->
let label,nts = label_to_store lcs t in
let child,others =
try (snd F_F I) (remove (fun (x,y) -> x = label) edges)
with Failure _ -> empty_net,edges in
let new_child = net_update lcs elem child (nts@rts) in
Netnode ((label,new_child)::others,tips)
in
fun lcs (t,elem) net -> net_update lcs elem net [t]
let lookup =
let label_for_lookup t =
let op,args = strip_comb t in
let nargs = length args in
match op with
|Const(n,_) -> Cnet(n,nargs),args
|Abs(_,b) -> Lnet nargs,b::args
|Var(n,_) -> Lcnet(n,nargs),args
|Comb _ -> assert false
in
let rec follow (Netnode(edges,tips)) = function
|[] -> tips
|t::rts ->
let label,nts = label_for_lookup t in
let collection =
try follow (assoc label edges) (nts@rts) with Failure _ -> []
in
let rec support = function
|[] -> [0,rts]
|t::ts ->
let ((k,nts')::res') as res = support ts in
(k+1,(t::nts'))::res
in
let follows =
let f (k,nts) =
try follow (assoc (Vnet k) edges) nts with Failure _ -> []
in
map f (support nts)
in
collection @ flat follows
in
fun t net -> follow net [t]
let rec filter p (Netnode(edges,tips)) =
Netnode(
List.map (fun l,n -> l,filter p n) edges,
List.filter p tips)
end;;