theory TreeStream = Main:

use tactics

method_setup circular_coinduction = "build_tactic (circular_coinduction_fun)" "all"
method_setup coinduction = "build_tactic (coinduction_fun)" "rule_tac R=?Rzero in ga_cogenerated, instantiate_tac Rzero %s1.?R,step"
method_setup coinduction_test = "build_tactic (coinduction_test_fun)" "rule_tac R=?Rzero in ga_cogenerated, instantiate_tac Rzero %s1.?R,step"
method_setup init = "build_tactic (init_fun)" "(simp|(solve,blast))?,init2_fun?"
method_setup breakup = "build_tactic (breakup_fun)" "simp,((exE|conjE)+)?,disjE"
method_setup solve= "build_tactic (solve_fun 1)" "((exE|conjE|conjI)+)?,(simp)?,((exE|conjE|conjI)+)?,(simp)?"
method_setup step = "build_tactic (step_fun)" "((disjI2)+)?,inst r (rcs union (trans r))"
method_setup close= "build_tactic (close_fun)" "((disjI1|disjI2)+)?,((exE|conjE)+)?,force_solve|solve,disji1+,blast"
method_setup close_or_step= "build_tactic (close_or_step_fun)" ""
method_setup force_finish = "build_tactic (force_finish_fun)" "force: inst r false,solve1"

typedecl "BinTree"
typedecl "Elem"
typedecl "Stream"
consts
"tree" :: "BinTree => Elem => BinTree => BinTree"
"left" :: "BinTree => BinTree"
"mirror" :: "BinTree => BinTree"
"node" :: "BinTree => Elem"
"right" :: "BinTree => BinTree"
"cons" :: "BinTree => Stream => Stream"
"hd" :: "Stream => BinTree"
"tl" :: "Stream => Stream"
"const" :: "BinTree => Stream"
"swap" :: "BinTree => BinTree => Stream"

consts
  BinRelImage :: "('a => 'b) => ('a => 'a => bool) => ('b => 'b => bool)"
  Trans_BinTree :: "('a => 'a => bool) => ('b => 'b => bool)"
  Trans_Stream :: "('a => 'a => bool) => ('b => 'b => bool)"
  union :: "('a => 'a => bool)  => ('a => 'a => bool) => ('a => 'a => bool)" (infixl 20)
defs
  BinRelImage_def [simp] : "BinRelImage f R == %x y . EX u v . R u v & x = f u & y = f v"
  Trans_BinTree_def [simp] : "Trans_BinTree R == (BinRelImage left R) union (BinRelImage right R)"
  Trans_Stream_def [simp] : "Trans_Stream R == (BinRelImage tl R)"
  union_def [simp] : "R union S == % x y . R x y | S x y"

axioms
  mirror_left [simp]: "!! bt1 :: BinTree . (left (mirror bt1)) = (mirror (right bt1))"
  mirror_node [simp]: "!! bt1 :: BinTree . (node (mirror bt1)) = (node bt1)"
  mirror_right [simp]: "!! bt1 :: BinTree . (right (mirror bt1)) = (mirror (left bt1))"
  const_hd [simp] : "!! bt :: BinTree . (hd (const bt)) = bt"
  const_tl [simp] : "!! bt :: BinTree . (tl (const bt)) = const bt"
  swap_hd [simp] : "!! bt1 :: BinTree . !! bt2 :: BinTree . (hd (swap bt1 bt2)) = bt1"
  swap_tl [simp] : "!! bt1 :: BinTree . !! bt2 :: BinTree . (tl (swap bt1 bt2)) = (swap bt2 bt1)"
  ga_cogenerated_BinTree: "!! R :: BinTree => BinTree => bool . !! u :: BinTree .  !! v :: BinTree . ! x :: BinTree . ! y :: BinTree .
                           ((R x) y) --> (((R (left x)) (left y)) & (node x) = (node y) & ((R (right x)) (right y))) ==> ((R u) v) ==> u = v"
  ga_selector_left: "!! X1 :: BinTree . !! X2 :: Elem . !! X3 :: BinTree . (left ((tree X1 X2) X3)) = X1"
  ga_selector_node: "!! X1 :: BinTree . !! X2 :: Elem . !! X3 :: BinTree . (node ((tree X1 X2) X3)) = X2"
  ga_selector_right: "!! X1 :: BinTree . !! X2 :: Elem . !! X3 :: BinTree . (right ((tree X1 X2) X3)) = X3"
  ga_cogenerated_Stream: "!! R :: Stream => Stream => bool . !! u :: Stream . !! v :: Stream . ! x :: Stream . ! y :: Stream .
                          ((R x) y) --> ((hd x) = (hd y) & ((R (tl x)) (tl y)))  ==> ((R u) v) ==> u = v"
  ga_selector_hd: "! X1 :: BinTree . ! X2 :: Stream . (hd (cons X1 X2)) = X1"
  ga_selector_tl: "! X1 :: BinTree . ! X2 :: Stream . (tl (cons X1 X2)) = X2"


(*theorem Tree_mirror: "!! b :: BinTree . mirror(mirror b) = b & x y=x y & x= z"
apply(rule conjI)
defer
apply(rule conjI)
defer
defer
apply(rule ga_cogenerated_BinTree)
apply(coinduction_test)
apply(circular_coinduction)
done

declare Tree_mirror [simp]*)


theorem TreeStream_swapmirror_const: "!! b :: BinTree . (swap (mirror(mirror b)) b = const b)"
(*apply(circular_coinduction)*)

apply(coinduction)
apply(init)
apply(breakup)
apply(solve)

(* second coinduction would start here (does not work yet)*)
apply(coinduction_test)


apply(init)


apply(step)
apply(solve)

apply(rule_tac x=x in exI)
apply(rule_tac x=y in exI)

apply(solve)
apply(close)
apply(close)

apply(breakup)

apply(solve)
apply(rule disjI1)
apply(blast)

apply(force_finish)
done

end
 
