Theory CoCallGraph

theory CoCallGraph
imports Launchbury.Vars "Launchbury.HOLCF-Join-Classes" "Launchbury.HOLCF-Utils" "Set-Cpo"
begin

default_sort type

typedef CoCalls = "{G :: (var × var) set.  sym G}"
  morphisms Rep_CoCall Abs_CoCall
  by (auto intro: exI[where x = "{}"] symI)

setup_lifting type_definition_CoCalls

instantiation CoCalls :: po
begin
lift_definition below_CoCalls :: "CoCalls  CoCalls  bool" is "(⊆)".
instance
  apply standard
  apply ((transfer, auto)+)
  done
end

lift_definition coCallsLub :: "CoCalls set  CoCalls" is "λ S.  S"
  by (auto intro: symI elim: symE)

lemma coCallsLub_is_lub: "S <<| coCallsLub S"
proof (rule is_lubI)
  show "S <| coCallsLub S"
    by (rule is_ubI, transfer, auto)
next
  fix u
  assume "S <| u"
  hence "x  S. x  u" by (auto dest: is_ubD)
  thus "coCallsLub S  u" by transfer auto
qed

instance CoCalls :: cpo
proof
  fix S :: "nat  CoCalls"
  show "x. range S <<| x" using coCallsLub_is_lub..
qed

lemma ccLubTransfer[transfer_rule]: "(rel_set pcr_CoCalls ===> pcr_CoCalls) Union lub"
proof-
  have "lub = coCallsLub"
    apply (rule)
    apply (rule lub_eqI)
    apply (rule coCallsLub_is_lub)
    done
  with coCallsLub.transfer
  show ?thesis by metis
qed

lift_definition is_cc_lub :: "CoCalls set  CoCalls  bool" is "(λ S x . x = Union S)".

lemma ccis_lubTransfer[transfer_rule]: "(rel_set pcr_CoCalls  ===> pcr_CoCalls ===> (=)) (λ S x . x = Union S) (<<|)"
proof-
  have " x xa . is_cc_lub x xa  xa = coCallsLub x" by transfer auto
  hence "is_cc_lub = (<<|)"
  apply -
  apply (rule, rule)
  by (metis coCallsLub_is_lub is_lub_unique)
  thus ?thesis using is_cc_lub.transfer by simp
qed

lift_definition coCallsJoin :: "CoCalls  CoCalls   CoCalls" is "(∪)"
    by (rule sym_Un)

lemma ccJoinTransfer[transfer_rule]: "(pcr_CoCalls ===> pcr_CoCalls ===> pcr_CoCalls) (∪) (⊔)"
proof-
  have "(⊔) = coCallsJoin"
    apply (rule)
    apply rule
    apply (rule lub_is_join)
    unfolding is_lub_def is_ub_def
    apply transfer
    apply auto
    done
  with coCallsJoin.transfer
  show ?thesis by metis
qed

lift_definition ccEmpty :: "CoCalls" is "{}" by (auto intro: symI)

lemma ccEmpty_below[simp]: "ccEmpty  G"
  by transfer auto

instance CoCalls :: pcpo
proof
  have "y . ccEmpty  y" by transfer simp
  thus "x. y. (x::CoCalls)  y"..
qed

lemma ccBotTransfer[transfer_rule]: "pcr_CoCalls {} "
proof-
  have "x. ccEmpty  x" by transfer simp
  hence "ccEmpty = " by (rule bottomI)
  thus ?thesis using ccEmpty.transfer by simp
qed

lemma cc_lub_below_iff:
  fixes G :: CoCalls
  shows "lub X  G  ( G'X. G'  G)" 
  by transfer auto

lift_definition ccField :: "CoCalls  var set" is Field.

lemma ccField_nil[simp]: "ccField  = {}"
  by transfer auto

lift_definition
  inCC :: "var  var  CoCalls  bool" ("_--__" [1000, 1000, 900] 900)
  is "λ x y s. (x,y)  s".

abbreviation
  notInCC :: "var  var  CoCalls  bool" ("_--__" [1000, 1000, 900] 900)
  where "x--yS  ¬ x--yS"

lemma notInCC_bot[simp]: "x--y  False"
  by transfer auto

lemma below_CoCallsI:
   "( x y. x--yG  x--yG')  G  G'"
  by transfer auto

lemma CoCalls_eqI:
   "( x y. x--yG  x--yG')  G = G'"
  by transfer auto

lemma in_join[simp]:
  "x--y  (GG')  x--yG  x--yG'"
by transfer auto

lemma in_lub[simp]: "x--y(lub S)  ( GS. x--yG)"
  by transfer auto

lemma in_CoCallsLubI:
  "x--yG  G  S  x--ylub S"
by transfer auto

lemma adm_not_in[simp]:
  assumes "cont t"
  shows "adm (λa. x--yt a)"
  by (rule admI) (auto simp add: cont2contlubE[OF assms])

lift_definition cc_delete :: "var  CoCalls  CoCalls"
  is "λ z. Set.filter (λ (x,y) . x  z  y  z)"
  by (auto intro!: symI elim: symE)

lemma ccField_cc_delete: "ccField (cc_delete x S)  ccField S - {x}"
  by transfer (auto simp add: Field_def )

lift_definition ccProd :: "var set  var set  CoCalls" (infixr "" 90)
  is "λ S1 S2. S1 × S2  S2 × S1"
  by (auto intro!: symI elim: symE)

lemma ccProd_empty[simp]: "{}  S = " by transfer auto

lemma ccProd_empty'[simp]: "S  {} = " by transfer auto

lemma ccProd_union2[simp]: "S  (S'  S'') = S  S'  S  S''"
  by transfer auto

lemma ccProd_Union2[simp]: "S  S' = ( XS'. ccProd S X)"
  by transfer auto

lemma ccProd_Union2'[simp]: "S  (XS'. f X) = ( XS'. ccProd S (f X))"
  by transfer auto

lemma in_ccProd[simp]: "x--y(S  S') = (x  S  y  S'  x  S'  y  S)"
  by transfer auto

lemma ccProd_union1[simp]: "(S'  S'')  S = S'  S  S''  S"
  by transfer auto

lemma ccProd_insert2: "S  insert x S' = S  {x}  S  S'"
  by transfer auto

lemma ccProd_insert1: "insert x S'  S = {x}  S  S'  S"
  by transfer auto

lemma ccProd_mono1: "S'  S''  S'  S  S''  S"
  by transfer auto

lemma ccProd_mono2: "S'  S''  S  S'  S  S''"
  by transfer auto

lemma ccProd_mono: "S  S'  T  T'  S  T  S'  T'"
  by transfer auto

lemma ccProd_comm: "S  S' = S'  S" by transfer auto

lemma ccProd_belowI:
   "( x y. x  S  y  S'  x--yG)  S  S'  G"
  by transfer (auto elim: symE)


lift_definition cc_restr :: "var set  CoCalls  CoCalls"
  is "λ S. Set.filter (λ (x,y) . x  S  y  S)"
  by (auto intro!: symI elim: symE)

abbreviation cc_restr_sym (infixl "G|`"  110) where "G G|` S  cc_restr S G"

lemma elem_cc_restr[simp]: "x--y(G G|` S) = (x--yG  x  S  y  S)"
  by transfer auto

lemma ccField_cc_restr: "ccField (G G|` S)  ccField G  S"
  by transfer (auto simp add: Field_def)

lemma cc_restr_empty: "ccField G  - S  G G|` S = "
  apply transfer
  apply (auto simp add: Field_def)
  apply (drule DomainI)
  apply (drule (1) subsetD)
  apply simp
  done

lemma cc_restr_empty_set[simp]: "cc_restr {} G = "
  by transfer auto
  
lemma cc_restr_noop[simp]: "ccField G  S  cc_restr S G = G"
  by transfer (force simp add: Field_def dest: DomainI RangeI elim: subsetD)

lemma cc_restr_bot[simp]: "cc_restr S  = "
  by simp

lemma ccRestr_ccDelete[simp]: "cc_restr (-{x}) G = cc_delete x G"
  by transfer auto

lemma cc_restr_join[simp]:
  "cc_restr S (G  G') = cc_restr S G  cc_restr S G'"
by transfer auto

lemma cont_cc_restr: "cont (cc_restr S)"
  apply (rule contI)
  apply (thin_tac "chain _")
  apply transfer
  apply auto
  done

lemmas cont_compose[OF cont_cc_restr, cont2cont, simp]

lemma cc_restr_mono1:
  "S  S'  cc_restr S G  cc_restr S' G" by transfer auto

lemma cc_restr_mono2:
  "G  G'  cc_restr S G  cc_restr S G'" by transfer auto

lemma cc_restr_below_arg:
  "cc_restr S G  G" by transfer auto

lemma cc_restr_lub[simp]:
  "cc_restr S (lub X) = ( GX. cc_restr S G)" by transfer auto

lemma elem_to_ccField: "x--yG  x  ccField G  y  ccField G"
  by transfer (auto simp add: Field_def)

lemma ccField_to_elem: "x  ccField G   y. x--yG"
  by transfer (auto simp add: Field_def dest: symD)

lemma cc_restr_intersect: "ccField G  ((S - S')  (S' - S)) = {}  cc_restr S G = cc_restr S' G"
  by (rule CoCalls_eqI) (auto dest: elem_to_ccField)

lemma cc_restr_cc_restr[simp]: "cc_restr S (cc_restr S' G) = cc_restr (S  S') G"
  by transfer auto

lemma cc_restr_twist: "cc_restr S (cc_restr S' G) = cc_restr S' (cc_restr S G) "
  by transfer auto

lemma cc_restr_cc_delete_twist: "cc_restr x (cc_delete S G) = cc_delete S (cc_restr x G)"
  by transfer auto

lemma cc_restr_ccProd[simp]:
  "cc_restr S (ccProd S1 S2) = ccProd (S1  S) (S2  S)"
  by transfer auto

lemma ccProd_below_cc_restr:
  "ccProd S S'  cc_restr S'' G  ccProd S S'  G  (S = {}  S' = {}  S  S''  S'  S'')"
  by transfer auto

lemma cc_restr_eq_subset: "S  S'  cc_restr S' G = cc_restr S' G2  cc_restr S G = cc_restr S G2"
  by transfer' (auto simp add: Set.filter_def)
 
definition ccSquare ("_2" [80] 80)
  where "S2 = ccProd S S"

lemma ccField_ccSquare[simp]: "ccField (S2) = S"
  unfolding ccSquare_def by transfer (auto simp add: Field_def)
  
lemma below_ccSquare[iff]: "(G  S2) = (ccField G  S)"
  unfolding ccSquare_def by transfer (auto simp add: Field_def)

lemma cc_restr_ccSquare[simp]: "(S'2) G|` S = (S'  S)2"
  unfolding ccSquare_def by auto

lemma ccSquare_empty[simp]: "{}2 = "
  unfolding ccSquare_def by simp

lift_definition ccNeighbors :: "var  CoCalls  var set" 
  is "λ x G. {y .(y,x)  G  (x,y)  G}".

lemma ccNeighbors_bot[simp]: "ccNeighbors x  = {}" by transfer auto

lemma cont_ccProd1:
  "cont (λ S. ccProd S S')"
  apply (rule contI)
  apply (thin_tac "chain _")
  apply (subst lub_set)
  apply transfer
  apply auto
  done

lemma cont_ccProd2:
  "cont (λ S'. ccProd S S')"
  apply (rule contI)
  apply (thin_tac "chain _")
  apply (subst lub_set)
  apply transfer
  apply auto
  done

lemmas cont_compose2[OF cont_ccProd1 cont_ccProd2, simp, cont2cont]

lemma cont_ccNeighbors[THEN cont_compose, cont2cont, simp]:
  "cont (λy. ccNeighbors x y)"
  apply (rule set_contI)
  apply (thin_tac "chain _")
  apply transfer
  apply auto
  done 


lemma ccNeighbors_join[simp]: "ccNeighbors x (G  G') = ccNeighbors x G  ccNeighbors x G'"
  by transfer auto

lemma ccNeighbors_ccProd:
  "ccNeighbors x (ccProd S S') = (if x  S then S' else {})  (if x  S' then S else {})"
by transfer auto

lemma ccNeighbors_ccSquare: 
  "ccNeighbors x (ccSquare S) = (if x  S then S else {})"
  unfolding ccSquare_def by (auto simp add: ccNeighbors_ccProd)

lemma ccNeighbors_cc_restr[simp]:
  "ccNeighbors x (cc_restr S G) = (if x  S then ccNeighbors x G  S else {})"
by transfer auto

lemma ccNeighbors_mono:
  "G  G'  ccNeighbors x G  ccNeighbors x G'"
  by transfer auto

lemma subset_ccNeighbors:
  "S  ccNeighbors x G  ccProd {x} S  G"
  by transfer (auto simp add: sym_def)

lemma elem_ccNeighbors[simp]:
  "y  ccNeighbors x G  (y--xG)"
  by transfer (auto simp add: sym_def)

lemma ccNeighbors_ccField:
  "ccNeighbors x G  ccField G" by transfer (auto simp add: Field_def)

lemma ccNeighbors_disjoint_empty[simp]:
  "ccNeighbors x G = {}  x  ccField G"
  by transfer (auto simp add: Field_def)

instance CoCalls :: Join_cpo
  by standard (metis coCallsLub_is_lub)

lemma ccNeighbors_lub[simp]: "ccNeighbors x (lub Gs) = lub (ccNeighbors x ` Gs)"
  by transfer (auto simp add: lub_set)

inductive list_pairs :: "'a list  ('a × 'a)  bool"
  where "list_pairs xs p  list_pairs (x#xs) p"
      | "y  set xs  list_pairs (x#xs) (x,y)"

lift_definition ccFromList :: "var list  CoCalls" is "λ xs. {(x,y). list_pairs xs (x,y)  list_pairs xs (y,x)}"
  by (auto intro: symI)

lemma ccFromList_Nil[simp]: "ccFromList [] = "
  by transfer (auto elim: list_pairs.cases)

lemma ccFromList_Cons[simp]: "ccFromList (x#xs) = ccProd {x} (set xs)  ccFromList xs"
  by transfer (auto elim: list_pairs.cases intro: list_pairs.intros)

lemma ccFromList_append[simp]: "ccFromList (xs@ys) = ccFromList xs  ccFromList ys  ccProd (set xs) (set ys)"
  by (induction xs) (auto simp add: ccProd_insert1[where S' = "set xs" for xs])

lemma ccFromList_filter[simp]:
  "ccFromList (filter P xs) = cc_restr {x. P x} (ccFromList xs)"
by (induction xs) (auto simp add: Collect_conj_eq)

lemma ccFromList_replicate[simp]: "ccFromList (replicate n x) = (if n  1 then   else ccProd {x} {x})"
  by (induction n) auto

definition ccLinear :: "var set  CoCalls  bool"
  where "ccLinear S G = ( xS.  yS. x--yG)"

lemma ccLinear_bottom[simp]:
  "ccLinear S "
  unfolding ccLinear_def by simp

lemma ccLinear_empty[simp]:
  "ccLinear {} G"
  unfolding ccLinear_def by simp

lemma ccLinear_lub[simp]:
  "ccLinear S (lub X) = ( GX. ccLinear S G)"
 unfolding ccLinear_def by auto

(*
lemma ccLinear_ccNeighbors:
  "ccLinear S G ⟹ ccNeighbors S G ∩ S = {}"
 unfolding ccLinear_def by transfer auto
*)

lemma ccLinear_cc_restr[intro]:
  "ccLinear S G  ccLinear S (cc_restr S' G)"
 unfolding ccLinear_def by transfer auto

(* TODO: Sort *)

lemma ccLinear_join[simp]:
  "ccLinear S (G  G')  ccLinear S G  ccLinear S G'"
  unfolding ccLinear_def
  by transfer auto

lemma ccLinear_ccProd[simp]:
  "ccLinear S (ccProd S1 S2)  S1  S = {}  S2  S = {}"
  unfolding ccLinear_def
  by transfer auto

lemma ccLinear_mono1: "ccLinear S' G  S  S'  ccLinear S G"
  unfolding ccLinear_def
  by transfer auto

lemma ccLinear_mono2: "ccLinear S G'  G  G'  ccLinear S G"
  unfolding ccLinear_def
  by transfer auto

lemma ccField_join[simp]:
  "ccField (G  G') = ccField G  ccField G'" by transfer auto

lemma ccField_lub[simp]:
  "ccField (lub S) = (ccField ` S)" by transfer auto

lemma ccField_ccProd:
  "ccField (ccProd S S') = (if S = {} then {} else if S' = {} then {} else  S  S')"
  by transfer (auto simp add: Field_def)

lemma ccField_ccProd_subset:
  "ccField (ccProd S S')   S  S'"
  by (simp add: ccField_ccProd)

lemma cont_ccField[THEN cont_compose, simp, cont2cont]:
  "cont ccField"
  by (rule set_contI) auto

end