Theory Intensional

(*  Title:       A Definitional Encoding of TLA in Isabelle/HOL
    Authors:     Gudmund Grov <ggrov at inf.ed.ac.uk>
                 Stephan Merz <Stephan.Merz at loria.fr>
    Year:        2011
    Maintainer:  Gudmund Grov <ggrov at inf.ed.ac.uk>
*)

section ‹Representing Intensional Logic›

theory Intensional 
imports Main
begin

text‹
  In higher-order logic, every proof rule has a corresponding tautology, i.e.
  the \emph{deduction theorem} holds. Isabelle/HOL implements this since object-level
  implication ($\longrightarrow$) and meta-level entailment ($\Longrightarrow$) 
  commute, viz. the proof rule impI:› @{thm impI}. 
  However, the deduction theorem does not hold for 
  most modal and temporal logics cite‹page 95› in "Lamport02"cite"Merz98".
  For example $A \vdash \Box A$ holds, meaning that if $A$ holds in any world, then
  it always holds. However, $\vdash A \longrightarrow \Box A$, stating that 
  $A$ always holds if it initially holds, is not valid.

  Merz  cite"Merz98" overcame this problem by creating an
  @{term Intensional} logic. It exploits Isabelle's 
  axiomatic type class feature  cite"Wenzel00b" by creating a type
  class @{term world}, which provides Skolem constants to associate formulas
  with the world they hold in. The class is trivial, not requiring any axioms.
›

class world 
text @{term world} is a type class of possible worlds. It is a subclass
  of all HOL types @{term type}. No axioms are provided, since its only
  purpose is to avoid silly use of the @{term Intensional} syntax.
›

subsection‹Abstract Syntax and Definitions›


type_synonym ('w,'a) expr = "'w  'a"         
type_synonym  'w form = "('w, bool) expr"

text ‹The intention is that @{typ 'a} will be used for unlifted
types (class @{term type}), while @{typ 'w} is lifted (class @{term world}). 
›


definition Valid :: "('w::world) form  bool"
  where "Valid A  w. A w"

definition const :: "'a  ('w::world, 'a) expr"
  where unl_con: "const c w  c"

definition lift :: "['a  'b, ('w::world, 'a) expr]  ('w,'b) expr"
  where unl_lift: "lift f x w  f (x w)"

definition lift2 :: "['a  'b  'c, ('w::world,'a) expr, ('w,'b) expr]  ('w,'c) expr"
  where unl_lift2: "lift2 f x y w  f (x w) (y w)"

definition lift3 :: "['a  'b => 'c  'd, ('w::world,'a) expr, ('w,'b) expr, ('w,'c) expr]  ('w,'d) expr"
  where unl_lift3: "lift3 f x y z w  f (x w) (y w) (z w)"

definition lift4 :: "['a  'b => 'c  'd  'e, ('w::world,'a) expr, ('w,'b) expr, ('w,'c) expr,('w,'d) expr]  ('w,'e) expr"
  where unl_lift4: "lift4 f x y z zz w  f (x w) (y w) (z w) (zz w)"

text @{term "Valid F"} asserts that the lifted formula @{term F} holds everywhere.
  @{term const} allows lifting of a constant, while @{term lift} through
  @{term lift4} allow functions with arity 1--4 to be lifted. (Note that there
  is no way to define a generic lifting operator for functions of arbitrary arity.)
›

definition RAll :: "('a  ('w::world) form)  'w form"  (binder Rall 10)
  where unl_Rall: "(Rall x. A x) w  x. A x w"

definition REx :: "('a  ('w::world) form)  'w form"  (binder Rex 10)
  where unl_Rex: "(Rex x. A x) w  x. A x w"

definition REx1 :: "('a  ('w::world) form)  'w form"  (binder Rex! 10)
  where unl_Rex1: "(Rex! x. A x) w  ∃!x. A x w"

text @{term RAll}, @{term REx} and @{term REx1} introduces ``rigid'' quantification
  over values (of non-world types) within ``intensional'' formulas. @{term RAll}
  is universal quantification, @{term REx} is existential quantifcation.
  @{term REx1} requires unique existence.
›

text ‹
  We declare the ``unlifting rules'' as rewrite rules that will be applied
  automatically.
›

lemmas intensional_rews[simp] = 
  unl_con unl_lift unl_lift2 unl_lift3 unl_lift4 
  unl_Rall unl_Rex unl_Rex1



subsection‹Concrete Syntax›

nonterminal
  lift and liftargs

text‹
  The non-terminal @{term lift} represents lifted expressions. The idea is to use 
  Isabelle's macro mechanism to convert between the concrete and abstract syntax.
›

syntax
  ""            :: "id  lift"                          (‹_›)
  ""            :: "longid  lift"                      (‹_›)
  ""            :: "var  lift"                         (‹_›)
  "_applC"      :: "[lift, cargs]  lift"               ((1_/ _) [1000, 1000] 999)
  ""            :: "lift  lift"                        ('(_'))
  "_lambda"     :: "[idts, 'a]  lift"                  ((3%_./ _) [0, 3] 3)
  "_constrain"  :: "[lift, type]  lift"                ((_::_) [4, 0] 3)
  ""            :: "lift  liftargs"                    (‹_›)
  "_liftargs"   :: "[lift, liftargs]  liftargs"        (‹_,/ _›)
  "_Valid"      :: "lift  bool"                        (( _) 5)
  "_holdsAt"    :: "['a, lift]  bool"                  ((_  _) [100,10] 10)

  (* Syntax for lifted expressions outside the scope of ⊢ or ⊨.*)
  "LIFT"        :: "lift  'a"                          (LIFT _›)

  (* generic syntax for lifted constants and functions *)
  "_const"      :: "'a  lift"                          ((#_) [1000] 999)
  "_lift"       :: "['a, lift]  lift"                  ((_<_>) [1000] 999)
  "_lift2"      :: "['a, lift, lift]  lift"            ((_<_,/ _>) [1000] 999)
  "_lift3"      :: "['a, lift, lift, lift]  lift"      ((_<_,/ _,/ _>) [1000] 999)
  "_lift4"      :: "['a, lift, lift, lift,lift]  lift"      ((_<_,/ _,/ _,/ _>) [1000] 999)

  (* concrete syntax for common infix functions: reuse same symbol *)
  "_liftEqu"    :: "[lift, lift]  lift"                ((_ =/ _) [50,51] 50)
  "_liftNeq"    :: "[lift, lift]  lift"                (infixl  50)
  "_liftNot"    :: "lift  lift"                        (¬ _› [90] 90)
  "_liftAnd"    :: "[lift, lift]  lift"                (infixr  35)
  "_liftOr"     :: "[lift, lift]  lift"                (infixr  30)
  "_liftImp"    :: "[lift, lift]  lift"                (infixr  25)
  "_liftIf"     :: "[lift, lift, lift]  lift"          ((if (_)/ then (_)/ else (_)) 10)
  "_liftPlus"   :: "[lift, lift]  lift"                ((_ +/ _) [66,65] 65)
  "_liftMinus"  :: "[lift, lift]  lift"                ((_ -/ _) [66,65] 65)
  "_liftTimes"  :: "[lift, lift]  lift"                ((_ */ _) [71,70] 70)
  "_liftDiv"    :: "[lift, lift]  lift"                ((_ div _) [71,70] 70)
  "_liftMod"    :: "[lift, lift]  lift"                ((_ mod _) [71,70] 70)
  "_liftLess"   :: "[lift, lift]  lift"                ((_/ < _)  [50, 51] 50)
  "_liftLeq"    :: "[lift, lift]  lift"                ((_/  _) [50, 51] 50)
  "_liftMem"    :: "[lift, lift]  lift"                ((_/  _) [50, 51] 50)
  "_liftNotMem" :: "[lift, lift]  lift"                ((_/  _) [50, 51] 50)
  "_liftFinset" :: "liftargs => lift"                    ({(_)})
  (** TODO: syntax for lifted collection / comprehension **)
  "_liftPair"   :: "[lift,liftargs]  lift"                   ((1'(_,/ _')))
  (* infix syntax for list operations *)
  "_liftCons" :: "[lift, lift]  lift"                  ((_ #/ _) [65,66] 65)
  "_liftApp"  :: "[lift, lift]  lift"                  ((_ @/ _) [65,66] 65)
  "_liftList" :: "liftargs  lift"                      ([(_)])

  (* Rigid quantification (syntax level) *)
  "_ARAll"  :: "[idts, lift]  lift"                    ((3! _./ _) [0, 10] 10)
  "_AREx"   :: "[idts, lift]  lift"                    ((3? _./ _) [0, 10] 10)
  "_AREx1"  :: "[idts, lift]  lift"                    ((3?! _./ _) [0, 10] 10)
  "_RAll"       :: "[idts, lift]  lift"                ((3_./ _) [0, 10] 10)
  "_REx"        :: "[idts, lift]  lift"                ((3_./ _) [0, 10] 10)
  "_REx1"       :: "[idts, lift]  lift"                ((3∃!_./ _) [0, 10] 10)

translations
  "_const"          "CONST const"

translations
  "_lift"          "CONST lift"
  "_lift2"         "CONST lift2"
  "_lift3"         "CONST lift3"
  "_lift4"         "CONST lift4"
  "_Valid"         "CONST Valid"

translations
  "_RAll x A"      "Rall x. A"
  "_REx x A"       "Rex x. A"
  "_REx1 x A"      "Rex! x. A"

translations
  "_ARAll"          "_RAll"
  "_AREx"          "_REx"
  "_AREx1"         "_REx1"

  "w  A"         "A w"
  "LIFT A"         "A::__"

translations
  "_liftEqu"       "_lift2 (=)"
  "_liftNeq u v"   "_liftNot (_liftEqu u v)"
  "_liftNot"       "_lift (CONST Not)"
  "_liftAnd"       "_lift2 (&)"
  "_liftOr"        "_lift2 ((|) )"
  "_liftImp"       "_lift2 (-->)"
  "_liftIf"        "_lift3 (CONST If)"
  "_liftPlus"      "_lift2 (+)"
  "_liftMinus"     "_lift2 (-)"
  "_liftTimes"     "_lift2 (*)"
  "_liftDiv"       "_lift2 (div)"
 "_liftMod"       "_lift2 (mod)"
  "_liftLess"      "_lift2 (<)"
  "_liftLeq"       "_lift2 (<=)"
  "_liftMem"       "_lift2 (:)"
  "_liftNotMem x xs"              "_liftNot (_liftMem x xs)"

translations
  "_liftFinset (_liftargs x xs)"  "_lift2 (CONST insert) x (_liftFinset xs)"
  "_liftFinset x"                 "_lift2 (CONST insert) x (_const (CONST Set.empty))"
  "_liftPair x (_liftargs y z)"   "_liftPair x (_liftPair y z)"
  "_liftPair"                     "_lift2 (CONST Pair)"
  "_liftCons"                     "_lift2 (CONST Cons)"
  "_liftApp"                      "_lift2 (@)"
  "_liftList (_liftargs x xs)"    "_liftCons x (_liftList xs)"
  "_liftList x"                   "_liftCons x (_const [])"

  "w  ¬ A"  "_liftNot A w"
  "w  A  B"  "_liftAnd A B w"
  "w  A  B"  "_liftOr A B w"
  "w  A  B"  "_liftImp A B w"
  "w  u = v"  "_liftEqu u v w"
  "w  x. A"  "_RAll x A w"
  "w  x. A"  "_REx x A w"
  "w  ∃!x. A"  "_REx1 x A w"

syntax (ASCII)
  "_Valid"      :: "lift  bool"                        ((|- _) 5)
  "_holdsAt"    :: "['a, lift]  bool"                  ((_ |= _) [100,10] 10)
  "_liftNeq"    :: "[lift, lift]  lift"                ((_ ~=/ _) [50,51] 50)
  "_liftNot"    :: "lift  lift"                        ((~ _) [90] 90)
  "_liftAnd"    :: "[lift, lift]  lift"                ((_ &/ _) [36,35] 35)
  "_liftOr"     :: "[lift, lift]  lift"                ((_ |/ _) [31,30] 30)
  "_liftImp"    :: "[lift, lift]  lift"                ((_ -->/ _) [26,25] 25)
  "_liftLeq"    :: "[lift, lift]  lift"                ((_/ <= _) [50, 51] 50)
  "_liftMem"    :: "[lift, lift]  lift"                ((_/ : _) [50, 51] 50)
  "_liftNotMem" :: "[lift, lift]  lift"                ((_/ ~: _) [50, 51] 50)
  "_RAll" :: "[idts, lift]  lift"                      ((3ALL _./ _) [0, 10] 10)
  "_REx"  :: "[idts, lift]  lift"                      ((3EX _./ _) [0, 10] 10)
  "_REx1" :: "[idts, lift]  lift"                      ((3EX! _./ _) [0, 10] 10)


subsection ‹Lemmas and Tactics›

lemma intD[dest]: " A  w  A"
proof -
  assume a:" A"
  from a have "w. w  A" by (auto simp add: Valid_def)
  thus ?thesis ..
qed

lemma intI [intro!]: assumes P1:"( w. w  A)" shows " A"
  using assms by (auto simp: Valid_def)

text‹
  Basic unlifting introduces a parameter @{term w} and applies basic rewrites, e.g 
  @{term " F = G"} becomes @{term "F w = G w"} and @{term " F  G"} becomes   
  @{term "F w  G w"}.
›

method_setup int_unlift = Scan.succeed (fn ctxt => SIMPLE_METHOD'
    (resolve_tac ctxt @{thms intI} THEN' rewrite_goal_tac ctxt @{thms intensional_rews})) "method to unlift and followed by intensional rewrites"

lemma inteq_reflection: assumes P1: " x=y" shows  "(x  y)"
proof -
  from P1 have P2: "w. x w = y w" by (unfold Valid_def unl_lift2)
  hence P3:"x=y" by blast
  thus "x  y" by (rule "eq_reflection")
qed

lemma int_simps:
  " (x=x) = #True"
  " (¬ #True) = #False"
  " (¬ #False) = #True"
  " (¬¬ P) = P"
  " ((¬ P) = P) = #False"
  " (P = (¬P)) = #False"
  " (P  Q) = (P = (¬ Q))"
  " (#True=P) = P"
  " (P=#True) = P"
  " (#True  P) = P"
  " (#False  P) = #True"
  " (P  #True) = #True"
  " (P  P) = #True"
  " (P  #False) = (¬P)"
  " (P  ~P) = (¬P)"
  " (P  #True) = P"
  " (#True  P) = P"
  " (P  #False) = #False"
  " (#False  P) = #False"
  " (P  P) = P"
  " (P  ~P) = #False"
  " (¬P  P) = #False"
  " (P  #True) = #True"
  " (#True  P) = #True"
  " (P  #False) = P"
  " (#False  P) = P"
  " (P  P) = P"
  " (P  ¬P) = #True"
  " (¬P  P) = #True"
  " ( x. P) = P"
  " ( x. P) = P"
  by auto

lemmas intensional_simps[simp] = int_simps[THEN inteq_reflection]

method_setup int_rewrite = Scan.succeed (fn ctxt => SIMPLE_METHOD' (rewrite_goal_tac ctxt @{thms intensional_simps})) "rewrite method at intensional level"

lemma Not_Rall: " (¬( x. F x)) = ( x. ¬F x)"
  by auto

lemma Not_Rex: " (¬( x. F x)) = ( x. ¬F x)"
  by auto

lemma TrueW [simp]: " #True"
  by auto

lemma int_eq: " X = Y  X = Y"
  by (auto simp: inteq_reflection)

lemma int_iffI: 
  assumes " F  G" and " G  F"
  shows " F = G"
  using assms by force

lemma int_iffD1: assumes h: " F = G" shows " F  G"
  using h by auto

lemma int_iffD2: assumes h: " F = G" shows " G  F"
  using h by auto

lemma lift_imp_trans: 
  assumes " A  B" and " B  C"
  shows " A  C"
  using assms by force

lemma lift_imp_neg: assumes " A  B" shows " ¬B  ¬A"
  using assms by auto

lemma lift_and_com:  " (A  B) = (B  A)"
  by auto

end