adamc@82
|
1 (* Copyright (c) 2008, Adam Chlipala
|
adamc@82
|
2 * All rights reserved.
|
adamc@82
|
3 *
|
adamc@82
|
4 * Redistribution and use in source and binary forms, with or without
|
adamc@82
|
5 * modification, are permitted provided that the following conditions are met:
|
adamc@82
|
6 *
|
adamc@82
|
7 * - Redistributions of source code must retain the above copyright notice,
|
adamc@82
|
8 * this list of conditions and the following disclaimer.
|
adamc@82
|
9 * - Redistributions in binary form must reproduce the above copyright notice,
|
adamc@82
|
10 * this list of conditions and the following disclaimer in the documentation
|
adamc@82
|
11 * and/or other materials provided with the distribution.
|
adamc@82
|
12 * - The names of contributors may not be used to endorse or promote products
|
adamc@82
|
13 * derived from this software without specific prior written permission.
|
adamc@82
|
14 *
|
adamc@82
|
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
adamc@82
|
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
adamc@82
|
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
adamc@82
|
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
adamc@82
|
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
adamc@82
|
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
adamc@82
|
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
adamc@82
|
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
adamc@82
|
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
adamc@82
|
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
adamc@82
|
25 * POSSIBILITY OF SUCH DAMAGE.
|
adamc@82
|
26 *)
|
adamc@82
|
27
|
adamc@82
|
28 structure Disjoint :> DISJOINT = struct
|
adamc@82
|
29
|
adamc@82
|
30 open Elab
|
adamc@82
|
31 open ElabOps
|
adamc@82
|
32
|
adamc@82
|
33 structure SS = BinarySetFn(struct
|
adamc@82
|
34 type ord_key = string
|
adamc@82
|
35 val compare = String.compare
|
adamc@82
|
36 end)
|
adamc@82
|
37
|
adamc@82
|
38 structure IS = IntBinarySet
|
adamc@82
|
39 structure IM = IntBinaryMap
|
adamc@82
|
40
|
adamc@82
|
41 type name_ineqs = {
|
adamc@82
|
42 namesC : SS.set,
|
adamc@82
|
43 namesR : IS.set,
|
adamc@82
|
44 namesN : IS.set
|
adamc@82
|
45 }
|
adamc@82
|
46
|
adamc@82
|
47 val name_default = {
|
adamc@82
|
48 namesC = SS.empty,
|
adamc@82
|
49 namesR = IS.empty,
|
adamc@82
|
50 namesN = IS.empty
|
adamc@82
|
51 }
|
adamc@82
|
52
|
adamc@82
|
53 type row_ineqs = {
|
adamc@82
|
54 namesC : SS.set,
|
adamc@82
|
55 namesR : IS.set,
|
adamc@82
|
56 namesN : IS.set,
|
adamc@82
|
57 rowsR : IS.set,
|
adamc@82
|
58 rowsN : IS.set
|
adamc@82
|
59 }
|
adamc@82
|
60
|
adamc@82
|
61 val row_default = {
|
adamc@82
|
62 namesC = SS.empty,
|
adamc@82
|
63 namesR = IS.empty,
|
adamc@82
|
64 namesN = IS.empty,
|
adamc@82
|
65 rowsR = IS.empty,
|
adamc@82
|
66 rowsN = IS.empty
|
adamc@82
|
67 }
|
adamc@82
|
68
|
adamc@82
|
69 fun nameToRow_ineqs {namesC, namesR, namesN} =
|
adamc@82
|
70 {namesC = namesC,
|
adamc@82
|
71 namesR = namesR,
|
adamc@82
|
72 namesN = namesN,
|
adamc@82
|
73 rowsR = IS.empty,
|
adamc@82
|
74 rowsN = IS.empty}
|
adamc@82
|
75
|
adamc@82
|
76 type env = {
|
adamc@82
|
77 namesR : name_ineqs IM.map,
|
adamc@82
|
78 namesN : name_ineqs IM.map,
|
adamc@82
|
79 rowsR : row_ineqs IM.map,
|
adamc@82
|
80 rowsN : row_ineqs IM.map
|
adamc@82
|
81 }
|
adamc@82
|
82
|
adamc@82
|
83 val empty = {
|
adamc@82
|
84 namesR = IM.empty,
|
adamc@82
|
85 namesN = IM.empty,
|
adamc@82
|
86 rowsR = IM.empty,
|
adamc@82
|
87 rowsN = IM.empty
|
adamc@82
|
88 }
|
adamc@82
|
89
|
adamc@82
|
90 datatype piece =
|
adamc@82
|
91 NameC of string
|
adamc@82
|
92 | NameR of int
|
adamc@82
|
93 | NameN of int
|
adamc@82
|
94 | RowR of int
|
adamc@82
|
95 | RowN of int
|
adamc@82
|
96 | Unknown
|
adamc@82
|
97
|
adamc@82
|
98 fun nameToRow (c, loc) =
|
adamc@82
|
99 (CRecord ((KUnit, loc), [((c, loc), (CUnit, loc))]), loc)
|
adamc@82
|
100
|
adamc@82
|
101 fun pieceToRow (p, loc) =
|
adamc@82
|
102 case p of
|
adamc@82
|
103 NameC s => nameToRow (CName s, loc)
|
adamc@82
|
104 | NameR n => nameToRow (CRel n, loc)
|
adamc@82
|
105 | NameN n => nameToRow (CNamed n, loc)
|
adamc@82
|
106 | RowR n => (CRel n, loc)
|
adamc@82
|
107 | RowN n => (CRel n, loc)
|
adamc@82
|
108 | Unknown => raise Fail "Unknown to row"
|
adamc@82
|
109
|
adamc@82
|
110 fun decomposeRow env c =
|
adamc@82
|
111 let
|
adamc@82
|
112 fun decomposeName (c, acc) =
|
adamc@82
|
113 case #1 (hnormCon env c) of
|
adamc@82
|
114 CName s => NameC s :: acc
|
adamc@82
|
115 | CRel n => NameR n :: acc
|
adamc@82
|
116 | CNamed n => NameN n :: acc
|
adamc@82
|
117 | _ => Unknown :: acc
|
adamc@82
|
118
|
adamc@82
|
119 fun decomposeRow (c, acc) =
|
adamc@82
|
120 case #1 (hnormCon env c) of
|
adamc@82
|
121 CRecord (_, xcs) => foldl (fn ((x, _), acc) => decomposeName (x, acc)) acc xcs
|
adamc@82
|
122 | CConcat (c1, c2) => decomposeRow (c1, decomposeRow (c2, acc))
|
adamc@82
|
123 | CRel n => RowR n :: acc
|
adamc@82
|
124 | CNamed n => RowN n :: acc
|
adamc@82
|
125 | _ => Unknown :: acc
|
adamc@82
|
126 in
|
adamc@82
|
127 decomposeRow (c, [])
|
adamc@82
|
128 end
|
adamc@82
|
129
|
adamc@82
|
130 fun assertPiece_name (ps, ineqs : name_ineqs) =
|
adamc@82
|
131 {namesC = foldl (fn (p', namesC) =>
|
adamc@82
|
132 case p' of
|
adamc@82
|
133 NameC s => SS.add (namesC, s)
|
adamc@82
|
134 | _ => namesC) (#namesC ineqs) ps,
|
adamc@82
|
135 namesR = foldl (fn (p', namesR) =>
|
adamc@82
|
136 case p' of
|
adamc@82
|
137 NameR n => IS.add (namesR, n)
|
adamc@82
|
138 | _ => namesR) (#namesR ineqs) ps,
|
adamc@82
|
139 namesN = foldl (fn (p', namesN) =>
|
adamc@82
|
140 case p' of
|
adamc@82
|
141 NameN n => IS.add (namesN, n)
|
adamc@82
|
142 | _ => namesN) (#namesN ineqs) ps}
|
adamc@82
|
143
|
adamc@82
|
144 fun assertPiece_row (ps, ineqs : row_ineqs) =
|
adamc@82
|
145 {namesC = foldl (fn (p', namesC) =>
|
adamc@82
|
146 case p' of
|
adamc@82
|
147 NameC s => SS.add (namesC, s)
|
adamc@82
|
148 | _ => namesC) (#namesC ineqs) ps,
|
adamc@82
|
149 namesR = foldl (fn (p', namesR) =>
|
adamc@82
|
150 case p' of
|
adamc@82
|
151 NameR n => IS.add (namesR, n)
|
adamc@82
|
152 | _ => namesR) (#namesR ineqs) ps,
|
adamc@82
|
153 namesN = foldl (fn (p', namesN) =>
|
adamc@82
|
154 case p' of
|
adamc@82
|
155 NameN n => IS.add (namesN, n)
|
adamc@82
|
156 | _ => namesN) (#namesN ineqs) ps,
|
adamc@82
|
157 rowsR = foldl (fn (p', rowsR) =>
|
adamc@82
|
158 case p' of
|
adamc@82
|
159 RowR n => IS.add (rowsR, n)
|
adamc@82
|
160 | _ => rowsR) (#rowsR ineqs) ps,
|
adamc@82
|
161 rowsN = foldl (fn (p', rowsN) =>
|
adamc@82
|
162 case p' of
|
adamc@82
|
163 RowN n => IS.add (rowsN, n)
|
adamc@82
|
164 | _ => rowsN) (#rowsN ineqs) ps}
|
adamc@82
|
165
|
adamc@82
|
166 fun assertPiece ps (p, denv) =
|
adamc@82
|
167 case p of
|
adamc@82
|
168 Unknown => denv
|
adamc@82
|
169 | NameC _ => denv
|
adamc@82
|
170
|
adamc@82
|
171 | NameR n =>
|
adamc@82
|
172 let
|
adamc@82
|
173 val ineqs = Option.getOpt (IM.find (#namesR denv, n), name_default)
|
adamc@82
|
174 val ineqs = assertPiece_name (ps, ineqs)
|
adamc@82
|
175 in
|
adamc@82
|
176 {namesR = IM.insert (#namesR denv, n, ineqs),
|
adamc@82
|
177 namesN = #namesN denv,
|
adamc@82
|
178 rowsR = #rowsR denv,
|
adamc@82
|
179 rowsN = #rowsN denv}
|
adamc@82
|
180 end
|
adamc@82
|
181
|
adamc@82
|
182 | NameN n =>
|
adamc@82
|
183 let
|
adamc@82
|
184 val ineqs = Option.getOpt (IM.find (#namesN denv, n), name_default)
|
adamc@82
|
185 val ineqs = assertPiece_name (ps, ineqs)
|
adamc@82
|
186 in
|
adamc@82
|
187 {namesR = #namesR denv,
|
adamc@82
|
188 namesN = IM.insert (#namesN denv, n, ineqs),
|
adamc@82
|
189 rowsR = #rowsR denv,
|
adamc@82
|
190 rowsN = #rowsN denv}
|
adamc@82
|
191 end
|
adamc@82
|
192
|
adamc@82
|
193 | RowR n =>
|
adamc@82
|
194 let
|
adamc@82
|
195 val ineqs = Option.getOpt (IM.find (#rowsR denv, n), row_default)
|
adamc@82
|
196 val ineqs = assertPiece_row (ps, ineqs)
|
adamc@82
|
197 in
|
adamc@82
|
198 {namesR = #namesR denv,
|
adamc@82
|
199 namesN = #namesN denv,
|
adamc@82
|
200 rowsR = IM.insert (#rowsR denv, n, ineqs),
|
adamc@82
|
201 rowsN = #rowsN denv}
|
adamc@82
|
202 end
|
adamc@82
|
203
|
adamc@82
|
204 | RowN n =>
|
adamc@82
|
205 let
|
adamc@82
|
206 val ineqs = Option.getOpt (IM.find (#rowsN denv, n), row_default)
|
adamc@82
|
207 val ineqs = assertPiece_row (ps, ineqs)
|
adamc@82
|
208 in
|
adamc@82
|
209 {namesR = #namesR denv,
|
adamc@82
|
210 namesN = #namesN denv,
|
adamc@82
|
211 rowsR = #rowsR denv,
|
adamc@82
|
212 rowsN = IM.insert (#rowsN denv, n, ineqs)}
|
adamc@82
|
213 end
|
adamc@82
|
214
|
adamc@82
|
215 fun assert env denv (c1, c2) =
|
adamc@82
|
216 let
|
adamc@82
|
217 val ps1 = decomposeRow env c1
|
adamc@82
|
218 val ps2 = decomposeRow env c2
|
adamc@82
|
219
|
adamc@82
|
220 val denv = foldl (assertPiece ps2) denv ps1
|
adamc@82
|
221 in
|
adamc@82
|
222 foldl (assertPiece ps1) denv ps2
|
adamc@82
|
223 end
|
adamc@82
|
224
|
adamc@82
|
225 fun nameEnter {namesC, namesR, namesN} =
|
adamc@82
|
226 {namesC = namesC,
|
adamc@82
|
227 namesR = IS.map (fn n => n + 1) namesR,
|
adamc@82
|
228 namesN = namesN}
|
adamc@82
|
229
|
adamc@82
|
230 fun rowEnter {namesC, namesR, namesN, rowsR, rowsN} =
|
adamc@82
|
231 {namesC = namesC,
|
adamc@82
|
232 namesR = IS.map (fn n => n + 1) namesR,
|
adamc@82
|
233 namesN = namesN,
|
adamc@82
|
234 rowsR = IS.map (fn n => n + 1) rowsR,
|
adamc@82
|
235 rowsN = rowsN}
|
adamc@82
|
236
|
adamc@82
|
237 fun enter {namesR, namesN, rowsR, rowsN} =
|
adamc@82
|
238 {namesR = IM.foldli (fn (n, ineqs, namesR) => IM.insert (namesR, n+1, nameEnter ineqs)) IM.empty namesR,
|
adamc@82
|
239 namesN = IM.map nameEnter namesN,
|
adamc@82
|
240 rowsR = IM.foldli (fn (n, ineqs, rowsR) => IM.insert (rowsR, n+1, rowEnter ineqs)) IM.empty rowsR,
|
adamc@82
|
241 rowsN = IM.map rowEnter rowsN}
|
adamc@82
|
242
|
adamc@82
|
243 fun getIneqs (denv : env) p =
|
adamc@82
|
244 case p of
|
adamc@82
|
245 Unknown => raise Fail "getIneqs: Unknown"
|
adamc@82
|
246 | NameC _ => raise Fail "getIneqs: NameC"
|
adamc@82
|
247 | NameR n => nameToRow_ineqs (Option.getOpt (IM.find (#namesR denv, n), name_default))
|
adamc@82
|
248 | NameN n => nameToRow_ineqs (Option.getOpt (IM.find (#namesN denv, n), name_default))
|
adamc@82
|
249 | RowR n => Option.getOpt (IM.find (#rowsR denv, n), row_default)
|
adamc@82
|
250 | RowN n => Option.getOpt (IM.find (#rowsN denv, n), row_default)
|
adamc@82
|
251
|
adamc@82
|
252 fun prove1' denv (p1, p2) =
|
adamc@82
|
253 let
|
adamc@82
|
254 val {namesC, namesR, namesN, rowsR, rowsN} = getIneqs denv p1
|
adamc@82
|
255 in
|
adamc@82
|
256 case p2 of
|
adamc@82
|
257 Unknown => raise Fail "prove1': Unknown"
|
adamc@82
|
258 | NameC s => SS.member (namesC, s)
|
adamc@82
|
259 | NameR n => IS.member (namesR, n)
|
adamc@82
|
260 | NameN n => IS.member (namesN, n)
|
adamc@82
|
261 | RowR n => IS.member (rowsR, n)
|
adamc@82
|
262 | RowN n => IS.member (rowsN, n)
|
adamc@82
|
263 end
|
adamc@82
|
264
|
adamc@82
|
265 fun prove1 denv (p1, p2) =
|
adamc@82
|
266 case (p1, p2) of
|
adamc@82
|
267 (NameC s1, NameC s2) => s1 <> s2
|
adamc@82
|
268 | (_, RowR _) => prove1' denv (p2, p1)
|
adamc@82
|
269 | (_, RowN _) => prove1' denv (p2, p1)
|
adamc@82
|
270 | _ => prove1' denv (p1, p2)
|
adamc@82
|
271
|
adamc@82
|
272 fun prove env denv (c1, c2, loc) =
|
adamc@82
|
273 let
|
adamc@82
|
274 val ps1 = decomposeRow env c1
|
adamc@82
|
275 val ps2 = decomposeRow env c2
|
adamc@82
|
276
|
adamc@82
|
277 val hasUnknown = List.exists (fn p => p = Unknown)
|
adamc@82
|
278 in
|
adamc@82
|
279 if hasUnknown ps1 orelse hasUnknown ps2 then
|
adamc@83
|
280 [(c1, c2)]
|
adamc@82
|
281 else
|
adamc@82
|
282 foldl (fn (p1, rem) =>
|
adamc@82
|
283 foldl (fn (p2, rem) =>
|
adamc@82
|
284 if prove1 denv (p1, p2) then
|
adamc@82
|
285 rem
|
adamc@82
|
286 else
|
adamc@82
|
287 (pieceToRow (p1, loc), pieceToRow (p2, loc)) :: rem) rem ps2)
|
adamc@82
|
288 [] ps1
|
adamc@82
|
289 end
|
adamc@82
|
290
|
adamc@82
|
291 end
|