1structure SharingTables :> SharingTables =
2struct
3
4open Term Type
5infix |>
6fun x |> f = f x
7
8structure Map = Binarymap
9exception SharingTables of string
10
11type 'a sexppr = 'a -> HOLsexp.t
12
13(* ----------------------------------------------------------------------
14    string sharing table
15   ---------------------------------------------------------------------- *)
16
17type stringtable =
18     {size : int, map : (string,int) Map.dict, list : string list}
19type id = {Thy : string, Other : string}
20type idtable = {idsize : int,
21                idmap : (id, int) Map.dict,
22                idlist : (int * int) list}
23
24val empty_strtable : stringtable =
25    {size = 0, map = Map.mkDict String.compare, list = []}
26
27local
28  open HOLsexp
29in
30fun enc_strtable (strtable : stringtable) =
31    tagged_encode "string-table" (list_encode String)
32                  (List.rev (#list strtable))
33val dec_strings =
34    Option.map Vector.fromList o
35    tagged_decode "string-table" (list_decode string_decode)
36
37fun enc_idtable (idtable : idtable) =
38    tagged_encode "id-table" (list_encode (pair_encode(Integer,Integer)))
39                  (List.rev (#idlist idtable))
40fun dec_ids strv =
41    Option.map (Vector.fromList o
42                map (fn (i,j) => {Thy = Vector.sub(strv,i),
43                                  Other = Vector.sub(strv,j)})) o
44    tagged_decode "id-table" (list_decode (pair_decode(int_decode,int_decode)))
45
46end (* local *)
47
48
49fun new_string s (strtable as {size,list,map}:stringtable) =
50    case Map.peek(map, s) of
51        SOME i => (i, strtable)
52      | NONE => (size, {size = size + 1,
53                        list = s :: list,
54                        map = Map.insert(map,s,size)})
55
56(* ----------------------------------------------------------------------
57    IDs (also known as Theory-X pairs, where X is a Name for a constant,
58    or Tyops for types)
59   ---------------------------------------------------------------------- *)
60
61
62fun make_shared_id (id as {Thy,Other} : id) (strtable, idtable) =
63    case Map.peek(#idmap idtable, id) of
64      SOME i => (i, strtable, idtable)
65    | NONE => let
66        val {idsize, idmap, idlist} = idtable
67        val (thyi, strtable) = new_string Thy strtable
68        val (otheri, strtable) = new_string Other strtable
69      in
70        (idsize, strtable,
71         {idsize = idsize + 1, idmap = Map.insert(idmap, id, idsize),
72          idlist = (thyi,otheri) :: idlist})
73      end
74fun id_compare ({Other = id1, Thy = thy1}, {Other = id2, Thy = thy2}) =
75    case String.compare(id1, id2) of
76      EQUAL => String.compare(thy1, thy2)
77    | x => x
78
79val empty_idtable : idtable = {idsize = 0,
80                               idmap = Map.mkDict id_compare,
81                               idlist = []}
82
83
84fun build_id_vector strings intpairs =
85    Vector.fromList
86      (map (fn (thyi,otheri) => {Thy = Vector.sub(strings,thyi),
87                                 Other = Vector.sub(strings,otheri)})
88           intpairs)
89
90
91(* ----------------------------------------------------------------------
92    Types
93   ---------------------------------------------------------------------- *)
94
95datatype shared_type = TYV of string
96                     | TYOP of int list
97
98type typetable = {tysize : int,
99                  tymap : (hol_type, int)Map.dict,
100                  tylist : shared_type list}
101
102local
103  open HOLsexp
104in
105fun shared_type_encode (TYV s) = String s
106  | shared_type_encode (TYOP is) = List(map Integer is)
107
108fun shared_type_decode s =
109    case string_decode s of
110        SOME str => SOME (TYV str)
111      | _ => Option.map TYOP (list_decode int_decode s)
112
113val enc_tytable : typetable encoder =
114    tagged_encode "type-table" (list_encode shared_type_encode) o List.rev o
115    #tylist
116
117end (* local *)
118
119fun make_shared_type ty strtable idtable table =
120    case Map.peek(#tymap table, ty) of
121      SOME i => (i, strtable, idtable, table)
122    | NONE => let
123      in
124        if is_vartype ty then let
125            val {tysize, tymap, tylist} = table
126          in
127            (tysize, strtable, idtable,
128             {tysize = tysize + 1,
129              tymap = Map.insert(tymap, ty, tysize),
130              tylist = TYV (dest_vartype ty) :: tylist})
131          end
132        else let
133            val {Thy, Tyop, Args} = dest_thy_type ty
134            val (id, strtable0, idtable0) =
135                make_shared_id {Thy = Thy, Other = Tyop} (strtable, idtable)
136            fun foldthis (tyarg, (results, strtable, idtable, table)) = let
137              val (result, strtable', idtable', table') =
138                  make_shared_type tyarg strtable idtable table
139            in
140              (result::results, strtable', idtable', table')
141            end
142            val (newargs, strtable', idtable', table') =
143                List.foldr foldthis ([], strtable0, idtable0, table) Args
144            val {tysize, tymap, tylist} = table'
145          in
146            (tysize, strtable', idtable',
147             {tysize = tysize + 1,
148              tymap = Map.insert(tymap, ty, tysize),
149              tylist = TYOP (id :: newargs) :: tylist})
150          end
151      end
152
153val empty_tytable : typetable =
154    {tysize = 0, tymap = Map.mkDict Type.compare, tylist = [] }
155
156fun build_type_vector idv shtylist = let
157  fun build1 (shty, (n, tymap)) =
158      case shty of
159        TYV s => (n + 1, Map.insert(tymap, n, Type.mk_vartype s))
160      | TYOP idargs => let
161          val (id, Args) = valOf (List.getItem idargs)
162          fun mapthis i =
163              Map.find(tymap, i)
164              handle Map.NotFound =>
165                     raise SharingTables ("build_type_vector: (" ^
166                                          String.concatWith " "
167                                                (map Int.toString Args) ^
168                                          "), " ^ Int.toString i ^
169                                          " not found")
170          val args = map mapthis Args
171          val {Thy,Other} = Vector.sub(idv, id)
172        in
173          (n + 1,
174           Map.insert(tymap, n,
175                      Type.mk_thy_type {Thy = Thy, Tyop = Other, Args = args}))
176        end
177  val (_, tymap) =
178      List.foldl build1 (0, Map.mkDict Int.compare) shtylist
179in
180  Vector.fromList (map #2 (Map.listItems tymap))
181end
182
183(* ----------------------------------------------------------------------
184    Terms
185   ---------------------------------------------------------------------- *)
186
187datatype shared_term = TMV of string * int
188                     | TMC of int * int
189                     | TMAp of int * int
190                     | TMAbs of int * int
191
192type termtable = {termsize : int,
193                  termmap : (term, int)Map.dict,
194                  termlist : shared_term list}
195
196local
197  open HOLsexp
198in
199fun shared_term_encode stm =
200    case stm of
201        TMV (s,i) => List[String s, Integer i]
202      | TMC (i,j) => List[Integer i, Integer j]
203      | TMAp(i,j) => List[Symbol "ap", Integer i, Integer j]
204      | TMAbs(i,j) => List[Symbol "ab", Integer i, Integer j]
205fun shared_term_decode s =
206    let
207      val (els, last) = strip_list s
208    in
209      if last <> NONE then NONE
210      else
211        case els of
212            [String s, Integer i] => SOME (TMV (s,i))
213          | [Integer i, Integer j] => SOME (TMC(i,j))
214          | [Symbol "ap", Integer i, Integer j] => SOME (TMAp(i,j))
215          | [Symbol "ab", Integer i, Integer j] => SOME (TMAbs(i,j))
216          | _ => NONE
217    end
218
219val enc_tmtable : termtable encoder =
220    tagged_encode "term-table" (list_encode shared_term_encode) o
221    List.rev o #termlist
222end (* local *)
223
224val empty_termtable : termtable =
225    {termsize = 0, termmap = Map.mkDict Term.compare, termlist = [] }
226
227fun make_shared_term tm (tables as (strtable,idtable,tytable,tmtable)) =
228    case Map.peek(#termmap tmtable, tm) of
229      SOME i => (i, tables)
230    | NONE => let
231      in
232        if is_var tm then let
233            val (s, ty) = dest_var tm
234            val (ty_i, strtable, idtable, tytable) =
235                make_shared_type ty strtable idtable tytable
236            val {termsize, termmap, termlist} = tmtable
237          in
238            (termsize,
239             (strtable, idtable, tytable,
240              {termsize = termsize + 1,
241               termmap = Map.insert(termmap, tm, termsize),
242               termlist = TMV (s, ty_i) :: termlist}))
243          end
244        else if is_const tm then let
245            val {Thy,Name,Ty} = dest_thy_const tm
246            val (id_i, strtable, idtable) =
247                make_shared_id {Thy = Thy, Other = Name} (strtable, idtable)
248            val (ty_i, strtable, idtable, tytable) =
249                make_shared_type Ty strtable idtable tytable
250            val {termsize, termmap, termlist} = tmtable
251          in
252            (termsize,
253             (strtable, idtable, tytable,
254              {termsize = termsize + 1,
255               termmap = Map.insert(termmap, tm, termsize),
256               termlist = TMC (id_i, ty_i) :: termlist}))
257          end
258        else if is_comb tm then let
259            val (f, x) = dest_comb tm
260            val (f_i, tables) = make_shared_term f tables
261            val (x_i, tables) = make_shared_term x tables
262            val (strtable, idtable, tytable, tmtable) = tables
263            val {termsize, termmap, termlist} = tmtable
264          in
265            (termsize,
266             (strtable, idtable, tytable,
267              {termsize = termsize + 1,
268               termmap = Map.insert(termmap, tm, termsize),
269               termlist = TMAp(f_i, x_i) :: termlist}))
270          end
271        else  (* must be an abstraction *) let
272            val (v, body) = dest_abs tm
273            val (v_i, tables) = make_shared_term v tables
274            val (body_i, tables) = make_shared_term body tables
275            val (strtable, idtable, tytable, tmtable) = tables
276            val {termsize, termmap, termlist} = tmtable
277          in
278            (termsize,
279             (strtable, idtable, tytable,
280              {termsize = termsize + 1,
281               termmap = Map.insert(termmap, tm, termsize),
282               termlist = TMAbs(v_i, body_i) :: termlist}))
283          end
284      end
285
286fun build_term_vector idv tyv shtmlist = let
287  fun build1 (shtm, (n, tmmap)) =
288      case shtm of
289        TMV (s, tyn) => (n + 1,
290                         Map.insert(tmmap, n, mk_var(s, Vector.sub(tyv, tyn))))
291      | TMC (idn, tyn) => let
292          val {Thy, Other} = Vector.sub(idv, idn)
293          val ty = Vector.sub(tyv, tyn)
294        in
295          (n + 1, Map.insert(tmmap, n, mk_thy_const {Name = Other, Thy = Thy,
296                                                     Ty = ty}))
297        end
298      | TMAp (f_n, xn) =>
299        (n + 1, Map.insert(tmmap, n, mk_comb(Map.find(tmmap, f_n),
300                                             Map.find(tmmap, xn))))
301      | TMAbs (vn, bodyn) =>
302        (n + 1, Map.insert(tmmap, n, mk_abs(Map.find(tmmap, vn),
303                                            Map.find(tmmap, bodyn))))
304  val (_, tmmap) = List.foldl build1 (0, Map.mkDict Int.compare) shtmlist
305in
306  Vector.fromList (map #2 (Map.listItems tmmap))
307end
308
309(* ----------------------------------------------------------------------
310    sharing table data more abstractly
311   ---------------------------------------------------------------------- *)
312
313type extract_data =
314 {named_terms : (string * Term.term) list,
315  unnamed_terms : Term.term list,
316  named_types : (string * Type.hol_type) list,
317  unnamed_types : Type.hol_type list,
318  theorems : (string * Thm.thm) list}
319
320datatype sharing_data_in = SDI of {strtable : stringtable,
321                                   idtable : idtable,
322                                   tytable : typetable,
323                                   tmtable : termtable,
324                                   exp : extract_data}
325
326fun empty_in exp = SDI{strtable = empty_strtable,
327                       idtable = empty_idtable,
328                       tytable = empty_tytable,
329                       tmtable = empty_termtable,
330                       exp = exp}
331
332fun add_strings strs (SDI {strtable,idtable,tytable,tmtable,exp}) =
333    let fun str1 (s, tab) = #2 (new_string s tab)
334        val strtable = List.foldl str1 strtable strs
335    in
336      SDI{strtable = strtable, idtable = idtable, tytable = tytable,
337          tmtable = tmtable, exp = exp}
338    end
339
340fun add_types tys (SDI{strtable,idtable,tytable,tmtable,exp}) =
341    let
342      fun dotypes (ty, (strtable, idtable, tytable)) = let
343        val (_, strtable, idtable, tytable) =
344            make_shared_type ty strtable idtable tytable
345      in
346        (strtable, idtable, tytable)
347      end
348      val (strtable,idtable,tytable) =
349          List.foldl dotypes (strtable, idtable, tytable) tys
350    in
351      SDI{strtable = strtable, idtable = idtable, tytable = tytable,
352          tmtable = tmtable, exp = exp}
353    end
354
355fun add_terms tms (SDI{strtable,idtable,tytable,tmtable,exp}) =
356    let
357      val tms = Term.all_atomsl tms empty_tmset |> HOLset.listItems
358      val (strtable,idtable,tytable,tmtable) =
359          List.foldl (fn (t,tables) => #2 (make_shared_term t tables))
360                     (strtable,idtable,tytable,tmtable)
361                     tms
362    in
363      SDI{strtable = strtable, idtable = idtable, tytable = tytable,
364          tmtable = tmtable, exp = exp}
365    end
366
367fun thm_atoms acc th = Term.all_atomsl (Thm.concl th :: Thm.hyp th) acc
368
369fun thml_atoms thlist acc =
370    case thlist of
371      [] => acc
372    | (th::ths) => thml_atoms ths (thm_atoms acc th)
373
374fun enc_dep findstr ((s,n),dl) =
375    let open HOLsexp
376        fun f (thy,l) = Cons(findstr thy, list_encode Integer l)
377    in
378      list_encode f ((s,[n]) :: dl)
379    end
380
381fun dest_dep d =
382    case d of
383        Dep.DEP_SAVED (did,thydl) => (did,thydl)
384      | Dep.DEP_UNSAVED dl => raise SharingTables "Can't encode unsaved dep"
385
386fun enc_tag findstr tag =
387    let open HOLsexp
388        val dep = Tag.dep_of tag
389        val ocl = #1 (Tag.dest_tag tag)
390    in
391      pair_encode(enc_dep findstr o dest_dep, list_encode String) (dep,ocl)
392    end
393
394fun thm_strings th =
395    let val (sn, dl) = dest_dep (Tag.dep_of (Thm.tag th) )
396    in
397      #1 sn :: map #1 dl
398    end
399
400fun build_sharing_data (ed : extract_data) =
401    let
402      val {named_types, named_terms, unnamed_types, unnamed_terms, theorems} =
403          ed
404      val sdi = empty_in ed
405                         |> add_types (map #2 named_types)
406                         |> add_types unnamed_types
407      val tm_atoms =
408          thml_atoms (map #2 theorems) empty_tmset
409                     |> Term.all_atomsl (unnamed_terms @ map #2 named_terms)
410    in
411      sdi |> add_terms (HOLset.listItems tm_atoms)
412          |> add_strings (map #1 theorems)
413          |> add_strings (List.concat (map (thm_strings o #2) theorems))
414    end
415
416fun write_string (SDI{strtable,...}) s =
417    Map.find(#map strtable,s)
418    handle Map.NotFound =>
419           raise SharingTables ("write_string: can't find \"" ^ s ^ "\"")
420fun write_type (SDI{tytable,...}) ty =
421    Map.find(#tymap tytable,ty)
422fun write_term (SDI{tmtable,...}) =
423    Term.write_raw (fn t => Map.find(#termmap tmtable,t))
424    handle Map.NotFound => raise SharingTables "write_term: can't find term"
425
426
427fun enc_sdata (sd as SDI{strtable,idtable,tytable,tmtable,exp}) =
428    let
429      open HOLsexp
430      val {unnamed_types,named_types,unnamed_terms,named_terms,theorems} = exp
431      val find_str = Integer o write_string sd
432      val ty_encode = Integer o write_type sd
433      val tm_encode = String o write_term sd
434
435      fun enc_thm(s,th) =
436          let
437            val (tag, asl, w) = (Thm.tag th, Thm.hyp th, Thm.concl th)
438            val i = Map.find(#map strtable, s)
439          in
440            pair3_encode (Integer,enc_tag find_str,list_encode tm_encode)
441                         (i, tag, w::asl)
442          end
443    in
444
445      tagged_encode "core-data" (
446        pair_encode (
447          tagged_encode "tables" (
448            pair4_encode(enc_strtable,enc_idtable,enc_tytable,enc_tmtable)
449          ),
450          tagged_encode "exports" (
451            pair3_encode(
452              pair_encode( (* types *)
453                list_encode ty_encode,
454                list_encode (pair_encode(String,ty_encode))
455              ),
456              pair_encode( (* terms *)
457                list_encode tm_encode,
458                list_encode (pair_encode(String,tm_encode))
459              ),
460              list_encode enc_thm
461            )
462          )
463        )
464      ) ((strtable,idtable,tytable,tmtable),
465         ((unnamed_types, named_types), (unnamed_terms, named_terms), theorems))
466    end
467
468type sharing_data_out =
469     (string Vector.vector * id Vector.vector * Type.hol_type Vector.vector *
470      Term.term Vector.vector * extract_data)
471
472
473type 'a depinfo = {head : 'a * int, deps : ('a * int list) list}
474fun mapdepinfo f ({head = (a,i),deps}:'a depinfo) : 'b depinfo =
475    {head = (f a, i), deps = map (fn (a,l) => (f a, l)) deps}
476
477fun read_thm strv tmvector {name,depinfo:int depinfo,tagnames,encoded_hypscon} =
478    let
479      val depinfo = mapdepinfo (fn i => Vector.sub(strv,i)) depinfo
480      val dd = (#head depinfo, #deps depinfo)
481      val terms = map (Term.read_raw tmvector) encoded_hypscon
482    in
483      (Vector.sub(strv, name), Thm.disk_thm((dd,tagnames), terms))
484    end
485
486val dep_decode = let
487  open HOLsexp
488  fun depmunge dilist =
489      case dilist of
490          [] => NONE
491        | (n,[i]) :: rest => SOME{head = (n,i), deps = rest}
492        | _ => NONE
493in
494  Option.mapPartial depmunge o
495  list_decode (pair_decode(int_decode, list_decode int_decode))
496end
497val deptag_decode = let open HOLsexp in
498                      pair_decode(dep_decode, list_decode string_decode)
499                    end
500val thm_decode =
501    let
502      open HOLsexp
503      fun thmmunge(i,(di,tags),tms) =
504          {name = i, depinfo = di, tagnames = tags, encoded_hypscon = tms}
505    in
506      Option.map thmmunge o
507      pair3_decode (int_decode, deptag_decode, list_decode string_decode)
508    end
509
510val prsexp = HOLPP.pp_to_string 70 HOLsexp.printer
511fun force s dec t =
512    case dec t of
513        NONE => raise SharingTables ("Couldn't decode \""^s^"\": "^prsexp t)
514      | SOME t => t
515
516fun dec_sdata {with_strings,with_stridty} t =
517    let
518      open HOLsexp
519      val decoder =
520            tagged_decode "core-data" (
521              pair_decode(
522                tagged_decode "tables" (
523                  pair4_decode(
524                    dec_strings,
525                    tagged_decode "id-table"
526                       (list_decode (pair_decode(int_decode, int_decode))),
527                    tagged_decode "type-table" (list_decode shared_type_decode),
528                    tagged_decode "term-table" (list_decode shared_term_decode)
529                  )
530                ),
531                tagged_decode "exports" (
532                  pair3_decode(
533                    pair_decode( (* types *)
534                      list_decode int_decode,
535                      list_decode (pair_decode(string_decode, int_decode))
536                    ),
537                    pair_decode( (* terms *)
538                      list_decode string_decode,
539                      list_decode (pair_decode(string_decode, string_decode))
540                    ),
541                    (* theorems *) list_decode thm_decode
542                  )
543                )
544              )
545            )
546    in
547      case decoder t of
548          NONE => NONE
549        | SOME ((strv,intplist,shtylist,shtmlist),
550                ((raw_untys, raw_nmtys), (raw_untms, raw_nmtms), rawthms)) =>
551          let
552            fun sub v i = Vector.sub(v,i)
553            val _ = with_strings (fn i => Vector.sub(strv,i))
554            val idv = build_id_vector strv intplist
555            val tyv = build_type_vector idv shtylist
556            val _ = with_stridty (sub strv, sub idv, tyv)
557            val tmv = build_term_vector idv tyv shtmlist
558            val untys = map (fn i => Vector.sub(tyv,i)) raw_untys
559            val nmtys = map (fn (s,i) => (s, Vector.sub(tyv,i))) raw_nmtys
560            val untms = map (Term.read_raw tmv) raw_untms
561            val nmtms = map (fn (nm,s) => (nm, Term.read_raw tmv s)) raw_nmtms
562            val thms = map (read_thm strv tmv) rawthms
563          in
564            SOME (strv,idv,tyv,tmv,
565                  {named_types = nmtys, unnamed_types = untys,
566                   named_terms = nmtms, unnamed_terms = untms,
567                   theorems = thms})
568          end
569    end
570
571fun export_from_sharing_data (_, _, _, _, exp) = exp
572fun read_term (_,_,_,tmv,_) = Term.read_raw tmv
573fun read_string (strv,_,_,_,_) i = Vector.sub(strv,i)
574
575end; (* struct *)
576