(* ========================================================================= *)
(* Computations with finite sets of nums.                                    *)
(*                                                                           *)
(*        (c) Copyright, Clelia Lomuto, Marco Maggesi, 2009.                 *)
(*          Distributed with HOL Light under same license terms              *)
(* ========================================================================= *)
(* ------------------------------------------------------------------------- *)
(* This file defines some conversions that operate on finite sets of nums    *)
(* represented literally in a trie-like structure (we call them `ntries').   *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Example:                                                                  *)
(* # NTRIE_COMPUTE NTRIE_REDUCE_CONV                                         *)
(*   `{10, 1001, 3} INTER {3, 7, 10} SUBSET {10, 10000} UNION {3, 33}`;;     *)
(* val it : thm =                                                            *)
(* |- {10, 1001, 3} INTER {3, 7, 10} SUBSET {10, 10000} UNION {3, 33} <=> T  *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Constructors for the ntrie representation of a set of nums.               *)
(* ------------------------------------------------------------------------- *)
let NEMPTY = new_definition
  `NEMPTY:num->bool = {}`;; 
(* ------------------------------------------------------------------------- *)
(* Membership.                                                               *)
(* ------------------------------------------------------------------------- *)
let NTRIE_IN_CONV : conv =
  let tth,pths = CONJ_PAIR NTRIE_IN in
  REWR_CONV tth THENC REWRITE_CONV[pths; CONJUNCT2 ARITH_EQ];;
(* ------------------------------------------------------------------------- *)
(* Inclusion.                                                                *)
(* ------------------------------------------------------------------------- *)
let NTRIE_SUBSET_CONV : conv =
  let tth,pths = CONJ_PAIR NTRIE_SUBSET in
  REWR_CONV tth THENC REWRITE_CONV[pths];;
(* ------------------------------------------------------------------------- *)
(* Equality.                                                                 *)
(* ------------------------------------------------------------------------- *)
let NTRIE_EQ_CONV : conv =
  let tth,pths = CONJ_PAIR NTRIE_EQ in
  REWR_CONV tth THENC REWRITE_CONV[pths];;
(* ------------------------------------------------------------------------- *)
(* Singleton.                                                                *)
(* ------------------------------------------------------------------------- *)
let NTRIE_SING_CONV =
  let tth,pths = CONJ_PAIR NTRIE_SING in
  REWR_CONV tth THENC RAND_CONV(REWRITE_CONV[pths; CONJUNCT2 ARITH_EQ]);;
(* ------------------------------------------------------------------------- *)
(* Insertion.                                                                *)
(* ------------------------------------------------------------------------- *)
let NTRIE_INSERT_CONV : conv =
  let tth,pths = CONJ_PAIR NTRIE_INSERT in
  REWR_CONV tth THENC
  RAND_CONV(REWRITE_CONV[pths; CONJUNCT2 NTRIE_SING; CONJUNCT2 ARITH_EQ]);;
(* ------------------------------------------------------------------------- *)
(* Union.                                                                    *)
(* ------------------------------------------------------------------------- *)
let NTRIE_UNION_CONV : conv =
  let tth,pths = CONJ_PAIR NTRIE_UNION in
  REWR_CONV tth THENC RAND_CONV(REWRITE_CONV[pths]);;
(* ------------------------------------------------------------------------- *)
(* Intersection.                                                             *)
(* Warning: rewriting with this theorem generates ntries which are not       *)
(* "minimal".  It has to be used in conjuction with NTRIE_RELATIONS.         *)
(* ------------------------------------------------------------------------- *)
let NTRIE_INTER_CONV : conv =
  let tth,pths = CONJ_PAIR NTRIE_INTER in
  REWR_CONV tth THENC RAND_CONV(REWRITE_CONV[pths; NTRIE_RELATIONS]);;
(* ------------------------------------------------------------------------- *)
(* Deleting an element.                                                      *)
(* Warning: rewriting with this theorem generates ntries which are not       *)
(* "minimal".  It has to be used in conjuction with NTRIE_RELATIONS.         *)
(* ------------------------------------------------------------------------- *)
let NTRIE_DELETE_CONV : conv =
  let tth,pths = CONJ_PAIR NTRIE_DELETE in
  REWR_CONV tth THENC RAND_CONV(REWRITE_CONV[pths; NTRIE_RELATIONS]);;
(* ------------------------------------------------------------------------- *)
(* Disjoint.                                                                 *)
(* ------------------------------------------------------------------------- *)
let NTRIE_DISJOINT_CONV : conv =
  let tth,pths = CONJ_PAIR NTRIE_DISJOINT in
  REWR_CONV tth THENC REWRITE_CONV[pths];;
(* ------------------------------------------------------------------------- *)
(* Difference.                                                               *)
(* ------------------------------------------------------------------------- *)
let NTRIE_DIFF_CONV : conv =
  let tth,pths = CONJ_PAIR NTRIE_DIFF in
  REWR_CONV tth THENC REWRITE_CONV[pths];;
(* ------------------------------------------------------------------------- *)
(* Image.                                                                    *)
(* ------------------------------------------------------------------------- *)
let NTRIE_IMAGE_CONV : conv -> conv =
  let [c1;c2;c3] = map REWR_CONV (CONJUNCTS NTRIE_IMAGE) in
  fun cnv ->
  let rec conv tm =
    (c1 ORELSEC (c2 THENC LAND_CONV (TRY_CONV BETA_CONV THENC cnv)) ORELSEC
     (c3 THENC
      RATOR_CONV (ONCE_DEPTH_CONV BETA_CONV THENC RAND_CONV conv) THENC
      conv)) tm in
  REWR_CONV IMAGE_EQ_NTRIE_IMAGE THENC (ONCE_DEPTH_CONV BETA_CONV) THENC conv;;
(* ------------------------------------------------------------------------- *)
(* Decoding of a set in ntrie form to the usual literal representation.      *)
(* ------------------------------------------------------------------------- *)
let NTRIE_DECODE_CONV : conv =
  
(* ------------------------------------------------------------------------- *)
(* Encoding of a set from the usual literal form to the ntrie form.          *)
(* ------------------------------------------------------------------------- *)
let NTRIE_ENCODE_CONV : conv=
  let itm = `(INSERT):num->(num->bool)->num->bool`
  and th = prove (`{} = NTRIE NEMPTY`, REWRITE_TAC[NTRIE; NEMPTY]) in
  let cnv1 = REWR_CONV th
  and cnv2 cnv tm =
    let fn,arg = dest_comb tm in
    if rator fn <> itm then fail () else
    AP_TERM fn (cnv arg) in
  let rec conv tm = (cnv1 ORELSEC (cnv2 conv THENC NTRIE_INSERT_CONV)) tm in
  conv;;
(* ------------------------------------------------------------------------- *)
(* Final hack-together.                                                      *)
(* ------------------------------------------------------------------------- *)
let NTRIE_REL_CONV : conv =
  let gconv_net = itlist (uncurry net_of_conv)
    [`NTRIE s = NTRIE t`, NTRIE_EQ_CONV;
     `NTRIE s SUBSET NTRIE t`, NTRIE_SUBSET_CONV;
     `DISJOINT (NTRIE s) (NTRIE t)`, NTRIE_DISJOINT_CONV;
     `NUMERA n IN NTRIE s`, NTRIE_IN_CONV]
    (basic_net()) in
  REWRITES_CONV gconv_net;;
let NTRIE_RED_CONV : conv =
  let gconv_net = itlist (uncurry net_of_conv)
    [`NTRIE s = NTRIE t`, NTRIE_EQ_CONV;
     `NTRIE s SUBSET NTRIE t`, NTRIE_SUBSET_CONV;
     `DISJOINT (NTRIE s) (NTRIE t)`, NTRIE_DISJOINT_CONV;
     `NUMERA n IN NTRIE s`, NTRIE_IN_CONV;
     `NUMERAL n INSERT NTRIE s`, NTRIE_INSERT_CONV;
     `NTRIE s UNION NTRIE t`, NTRIE_UNION_CONV;
     `NTRIE s INTER NTRIE t`, NTRIE_INTER_CONV;
     `NTRIE s DELETE NUMERAL n`, NTRIE_DELETE_CONV;
     `NTRIE s DIFF NTRIE t`, NTRIE_DIFF_CONV]
    (basic_net()) in
  REWRITES_CONV gconv_net;;
let NTRIE_REDUCE_CONV = DEPTH_CONV NTRIE_RED_CONV;;
let NTRIE_REDUCE_TAC = CONV_TAC NTRIE_REDUCE_CONV;;
let NTRIE_COMPUTE (cnv : conv) : conv =
  ONCE_DEPTH_CONV NTRIE_ENCODE_CONV THENC
  cnv THENC
  ONCE_DEPTH_CONV NTRIE_DECODE_CONV;;