You are an expert Lean4 and formal verification agent proving a Lean4 theorem. Your output **must** strictly adhere to the specified format.

### Input Information
You will receive the following components, relevant to the target theorem:
* <all_available_defs>: Definitions available from imported modules (either from the current Lean repository or from Mathlib)
* <all_available_lemmas>: Lemmas/theorems available that may assist the proof.
* <local_ctx>...</local_ctx>: The local file context (imports, namespaces, definitions, comments, etc.) from the top of the file up to—but not including—the target theorem or any previously defined local lemmas/theorems.
* <target_theorem>...</target_theorem>: The target theorem statement, ending with `:=`.

**Notes**
1. Definitions include their full bodies, but for definitions whose bodies contain proofs, the proof parts are replaced by `admit` (i.e., admit /- proof elided -/), while the rest of the definition is kept unchanged; lemmas include only their statements.
2. You may freely reference any definition or lemma contained in these tags without redefining them.
3. The tags for available definitions and lemmas (all_available_defs, all_available_lemmas) may be omitted if empty.

### Output Format & Requirements
Your output MUST contain a complete, syntactically correct Lean 4 proof for the target theorem.

**Strict Output Structure:**
<reasoning> 
...
</reasoning> 

<lean4_invented_lemmas>
-- each lemma is a full Lean 4 declaration with a complete proof
...
</lean4_invented_lemmas>

<lean4_proof>
-- Lean 4 proof body of the target theorem
...
</lean4_proof>

**Requirements:**
1. <reasoning> and <lean4_invented_lemmas> are OPTIONAL. Include them only if they aid proof construction.
2. <lean4_proof> MUST contain only the proof body (tactics/terms), starting by "by", NOT the theorem declaration.
3. <lean4_invented_lemmas> (if present) MUST contain syntactically correct lemma declarations that type checks AND complete proof bodies. Defining a lemma using `axiom` is NOT allowed.
4. <reasoning> contains high-level proof planning.
5. If you create a lemma under <lean4_invented_lemmas> whose name is namespaced (e.g., X.Y.Z), you MUST always refer to it using its fully qualified name. Do NOT rely on shortened names. For example, write rw [X.Y.Z], not rw [Z] for invented lemmas.
6. All Lean 4 code MUST be syntactically correct. No `sorry`, `admit`, or non-Lean text. Comments allowed using `--` or `/- ... -/`.
7. Follow the tags and structure EXACTLY. No extra text before, between, or after the sections.
8. Do NOT wrap invented lemmas in a `mutual` block unless they have genuine mutual recursion. Declare each lemma independently.

### Examples are provided here (example input are under "User Prompt", and example assistant response are under "Agent Response"):
Example 1 ------------------- 
User Prompt:
<all_available_defs>
structure BitVec (w : Nat) where
  /-- Construct a `BitVec w` from a number less than `2^w`.
  O(1), because we use `Fin` as the internal representation of a bitvector. -/
  ofFin ::

  /-- Interpret a bitvector as a number less than `2^w`.
  O(1), because we use `Fin` as the internal representation of a bitvector. -/
  toFin : Fin (hPow 2 w)
</all_available_defs>

<all_available_lemmas>
theorem List.getElem_append_left{α : Type u_1} {l₁ l₂ : List α} {i : Nat} (hn : i < l₁.length) : (l₁ ++ l₂)[i] = l₁[i]
theorem getElem_eq_testBit_toNat (x : BitVec w) (i : Nat) (h : i < w) :
  x[i] = x.toNat.testBit i := rfl
@[simp, grind =] theorem toNat_cons (b : Bool) (x : BitVec w) :
    (cons b x).toNat = (b.toNat <<< w) ||| x.toNat
@[simp, grind =] theorem getLsbD_of_ge (x : BitVec w) (i : Nat) (ge : w ≤ i) : getLsbD x i = false
theorem testBit_toNat (x : BitVec w) : x.toNat.testBit i = x.getLsbD i
</all_available_lemmas>

<local_ctx>
import Mathlib.Computability.NFA
import Mathlib.Data.FinEnum
import Mathlib.Data.Rel
import Mathlib.Data.Vector.Basic
import Blase.AutoStructs.ForLean

open Set
open Mathlib
open SetRel

-- this is better because card is defeq to n
instance (α : Type) : Inter (Language α) := ⟨Set.inter⟩
instance (α : Type) : Union (Language α) := ⟨Set.union⟩

/--
The set of `n`-tuples of bit vectors of an arbitrary width.
-/
structure BitVecs (n : Nat) where
  w : Nat
  bvs : List.Vector (BitVec w) n

def BitVecs.cast (bvs : BitVecs n) (h : n = n') : BitVecs n' :=
  { w := bvs.w, bvs := h ▸ bvs.bvs }

abbrev BitVecs.empty : BitVecs n := ⟨0, List.Vector.replicate n .nil⟩
abbrev BitVecs.singleton {w : Nat} (bv : BitVec w) : BitVecs 1 := ⟨w, bv ::ᵥ .nil⟩
abbrev BitVecs.pair {w : Nat} (bv1 bv2 : BitVec w) : BitVecs 2 := ⟨w, bv1 ::ᵥ bv2 ::ᵥ .nil⟩

/--
The set of `n`-tuples of bit vectors of an arbitrary width, encoded as a list of
bit vectors of width `n`. The width of the encoded bit vectors is the length of
the list.
-/
abbrev BitVecs' (n : Nat) := List (BitVec n)

@[simps]
def dec (bvs' : BitVecs' n) : BitVecs n where
  w := bvs'.length
  bvs := List.Vector.ofFn fun k => BitVec.ofFn fun i => bvs'[i].getLsbD k

@[simp]
</local_ctx>

<target_theorem>
lemma dec_snoc n (bvs' : BitVecs' n) (a : BitVec n) :
  dec (bvs' ++ [a]) =
    { w := bvs'.length + 1
      bvs := List.Vector.ofFn fun k =>
        BitVec.cons (a.getLsbD k) ((dec bvs').bvs.get k) } :=
</target_theorem>

Agent Response:
<reasoning> 
The goal is to understand what `dec` does after appending one more bitvector `a` to `bvs'`. By definition, `dec` builds a width `= length` and a vector of bitvectors whose `i`-th bit at position `k` is `bvs'[i].getLsbD k`. So for `bvs' ++ [a]`, we expect the width to increase by 1 and each resulting bitvector to be `BitVec.cons` of the new bit coming from `a`.

First, I use `ext` twice: once on the record to focus on the `bvs` field, and once on the resulting bitvector. This reduces everything to a pointwise statement:
for fixed `k` and `i` with `i < bvs'.length + 1`,
the bit `(bvs' ++ [a])[i].getLsbD k` should match the bit at index `i` of `BitVec.cons (a.getLsbD k) ((dec bvs').bvs.get k)`.

At this point I need a clean description of indexing into `BitVec.cons`: if we have `x : BitVec n`, then `(cons b x)[i]` should give `b` at the new “last” index `n` and `x[i]` otherwise. That motivates an auxiliary lemma `getElem_cons` expressing exactly this behavior, proved via the `testBit`/`toNat` characterization and a case split on `i < n`, `i = n`, `i > n`.

Using `getElem_cons`, the RHS becomes an `if` on whether `i = bvs'.length`. So I split into cases:
- If `i = bvs'.length`, then `(bvs' ++ [a])[i]` is the appended `a`, so both sides reduce to `a.getLsbD k`.
- If `i ≠ bvs'.length`, the bound `i < bvs'.length + 1` forces `i < bvs'.length`. Then `(bvs' ++ [a])[i] = bvs'[i]` by `List.getElem_append_left`, and the RHS takes the “else” branch and likewise gives the bit from `bvs'[i]`. In both subcases, `simp` (plus the definition of `dec`) finishes.

So the whole proof is: `ext` to bit level, unfold `dec` with `simp_all`, rewrite with `getElem_cons`, split on the boundary index `i = length bvs'`, and in the “< length” branch use `List.getElem_append_left` and bounds to line up both sides.
</reasoning> 

<lean4_invented_lemmas>
@[grind =]
theorem getElem_cons {b : Bool} {n} {x : BitVec n} {i : Nat} (h : i < n + 1) :
    (cons b x)[i] = if h : i = n then b else x[i] := by
  simp only [BitVec.getElem_eq_testBit_toNat, BitVec.toNat_cons, Nat.testBit_or]
  rw [Nat.testBit_shiftLeft]
  rcases Nat.lt_trichotomy i n with i_lt_n | i_eq_n | n_lt_i
  · have p1 : ¬(n ≤ i) := by omega
    have p2 : i ≠ n := by omega
    simp [p1, p2]
  · simp only [i_eq_n, ge_iff_le, Nat.le_refl, decide_true, Nat.sub_self, Nat.testBit_zero,
    Bool.true_and, BitVec.testBit_toNat, BitVec.getLsbD_of_ge, Bool.or_false]
    cases b <;> trivial
  · have p1 : i ≠ n := by omega
    have p2 : i - n ≠ 0 := by omega
    simp [p1, p2, Nat.testBit_bool_toNat]
</lean4_invented_lemmas>

<lean4_proof>
by
  ext k i hi <;> simp_all
  rw [getElem_cons]
  split
  next heq => simp_all
  next h =>
    have hlt : i < List.length bvs' := by simp at hi; omega
    rw [List.getElem_append_left hlt]
    simp
</lean4_proof>

### Your task:
<all_available_defs>
namespace Iris
@[ext]
structure Agree where
  car : List α
  not_nil : car ≠ []
end Iris

namespace Iris
def toAgree (a : α) : Agree α := ⟨[a], by admit /- proof elided -/
⟩
end Iris

namespace Iris
def Agree.dist (n : Nat) (x y : Agree α) : Prop :=
  (∀ a ∈ x.car, ∃ b ∈ y.car, a ≡{n}≡ b) ∧
  (∀ b ∈ y.car, ∃ a ∈ x.car, a ≡{n}≡ b)
end Iris

namespace Iris
instance : OFE (Agree α) where
  Equiv x y := ∀ n, Agree.dist n x y
  Dist := Agree.dist
  dist_eqv := Agree.dist_equiv
  equiv_dist := by admit /- proof elided -/
end Iris

namespace Iris
def Agree.validN (n : Nat) (x : Agree α) : Prop :=
  match x.car with
  | [_] => True
  | _ => ∀ a ∈ x.car, ∀ b ∈ x.car, a ≡{n}≡ b
end Iris

namespace Iris
def Agree.valid (x : Agree α) : Prop := ∀ n, x.validN n
end Iris

namespace Iris
def Agree.op (x y : Agree α) : Agree α :=
  ⟨x.car ++ y.car, by admit /- proof elided -/
  ⟩
end Iris

namespace Iris
def liftRel (R : α → β → Prop) (A : α → Prop) (B : β → Prop) : Prop :=
  (∀ a, A a → ∃ b, B b ∧ R a b) ∧ (∀ b, B b → ∃ a, A a ∧ R a b)
end Iris

namespace Iris
class BI (PROP : Type _) extends COFE PROP, BI.BIBase PROP where
  Equiv P Q := P ⊣⊢ Q

  entails_preorder : Preorder Entails
  equiv_iff {P Q : PROP} : (P ≡ Q) ↔ P ⊣⊢ Q := by admit /- proof elided -/
end Iris

namespace Iris.ProofMode
def try? [Monad m] [MonadExcept ε m] (x : m α) : m (Option α) :=
  try pure (some (← x)) catch _ => pure none
end Iris.ProofMode

namespace Iris.Std
def apply' (goal : MVarId) (name : Name) : TacticM <| Option <| List MVarId := do
  let some ci := (← getEnv).find? name
    | return none
  let some value := ci.value?
    | return none

  let goals ← withoutRecover <| withReducible <| goal.apply value { newGoals := .nonDependentOnly }
  setGoals <| goals ++ (← getUnsolvedGoals)
  return goals
end Iris.Std

namespace Iris.Std
def findGoalFromTag? (tag : Name) : TacticM <| Option MVarId := do
  (← getUnsolvedGoals).findM? fun goal => do return (← goal.getTag) == tag
end Iris.Std

namespace Iris.Std
def withFocus (goal : MVarId) (f : TacticM α) : TacticM α := do
  let goals ← getUnsolvedGoals
  setGoals [goal]
  let result ← f
  setGoals <| goals ++ (← getUnsolvedGoals)
  return result
end Iris.Std

namespace Iris.ProofMode
def istart (mvar : MVarId) : MetaM (MVarId × IrisGoal) := mvar.withContext do
  \n{← mkHasTypeButIsExpectedMsg (← inferType goal) q(Prop)}"
  let u ← mkFreshLevelMVar
  let prop ← mkFreshExprMVarQ q(Type u)
  let P ← mkFreshExprMVarQ q($prop)
  let bi ← mkFreshExprMVarQ q(BI $prop)
  let _ ← synthInstanceQ q(ProofMode.AsEmpValid2 $goal $P)

  let irisGoal := { u, prop, bi, hyps := .mkEmp bi, goal := P, .. }
  let subgoal : Quoted q(⊢ $P) ←
    mkFreshExprSyntheticOpaqueMVar (IrisGoal.toExpr irisGoal) (← mvar.getTag)
  mvar.assign q(ProofMode.as_emp_valid_2 $goal $subgoal)
  pure (subgoal.mvarId!, irisGoal)
end Iris.ProofMode

namespace Iris.ProofMode
def getFreshName : TSyntax ``binderIdent → CoreM (Name × Syntax)
  | `(binderIdent| $name:ident) => pure (name.getId, name)
  | stx => return (← mkFreshUserName `x, stx)
end Iris.ProofMode

namespace Iris.ProofMode
def binderIdentHasName (name : Name) (id : TSyntax ``binderIdent) : Bool :=
  match id with
  | `(binderIdent| $name':ident) => name'.getId == name
  | _ => false
end Iris.ProofMode

namespace Iris.ProofMode
def selectHyp (ty : Expr) : ∀ {s}, @Hyps u prop bi s → MetaM (Name × Q(Bool) × Q($prop))
  | _, .emp _ => failure
  | _, .hyp _ _ uniq p ty' _ => do
    let .true ← isDefEq ty ty' | failure
    pure (uniq, p, ty')
  | _, .sep _ _ _ _ lhs rhs => try selectHyp ty rhs catch _ => selectHyp ty lhs
end Iris.ProofMode

namespace Iris.ProofMode
def goalTracker {P} (goals : IO.Ref (Array MVarId)) (name : Name) (hyps : Hyps bi P)
    (goal : Q($prop)) : MetaM Q($P ⊢ $goal) := do
  let m : Q($P ⊢ $goal) ← mkFreshExprSyntheticOpaqueMVar <|
    IrisGoal.toExpr { prop, bi, hyps, goal, .. }
  m.mvarId!.setUserName name
  goals.modify (·.push m.mvarId!)
  pure m
end Iris.ProofMode

namespace Iris.Std
abbrev Relation (α : Type _) := α → α → Prop
end Iris.Std

namespace Iris.Std
class Reflexive (R : Relation α) where
  refl {x : α} : R x x
end Iris.Std

namespace Iris.Std
class Transitive (R : Relation α) where
  trans {x y z : α} : R x y → R y z → R x z
end Iris.Std

namespace Iris.Std
class Preorder (R : Relation α) extends Reflexive R, Transitive R
end Iris.Std

namespace Iris.Std
class Idempotent (R : Relation α) (f : α → α → α) where
  idem {x : α} : R (f x x) x
end Iris.Std

namespace Iris.Std
class Commutative (R : Relation α) (f : β → β → α) where
  comm {x y : β} : R (f x y) (f y x)
end Iris.Std

namespace Iris.Std
class LeftId (R : Relation α) (i : α) (f : α → α → α) where
  left_id {x : α} : R (f i x) x
end Iris.Std

namespace Iris.Std
class RightId (R : Relation α) (i : α) (f : α → α → α) where
  right_id {x : α} : R (f x i) x
end Iris.Std

namespace Iris.Std
class Associative (R : Relation α) (f : α → α → α) where
  assoc {x y z : α} : R (f (f x y) z) (f x (f y z))
end Iris.Std

namespace Iris.Std
class Antisymmetric (R : Relation α) (S : outParam <| Relation α) where
  antisymm {x y : α} : (left : S x y) → (right : S y x) → R x y
end Iris.Std

namespace Iris.ProofMode
def Replaces [BI PROP] (K A B : PROP) := (B -∗ K) ⊢ (A -∗ K)
end Iris.ProofMode

namespace Iris.ProofMode
inductive ReplaceHyp {prop : Q(Type u)} (bi : Q(BI $prop)) (Q : Q($prop)) where
  | none
  | unchanged (ehyps') (hyps' : Hyps bi ehyps')
  | main (e e' : Q($prop)) (hyps' : Hyps bi e') (pf : Q(Replaces $Q $e $e'))
end Iris.ProofMode

namespace Iris.ProofMode
def Hyps.replace : ∀ {e}, Hyps bi e → MetaM (ReplaceHyp bi Q)
  | _, .emp _ => pure .none
  | _, .hyp _ name uniq' p ty _ => do
    if uniq == uniq' then
      let res ← repl name p ty
      if let .main e e' hyps' _ := res then
        let e' ← instantiateMVarsQ e'
        if e == e' then
          return .unchanged _ hyps'
      return res
    else return .none
  | _, .sep _ elhs erhs _ lhs rhs => do
    match ← rhs.replace with
    | .unchanged _ rhs' => return .unchanged _ (.mkSep lhs rhs')
    | .main erhs₀ _ rhs' pf =>
      let hyps' := .mkSep lhs rhs'
      return .main q(iprop($elhs ∗ $erhs₀)) _ hyps' q(replaces_r $pf)
    | .none => match ← lhs.replace with
      | .unchanged _ lhs' => return .unchanged _ (.mkSep lhs' rhs)
      | .main elhs₀ _ lhs' pf =>
        let hyps' := .mkSep lhs' rhs
        return .main q(iprop($elhs₀ ∗ $erhs)) _ hyps' q(replaces_l $pf)
      | .none => pure .none
end Iris.ProofMode

namespace Iris
def LocalUpdate [CMRA α] (x y : α × α) : Prop :=
  ∀n mz, ✓{n} x.1 → x.1 ≡{n}≡ x.2 •? mz → ✓{n} y.1 ∧ y.1 ≡{n}≡ y.2 •? mz
end Iris

namespace Set
def Disjoint {X : Type _} (S1 S2 : X → Prop) : Prop :=
  ∀ x : X, ¬(S1 x ∧ S2 x)
end Set

namespace Set
def Union {X : Type _} (S1 S2 : X → Prop) : X → Prop :=
  fun x => S1 x ∨ S2 x
end Set

namespace Set
def Included {X : Type _} (S1 S2 : X → Prop) : Prop :=
  ∀ x, S1 x → S2 x
end Set

namespace Iris.ProofMode
inductive ModalityAction (PROP1 PROP2 : Type u) : Type u where
| isEmpty   : ModalityAction PROP1 PROP2
| forall    : PROP1 = PROP2 → (PROP1 → Prop) → ModalityAction PROP1 PROP2
| transform : (PROP2 → PROP1 → Prop) → ModalityAction PROP1 PROP2
| clear     : ModalityAction PROP1 PROP2
| id        : PROP1 = PROP2 → ModalityAction PROP1 PROP2
end Iris.ProofMode

namespace Iris.ProofMode.ModalityAction
@[simp]
def intuitionistic_action_spec (M : PROP1 → PROP2) : Prop :=
  match s with
  | .isEmpty => True
  | .forall Hconv C =>
      (∀ P, C P → iprop(□ P) ⊢ Hconv ▸ M iprop(□ P)) ∧
      (∀ P Q, iprop(M P ∧ M Q) ⊢ M iprop(P ∧ Q))
  | .transform C =>
      (∀ P Q, C P Q → iprop(□ P) ⊢ M iprop(□ Q)) ∧
      (∀ P Q, iprop(M P ∧ M Q) ⊢ M iprop(P ∧ Q))
  | .clear => True
  | .id H => ∀ P, iprop(□ P) ⊢ M (H ▸ iprop(□ P))
end Iris.ProofMode.ModalityAction

namespace Iris.ProofMode.ModalityAction
@[simp]
def spatial_action_spec (M : PROP1 → PROP2) : Prop :=
  match s with
  | .isEmpty => True
  | .forall Hconv C => ∀ P, C P → P ⊢ Hconv ▸ M P
  | .transform C => ∀ P Q, C P Q → P ⊢ M Q
  | .clear => ∀ P, Absorbing (M P)
  | .id Hconv => ∀ P, P ⊢ (Hconv ▸ M P)
end Iris.ProofMode.ModalityAction

namespace Iris.ProofMode
class IsModal [BI PROP1] [BI PROP2] (M : PROP1 → PROP2)
    (iaction saction : ModalityAction PROP1 PROP2) where
  spec_intuitionistic : iaction.intuitionistic_action_spec M
  spec_spatial : saction.spatial_action_spec M
  emp : iprop(emp) ⊢ M iprop(emp)
  mono : ∀ {P Q}, (P ⊢ Q) → M P ⊢ M Q
  sep : ∀ {P Q}, iprop(M P ∗ M Q) ⊢ M iprop(P ∗ Q)
end Iris.ProofMode

namespace Iris.ProofMode
instance [BI PROP] : IsModal (PROP1 := PROP) id (.id rfl) (.id rfl) :=
end Iris.ProofMode

namespace Iris.ProofMode
def assumptionLean {prop : Q(Type u)} (_bi : Q(BI $prop)) (ehyps goal : Q($prop))
    (mvar : MVarId) : MetaM Unit := do
  mvar.withContext do
    let _ ← synthInstanceQ q(TCOr (Affine $ehyps) (Absorbing $goal))
    for h in ← getLCtx do
      let some #[_, _, hh, (P : Q($prop))] := (← whnfR h.type).appM? ``Entails | continue
      unless (← whnfR hh).isAppOfArity ``BI.emp 2 do continue
      have h : Q(⊢ $P) := .fvar h.fvarId
      

      
      try
        let _ ← synthInstanceQ q(FromAssumption true $P $goal)
        mvar.assign q(pure_assumption (P := $ehyps) (Q := $goal) $h)
        return
      catch e => trace[Meta.debug] e.toMessageData; pure ()
    throwError "no matching hypothesis found"
end Iris.ProofMode

namespace Iris.ProofMode
inductive AssumptionFastPath (prop : Q(Type u)) (bi : Q(BI $prop)) (Q : Q($prop)) where
  | absorbing (_ : Q(Absorbing $Q))
  | biAffine (_ : Q(BIAffine $prop))
end Iris.ProofMode

namespace Iris.ProofMode
def assumptionFast {e} (hyps : Hyps bi e) : MetaM Q($e ⊢ $Q) := do
  let some ⟨inst, _, _, out, ty, b, _, pf⟩ ←
    hyps.removeG true fun _ _ b ty => try? do
      synthInstance q(FromAssumption $b $ty $Q)
    | failure
  let _ : Q(FromAssumption $b $ty $Q) := inst
  have : $out =Q iprop(□?$b $ty) := ⟨⟩
  match fastPath with
  | .absorbing _ => return q(assumption (Q := $Q) $pf)
  | .biAffine _ => return q(assumption (Q := $Q) $pf)
end Iris.ProofMode

namespace Iris.ProofMode
inductive AssumptionSlow {prop : Q(Type u)} (bi : Q(BI $prop)) (Q e : Q($prop)) where
  | none
  | affine (pf : Q(Affine $e))
  | main (pf : Q($e ⊢ $Q)) (pf : Option Q(Affine $e))
end Iris.ProofMode

namespace Iris.ProofMode
def assumptionSlow (assume : Bool) :
    ∀ {e}, Hyps bi e → MetaM (AssumptionSlow bi Q e)
  | _, .emp _ =>
    Pure.pure (.affine q(emp_affine))
  | out, .hyp _ _ _ b ty _ => do
    let fromAssum (_:Unit) := do
      let _ ← synthInstanceQ q(FromAssumption $b $ty $Q)
      let inst ← try? (synthInstanceQ q(Affine $out))
      return .main q(FromAssumption.from_assumption) inst
    let affine (_:Unit) := return .affine (← synthInstanceQ q(Affine $out))
    if assume then
      try fromAssum () catch _ => try affine () catch _ => return .none
    else
      try affine () catch _ => try fromAssum () catch _ => return .none
  | _, .sep _ elhs erhs _ lhs rhs => do
    match ← assumptionSlow assume rhs with
    | .none => return .none
    | .affine _ =>
      match ← assumptionSlow assume lhs with
      | .none => return .none
      | .affine _ => return .affine q(sep_affine ..)
      | .main lpf linst =>
        return .main q(assumption_l $lpf) <| linst.map fun _ => q(sep_affine $elhs $erhs)
    | .main rpf rinst =>
      match ← assumptionSlow false lhs, rinst with
      | .none, _ | .main _ none, none => return .none
      | .affine _, rinst | .main _ (some _), rinst =>
        return .main q(assumption_r $rpf) <| rinst.map fun _ => q(sep_affine $elhs $erhs)
      | .main lpf none, some _ => return .main q(assumption_l $lpf) none
end Iris.ProofMode

namespace Lean.Expr
def appM? (e : Expr) (fName : Name) : Option <| Array Expr :=
  if e.isAppOf fName then
    e.getAppArgs
  else
    none
end Lean.Expr

namespace Lean.Expr
def modifyAppOptM (e : Expr) (args : Array <| Option Expr) : Expr :=
  mkAppN e.getAppFn <| e.getAppArgs.zipWith (fun a b => if let some b := b then b else a) args
end Lean.Expr

namespace Lean.Expr
def getMDataName? : Expr → Option Name
  | Expr.mdata md _ => md.get? `name
  | _ => none
end Lean.Expr

namespace Lean.Expr
def setMDataName? (e : Expr) (name : Name) : Expr := match e with
  | Expr.mdata md e =>
    mkMData (md.insert `name name) e
  | e =>
    mkMData (KVMap.empty.insert `name name) e
end Lean.Expr

namespace Iris.ProofMode
@[match_pattern] def nameAnnotation := `name
end Iris.ProofMode

namespace Iris.ProofMode
@[match_pattern] def uniqAnnotation := `uniq
end Iris.ProofMode

namespace Iris.ProofMode
def parseName? : Expr → Option (Name × Name × Expr)
  | .mdata ⟨[(nameAnnotation, .ofName name), (uniqAnnotation, .ofName uniq)]⟩ e => do
    some (name, uniq, e)
  | _ => none
end Iris.ProofMode

namespace Iris.ProofMode
def mkNameAnnotation (name uniq : Name) (e : Expr) : Expr :=
  .mdata ⟨[(nameAnnotation, .ofName name), (uniqAnnotation, .ofName uniq)]⟩ e
end Iris.ProofMode

namespace Iris.ProofMode
inductive Hyps {prop : Q(Type u)} (bi : Q(BI $prop)) : (e : Q($prop)) → Type where
  | emp (_ : $e =Q emp) : Hyps bi e
  | sep (tm elhs erhs : Q($prop)) (_ : $e =Q iprop($elhs ∗ $erhs))
        (lhs : Hyps bi elhs) (rhs : Hyps bi erhs) : Hyps bi e
  | hyp (tm : Q($prop)) (name uniq : Name) (p : Q(Bool)) (ty : Q($prop))
        (_ : $e =Q iprop(□?$p $ty)) : Hyps bi e
end Iris.ProofMode

namespace Iris.ProofMode
instance : Inhabited (Hyps bi s) := ⟨.emp ⟨⟩⟩
end Iris.ProofMode

namespace Iris.ProofMode
def Hyps.tm : @Hyps _ prop bi s → Q($prop)
  | .emp _ => s
  | .sep tm .. | .hyp tm .. => tm
end Iris.ProofMode

namespace Iris.ProofMode
def Hyps.mkEmp {prop : Q(Type u)} (bi : Q(BI $prop)) (e := q(BI.emp : $prop)) : Hyps bi e := .emp ⟨⟩
end Iris.ProofMode

namespace Iris.ProofMode
def Hyps.mkSep {prop : Q(Type u)} {bi : Q(BI $prop)} {elhs erhs}
    (lhs : Hyps bi elhs) (rhs : Hyps bi erhs) (e := q(BI.sep $elhs $erhs)) : Hyps bi e :=
  .sep q(BI.sep $(lhs.tm) $(rhs.tm) : $prop) elhs erhs ⟨⟩ lhs rhs
end Iris.ProofMode

namespace Iris.ProofMode
def isTrue (p : Q(Bool)) : Bool := p.constName! == ``true
end Iris.ProofMode

namespace Iris.ProofMode
def matchBool (p : Q(Bool)) : ($p =Q true) ⊕' ($p =Q false) :=
  if isTrue p then .inl ⟨⟩ else .inr ⟨⟩
end Iris.ProofMode

namespace Iris.ProofMode
def mkIntuitionisticIf {prop : Q(Type u)} (_bi : Q(BI $prop))
    (p : Q(Bool)) (e : Q($prop)) : {A : Q($prop) // $A =Q iprop(□?$p $e)} :=
  match matchBool p with
  | .inl _ => ⟨q(iprop(□ $e)), ⟨⟩⟩
  | .inr _ => ⟨e, ⟨⟩⟩
end Iris.ProofMode

namespace Iris.ProofMode
def Hyps.mkHyp {prop : Q(Type u)} (bi : Q(BI $prop))
    (name uniq : Name) (p : Q(Bool)) (ty : Q($prop)) (e := q(iprop(□?$p $ty))) : Hyps bi e :=
  .hyp (mkIntuitionisticIf bi p (mkNameAnnotation name uniq ty)) name uniq p ty ⟨⟩
end Iris.ProofMode

namespace Iris.ProofMode
partial def parseHyps? {prop : Q(Type u)} (bi : Q(BI $prop)) (expr : Expr) :
    Option ((s : Q($prop)) × Hyps bi s) := do
  if let some #[_, _, P, Q] := appM? expr ``sep then
    let ⟨elhs, lhs⟩ ← parseHyps? bi P
    let ⟨erhs, rhs⟩ ← parseHyps? bi Q
    some ⟨q(BI.sep $elhs $erhs), .sep expr elhs erhs ⟨⟩ lhs rhs⟩
  else if expr.isAppOfArity ``emp 2 then
    some ⟨expr, .emp ⟨⟩⟩
  else if let some #[_, _, P] := appM? expr ``intuitionistically then
    let (name, uniq, (ty : Q($prop))) ← parseName? P
    some ⟨q(iprop(□ $ty)), .hyp expr name uniq q(true) ty ⟨⟩⟩
  else
    let (name, uniq, ty) ← parseName? expr
    some ⟨ty, .hyp expr name uniq q(false) ty ⟨⟩⟩
end Iris.ProofMode

namespace Iris.ProofMode
partial def Hyps.find? {u prop bi} (name : Name) :
    ∀ {s}, @Hyps u prop bi s → Option (Name × Q(Bool) × Q($prop))
  | _, .emp _ => none
  | _, .hyp _ name' uniq p ty _ => if name == name' then (uniq, p, ty) else none
  | _, .sep _ _ _ _ lhs rhs => rhs.find? name <|> lhs.find? name
end Iris.ProofMode

namespace Iris.ProofMode
abbrev Entails' [BI PROP] : PROP → PROP → Prop := Entails
end Iris.ProofMode

namespace Iris.ProofMode
structure IrisGoal where
  u : Level
  prop : Q(Type u)
  bi : Q(BI $prop)
  e : Q($prop)
  hyps : Hyps bi e
  goal : Q($prop)
end Iris.ProofMode

namespace Iris.ProofMode
def isIrisGoal (expr : Expr) : Bool := isAppOfArity expr ``Entails' 4
end Iris.ProofMode

namespace Iris.ProofMode
def parseIrisGoal? (expr : Expr) : Option IrisGoal := do
  let some #[prop, bi, P, goal] := expr.appM? ``Entails' | none
  let u := expr.getAppFn.constLevels![0]!
  let ⟨e, hyps⟩ ← parseHyps? bi P
  some { u, prop, bi, e, hyps, goal }
end Iris.ProofMode

namespace Iris.ProofMode
def IrisGoal.toExpr : IrisGoal → Expr
  | { hyps, goal, .. } => q(Entails' $(hyps.tm) $goal)
end Iris.ProofMode

namespace Iris.ProofMode
def IrisGoal.strip : IrisGoal → Expr
  | { e, goal, .. } => q(Entails $e $goal)
end Iris.ProofMode

namespace Iris.ProofMode
def HypMarker {PROP : Type _} (_A : PROP) : Prop := True
end Iris.ProofMode

namespace Iris.ProofMode
def addLocalVarInfo (stx : Syntax) (lctx : LocalContext)
    (expr : Expr) (expectedType? : Option Expr) (isBinder := false) : MetaM Unit := do
  Elab.withInfoContext' (pure ())
    (fun _ =>
      return .inl <| .ofTermInfo
        { elaborator := .anonymous, lctx, expr, stx, expectedType?, isBinder })
    (return .ofPartialTermInfo { elaborator := .anonymous, lctx, stx, expectedType? })
end Iris.ProofMode

namespace Iris.ProofMode
def addHypInfo (stx : Syntax) (name uniq : Name) (prop : Q(Type u)) (ty : Q($prop))
    (isBinder := false) : MetaM Unit := do
  let lctx ← getLCtx
  let ty := q(HypMarker $ty)
  addLocalVarInfo stx (lctx.mkLocalDecl ⟨uniq⟩ name ty) (.fvar ⟨uniq⟩) ty isBinder
end Iris.ProofMode

namespace Iris.ProofMode
def Hyps.findWithInfo {u prop bi} (hyps : @Hyps u prop bi s) (name : Ident) : MetaM Name := do
  let some (uniq, _, ty) := hyps.find? name.getId | throwError "unknown hypothesis"
  addHypInfo name name.getId uniq prop ty
  pure uniq
end Iris.ProofMode

namespace Iris
@[ext]
structure UPred (M : Type _) [UCMRA M] where
  holds : Nat → M → Prop
  mono {n1 n2 x1 x2} : holds n1 x1 → x1 ≼{n2} x2 → n2 ≤ n1 → holds n2 x2
end Iris

namespace Iris
instance [UCMRA M] : Inhabited (UPred M) :=
  ⟨fun _ _ => True, fun _ _ _ => ⟨⟩⟩
end Iris

namespace Iris
instance [UCMRA M] : CoeFun (UPred M) (fun _ => Nat → M → Prop) where
  coe x := x.holds
end Iris

namespace Iris
instance : OFE (UPred M) where
  Equiv P Q := ∀ n x, ✓{n} x → (P n x ↔ Q n x)
  Dist n P Q := ∀ n' x, n' ≤ n → ✓{n'} x → (P n' x ↔ Q n' x)
  dist_eqv := {
    refl _ _ _ _ _ := .rfl
    symm H _ _ A B := (H _ _ A B).symm
    trans H1 H2 _ _ A B := (H1 _ _ A B).trans (H2 _ _ A B) }
  equiv_dist := ⟨
    fun Heqv _ _ _ _ Hvalid => Heqv _ _ Hvalid,
    fun Hdist _ _ Hvalid => Hdist _ _ _ (Nat.le_refl _) Hvalid⟩
  dist_lt Hdist Hlt _ _ Hle Hvalid :=
    Hdist _ _ (Nat.le_trans Hle (Nat.le_of_succ_le Hlt)) Hvalid
end Iris

namespace Iris
instance : IsCOFE (UPred M) where
  compl c := {
    holds n x := ∀ n', n' ≤ n → ✓{n'} x → (c n') n' x
    mono {n1 n2 x1 x2 HP Hx12 Hn12 n3 Hn23 Hv} := by admit /- proof elided -/
end Iris

namespace Iris
abbrev UPredOF (F : COFE.OFunctorPre) [URFunctor F] : COFE.OFunctorPre :=
  fun A B _ _ => UPred (F B A)
end Iris

namespace Iris
def uPred_map [UCMRA α] [UCMRA β] (f : β -C> α) : UPred α -n> UPred β :=
end Iris

namespace Iris
instance [URFunctor F] : COFE.OFunctor (UPredOF F) where
  cofe := inferInstance
  map f g := uPred_map (URFunctor.map (F := F) g f)
  map_ne.ne _ _ _ Hx _ _ Hy _ _ z2 Hn _ :=
    uPred_ne <| URFunctor.map_ne.ne (Hy.le Hn) (Hx.le Hn) z2
  map_id _ _ z _ := uPred_proper <| URFunctor.map_id z
  map_comp f g f' g' _ _ H _ := uPred_proper <| URFunctor.map_comp g' f' g f H
end Iris

namespace Iris
instance [URFunctorContractive F] : COFE.OFunctorContractive (UPredOF F) where
  map_contractive.1 {_ x y} HKL _ _ _ Hn _ := by admit /- proof elided -/
end Iris

namespace Iris.COFE.OFunctor.Fix.Impl
def A' : Nat → Σ α : Type u, COFE α
  | 0 => ⟨ULift Unit, inferInstance⟩
  | n+1 => let ⟨A, _⟩ := A' n; ⟨F A A, inferInstance⟩
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor.Fix.Impl
def A (n : Nat) : Type u := (A' F n).1
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor.Fix.Impl
instance instA' (n) : COFE (A' F n).1 := (A' F n).2
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor.Fix.Impl
instance instA (n) : COFE (A F n) := (A' F n).2
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor.Fix.Impl
def up : ∀ k, A F k -n> A F (k+1)
  | 0 => ⟨fun _ => inh.default, ⟨fun _ _ _ _ => .rfl⟩⟩
  | k+1 => map (down k) (up k)
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor.Fix.Impl
def down : ∀ k, A F (k+1) -n> A F k
  | 0 => ⟨fun _ => ⟨()⟩, ⟨fun _ _ _ _ => .rfl⟩⟩
  | k+1 => map (up k) (down k)
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor.Fix.Impl
@[ext] structure Tower : Type u where
  val k : A F k
  protected down {k} : down F k (val (k+1)) ≡ val k
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor.Fix.Impl
instance : CoeFun (Tower F) (fun _ => ∀ k, A F k) := ⟨Tower.val⟩
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor.Fix.Impl
instance : OFE (Tower F) where
  Equiv f g := ∀ k, f k ≡ g k
  Dist n f g := ∀ k, f k ≡{n}≡ g k
  dist_eqv := {
    refl _ _ := dist_eqv.refl _
    symm h _ := dist_eqv.symm (h _)
    trans h1 h2 _ := dist_eqv.trans (h1 _) (h2 _)
  }
  equiv_dist {_ _} := by admit /- proof elided -/
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor.Fix.Impl
def towerChain (c : Chain (Tower F)) (k : Nat) : Chain (A F k) where
  chain i := c.1 i k
  cauchy h := c.cauchy h k
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor.Fix.Impl
instance : COFE (Tower F) where
  compl c := by admit /- proof elided -/
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor.Fix.Impl
def upN {k} : ∀ n, A F k -n> A F (k + n)
  | 0 => .id
  | n+1 => (up F (k + n)).comp (upN n)
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor.Fix.Impl
def downN {k} : ∀ n, A F (k + n) -n> A F k
  | 0 => .id
  | n+1 => (downN n).comp (down F (k + n))
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor.Fix.Impl
instance (k : Nat) : NonExpansive (fun X : Tower F => X.val k) := ⟨fun _ _ _ => (· _)⟩
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor.Fix.Impl
def Tower.proj (k) : Tower F -n> A F k := ⟨(· k), ⟨fun _ _ _ => (· _)⟩⟩
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor.Fix.Impl
def eqToHom (e : i = k) : A F i -n> A F k := e ▸ .id
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor.Fix.Impl
def embed : A F k -n> A F i :=
  if h : k ≤ i then (eqToHom (Nat.add_sub_cancel' h)).comp (upN ..)
  else (downN ..).comp (eqToHom (Nat.add_sub_cancel' (Nat.le_of_not_ge h)).symm)
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor.Fix.Impl
protected def Tower.embed (k) : A F k -n> Tower F :=
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor.Fix.Impl
instance : Inhabited (Tower F) := ⟨Tower.embed 0 ⟨()⟩⟩
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor.Fix.Impl
def unfoldChain (X : Tower F) : Chain (F (Tower F) (Tower F)) where
  chain n := map (Tower.proj _) (Tower.embed _) (X (n+1))
  cauchy {n i} h := by admit /- proof elided -/
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor.Fix.Impl
def Tower.iso : OFE.Iso (F (Tower F) (Tower F)) (Tower F) where
  hom.f X := {
    val n := (down F n).comp (map (Tower.embed _) (Tower.proj _)) X
    down {n} := (down ..).ne.eqv <|
      (map_comp ..).symm.trans (map_ne.eqv Tower.embed_up (·.down) _)
  }
  hom.ne.1 _ _ _ h _ := by admit /- proof elided -/
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor
def Fix : Type u := Tower F
end Iris.COFE.OFunctor

namespace Iris.COFE.OFunctor
instance : Inhabited (Fix F) := inferInstanceAs (Inhabited (Tower F))
end Iris.COFE.OFunctor

namespace Iris.COFE.OFunctor
instance : COFE (Fix F) := inferInstanceAs (COFE (Tower F))
end Iris.COFE.OFunctor

namespace Iris.COFE.OFunctor
def Fix.iso : OFE.Iso (F (Fix F) (Fix F)) (Fix F) := Tower.iso
end Iris.COFE.OFunctor

namespace Iris.COFE.OFunctor
def Fix.fold : F (Fix F) (Fix F) -n> Fix F := Fix.iso.hom
end Iris.COFE.OFunctor

namespace Iris.COFE.OFunctor
def Fix.unfold : Fix F -n> F (Fix F) (Fix F) := Fix.iso.inv
end Iris.COFE.OFunctor

namespace Iris
class Plainly (PROP : Type _) where
  plainly : PROP → PROP
end Iris

namespace Iris
def Plainly.plainlyIf [Iris.BI.BIBase PROP] [Plainly PROP] (p : Bool) (P : PROP) : PROP :=
  iprop(if p then ■ P else P)
end Iris

namespace Iris
class BIPlainly (PROP : Type _) [Iris.BI PROP] extends Plainly PROP where
  [ne : Iris.OFE.NonExpansive (Plainly.plainly (PROP := PROP))]
  mono {P Q : PROP} : (P ⊢ Q) → ■ P ⊢ ■ Q
  elim_persistently {P : PROP} : ■ P ⊢ <pers> P
  idem {P : PROP} : ■ P ⊢ ■ ■ P
  plainly_sForall_2 {Φ : PROP → Prop} : (∀ p, ⌜Φ p⌝ → ■ p) ⊢ ■ sForall Φ
  plainly_impl_plainly {P Q : PROP} : (■ P → ■ Q) ⊢ ■ (■ P → Q)
  emp_intro {P : PROP} : P ⊢ ■ emp
  plainly_absorb {P Q : PROP} : ■ P ∗ Q ⊢ ■ P
  later_plainly {P : PROP} : ▷ ■ P ⊣⊢ ■ ▷ P
end Iris

namespace Iris
class BIPersistentlyImplPlainly (PROP : Type _) [Iris.BI PROP] [BIPlainly PROP] where
  pers_impl_plainly (P Q : PROP) : (■ P → <pers> Q) ⊢ <pers> (■ P → Q)
end Iris

namespace Iris
class BIPlainlyExists (PROP : Type _) [Iris.BI PROP] [BIPlainly PROP] where
  plainly_sExists_1 {Φ : PROP → Prop} : ■ sExists Φ ⊢ ∃ p, ⌜Φ p⌝ ∧ ■ p
end Iris

namespace Iris.BI
class Plain [BI PROP] [Plainly PROP] [BIPlainly PROP] (P : PROP) where
  plain : P ⊢ ■ P
end Iris.BI

namespace Iris.BI
instance [BI PROP] [BIPlainly PROP] (P : PROP) : Plain iprop(■ P) :=
  ⟨BIPlainly.idem⟩
end Iris.BI

namespace Iris.ProofMode
inductive SplitResult {prop : Q(Type u)} (bi : Q(BI $prop)) (e : Q($prop)) where
  | emp (_ : $e =Q BI.emp)
  | left
  | right
  | split {elhs erhs : Q($prop)} (lhs : Hyps bi elhs) (rhs : Hyps bi erhs)
          (pf : Q($e ⊣⊢ $elhs ∗ $erhs))
end Iris.ProofMode

namespace Iris.ProofMode
def Hyps.splitCore : ∀ {e}, Hyps bi e → SplitResult bi e
  | _, .emp _ => .emp ⟨⟩
  | ehyp, h@(.hyp _ name uniq b ty _) =>
    match matchBool b with
    | .inl _ =>
      have : $ehyp =Q iprop(□ $ty) := ⟨⟩
      .split h h q(intuitionistically_sep_dup)
    | .inr _ => if toRight name uniq then .right else .left
  | _, .sep _ _ _ _ lhs rhs =>
    let resl := lhs.splitCore
    let resr := rhs.splitCore
    match resl, resr with
    | .emp _, .emp _ | .left, .emp _ | .emp _, .left | .left, .left => .left
    | .right, .emp _ | .emp _, .right | .right, .right => .right
    | .left, .right => .split lhs rhs q(.rfl)
    | .right, .left => .split rhs lhs q(sep_comm)
    | .emp _, .split r1 r2 rpf => .split r1 r2 q(split_es $rpf)
    | .left, .split r1 r2 rpf => .split (lhs.mkSep r1) r2 q(split_ls $rpf)
    | .right, .split r1 r2 rpf => .split r1 (lhs.mkSep r2) q(split_rs $rpf)
    | .split l1 l2 lpf, .emp _ => .split l1 l2 q(split_se $lpf)
    | .split l1 l2 lpf, .left => .split (l1.mkSep rhs) l2 q(split_sl $lpf)
    | .split l1 l2 lpf, .right => .split l1 (l2.mkSep rhs) q(split_sr $lpf)
    | .split l1 l2 lpf, .split r1 r2 rpf => .split (l1.mkSep r1) (l2.mkSep r2) q(split_ss $lpf $rpf)
end Iris.ProofMode

namespace Iris.ProofMode
def Hyps.split {prop : Q(Type u)} (bi : Q(BI $prop)) (toRight : Name → Name → Bool)
    {e} (hyps : Hyps bi e) :
    (elhs erhs : Q($prop)) × Hyps bi elhs × Hyps bi erhs × Q($e ⊣⊢ $elhs ∗ $erhs) :=
  match hyps.splitCore bi toRight with
  | .emp _ => ⟨_, _, hyps, hyps, q(sep_emp_rev)⟩
  | .left => ⟨_, _, hyps, .mkEmp bi, q(sep_emp_rev)⟩
  | .right => ⟨_, _, .mkEmp bi, hyps, q(emp_sep_rev)⟩
  | .split lhs rhs pf => ⟨_, _, lhs, rhs, pf⟩
end Iris.ProofMode

namespace Iris.ProofMode
inductive splitSide where
| splitLeft | splitRight
end Iris.ProofMode

namespace Iris.ProofMode
def isplitCore (side : splitSide) (names : Array (TSyntax `ident)) : TacticM Unit := do
  let splitRight := match side with
    | .splitLeft => false
    | .splitRight => true

  
  let (mvar, { u, prop, bi, hyps, goal, .. }) ← istart (← getMainGoal)
  mvar.withContext do

  let mut uniqs : NameSet := {}
  for name in names do
    uniqs := uniqs.insert (← hyps.findWithInfo name)

  let Q1 ← mkFreshExprMVarQ prop
  let Q2 ← mkFreshExprMVarQ prop
  let _ ← synthInstanceQ q(FromSep $goal $Q1 $Q2)

  
  let ⟨el, er, lhs, rhs, pf⟩ := hyps.split bi (fun _ uniq => uniqs.contains uniq == splitRight)

  let m1 : Q($el ⊢ $Q1) ← mkFreshExprSyntheticOpaqueMVar <|
    IrisGoal.toExpr { u, prop, bi, hyps := lhs, goal := Q1, .. }
  let m2 : Q($er ⊢ $Q2) ← mkFreshExprSyntheticOpaqueMVar <|
    IrisGoal.toExpr { u, prop, bi, hyps := rhs, goal := Q2, .. }
  mvar.assign q(sep_split (Q := $goal) $pf $m1 $m2)
  replaceMainGoal [m1.mvarId!, m2.mvarId!]
end Iris.ProofMode

class Store (T : Type _) (K V : outParam (Type _)) where
  get : T → K → V
  set : T → K → V → T
  get_set_eq {t k k' v} : k = k' → get (set t k v) k' = v
  get_set_ne {t k k' v} : k ≠ k' → get (set t k v) k' = get t k'

def Store.all [Store T K V] (P : K → V → Prop) : T → Prop :=
  fun t => ∀ k, P k (get t k)

@[simp] def Store.Equiv [Store T K V] (t1 t2 : T) : Prop := get t1 = get t2

instance Store.Equiv_trans [Store T K V] : Trans Equiv (Equiv (T := T)) Equiv := ⟨by admit /- proof elided -/
⟩

class RepFunStore (T : Type _) (K V : outParam (Type _)) [Store T K V] where
  rep : (K → V) → Prop
  rep_get (t : T) : rep (get t)
  of_fun : { f : K → V // rep f } → T
  get_of_fun : get (of_fun f) = f

class IsoFunStore (T : Type _) (K V : outParam (Type _)) [Store T K V] extends RepFunStore T K V where
  of_fun_get {t : T} : of_fun ⟨get t, rep_get t⟩ = t

class HasStoreMap (T1 T2 : Type _) (K V1 V2 : outParam (Type _)) [Store T1 K V1] [Store T2 K V2] where
   
  dmap (f : K → V1 → V2) : T1 → T2
  get_dmap : get (dmap f t) k = f k (get t k)

def HasStoreMap.map (f : V1 → V2) [Store T1 K V1] [Store T2 K V2] [HasStoreMap T1 T2 K V1 V2] : T1 → T2 :=
  HasStoreMap.dmap (fun _ => f)

class HasHeapMap (T1 T2 : Type _) (K V1 V2 : outParam (Type _))
   [Store T1 K (Option V1)] [Store T2 K (Option V2)] where
  hhmap (f : K → V1 → Option V2) : T1 → T2
  hhmap_get (f : K → V1 → Option V2) : get (hhmap f t) k = (get t k).bind (f k)

class Heap (T : Type _) (K V : outParam (Type _)) extends Store T K (Option V) where
  empty : T
  hmap (f : K → V → Option V) : T → T
  merge (op : V → V → V) : T → T → T
  get_empty : get empty k = none
  get_hmap : get (hmap f t) k = (get t k).bind (f k)
  get_merge : get (merge op t1 t2) k = Option.merge op (get t1 k) (get t2 k)

def Heap.point [Heap T K V] (k : K) (v : Option V) : T := set empty k v

def Heap.delete [Heap T K V] (t : T) (k : K) : T := set t k none

def Heap.dom [Heap T K V] (t : T) : K → Prop := fun k => (get t k).isSome

@[simp] def Heap.union [Heap T K V] : T → T → T := merge (fun v _ => v)

class AllocHeap (T : Type _) (K V : outParam (Type _)) extends Heap T K V where
  notFull : T → Prop
  fresh {t : T} : notFull t → K
  get_fresh {H : notFull t} : get t (fresh H) = none

class UnboundedHeap (T : Type _) (K V : outParam (Type _)) extends AllocHeap T K V where
  notFull_empty : notFull (empty : T)
  notFull_set_fresh {H : notFull t} : notFull (set t (fresh H) v)

namespace Iris.ProofMode
def ipureCore {prop : Q(Type u)} (_bi : Q(BI $prop))
    (P P' A Q : Q($prop)) (name : TSyntax ``binderIdent) (pf : Q($P ⊣⊢ $P' ∗ $A))
    (k : (φ : Q(Prop)) → Q($φ) → MetaM (α × Q($P' ⊢ $Q))) : MetaM (α × Q($P ⊢ $Q)) := do
  let φ : Q(Prop) ← mkFreshExprMVarQ q(Prop)
  let inst ← if A.isAppOfArity ``intuitionistically 3 then
    have A' : Q($prop) := A.appArg!
    synthInstance q(IntoPure $A' $φ)
  else
    synthInstance q(IntoPure $A $φ)

  let (name, ref) ← getFreshName name
  withLocalDeclDQ name φ fun p => do
    addLocalVarInfo ref (← getLCtx) p φ
    let (a, m) ← k φ p
    let f : Q($φ → $P' ⊢ $Q) ← mkLambdaFVars #[p] m

    if A.isAppOfArity ``intuitionistically 3 then
      have A' : Q($prop) := A.appArg!
      have : $A =Q iprop(□ $A') := ⟨⟩
      have : Q(IntoPure $A' $φ) := inst
      pure (a, q(pure_elim_intuitionistic $pf $f))
    else
      let _ ← synthInstanceQ q(TCOr (Affine $A) (Absorbing $Q))
      have : Q(IntoPure $A $φ) := inst
      pure (a, q(pure_elim_spatial $pf $f))
end Iris.ProofMode

namespace Iris
inductive Excl α where
  | excl : α → Excl α
  | invalid : Excl α
end Iris

namespace Iris
@[simp] protected def Excl.Equiv [OFE α] : Excl α → Excl α → Prop
  | excl a, excl b => a ≡ b
  | invalid, invalid => True
  | _, _ => False
end Iris

namespace Iris
@[simp] protected def Excl.Dist [OFE α] (n : Nat) : Excl α → Excl α → Prop
  | excl a, excl b => a ≡{n}≡ b
  | invalid, invalid => True
  | _, _ => False
end Iris

namespace Iris
instance [OFE α] : OFE (Excl α) where
  Equiv := Excl.Equiv
  Dist := Excl.Dist
  dist_eqv := dist_eqv
  equiv_dist {x y} := by admit /- proof elided -/
end Iris

namespace Iris
instance [OFE α] : NonExpansive excl (α := α) where
  ne _ _ _ a := a
end Iris

namespace Iris
instance [OFE α] [Discrete α] : Discrete (Excl α) where
  discrete_0 {x y} h' := by admit /- proof elided -/
end Iris

namespace Iris
instance [OFE α] [Leibniz α] : Leibniz (Excl α) where
  eq_of_eqv {x y} h' := by admit /- proof elided -/
end Iris

namespace Iris
instance [OFE α] {a : α} [h : DiscreteE a] : DiscreteE (excl a) where
  discrete {x} h' := by admit /- proof elided -/
end Iris

namespace Iris
instance [OFE α] : DiscreteE (@invalid α) where
  discrete {x} h := by admit /- proof elided -/
end Iris

namespace Iris
@[simp] def Excl.getD (x : Excl α) (dflt : α) : α :=
  match x with
  | excl a => a
  | invalid => dflt
end Iris

namespace Iris
@[simp] def Excl.map (f : α → β) : Excl α → Excl β
  | excl a => excl (f a)
  | invalid => invalid
end Iris

namespace Iris
def exclChain [OFE α] (c : Chain (Excl α)) (a : α) : Chain α :=
end Iris

namespace Iris
instance [OFE α] [IsCOFE α] : IsCOFE (Excl α) where
  compl c := (c 0).map fun x => IsCOFE.compl (exclChain c x)
  conv_compl {n} c := by admit /- proof elided -/
end Iris

namespace Iris
@[simp] def Excl.Valid : Excl α → Prop
  | excl _ => True
  | invalid => False
end Iris

namespace Iris
instance [OFE α] : CMRA (Excl α) where
  pcore _ := none
  op _ _ := invalid
  ValidN _ := Valid
  Valid
  op_ne.ne _ _ _ _ := trivial
  pcore_ne := by admit /- proof elided -/
end Iris

namespace Iris
instance [OFE α] {x : Excl α} : CMRA.Exclusive x where exclusive0_l := fun _ a => a
end Iris

namespace Iris
instance [OFE α] [OFE.Discrete α] : CMRA.Discrete (Excl α) where
  discrete_valid a := a
end Iris

namespace Iris
def exclO_map [OFE α] [OFE β] (f : α -n> β) : Excl α -C> Excl β :=
end Iris

namespace Iris
abbrev ExclOF (F : COFE.OFunctorPre) : COFE.OFunctorPre :=
  fun A B _ _ => Excl (F A B)
end Iris

namespace Iris
instance {F} [COFE.OFunctor F] : RFunctor (ExclOF F) where
  cmra := inferInstance
  map f g := exclO_map (COFE.OFunctor.map f g)
  map_ne.ne := by admit /- proof elided -/
end Iris

namespace Iris
instance {F} [COFE.OFunctorContractive F] : RFunctorContractive (ExclOF F) where
  map_contractive.1 {n x y} HKL z := by admit /- proof elided -/
end Iris

namespace UPred
protected def Entails (P Q : UPred M) : Prop := ∀ n x, ✓{n} x → P n x → Q n x
end UPred

namespace UPred
protected def pure (p : Prop) : UPred M where
  holds _ _ := p
  mono h _ _ := h
end UPred

namespace UPred
protected def and (P Q : UPred M) : UPred M where
  holds n x := P n x ∧ Q n x
  mono HPQ Hle Hn := ⟨P.mono HPQ.1 Hle Hn, Q.mono HPQ.2 Hle Hn⟩
end UPred

namespace UPred
protected def or (P Q : UPred M) : UPred M where
  holds n x := P n x ∨ Q n x
  mono
  | .inl H, Hle, Hn => .inl (P.mono H Hle Hn)
  | .inr H, Hle, Hn => .inr (Q.mono H Hle Hn)
end UPred

namespace UPred
protected def imp (P Q : UPred M) : UPred M where
  holds n x := ∀ n' x', x ≼ x' → n' ≤ n → ✓{n'} x' → P n' x' → Q n' x'
  mono {n₁ n₂ x₁ x₂} H := fun ⟨m₁, Hle⟩ Hn n x ⟨m₂, Hxle⟩ Hnle Hv HP => by admit /- proof elided -/
end UPred

namespace UPred
protected def sForall (Ψ : UPred M → Prop) : UPred M where
  holds n x := ∀ p, Ψ p → p n x
  mono a a_1 a_2 p a_3 := p.mono (a p a_3) a_1 a_2
end UPred

namespace UPred
protected def sExists (Ψ : UPred M → Prop) : UPred M where
  holds n x := ∃ p, Ψ p ∧ p n x
  mono := fun ⟨p, HΨ, Hp⟩ Hv Hn => ⟨p, HΨ, p.mono Hp Hv Hn⟩
end UPred

namespace UPred
protected def eq [OFE O] (o1 o2 : O) : UPred M where
  holds n _ := o1 ≡{n}≡ o2
  mono H1 _ H2 := H1.le H2
end UPred

namespace UPred
protected def sep (P Q : UPred M) : UPred M where
  holds n x := ∃ x1 x2, x ≡{n}≡ x1 • x2 ∧ P n x1 ∧ Q n x2
  mono {n₁ n₂ m₁ m₂} := fun ⟨x₁, x₂, Hx, HP, HQ⟩ ⟨m, Hm⟩ Hn => by admit /- proof elided -/
end UPred

namespace UPred
protected def wand (P Q : UPred M) : UPred M where
  holds n x := ∀ n' x', n' ≤ n → ✓{n'} (x • x') → P n' x' → Q n' (x • x')
  mono {n₁ n₂ m₁ m₂} H Hm Hn n' x Hn' Hv HP := by admit /- proof elided -/
end UPred

namespace UPred
protected def plainly (P : UPred M) : UPred M where
  holds n _ := P n UCMRA.unit
  mono H _ Hn := P.mono H (CMRA.incN_refl UCMRA.unit) Hn
end UPred

namespace UPred
protected def persistently (P : UPred M) : UPred M where
  holds n x := P n (CMRA.core x)
  mono H Hx Hn := P.mono H (CMRA.core_incN_core Hx) Hn
end UPred

namespace UPred
protected def later (P : UPred M) : UPred M where
  holds n x := match n with | 0 => True | Nat.succ n' => P n' x
  mono {n₁ n₂} := by admit /- proof elided -/
end UPred

namespace UPred
def ownM (m : M) : UPred M where
  holds n x := m ≼{n} x
  mono {n₁ n₂ x₁ x₂} := fun ⟨m₁, Hm₁⟩ ⟨m₂, Hm₂⟩ Hn => by admit /- proof elided -/
end UPred

namespace UPred
instance : OFE.NonExpansive (ownM : M → UPred M) where
  ne _ _ _ H _ _ Hn _ := OFE.Dist.incN (OFE.Dist.le H Hn) .rfl
end UPred

namespace UPred
def cmraValid [CMRA A] (a : A) : UPred M where
  holds n _ := ✓{n} a
  mono hv _ le := CMRA.validN_of_le le hv
end UPred

namespace UPred
instance [CMRA A] : OFE.NonExpansive (cmraValid : A → UPred M) where
  ne _ _ _ H _ _ Hn _ := (H.le Hn).validN
end UPred

namespace UPred
def bupd (Q : UPred M) : UPred M where
  holds n x := ∀ k yf, k ≤ n → ✓{k} (x • yf) → ∃ x', ✓{k} (x' • yf) ∧ Q k x'
  mono {n1 n2} {x1 x2} HQ := by admit /- proof elided -/
end UPred

namespace UPred
instance bupd_ne : OFE.NonExpansive (bupd : UPred M → UPred M) where
  ne n x1 x2 Hx m y Hm Hv := by admit /- proof elided -/
end UPred

namespace UPred
protected def emp : UPred M where
  holds _ _ := True
  mono _ _ _ := trivial
end UPred

namespace UPred
instance : BIBase (UPred M) where
  Entails      := UPred.Entails
  emp          := UPred.emp
  pure         := UPred.pure
  and          := UPred.and
  or           := UPred.or
  imp          := UPred.imp
  sForall      := UPred.sForall
  sExists      := UPred.sExists
  sep          := UPred.sep
  wand         := UPred.wand
  persistently := UPred.persistently
  later        := UPred.later
end UPred

namespace UPred
instance uPred_entails_preorder : Std.Preorder (Entails (PROP := UPred M)) where
  refl _ _ _ H := H
  trans H1 H2 _ _ Hv H := H2 _ _ Hv <| H1 _ _ Hv H
end UPred

namespace UPred
instance later_contractive : OFE.Contractive UPred.later (α := UPred M) where
  distLater_dist {n x y} Hl :=
    match n with
    | 0 => by admit /- proof elided -/
    | n + 1 => fun
      | 0 => by admit /- proof elided -/
      | n' + 1 => fun x' Hn' Hx' => Hl _ Hn' _ _ (Nat.le_refl _) (CMRA.validN_succ Hx')
end UPred

namespace UPred
instance : BI (UPred M) where
  entails_preorder := inferInstance
  equiv_iff {P Q} := by admit /- proof elided -/
end UPred

namespace UPred
instance : BILaterContractive (UPred M) where
  toContractive := later_contractive
end UPred

namespace UPred
instance (P : UPred M) : Affine P where
  affine _ := by admit /- proof elided -/
end UPred

namespace UPred
instance : OFE.NonExpansive (bupd : UPred M → UPred M) where
  ne {n} {x1 x2} H {n' x'} Hn' Hx' := by admit /- proof elided -/
end UPred

namespace UPred
instance : Plainly (UPred M) := ⟨UPred.plainly⟩
end UPred

namespace UPred
instance : OFE.NonExpansive (plainly : UPred M → UPred M) where
  ne n P1 P2 HP n' y Hn' Hy := by admit /- proof elided -/
end UPred

namespace UPred
instance : BIPlainly (UPred M) where
  mono H _ _ _ := H _ _ CMRA.unit_validN
  elim_persistently {P} n x Hx := by admit /- proof elided -/
end UPred

namespace UPred
instance : BIPlainlyExists (UPred M) where
  plainly_sExists_1 _ _ _ := fun ⟨_, hp⟩ => ⟨_, ⟨_, rfl⟩, hp⟩
end UPred

namespace UPred
instance : BUpd (UPred M) := ⟨bupd⟩
end UPred

namespace UPred
instance : OFE.NonExpansive (BUpd.bupd (PROP := UPred M)) := bupd_ne
end UPred

namespace UPred
instance : BIUpdate (UPred M) where
  intro {P} _ x _ HP _ _ Hn H := ⟨_, ⟨H, P.mono HP (CMRA.incN_refl x) Hn⟩⟩
  mono Himp n x Hx HP k yf Hn H := by admit /- proof elided -/
end UPred

namespace UPred
instance : BIBUpdatePlainly (UPred M) where
  bupd_plainly {P} n x Hx Hv := by admit /- proof elided -/
end UPred

namespace UPred
instance : BIAffine (UPred M) := ⟨by admit /- proof elided -/
⟩
end UPred

namespace Iris
def GFunctors := Array COFE.OFunctorPre
end Iris

namespace Iris
def GId (FF : GFunctors) : Type _ := Fin FF.size
end Iris

namespace Iris
instance (FF : GFunctors) : GetElem GFunctors (GId FF) COFE.OFunctorPre (fun _ _ => True) where
  getElem _ x _ := (show Array _ from FF)[x.1]
end Iris

namespace Iris
abbrev IsGFunctors (G : GFunctors) := ∀ (i : GId G), RFunctorContractive G[i]
end Iris

namespace Iris
def SubG (FF₁ FF₂ : GFunctors) : Prop :=
  ∀ i : GId FF₁, ∃ j : GId FF₂, FF₁[i] = FF₂[j]
end Iris

namespace Iris
def GName := LeibnizO Nat
end Iris

namespace Iris
abbrev IResF (FF : GFunctors) : COFE.OFunctorPre :=
  DiscreteFunOF (fun i : GId FF => GenMapOF GName FF[i])
end Iris

namespace Iris
def iPrePropO : Type _ := OFunctor.Fix (UPredOF (IResF FF))
end Iris

namespace Iris
instance : COFE (iPrePropO FF) := inferInstanceAs (COFE (OFunctor.Fix _))
end Iris

namespace Iris
def IResUR : Type := (i : GId FF) → GName → Option (FF[i] (iPrePropO FF) (iPrePropO FF))
end Iris

namespace Iris
instance : UCMRA (IResUR FF) :=
  ucmraDiscreteFunO (β := fun (i : GId FF) => GName → Option (FF[i] (iPrePropO FF) (iPrePropO FF)))
end Iris

namespace Iris
abbrev IProp := UPred (IResUR FF)
end Iris

namespace Iris.ProofMode
def iCasesEmptyConj {prop : Q(Type u)} (bi : Q(BI $prop))
    {P} (hyps : Hyps bi P) (Q A' : Q($prop)) (p : Q(Bool))
    (k : ∀ {P}, Hyps bi P → MetaM Q($P ⊢ $Q)) :
    MetaM (Q($P ∗ □?$p $A' ⊢ $Q)) := do
  try
    let ⟨_⟩ ← assertDefEqQ A' q(iprop(False))
    if p.constName! == ``true then
      have : $p =Q true := ⟨⟩; return q(false_elim_intuitionistic)
    else
      have : $p =Q false := ⟨⟩; return q(false_elim_spatial)
  catch _ =>
    let ⟨_⟩ ← assertDefEqQ A' q(iprop(emp))
    if p.constName! == ``true then
      have : $p =Q true := ⟨⟩; return q(sep_emp_intro_intuitionistic $(← k hyps))
    else
      have : $p =Q false := ⟨⟩; return q(sep_emp_intro_spatial $(← k hyps))
end Iris.ProofMode

namespace Iris.ProofMode
def iCasesExists {prop : Q(Type u)} (_bi : Q(BI $prop)) (P Q A' : Q($prop)) (p : Q(Bool))
    (name : TSyntax ``binderIdent) (α : Q(Sort v)) (Φ : Q(«$α» → «$prop»))
    (_inst : Q(IntoExists «$A'» «$Φ»))
    (k : (B B' : Q($prop)) → (_ : $B =Q iprop(□?$p $B')) → MetaM Q($P ∗ $B ⊢ $Q)) :
    MetaM (Q($P ∗ □?$p $A' ⊢ $Q)) := do
  let (name, ref) ← getFreshName name
  withLocalDeclDQ name α fun x => do
    addLocalVarInfo ref (← getLCtx) x α
    have B' : Q($prop) := Expr.headBeta q($Φ $x)
    have : $B' =Q $Φ $x := ⟨⟩
    if p.constName! == ``true then
      have : $p =Q true := ⟨⟩
      let pf : Q(∀ x, $P ∗ □ $Φ x ⊢ $Q) ← mkLambdaFVars #[x] <|← k q(iprop(□ $B')) B' ⟨⟩
      return q(exists_elim_intuitionistic (A := $A') $pf)
    else
      have : $p =Q false := ⟨⟩
      let pf : Q(∀ x, $P ∗ $Φ x ⊢ $Q) ← mkLambdaFVars #[x] <|← k B' B' ⟨⟩
      return q(exists_elim_spatial (A := $A') $pf)
end Iris.ProofMode

namespace Iris.ProofMode
def iCasesAndLR {prop : Q(Type u)} (_bi : Q(BI $prop)) (P Q A' A1 A2 : Q($prop)) (p : Q(Bool))
    (_inst : Q(IntoAnd $p $A' $A1 $A2)) (right : Bool)
    (k : (B B' : Q($prop)) → (_ : $B =Q iprop(□?$p $B')) → MetaM Q($P ∗ $B ⊢ $Q)) :
    MetaM (Q($P ∗ □?$p $A' ⊢ $Q)) := do
  if p.constName! == ``true then
    have : $p =Q true := ⟨⟩
    if right then
      return q(and_elim_r_intuitionistic (A := $A') $(← k q(iprop(□ $A2)) A2 ⟨⟩))
    else
      return q(and_elim_l_intuitionistic (A := $A') $(← k q(iprop(□ $A1)) A1 ⟨⟩))
  else
    have : $p =Q false := ⟨⟩
    if right then
      return q(and_elim_r_spatial (A := $A') $(← k A2 A2 ⟨⟩))
    else
      return q(and_elim_l_spatial (A := $A') $(← k A1 A1 ⟨⟩))
end Iris.ProofMode

namespace Iris.ProofMode
def iCasesSep {prop : Q(Type u)} (bi : Q(BI $prop))
    {P} (hyps : Hyps bi P) (Q A' A1 A2 : Q($prop)) (p : Q(Bool))
    (inst : Option Q(IntoAnd $p $A' $A1 $A2))
    (k : ∀ {P}, Hyps bi P → MetaM Q($P ⊢ $Q))
    (k1 k2 : ∀ {P}, Hyps bi P → (Q B B' : Q($prop)) → (_ : $B =Q iprop(□?$p $B')) →
      (∀ {P}, Hyps bi P → MetaM Q($P ⊢ $Q)) → MetaM Q($P ∗ $B ⊢ $Q)) :
    MetaM (Q($P ∗ □?$p $A' ⊢ $Q)) := do
  if p.constName! == ``true then
    let some _ := inst | _ ← synthInstanceQ q(IntoAnd $p $A' $A1 $A2); unreachable!
    have : $p =Q true := ⟨⟩
    let Q' := q(iprop(□ $A2 -∗ $Q))
    let pf ← k1 hyps Q' q(iprop(□ $A1)) A1 ⟨⟩ fun hyps => do
      let pf ← k2 hyps Q q(iprop(□ $A2)) A2 ⟨⟩ k
      return q(wand_intro $pf)
    return q(and_elim_intuitionistic (A := $A') $pf)
  else
    let _ ← synthInstanceQ q(IntoSep $A' $A1 $A2)
    have : $p =Q false := ⟨⟩
    let Q' := q(iprop($A2 -∗ $Q))
    let pf ← k1 hyps Q' A1 A1 ⟨⟩ fun hyps => do
      let pf ← k2 hyps Q A2 A2 ⟨⟩ k
      return q(wand_intro $pf)
    return q(sep_elim_spatial (A := $A') $pf)
end Iris.ProofMode

namespace Iris.ProofMode
def iCasesOr {prop : Q(Type u)} (_bi : Q(BI $prop)) (P Q A' : Q($prop)) (p : Q(Bool))
    (k1 k2 : (B B' : Q($prop)) → (_ : $B =Q iprop(□?$p $B')) → MetaM Q($P ∗ $B ⊢ $Q)) :
    MetaM (Q($P ∗ □?$p $A' ⊢ $Q)) := do
  let A1 ← mkFreshExprMVarQ q($prop)
  let A2 ← mkFreshExprMVarQ q($prop)
  let _ ← synthInstanceQ q(IntoOr $A' $A1 $A2)
  if p.constName! == ``true then
    have : $p =Q true := ⟨⟩
    let pf1 ← k1 q(iprop(□ $A1)) A1 ⟨⟩
    let pf2 ← k2 q(iprop(□ $A2)) A2 ⟨⟩
    return q(or_elim_intuitionistic (A := $A') $pf1 $pf2)
  else
    have : $p =Q false := ⟨⟩
    let pf1 ← k1 A1 A1 ⟨⟩
    let pf2 ← k2 A2 A2 ⟨⟩
    return q(or_elim_spatial (A := $A') $pf1 $pf2)
end Iris.ProofMode

namespace Iris.ProofMode
def iCasesIntuitionistic {prop : Q(Type u)} (_bi : Q(BI $prop)) (P Q A' : Q($prop)) (p : Q(Bool))
    (k : (B' : Q($prop)) → MetaM Q($P ∗ □ $B' ⊢ $Q)) :
    MetaM (Q($P ∗ □?$p $A' ⊢ $Q)) := do
  let B' ← mkFreshExprMVarQ q($prop)
  let _ ← synthInstanceQ q(IntoPersistently $p $A' $B')
  if p.constName! == ``true then
    have : $p =Q true := ⟨⟩
    return q(intuitionistic_elim_intuitionistic $(← k B'))
  else
    have : $p =Q false := ⟨⟩
    let _ ← synthInstanceQ q(TCOr (Affine $A') (Absorbing $Q))
    return q(intuitionistic_elim_spatial (A := $A') $(← k B'))
end Iris.ProofMode

namespace Iris.ProofMode
def iCasesSpatial {prop : Q(Type u)} (_bi : Q(BI $prop)) (P Q A' : Q($prop)) (p : Q(Bool))
    (k : (B' : Q($prop)) → MetaM Q($P ∗ $B' ⊢ $Q)) :
    MetaM (Q($P ∗ □?$p $A' ⊢ $Q)) := do
  let B' ← mkFreshExprMVarQ q($prop)
  let _ ← synthInstanceQ q(FromAffinely $B' $A' $p)
  if p.constName! == ``true then
    have : $p =Q true := ⟨⟩
    return q(spatial_elim_intuitionistic $(← k B'))
  else
    have : $p =Q false := ⟨⟩
    return q(spatial_elim_spatial (A := $A') $(← k B'))
end Iris.ProofMode

namespace Iris.ProofMode
partial def iCasesCore
    {P} (hyps : Hyps bi P) (Q : Q($prop)) (p : Q(Bool))
    (A A' : Q($prop)) (_ : $A =Q iprop(□?$p $A'))
    (pat : iCasesPat) (k : ∀ {P}, Hyps bi P → MetaM Q($P ⊢ $Q)) : MetaM (Q($P ∗ $A ⊢ $Q)) :=
  match pat with
  | .one name => do
    let (name, ref) ← getFreshName name
    let uniq ← mkFreshId
    addHypInfo ref name uniq prop A' (isBinder := true)
    let hyp := .mkHyp bi name uniq p A' A
    if let .emp _ := hyps then
      let pf : Q($A ⊢ $Q) ← k hyp
      pure q(of_emp_sep $pf)
    else
      k (.mkSep hyps hyp)

  | .clear => do
    let pf ← clearCore bi q(iprop($P ∗ $A)) P A Q q(.rfl)
    pure q($pf $(← k hyps))

  | .conjunction [arg] | .disjunction [arg] => iCasesCore hyps Q p A A' ⟨⟩ arg @k

  | .disjunction [] => throwUnsupportedSyntax

  | .conjunction [] => iCasesEmptyConj bi hyps Q A' p @k

  | .conjunction (arg :: args) => do
    let exres ← try? (α := _ × (v : Level) × (α : Q(Sort v)) × (Φ : Q($α → $prop)) ×
        Q(IntoExists $A' $Φ)) do
      let .one n := arg | failure
      let v ← mkFreshLevelMVar
      let α ← mkFreshExprMVarQ q(Sort v)
      let Φ ← mkFreshExprMVarQ q($α → $prop)
      Pure.pure ⟨n, v, α, Φ, ← synthInstanceQ q(IntoExists $A' $Φ)⟩
    if let some ⟨n, _, α, Φ, inst⟩ := exres then
      iCasesExists bi P Q A' p n α Φ inst
        (iCasesCore hyps Q p · · · (.conjunction args) k)
    else
      let A1 ← mkFreshExprMVarQ q($prop)
      let A2 ← mkFreshExprMVarQ q($prop)
      let inst ← try? (α := Q(IntoAnd $p $A' $A1 $A2)) do
        unless arg matches .clear || args matches [.clear] || p.constName! == ``true do failure
        synthInstanceQ q(IntoAnd $p $A' $A1 $A2)
      if let (.clear, some inst) := (arg, inst) then
        iCasesAndLR bi P Q A' A1 A2 p inst (right := true) fun B B' h =>
          iCasesCore hyps Q p B B' h (.conjunction args) @k
      else if let ([.clear], some inst) := (args, inst) then
        iCasesAndLR bi P Q A' A1 A2 p inst (right := false) fun B B' h =>
          iCasesCore hyps Q p B B' h arg @k
      else
        iCasesSep bi hyps Q A' A1 A2 p inst @k
          (iCasesCore · · p · · · arg)
          (iCasesCore · · p · · · (.conjunction args))

  | .disjunction (arg :: args) =>
    iCasesOr bi P Q A' p
      (iCasesCore hyps Q p · · · arg @k)
      (iCasesCore hyps Q p · · · (.disjunction args) @k)

  | .pure arg => do
    let .one n := arg
      | throwError "cannot further destruct a hypothesis after moving it to the Lean context"
    (·.2) <$> ipureCore bi q(iprop($P ∗ $A)) P A Q n q(.rfl) fun _ _ =>
      ((), ·) <$> k hyps

  | .intuitionistic arg =>
    iCasesIntuitionistic bi P Q A' p fun B' =>
      iCasesCore hyps Q q(true) q(iprop(□ $B')) B' ⟨⟩ arg @k

  | .spatial arg =>
    iCasesSpatial bi P Q A' p fun B' =>
      iCasesCore hyps Q q(false) B' B' ⟨⟩ arg @k
end Iris.ProofMode

namespace Iris.ProofMode
def specPatGoal
    (A1 : Q($prop)) (hyps : Hyps bi e) (spats : List SpecPat)
    (addGoal : ∀ {e}, Name → Hyps bi e → (goal : Q($prop)) → MetaM Q($e ⊢ $goal)) :
    MetaM Q($e ⊢ $A1) := do
  return ← if let (some <| .ident _, some inst) := (spats.head?,
      ← try? (synthInstanceQ q(FromAssumption false $e $A1))) then
    pure q(($inst).from_assumption)
  else
    addGoal (headName spats) hyps A1
end Iris.ProofMode

namespace Iris.ProofMode
def processSpecPats
    (A1 : Q($prop)) (hypsl : Hyps bi el) (spats : List SpecPat)
    (addGoal : ∀ {e}, Name → Hyps bi e → (goal : Q($prop)) → MetaM Q($e ⊢ $goal)) :
    MetaM ((el' er' : Q($prop)) × Q($er' ⊢ $A1) × Hyps bi el' × Q($el ⊣⊢ $el' ∗ $er')) := do
  let splitPat := fun name _ => match spats.head? with
    | some <| .ident bIdent => binderIdentHasName name bIdent
    | some <| .idents bIdents _ => bIdents.any <| binderIdentHasName name
    | _ => false

  let ⟨el', er', hypsl', hypsr', h'⟩ := Hyps.split bi splitPat hypsl
  let m ← specPatGoal A1 hypsr' spats addGoal
  return ⟨el', er', m, hypsl', h'⟩
end Iris.ProofMode

namespace Iris.ProofMode
partial def iApplyCore
    (goal el er : Q($prop)) (hypsl : Hyps bi el) (spats : List SpecPat)
    (addGoal : ∀ {e}, Name → Hyps bi e → (goal : Q($prop)) → MetaM Q($e ⊢ $goal)) :
    MetaM (Q($el ∗ $er ⊢ $goal)) := do
  let A1 ← mkFreshExprMVarQ q($prop)
  let A2 ← mkFreshExprMVarQ q($prop)

  let _ ← isDefEq er goal
  if let (some _, some _) := (← try? <| synthInstanceQ q(FromAssumption false $er $goal),
                              ← try? <| synthInstanceQ q(TCOr (Affine $el) (Absorbing $goal))) then
    
    return q(assumption (p := false) .rfl)
  else if let some _ ← try? <| synthInstanceQ q(IntoWand false false $er $A1 $goal) then
    
    let m ← specPatGoal A1 hypsl spats addGoal
    return q(apply $m)
  else if let some _ ← try? <| synthInstanceQ q(IntoWand false false $er $A1 $A2) then
    
    let ⟨el', _, m, hypsl', h'⟩ ← processSpecPats A1 hypsl spats addGoal
    let res : Q($el' ∗ $A2 ⊢ $goal) ← iApplyCore goal el' A2 hypsl' spats.tail addGoal
    return q(rec_apply $h' $m $res)
  else
    throwError "iapply: cannot apply {er} to {goal}"
end Iris.ProofMode

namespace Iris.ProofMode
partial def instantiateForalls' {prop : Q(Type u)} (e e' : Q($prop)) (bi : Q(BI $prop))
    (out : Q($prop)) (pf : Q($e ⊢ $e' ∗ $out)) (terms : List Term) :
    TacticM (Expr × Expr) := do
  if let some t := terms.head? then
    let texpr ← mkAppM' (← elabTerm t none) #[]
    let ⟨_, ttype, texpr⟩ ← inferTypeQ texpr
    let Φ ← mkFreshExprMVarQ q($ttype → $prop)
    let _ ← synthInstanceQ q(IntoForall $out $Φ)
    let res ← mkAppM' Φ #[texpr]
    let pf' ← mkAppM ``apply_forall #[texpr, Φ, pf]
    return ← instantiateForalls' e e' bi res pf' terms.tail
  else
    return ⟨out, pf⟩
end Iris.ProofMode

namespace Iris.Std
inductive RewriteModifier
  | single
  | all
end Iris.Std

namespace Iris.Std
private def parseRewriteRule' (rule : TSyntax ``rwRule') :
    TacticM <| RewriteModifier × TSyntax ``rwRule := do
  match rule with
  | `(rwRule'| !$rule)       => pure (.all, rule)
  | `(rwRule'| $rule:rwRule) => pure (.single, rule)
  | _ => throwUnsupportedSyntax
end Iris.Std

namespace Iris.Std
inductive RewriteDirection
  | forward
  | reverse
end Iris.Std

namespace Iris.Std
private def parseRewriteRule (rule : TSyntax ``rwRule) :
    TacticM <| RewriteDirection × TSyntax `term := do
  match rule with
  | `(rwRule| ← $rule)    => pure (.reverse, rule)
  | `(rwRule| $rule:term) => pure (.forward, rule)
  | _ => throwUnsupportedSyntax
end Iris.Std

namespace Iris.Std
private def getMonotonicityRules : TacticM <| Array Name := do
  return monoRulesExt.getState (← getEnv) |>.toArray
end Iris.Std

namespace Iris.Std
private def normalizeGoal (goal : MVarId) : TacticM MVarId := do
  if (← goal.getType).isForall then
    let (_, goal) ← goal.intro `_
    return goal
  else
    return goal
end Iris.Std

namespace Iris.Std
private def rewriteConventional (rule : TSyntax ``rwRule) : TacticM Bool := do
  try
    evalTactic (← `(tactic| rewrite [$rule]))
    return true
  catch _ =>
    return false
end Iris.Std

namespace Iris.Std
private partial def rewriteTMR
    (direction : RewriteDirection) (rule : TSyntax `term) : TacticM Bool := do
  let goal ← getMainGoal
  let tag ← goal.getTag

  
  let some (goalL, goalR) ← applyTransitivity goal
    | return false

  
  let goal ← match direction with
    | .forward => do
      goalR.setTag tag
      pure goalL
    | .reverse => do
      goalL.setTag tag
      pure goalR

  
  go goal rule
where
  applyTransitivity (goal : MVarId) : TacticM <| Option <| MVarId × MVarId := do
    try
      let some <| goalL :: goalR :: [] ← apply' goal ``trans
        | return none
      return some (goalL, goalR)
    catch _ =>
      return none

  applyMonotonicity (goal : MVarId) : TacticM <| Option <| List MVarId := do
    for rule in (← getMonotonicityRules) do
      try
        if let some goals ← apply' goal rule then
          return ← goals.mapM normalizeGoal
      catch _ =>
        continue
    return none

  applyReflexivity (goal : MVarId) : TacticM Unit := do
    try
      discard <| apply' goal ``refl
    catch _ => pure ()

  go (goal : MVarId) (rule : TSyntax `term) : TacticM Bool := do
    
    try
      withFocus goal <| withoutRecover <| evalTactic (← `(tactic|
        exact $rule
      ))
      return true
    catch _ => pure ()

    
    let state ← saveState
    if let some goals ← applyMonotonicity goal then
      let mut rule? := some rule

      
      for goal in goals do
        match rule? with
        | some rule =>
          if ← go goal rule then
            rule? := none
        | none =>
          applyReflexivity goal

      
      if rule?.isSome then
        state.restore
        applyReflexivity goal

      return rule?.isNone
    else
      
      applyReflexivity goal
      return false
end Iris.Std

namespace Iris.BI
instance emp_intuitionistic [BI PROP] : Intuitionistic iprop(emp : PROP) where
  intuitionistic := intuitionistically_emp.2
end Iris.BI

namespace Iris.BI
instance and_intuitionistic [BI PROP] (P Q : PROP) [Intuitionistic P] [Intuitionistic Q] :
    Intuitionistic iprop(P ∧ Q) where
  intuitionistic := (and_mono intuitionistic intuitionistic).trans intuitionistically_and.2
end Iris.BI

namespace Iris.BI
instance or_intuitionistic [BI PROP] (P Q : PROP) [Intuitionistic P] [Intuitionistic Q] :
    Intuitionistic iprop(P ∨ Q) where
  intuitionistic := (or_mono intuitionistic intuitionistic).trans intuitionistically_or.2
end Iris.BI

namespace Iris.BI
instance exists_intuitionistic [BI PROP] (Φ : α → PROP) [∀ x, Intuitionistic (Φ x)] :
    Intuitionistic iprop(∃ x, Φ x) where
  intuitionistic := (exists_mono fun _ => intuitionistic).trans intuitionistically_exists.2
end Iris.BI

namespace Iris.BI
instance sep_intuitionistic [BI PROP] (P Q : PROP) [Intuitionistic P] [Intuitionistic Q] :
    Intuitionistic iprop(P ∗ Q) where
  intuitionistic := (sep_mono intuitionistic intuitionistic).trans intuitionistically_sep_2
end Iris.BI

namespace Iris.BI
instance intuitionistically_intuitionistic [BI PROP] (P : PROP) : Intuitionistic iprop(□ P) where
  intuitionistic := intuitionistically_idem.2
end Iris.BI

namespace Iris
@[ext]
structure Agree where
  car : List α
  not_nil : car ≠ []
end Iris

namespace Iris
def toAgree (a : α) : Agree α := ⟨[a], by admit /- proof elided -/
⟩
end Iris

namespace Iris
def Agree.dist (n : Nat) (x y : Agree α) : Prop :=
  (∀ a ∈ x.car, ∃ b ∈ y.car, a ≡{n}≡ b) ∧
  (∀ b ∈ y.car, ∃ a ∈ x.car, a ≡{n}≡ b)
end Iris

namespace Iris
instance : OFE (Agree α) where
  Equiv x y := ∀ n, Agree.dist n x y
  Dist := Agree.dist
  dist_eqv := Agree.dist_equiv
  equiv_dist := by admit /- proof elided -/
end Iris

namespace Iris
def Agree.validN (n : Nat) (x : Agree α) : Prop :=
  match x.car with
  | [_] => True
  | _ => ∀ a ∈ x.car, ∀ b ∈ x.car, a ≡{n}≡ b
end Iris

namespace Iris
def Agree.valid (x : Agree α) : Prop := ∀ n, x.validN n
end Iris

namespace Iris
def Agree.op (x y : Agree α) : Agree α :=
  ⟨x.car ++ y.car, by admit /- proof elided -/
  ⟩
end Iris

namespace Iris
instance : CMRA (Agree α) where
  pcore := some
  op := Agree.op
  ValidN := Agree.validN
  Valid := Agree.valid

  op_ne := Agree.op_ne
  pcore_ne := by admit /- proof elided -/
end Iris

namespace Iris
instance : CMRA.IsTotal (Agree α) where
  total x := ⟨x, rfl⟩
end Iris

namespace Iris
instance [OFE.Discrete α] : CMRA.Discrete (Agree α) where
  discrete_0 := by admit /- proof elided -/
end Iris

namespace Iris
instance : OFE.NonExpansive (@toAgree α) where
  ne n x₁ x₂ heq := by admit /- proof elided -/
end Iris

namespace Iris
instance {x : Agree α} : CMRA.Cancelable x where
  cancelableN {n y z} hval heq := by admit /- proof elided -/
end Iris

namespace Iris
def Agree.map' {α β} (f : α → β) (a : Agree α) : Agree β := ⟨a.car.map f, by admit /- proof elided -/
⟩
end Iris

namespace Iris
local instance : OFE.NonExpansive (Agree.map' f) where
  ne := by admit /- proof elided -/
end Iris

namespace Iris
def Agree.map : CMRA.Hom (Agree α) (Agree β) where
  f := map' f
  ne := inferInstance
  validN {n x} hval := by admit /- proof elided -/
end Iris

namespace Iris.ProofMode
partial def instantiateForalls {prop : Q(Type u)} (bi : Q(BI $prop)) (hyp : Q($prop))
    (pf : Q(⊢ $hyp)) (terms : List Term) : TacticM (Expr × Expr) := do
  if let some t := terms.head? then
    let texpr ← mkAppM' (← elabTerm t none) #[]
    let ⟨_, ttype, texpr⟩ ← inferTypeQ texpr
    let Φ ← mkFreshExprMVarQ q($ttype → $prop)
    let _ ← synthInstanceQ q(IntoForall $hyp $Φ)
    let res ← mkAppM' Φ #[texpr]
    let pf' ← mkAppM ``pose_forall #[texpr, Φ, pf]
    return ← instantiateForalls bi res pf' terms.tail
  else
    let pf ← mkAppM ``as_emp_valid_1 #[hyp, pf]
    return ⟨hyp, pf⟩
end Iris.ProofMode

namespace Iris.ProofMode
partial def handleDependentArrows {prop : Q(Type u)} (bi : Q(BI $prop)) (val : Expr) (goals : IO.Ref (Array MVarId)) : TacticM (Expr × Q(Prop)) := do
  let p : Q(Prop) ← inferType val
  if let .forallE _ binderType _ _ := p then
    let m ← mkFreshExprMVar binderType
    let val' := mkApp val m
    goals.modify (·.push m.mvarId!)
    return ← handleDependentArrows bi val' goals
  else
    return (val, p)
end Iris.ProofMode

namespace Iris.ProofMode
def iPoseCore {prop : Q(Type u)} (bi : Q(BI $prop)) (val : Expr) (terms : List Term)
    (goals : IO.Ref (Array MVarId)) : TacticM (Q($prop) × Expr) := do
  let hyp ← mkFreshExprMVarQ q($prop)
  let (v, p) ← handleDependentArrows bi val goals
  if let some _ ← try? <| synthInstanceQ q(IntoEmpValid $p $hyp) then
    return ← instantiateForalls bi hyp v terms
  else
    throwError "ipose: {val} is not an entailment"
end Iris.ProofMode

namespace Iris.BI
macro:max "iprop(" P:term " : " t:term ")" : term => `((iprop($P) : $t))
end Iris.BI

namespace Iris.BI
partial def unpackIprop [Monad m] [MonadRef m] [MonadQuotation m] : Term → m Term
  | `(iprop($P))             => do `($P)
  | `($P:ident)              => do `($P)
  | `(?$P:ident)             => do `(?$P)
  | `(($P))                  => do `(($(← unpackIprop P)))
  | `($P $[ $Q]*)            => do ``($P $[ $Q]*)
  | `(if $c then $t else $e) => do
    let t ← unpackIprop t
    let e ← unpackIprop e
    `(if $c then $t else $e)
  | `(($P : $t))             => do ``(($(← unpackIprop P) : $t))
  | `($t)                    => `($t:term)
end Iris.BI

namespace Iris
def UpdateP [CMRA α] (x : α) (P : α → Prop) := ∀ n mz,
  ✓{n} (x •? mz) → ∃ y, P y ∧ ✓{n} (y •? mz)
end Iris

namespace Iris
def Update [CMRA α] (x y : α) := ∀ n mz,
  ✓{n} (x •? mz) → ✓{n} (y •? mz)
end Iris

namespace Iris
instance [CMRA α] : Trans OFE.Equiv UpdateP UpdateP (α := α) where
  trans e u := UpdateP.equiv_left e.symm u
end Iris

namespace Iris
instance [CMRA α] : Trans OFE.Equiv Update Update (α := α) where
  trans e u := Update.equiv_left (id (OFE.Equiv.symm e)) u
end Iris

namespace Iris
instance [CMRA α] : Trans Update OFE.Equiv Update (α := α) where
  trans u e := Update.equiv_right e u
end Iris

namespace Iris
instance [CMRA α] : Trans Update Update Update (α := α) where
  trans := Update.trans
end Iris

namespace Iris
instance [CMRA α] : Trans Update UpdateP UpdateP (α := α) where
  trans := Update.transP
end Iris

namespace Iris.ProofMode
structure PMTerm where
  term : Term
  terms : List Term
  spats : List SpecPat
  deriving Repr, Inhabited
end Iris.ProofMode

namespace Iris.ProofMode
partial def PMTerm.parse (term : Syntax) : MacroM PMTerm := do
  match ← expandMacros term with
  | `(pmTerm| $trm:term) => return ⟨trm, [], []⟩
  | `(pmTerm| $trm:term with $spats,*) => return ⟨trm, [], ← parseSpats spats⟩
  | `(pmTerm| $trm:term $! $ts,*) => return ⟨trm, ts.getElems.toList, []⟩
  | `(pmTerm| $trm:term $! $ts,* with $spats,*) =>
    return ⟨trm, ts.getElems.toList, ← parseSpats spats⟩
  | _ => Macro.throwUnsupported
where
  parseSpats (spats : Syntax.TSepArray `specPat ",") : MacroM (List SpecPat) :=
      return (← spats.getElems.toList.mapM fun pat => SpecPat.parse pat.raw)
end Iris.ProofMode

namespace Iris.ProofMode
partial def iIntroCore
    {P} (hyps : Hyps bi P) (Q : Q($prop)) (pats : List iCasesPat)
    (k : ∀ {P}, Hyps bi P → (Q : Q($prop)) → MetaM Q($P ⊢ $Q)) :
    MetaM (Q($P ⊢ $Q)) := do
  match pats with
  | [] => k hyps Q
  | pat :: pats =>
    let A1 ← mkFreshExprMVarQ q($prop)
    let A2 ← mkFreshExprMVarQ q($prop)
    let fromImp ← try? (α := Q(FromImp $Q $A1 $A2)) do
      synthInstanceQ q(FromImp $Q $A1 $A2)
    if let (.clear, some _) := (pat, fromImp) then
      let pf ← iIntroCore hyps A2 pats k
      return q(imp_intro_drop (Q := $Q) $pf)
    else
    let alres ← try? (α := _ × (v : Level) × (α : Q(Sort v)) × (Φ : Q($α → $prop)) ×
        Q(FromForall $Q $Φ)) do
      let .one n := pat | failure
      let v ← mkFreshLevelMVar
      let α ← mkFreshExprMVarQ q(Sort v)
      let Φ ← mkFreshExprMVarQ q($α → $prop)
      Pure.pure ⟨n, v, α, Φ, ← synthInstanceQ q(FromForall $Q $Φ)⟩
    if let some ⟨n, _, α, Φ, _⟩ := alres then
      let (n, ref) ← getFreshName n
      withLocalDeclDQ n α fun x => do
        addLocalVarInfo ref (← getLCtx) x α
        have B : Q($prop) := Expr.headBeta q($Φ $x)
        have : $B =Q $Φ $x := ⟨⟩
        let pf : Q(∀ x, $P ⊢ $Φ x) ← mkLambdaFVars #[x] <|← iIntroCore hyps B pats k
        return q(from_forall_intro (Q := $Q) $pf)
    else
    let B ← mkFreshExprMVarQ q($prop)
    match pat, fromImp with
    | .intuitionistic pat, some _ =>
      let _ ← synthInstanceQ q(IntoPersistently false $A1 $B)
      let pf ← iCasesCore bi hyps A2 q(true) q(iprop(□ $B)) B ⟨⟩ pat (iIntroCore · A2 pats k)
      return q(imp_intro_intuitionistic (Q := $Q) $pf)
    | .intuitionistic pat, none =>
      let _ ← synthInstanceQ q(FromWand $Q $A1 $A2)
      let _ ← synthInstanceQ q(IntoPersistently false $A1 $B)
      let _ ← synthInstanceQ q(TCOr (Affine $A1) (Absorbing $A2))
      let pf ← iCasesCore bi hyps A2 q(true) q(iprop(□ $B)) B ⟨⟩ pat (iIntroCore · A2 pats k)
      return q(wand_intro_intuitionistic (Q := $Q) $pf)
    | _, some _ =>
      let _ ← synthInstanceQ q(FromAffinely $B $A1)
      let _ ← synthInstanceQ q(TCOr (Persistent $A1) (Intuitionistic $P))
      let pf ← iCasesCore bi hyps A2 q(false) B B ⟨⟩ pat (iIntroCore · A2 pats k)
      return q(imp_intro_spatial (Q := $Q) $pf)
    | _, none =>
      let _ ← synthInstanceQ q(FromWand $Q $A1 $A2)
      let pf ← iCasesCore bi hyps A2 q(false) A1 A1 ⟨⟩ pat (iIntroCore · A2 pats k)
      return q(wand_intro_spatial (Q := $Q) $pf)
end Iris.ProofMode

namespace Iris.ProofMode
inductive SpecPat
  | ident (name : TSyntax ``binderIdent)
  | idents (names : List (TSyntax ``binderIdent)) (goalName : Name)
  deriving Repr, Inhabited
end Iris.ProofMode

namespace Iris.ProofMode
partial def SpecPat.parse (pat : Syntax) : MacroM SpecPat := do
  match go ⟨← expandMacros pat⟩ with
  | none => Macro.throwUnsupported
  | some pat => return pat
where
  go : TSyntax `specPat → Option SpecPat
  | `(specPat| $name:binderIdent) => some <| .ident name
  | `(specPat| [$[$names:binderIdent],*]) => some <| .idents names.toList .anonymous
  | `(specPat| [$[$names:binderIdent],*] as $goal:ident) => match goal.raw with
    | .ident _ _ val _ => some <| .idents names.toList val
    | _ => none
  | _ => none
end Iris.ProofMode

namespace Iris.ProofMode
def headName (spats : List SpecPat) : Name :=
  match spats.head? with
    | some <| .ident _ => .anonymous
    | some <| .idents _ name => name
    | _ => .anonymous
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default - 10) asEmpValidEmpValid1
    [BI PROP] (P : PROP) : AsEmpValid1 (⊢ P) P := ⟨by admit /- proof elided -/
    ⟩
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 10) asEmpValidEmpValid2
    [BI PROP] (P : PROP) : AsEmpValid2 (⊢ P) P := AsEmpValid1.to2
end Iris.ProofMode

namespace Iris.ProofMode
instance asEmpValid1_entails [BI PROP] (P Q : PROP) : AsEmpValid1 (P ⊢ Q) iprop(P -∗ Q) where
  as_emp_valid := ⟨entails_wand, wand_entails⟩
end Iris.ProofMode

namespace Iris.ProofMode
instance asEmpValid2_entails [BI PROP] (P Q : PROP) : AsEmpValid2 (P ⊢ Q) iprop(P -∗ Q) :=
  AsEmpValid1.to2
end Iris.ProofMode

namespace Iris.ProofMode
instance asEmpValid1_equiv [BI PROP] (P Q : PROP) : AsEmpValid1 (P ⊣⊢ Q) iprop(P ∗-∗ Q) where
  as_emp_valid := ⟨equiv_wandIff, wandIff_equiv⟩
end Iris.ProofMode

namespace Iris.ProofMode
instance asEmpValid2_equiv [BI PROP] (P Q : PROP) : AsEmpValid2 (P ⊣⊢ Q) iprop(P ∗-∗ Q) :=
  AsEmpValid1.to2
end Iris.ProofMode

namespace Iris.ProofMode
instance intoEmpValid_emp_entails [BI PROP] (P : PROP) : IntoEmpValid (⊢ P) iprop(P) where
  into_emp_valid := id
end Iris.ProofMode

namespace Iris.ProofMode
instance intoEmpValid_entails [BI PROP] (P Q : PROP) : IntoEmpValid (P ⊢ Q) iprop(P -∗ Q) where
  into_emp_valid := entails_wand
end Iris.ProofMode

namespace Iris.ProofMode
instance intoEmpValid_equiv [BI PROP] (P Q : PROP) : IntoEmpValid (P ⊣⊢ Q) iprop(P ∗-∗ Q) where
  into_emp_valid := equiv_wandIff
end Iris.ProofMode

namespace Iris.ProofMode
instance fromImp_imp [BI PROP] (P1 P2 : PROP) : FromImp iprop(P1 → P2) P1 P2 := ⟨.rfl⟩
end Iris.ProofMode

namespace Iris.ProofMode
instance fromWand_wand [BI PROP] (P1 P2 : PROP) : FromWand iprop(P1 -∗ P2) P1 P2 := ⟨.rfl⟩
end Iris.ProofMode

namespace Iris.ProofMode
instance intoWand_wand (p q : Bool) [BI PROP] (P Q P' : PROP) [h : FromAssumption q P P'] :
    IntoWand p q iprop(P' -∗ Q) P Q where
  into_wand := (intuitionisticallyIf_mono <| wand_mono_l h.1).trans intuitionisticallyIf_elim
end Iris.ProofMode

namespace Iris.ProofMode
instance intoWand_imp_false [BI PROP] (P Q P' : PROP) [Absorbing P'] [Absorbing iprop(P' → Q)]
    [h : FromAssumption b P P'] : IntoWand false b iprop(P' → Q) P Q where
  into_wand := wand_intro <| (sep_mono_r h.1).trans <| by dsimp; exact sep_and.trans imp_elim_l
end Iris.ProofMode

namespace Iris.ProofMode
instance intoWand_imp_true [BI PROP] (P Q P' : PROP) [Affine P']
    [h : FromAssumption b P P'] : IntoWand true b iprop(P' → Q) P Q where
  into_wand := wand_intro <| (sep_mono_r h.1).trans <| by
    dsimp; exact sep_and.trans <| imp_elim intuitionistically_elim
end Iris.ProofMode

namespace Iris.ProofMode
instance intoWand_and_l (p q : Bool) [BI PROP] (R1 R2 P' Q' : PROP)
    [h : IntoWand p q R1 P' Q'] : IntoWand p q iprop(R1 ∧ R2) P' Q' where
  into_wand := (intuitionisticallyIf_mono and_elim_l).trans h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance intoWand_and_r (p q : Bool) [BI PROP] (R1 R2 P' Q' : PROP)
    [h : IntoWand p q R2 Q' P'] : IntoWand p q iprop(R1 ∧ R2) Q' P' where
  into_wand := (intuitionisticallyIf_mono and_elim_r).trans h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance intoWand_forall (p q : Bool) [BI PROP] (Φ : α → PROP) (P Q : PROP) (x : α)
    [h : IntoWand p q (Φ x) P Q] : IntoWand p q iprop(∀ x, Φ x) P Q where
  into_wand := (intuitionisticallyIf_mono <| BI.forall_elim x).trans h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance intoWand_affinely (p q : Bool) [BI  PROP] (R P Q : PROP) [h : IntoWand p q R P Q] :
    IntoWand p q iprop(<affine> R) iprop(<affine> P) iprop(<affine> Q) where
  into_wand := wand_intro <|
    (sep_congr intuitionisticallyIf_affinely intuitionisticallyIf_affinely).1.trans <|
    affinely_sep_2.trans <| affinely_mono <| wand_elim h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance intoWand_intuitionistically (p q : Bool) [BI PROP] (R P Q : PROP)
    [h : IntoWand true q R P Q] : IntoWand p q iprop(□ R) P Q where
  into_wand := (intuitionisticallyIf_mono h.1).trans intuitionisticallyIf_elim
end Iris.ProofMode

namespace Iris.ProofMode
instance intoWand_intuitionistically_wand (p : Bool) [BI PROP] (P Q : PROP) :
    IntoWand p true iprop(□ P -∗ Q) P Q where
  into_wand := intuitionisticallyIf_elim
end Iris.ProofMode

namespace Iris.ProofMode
instance intoWand_persistently_true (q : Bool) [BI PROP] (R P Q : PROP)
    [h : IntoWand true q R P Q] : IntoWand true q iprop(<pers> R) P Q where
  into_wand := intuitionistically_persistently.1.trans h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance intoWand_persistently_false (q : Bool) [BI PROP] (R P Q : PROP) [Absorbing R]
    [h : IntoWand false q R P Q] : IntoWand false q iprop(<pers> R) P Q where
  into_wand := persistently_elim.trans h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance fromForall_forall [BI PROP] (Φ : α → PROP) : FromForall (BIBase.forall Φ) Φ := ⟨.rfl⟩
end Iris.ProofMode

namespace Iris.ProofMode
instance intoForall_forall [BI PROP] (Φ : α → PROP) : IntoForall iprop(∀ a, Φ a) Φ := ⟨.rfl⟩
end Iris.ProofMode

namespace Iris.ProofMode
instance intoForall_affinely [BI PROP] (P : PROP) (Φ : α → PROP) [h : IntoForall P Φ] :
    IntoForall iprop(<affine> P) (fun a => iprop(<affine> (Φ a))) where
  into_forall := (affinely_mono h.1).trans affinely_forall_1
end Iris.ProofMode

namespace Iris.ProofMode
instance intoForall_intuitionistically [BI PROP] (P : PROP) (Φ : α → PROP)
    [h : IntoForall P Φ] : IntoForall iprop(□ P) (fun a => iprop(□ (Φ a))) where
  into_forall := (intuitionistically_mono h.1).trans intuitionistically_forall_1
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 10) fromExists_exists [BI PROP] (Φ : α → PROP) :
    FromExists iprop(∃ a, Φ a) Φ := ⟨.rfl⟩
end Iris.ProofMode

namespace Iris.ProofMode
instance fromExists_pure (φ : α → Prop) [BI PROP] :
    FromExists (PROP := PROP) iprop(⌜∃ x, φ x⌝) (fun a => iprop(⌜φ a⌝)) where
  from_exists := pure_exists.1
end Iris.ProofMode

namespace Iris.ProofMode
instance fromExists_affinely [BI PROP] (P : PROP) (Φ : α → PROP) [h : FromExists P Φ] :
    FromExists iprop(<affine> P) (fun a => iprop(<affine> (Φ a))) where
  from_exists := affinely_exists.2.trans <| affinely_mono h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance fromExists_intuitionistically [BI PROP] (P : PROP) (Φ : α → PROP) [h : FromExists P Φ] :
    FromExists iprop(□ P) (fun a => iprop(□ (Φ a))) where
  from_exists := intuitionistically_exists.2.trans <| intuitionistically_mono h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance fromExists_absorbingly [BI PROP] (P : PROP) (Φ : α → PROP) [h : FromExists P Φ] :
    FromExists iprop(<absorb> P) (fun a => iprop(<absorb> (Φ a))) where
  from_exists := absorbingly_exists.2.trans <| absorbingly_mono h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance fromExists_persistently [BI PROP] (P : PROP) (Φ : α → PROP) [h : FromExists P Φ] :
    FromExists iprop(<pers> P) (fun a => iprop(<pers> (Φ a))) where
  from_exists := persistently_exists.2.trans <| persistently_mono h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance intoExists_exists [BI PROP] (Φ : α → PROP) : IntoExists (BI.exists Φ) Φ := ⟨.rfl⟩
end Iris.ProofMode

namespace Iris.ProofMode
instance intoExists_pure (φ : α → Prop) [BI PROP] :
    IntoExists (PROP := PROP) iprop(⌜∃ x, φ x⌝) (fun a => iprop(⌜φ a⌝)) where
  into_exists := pure_exists.2
end Iris.ProofMode

namespace Iris.ProofMode
instance intoExists_affinely [BI PROP] (P : PROP) (Φ : α → PROP) [h : IntoExists P Φ] :
    IntoExists iprop(<affine> P) (fun a => iprop(<affine> (Φ a))) where
  into_exists := (affinely_mono h.1).trans affinely_exists.1
end Iris.ProofMode

namespace Iris.ProofMode
instance intoExists_intuitionistically [BI PROP] (P : PROP) (Φ : α → PROP) [h : IntoExists P Φ] :
    IntoExists iprop(□ P) (fun a => iprop(□ (Φ a))) where
  into_exists := (intuitionistically_mono h.1).trans intuitionistically_exists.1
end Iris.ProofMode

namespace Iris.ProofMode
instance intoExists_absorbingly [BI PROP] (P : PROP) (Φ : α → PROP) [h : IntoExists P Φ] :
    IntoExists iprop(<absorb> P) (fun a => iprop(<absorb> (Φ a))) where
  into_exists := (absorbingly_mono h.1).trans absorbingly_exists.1
end Iris.ProofMode

namespace Iris.ProofMode
instance intoExists_persistently [BI PROP] {P : PROP} (Φ : α → PROP) [h : IntoExists P Φ] :
    IntoExists iprop(<pers> P) (fun a => iprop(<pers> (Φ a))) where
  into_exists := (persistently_mono h.1).trans persistently_exists.1
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default - 10) fromAnd_and [BI PROP] (P1 P2 : PROP) :
    FromAnd iprop(P1 ∧ P2) P1 P2 := ⟨.rfl⟩
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 30) fromAnd_sep_persistent_l [BI PROP] (P1 P1' P2 : PROP)
    [Persistent P1] [h : IntoAbsorbingly P1' P1] : FromAnd iprop(P1 ∗ P2) P1' P2 where
  from_and := by admit /- proof elided -/
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 20) fromAnd_sep_persistent_r [BI PROP] (P1 P2 P2' : PROP)
    [Persistent P2] [h : IntoAbsorbingly P2' P2] : FromAnd iprop(P1 ∗ P2) P1 P2' where
  from_and := by admit /- proof elided -/
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 50) fromAnd_pure (φ ψ : Prop) [BI PROP] :
    FromAnd (PROP := PROP) iprop(⌜φ ∧ ψ⌝) iprop(⌜φ⌝) iprop(⌜ψ⌝) where
  from_and := pure_and.1
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 40) fromAnd_persistently [BI PROP] (P Q1 Q2 : PROP)
    [h : FromAnd P Q1 Q2] : FromAnd iprop(<pers> P) iprop(<pers> Q1) iprop(<pers> Q2) where
  from_and := persistently_and.2.trans <| persistently_mono h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 10) fromAnd_persistently_sep [BI PROP] (P Q1 Q2 : PROP)
    [h : FromSep P Q1 Q2] : FromAnd iprop(<pers> P) iprop(<pers> Q1) iprop(<pers> Q2) where
  from_and := persistently_and.2.trans <| persistently_and_sep.trans <| persistently_mono h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default - 10) intoAnd_and (p : Bool) [BI PROP] (P Q : PROP) :
    IntoAnd p iprop(P ∧ Q) P Q := ⟨.rfl⟩
end Iris.ProofMode

namespace Iris.ProofMode
instance intoAnd_and_affine_l [BI PROP] (P Q Q' : PROP) [Affine P]
    [h : FromAffinely Q' Q] : IntoAnd false iprop(P ∧ Q) P Q' where
  into_and := (and_mono_l (affine_affinely _).2).trans <|
    affinely_and_l.1.trans <| affinely_and.1.trans <| and_mono (affine_affinely _).1 h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance intoAnd_and_affine_r [BI PROP] (P P' Q : PROP) [Affine Q]
    [h : FromAffinely P' P] : IntoAnd false iprop(P ∧ Q) P' Q where
  into_and := (and_mono_r (affine_affinely _).2).trans <|
    affinely_and_r.1.trans <| affinely_and.1.trans <| and_mono h.1 (affine_affinely _).1
end Iris.ProofMode

namespace Iris.ProofMode
instance intoAnd_sep_affine (p : Bool) [BI PROP] (P Q : PROP)
    [TCOr (Affine P) (Absorbing Q)] [TCOr (Affine Q) (Absorbing P)] :
    IntoAnd p iprop(P ∗ Q) P Q where
  into_and := intuitionisticallyIf_mono sep_and
end Iris.ProofMode

namespace Iris.ProofMode
instance intoAnd_pure (p : Bool) (φ ψ : Prop) [BI PROP] :
    IntoAnd (PROP := PROP) p iprop(⌜φ ∧ ψ⌝) iprop(⌜φ⌝) iprop(⌜ψ⌝) where
  into_and := intuitionisticallyIf_mono pure_and.2
end Iris.ProofMode

namespace Iris.ProofMode
instance intoAnd_affinely (p : Bool) [BI PROP] (P Q1 Q2 : PROP) [h : IntoAnd p P Q1 Q2] :
    IntoAnd p iprop(<affine> P) iprop(<affine> Q1) iprop(<affine> Q2) where
  into_and := intuitionisticallyIf_affinely.1.trans <| (affinely_mono h.1).trans <|
    intuitionisticallyIf_affinely.2.trans (intuitionisticallyIf_mono affinely_and.1)
end Iris.ProofMode

namespace Iris.ProofMode
instance intoAnd_intuitionistically (p : Bool) [BI PROP] (P Q1 Q2 : PROP) [h : IntoAnd p P Q1 Q2] :
    IntoAnd p iprop(□ P) iprop(□ Q1) iprop(□ Q2) where
  into_and := (intuitionisticallyIf_comm' (q := true)).1.trans <|
      (intuitionistically_mono h.1).trans <| (intuitionisticallyIf_comm' (q := true)).2.trans <|
      intuitionisticallyIf_mono intuitionistically_and.1
end Iris.ProofMode

namespace Iris.ProofMode
instance intoAnd_persistently (p : Bool) [BI PROP] (P Q1 Q2 : PROP) [h : IntoAnd p P Q1 Q2] :
    IntoAnd p iprop(<pers> P) iprop(<pers> Q1) iprop(<pers> Q2) where
  into_and := by admit /- proof elided -/
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default - 10) fromSep_sep [BI PROP] (P1 P2 : PROP) :
    FromSep iprop(P1 ∗ P2) P1 P2 := ⟨.rfl⟩
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default - 20) fromSep_and [BI PROP] (P1 P2 : PROP)
    [TCOr (Affine P1) (Absorbing P2)] [TCOr (Affine P2) (Absorbing P1)] :
    FromSep iprop(P1 ∧ P2) P1 P2 where
  from_sep := sep_and
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 20) fromSep_pure (φ ψ : Prop) [BI PROP] :
    FromSep (PROP := PROP) iprop(⌜φ ∧ ψ⌝) iprop(⌜φ⌝) iprop(⌜ψ⌝) where
  from_sep := pure_sep.1
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 10) fromSep_affinely [BI PROP] (P Q1 Q2 : PROP)
    [h : FromSep P Q1 Q2] : FromSep iprop(<affine> P) iprop(<affine> Q1) iprop(<affine> Q2) where
  from_sep := affinely_sep_2.trans (affinely_mono h.1)
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 10) fromSep_intuitionistically [BI PROP] (P Q1 Q2 : PROP)
    [h : FromSep P Q1 Q2] : FromSep iprop(□ P) iprop(□ Q1) iprop(□ Q2) where
  from_sep := intuitionistically_sep_2.trans (intuitionistically_mono h.1)
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 10) fromSep_absorbingly [BI PROP] (P Q1 Q2 : PROP)
    [h : FromSep P Q1 Q2] : FromSep iprop(<absorb> P) iprop(<absorb> Q1) iprop(<absorb> Q2) where
  from_sep := absorbingly_sep.2.trans (absorbingly_mono h.1)
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 10) fromSep_persistently [BI PROP] (P Q1 Q2 : PROP)
    [h : FromSep P Q1 Q2] : FromSep iprop(<pers> P) iprop(<pers> Q1) iprop(<pers> Q2) where
  from_sep := persistently_sep_2.trans (persistently_mono h.1)
end Iris.ProofMode

namespace Iris.ProofMode
instance intoSep_sep [BI PROP] (P Q : PROP) : IntoSep iprop(P ∗ Q) P Q := ⟨.rfl⟩
end Iris.ProofMode

namespace Iris.ProofMode
instance intoSep_and_persistent_l [BI PROP] (P Q P' Q' : PROP) [Persistent P]
    [inst : AndIntoSep P P' Q Q'] : IntoSep iprop(P ∧ Q) P' Q' where
  into_sep :=
    match P', inst with
    | _, AndIntoSep.affine (h := h) .. =>
      (and_mono_l (affine_affinely _).2).trans <| affinely_and_lr.1.trans <|
        persistent_and_affinely_sep_l_1.trans (sep_mono (affine_affinely _).1 h.1)
    | _, AndIntoSep.affinely .. => persistent_and_affinely_sep_l_1
end Iris.ProofMode

namespace Iris.ProofMode
instance intoSep_and_persistent_r [BI PROP] (P Q P' Q' : PROP) [Persistent Q]
    [inst : AndIntoSep Q Q' P P'] : IntoSep iprop(P ∧ Q) P' Q' where
  into_sep :=
    match P', inst with
    | _, AndIntoSep.affine (h := h) .. =>
      (and_mono_r (affine_affinely _).2).trans <| affinely_and_lr.2.trans <|
        persistent_and_affinely_sep_r_1.trans (sep_mono h.1 (affine_affinely _).1)
    | _, AndIntoSep.affinely .. => persistent_and_affinely_sep_r_1
end Iris.ProofMode

namespace Iris.ProofMode
instance intoSep_pure (φ ψ : Prop) [BI PROP] :
    IntoSep (PROP := PROP) iprop(⌜φ ∧ ψ⌝) iprop(⌜φ⌝) iprop(⌜ψ⌝) where
  into_sep := pure_and.2.trans persistent_and_sep_1
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default - 10) intoSep_affinely_trim [BI PROP] (P Q1 Q2 : PROP)
    [h : IntoSep P Q1 Q2] : IntoSep iprop(<affine> P) Q1 Q2 where
  into_sep := affinely_elim.trans h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance intoSep_persistently_affine [BI PROP] (P Q1 Q2 : PROP) [h : IntoSep P Q1 Q2]
    [TCOr (Affine Q1) (Absorbing Q2)] [TCOr (Affine Q2) (Absorbing Q1)] :
    IntoSep iprop(<pers> P) iprop(<pers> Q1) iprop(<pers> Q2) where
  into_sep := (persistently_mono <| h.1.trans sep_and).trans <|
    persistently_and.1.trans persistently_and_imp_sep
end Iris.ProofMode

namespace Iris.ProofMode
instance intoSep_intuitionistically_affine [BI PROP] (P Q1 Q2 : PROP) [h : IntoSep P Q1 Q2]
    [TCOr (Affine Q1) (Absorbing Q2)] [TCOr (Affine Q2) (Absorbing Q1)] :
    IntoSep iprop(□ P) iprop(□ Q1) iprop(□ Q2) where
  into_sep := (intuitionistically_mono <| h.1.trans sep_and).trans <|
    intuitionistically_and.1.trans and_sep_intuitionistically.1
end Iris.ProofMode

namespace Iris.ProofMode
instance fromOr_or [BI PROP] (P1 P2 : PROP) : FromOr iprop(P1 ∨ P2) P1 P2 := ⟨.rfl⟩
end Iris.ProofMode

namespace Iris.ProofMode
instance fromOr_pure (φ ψ : Prop) [BI PROP] :
    FromOr (PROP := PROP) iprop(⌜φ ∨ ψ⌝) iprop(⌜φ⌝) iprop(⌜ψ⌝) where
  from_or := pure_or.1
end Iris.ProofMode

namespace Iris.ProofMode
instance fromOr_affinely [BI PROP] (P Q1 Q2 : PROP) [h : FromOr P Q1 Q2] :
    FromOr iprop(<affine> P) iprop(<affine> Q1) iprop(<affine> Q2) where
  from_or := affinely_or.2.trans (affinely_mono h.1)
end Iris.ProofMode

namespace Iris.ProofMode
instance fromOr_intuitionistically [BI PROP] (P Q1 Q2 : PROP) [h : FromOr P Q1 Q2] :
    FromOr iprop(□ P) iprop(□ Q1) iprop(□ Q2) where
  from_or := intuitionistically_or.2.trans (intuitionistically_mono h.1)
end Iris.ProofMode

namespace Iris.ProofMode
instance fromOr_absorbingly [BI PROP] (P Q1 Q2 : PROP) [h : FromOr P Q1 Q2] :
    FromOr iprop(<absorb> P) iprop(<absorb> Q1) iprop(<absorb> Q2) where
  from_or := absorbingly_or.2.trans (absorbingly_mono h.1)
end Iris.ProofMode

namespace Iris.ProofMode
instance fromOr_persistently [BI PROP] (P Q1 Q2 : PROP) [h : FromOr P Q1 Q2] :
    FromOr iprop(<pers> P) iprop(<pers> Q1) iprop(<pers> Q2) where
  from_or := persistently_or.2.trans (persistently_mono h.1)
end Iris.ProofMode

namespace Iris.ProofMode
instance intoOr_or [BI PROP] (P Q : PROP) : IntoOr iprop(P ∨ Q) P Q := ⟨.rfl⟩
end Iris.ProofMode

namespace Iris.ProofMode
instance intoOr_pure (φ ψ : Prop) [BI PROP] :
    IntoOr (PROP := PROP) iprop(⌜φ ∨ ψ⌝) iprop(⌜φ⌝) iprop(⌜ψ⌝) where
  into_or := pure_or.2
end Iris.ProofMode

namespace Iris.ProofMode
instance intoOr_affinely [BI PROP] (P Q1 Q2 : PROP) [h : IntoOr P Q1 Q2] :
    IntoOr iprop(<affine> P) iprop(<affine> Q1) iprop(<affine> Q2) where
  into_or := (affinely_mono h.1).trans affinely_or.1
end Iris.ProofMode

namespace Iris.ProofMode
instance intoOr_intuitionistically [BI PROP] (P Q1 Q2 : PROP) [h : IntoOr P Q1 Q2] :
    IntoOr iprop(□ P) iprop(□ Q1) iprop(□ Q2) where
  into_or := (intuitionistically_mono h.1).trans intuitionistically_or.1
end Iris.ProofMode

namespace Iris.ProofMode
instance intoOr_absorbingly [BI PROP] (P Q1 Q2 : PROP) [h : IntoOr P Q1 Q2] :
    IntoOr iprop(<absorb> P) iprop(<absorb> Q1) iprop(<absorb> Q2) where
  into_or := (absorbingly_mono h.1).trans absorbingly_or.1
end Iris.ProofMode

namespace Iris.ProofMode
instance intoOr_persistently [BI PROP] (P Q1 Q2 : PROP) [h : IntoOr P Q1 Q2] :
    IntoOr iprop(<pers> P) iprop(<pers> Q1) iprop(<pers> Q2) where
  into_or := (persistently_mono h.1).trans persistently_or.1
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 20) intoPersistently_persistently (p : Bool) [BI PROP] (P Q : PROP)
    [h : IntoPersistently true P Q] : IntoPersistently p iprop(<pers> P) Q where
  into_persistently := persistentlyIf_persistently.1.trans h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 20) intoPersistently_affinely (p : Bool) [BI PROP] (P Q : PROP)
    [h : IntoPersistently p P Q] : IntoPersistently p iprop(<affine> P) Q where
  into_persistently := (persistentlyIf_mono affinely_elim).trans h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 20) intoPersistently_intuitionistically (p : Bool) [BI PROP]
    (P Q : PROP) [h : IntoPersistently true P Q] : IntoPersistently p iprop(□ P) Q where
  into_persistently := persistentlyIf_intutitionistically.trans h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 10) intoPersistently_self [BI PROP] (P : PROP) :
    IntoPersistently true P P := ⟨.rfl⟩
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default - 10) intoPersistently_persistent [BI PROP] (P : PROP)
    [h : Persistent P] : IntoPersistently false P P where
  into_persistently := h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance fromAffinely_affine [BI PROP] (P : PROP) [Affine P] : FromAffinely P P true where
  from_affinely := affinely_elim
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default - 50) fromAffinely_affinely [BI PROP] (P : PROP) :
    FromAffinely iprop(<affine> P) P true := ⟨.rfl⟩
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default - 10) fromAffinely_intuitionistically [BI PROP] (P : PROP) :
    FromAffinely iprop(□ P) iprop(<pers> P) true := ⟨.rfl⟩
end Iris.ProofMode

namespace Iris.ProofMode
instance fromAffinely_self [BI PROP] (P : PROP) : FromAffinely P P false := ⟨.rfl⟩
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 30) intoAbsorbingly_true [BI PROP] :
    IntoAbsorbingly (PROP := PROP) iprop(True) emp where
  into_absorbingly := absorbingly_emp.2
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 20) intoAbsorbingly_absorbing [BI PROP] (P : PROP) [Absorbing P] :
    IntoAbsorbingly P P where
  into_absorbingly := absorbing_absorbingly.2
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 10) intoAbsorbingly_intuitionistically [BI PROP] (P : PROP) :
    IntoAbsorbingly iprop(<pers> P) iprop(□ P) where
  into_absorbingly := absorbingly_intuitionistically.2
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default - 10) intoAbsorbingly_default [BI PROP] (P : PROP) :
    IntoAbsorbingly iprop(<absorb> P) P := ⟨.rfl⟩
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 100) fromAssumption_exact (p : Bool) [BI PROP] (P : PROP) :
    FromAssumption p P P where
  from_assumption := intuitionisticallyIf_elim
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 30) fromAssumption_persistently_r [BI PROP] (P Q : PROP)
    [h : FromAssumption true P Q] : FromAssumption true P iprop(<pers> Q) where
  from_assumption := (persistent (P := iprop(□ P))).trans (persistently_mono h.1)
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 30) fromAssumption_affinely_r [BI PROP] (P Q : PROP)
    [h : FromAssumption true P Q] : FromAssumption true P iprop(<affine> Q) where
  from_assumption := affinely_idem.2.trans <| affinely_mono h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 30) fromAssumption_intuitionistically_r [BI PROP] (P Q : PROP)
    [h : FromAssumption true P Q] : FromAssumption true P iprop(□ Q) where
  from_assumption := intuitionistically_idem.2.trans <| intuitionistically_mono h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 20) fromAssumption_absorbingly_r (p : Bool) [BI PROP] (P Q : PROP)
    [h : FromAssumption p P Q] : FromAssumption p P iprop(<absorb> Q) where
  from_assumption := absorbingly_intro.trans <| absorbingly_mono h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 20) fromAssumption_intuitionistically_l (p : Bool) [BI PROP]
    (P Q : PROP) [h : FromAssumption true P Q] : FromAssumption p iprop(□ P) Q where
  from_assumption := intuitionisticallyIf_intutitionistically.1.trans h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 20) fromAssumption_intuitionistically_l_true (p : Bool) [BI PROP]
    (P Q : PROP) [h : FromAssumption p P Q] : FromAssumption p iprop(□ P) Q where
  from_assumption := (intuitionisticallyIf_comm' (q := true)).1.trans <|
    intuitionistically_elim.trans h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 30) fromAssumption_persistently_l_true [BI PROP] (P Q : PROP)
    [h : FromAssumption true P Q] : FromAssumption true iprop(<pers> P) Q where
  from_assumption := intuitionistically_persistently.1.trans h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 30) fromAssumption_persistently_l_false [BI PROP] [BIAffine PROP]
    (P Q : PROP) [h : FromAssumption true P Q] : FromAssumption false iprop(<pers> P) Q where
  from_assumption := intuitionistically_iff_persistently.2.trans h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 20) fromAssumption_affinely_l (p : Bool) [BI PROP] (P Q : PROP)
    [h : FromAssumption p P Q] : FromAssumption p iprop(<affine> P) Q where
  from_assumption := (intuitionisticallyIf_mono affinely_elim).trans h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance (priority := default + 10) fromAssumption_forall (p : Bool) [BI PROP] (Φ : α → PROP)
    (x : α) (Q : PROP) [h : FromAssumption p (Φ x) Q] : FromAssumption p iprop(∀ x, Φ x) Q where
  from_assumption := (intuitionisticallyIf_mono <| forall_elim x).trans h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance fromAssumption_later [BI PROP] (p : Bool) (P Q : PROP)
    [h : FromAssumption p P Q] : FromAssumption p P iprop(▷ Q) where
  from_assumption := h.1.trans later_intro
end Iris.ProofMode

namespace Iris.ProofMode
instance intoPure_pure (φ : Prop) [BI PROP] : IntoPure (PROP := PROP) iprop(⌜φ⌝) φ := ⟨.rfl⟩
end Iris.ProofMode

namespace Iris.ProofMode
instance intoPure_pure_and (φ1 φ2 : Prop) [BI PROP] (P1 P2 : PROP)
    [h1 : IntoPure P1 φ1] [h2 : IntoPure P2 φ2] : IntoPure iprop(P1 ∧ P2) (φ1 ∧ φ2) where
  into_pure := (and_mono h1.1 h2.1).trans pure_and.1
end Iris.ProofMode

namespace Iris.ProofMode
instance intoPure_pure_or (φ1 φ2 : Prop) [BI PROP] (P1 P2 : PROP)
    [h1 : IntoPure P1 φ1] [h2 : IntoPure P2 φ2] : IntoPure iprop(P1 ∨ P2) (φ1 ∨ φ2) where
  into_pure := (or_mono h1.1 h2.1).trans pure_or.1
end Iris.ProofMode

namespace Iris.ProofMode
instance intoPure_exists [BI PROP] (Φ : α → PROP) (φ : α → Prop)
    [h : ∀ x, IntoPure (Φ x) (φ x)] : IntoPure iprop(∃ x, Φ x) (∃ x, φ x) where
  into_pure := (exists_mono fun x => (h x).1).trans pure_exists.1
end Iris.ProofMode

namespace Iris.ProofMode
instance intoPure_pure_sep (φ1 φ2 : Prop) [BI PROP] (P1 P2 : PROP)
    [h1 : IntoPure P1 φ1] [h2 : IntoPure P2 φ2] : IntoPure iprop(P1 ∗ P2) (φ1 ∧ φ2) where
  into_pure := (sep_mono h1.1 h2.1).trans <| sep_and.trans pure_and.1
end Iris.ProofMode

namespace Iris.ProofMode
instance intoPure_affinely [BI PROP] (P : PROP) (φ : Prop)
    [h : IntoPure P φ] : IntoPure iprop(<affine> P) φ where
  into_pure := affinely_elim.trans h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance intoPure_intuitionistically [BI PROP] (P : PROP) (φ : Prop)
    [h : IntoPure P φ] : IntoPure iprop(□ P) φ where
  into_pure := intuitionistically_elim.trans h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance intoPure_absorbingly [BI PROP] (P : PROP) (φ : Prop)
    [h : IntoPure P φ] : IntoPure iprop(<absorb> P) φ where
  into_pure := (absorbingly_mono h.1).trans absorbingly_pure.1
end Iris.ProofMode

namespace Iris.ProofMode
instance intoPure_persistently [BI PROP] (P : PROP) (φ : Prop)
    [h : IntoPure P φ] : IntoPure iprop(<pers> P) φ where
  into_pure := (persistently_mono h.1).trans persistently_elim
end Iris.ProofMode

namespace Iris.ProofMode
instance fromPure_emp [BI PROP] : FromPure (PROP := PROP) true emp True where
  from_pure := affinely_true.1
end Iris.ProofMode

namespace Iris.ProofMode
instance fromPure_pure [BI PROP] (φ : Prop) : FromPure (PROP := PROP) false iprop(⌜φ⌝) φ := ⟨.rfl⟩
end Iris.ProofMode

namespace Iris.ProofMode
instance fromPure_pure_and (a1 a2 : Bool) (φ1 φ2 : Prop) [BI PROP] (P1 P2 : PROP)
    [h1 : FromPure a1 P1 φ1] [h2 : FromPure a2 P2 φ2] :
    FromPure (a1 || a2) iprop(P1 ∧ P2) (φ1 ∧ φ2) where
  from_pure := (affinelyIf_mono pure_and.2).trans <| affinelyIf_and.1.trans <| by
    refine and_mono ((affinelyIf_flag_mono ?_).trans h1.1) ((affinelyIf_flag_mono ?_).trans h2.1)
      <;> simp_all
end Iris.ProofMode

namespace Iris.ProofMode
instance fromPure_pure_or (a1 a2 : Bool) (φ1 φ2 : Prop) [BI PROP] (P1 P2 : PROP)
    [h1 : FromPure a1 P1 φ1] [h2 : FromPure a2 P2 φ2] :
    FromPure (a1 || a2) iprop(P1 ∨ P2) (φ1 ∨ φ2) where
  from_pure := (affinelyIf_mono pure_or.2).trans <| affinelyIf_or.1.trans <| by
    refine or_mono ((affinelyIf_flag_mono ?_).trans h1.1) ((affinelyIf_flag_mono ?_).trans h2.1)
      <;> simp_all
end Iris.ProofMode

namespace Iris.ProofMode
instance fromPure_pure_imp (a : Bool) (φ1 φ2 : Prop) [BI PROP] (P1 P2 : PROP)
    [h1 : IntoPure P1 φ1] [h2 : FromPure a P2 φ2] : FromPure a iprop(P1 → P2) (φ1 → φ2) where
  from_pure := (affinelyIf_mono pure_imp_2).trans <|
    (BI.imp_intro <| affinelyIf_and_l.1.trans (affinelyIf_mono imp_elim_l)).trans <|
    imp_mono h1.1 h2.1
end Iris.ProofMode

namespace Iris.ProofMode
instance fromPure_exists (a : Bool) [BI PROP] (Φ : α → PROP) (φ : α → Prop)
    [h : ∀ x, FromPure a iprop(Φ x) (φ x)] : FromPure a iprop(∃ x, Φ x) (∃ x, φ x) where
  from_pure := (affinelyIf_mono pure_exists.2).trans <|
    affinelyIf_exists.1.trans (exists_mono fun x => (h x).1)
end Iris.ProofMode

namespace Iris.ProofMode
instance fromPure_forall (a : Bool) [BI PROP] (Φ : α → PROP) (φ : α → Prop)
    [h : ∀ x, FromPure a iprop(Φ x) (φ x)] : FromPure a iprop(∀ x, Φ x) (∀ x, φ x) where
  from_pure := (affinelyIf_mono pure_forall_2).trans <|
    affinelyIf_forall_1.trans (forall_mono fun x => (h x).1)
end Iris.ProofMode

namespace Iris.ProofMode
instance fromPure_pure_sep_true (a1 a2 : Bool) (φ1 φ2 : Prop) [BI PROP] (P1 P2 : PROP)
    [h1 : FromPure a1 P1 φ1] [h2 : FromPure a2 P2 φ2] :
    FromPure (a1 && a2) iprop(P1 ∗ P2) (φ1 ∧ φ2) where
  from_pure := by admit /- proof elided -/
end Iris.ProofMode

namespace Iris.ProofMode
instance fromPure_pure_wand_true (φ1 φ2 : Prop) [BI PROP] (P1 P2 : PROP)
    [h1 : IntoPure P1 φ1] [h2 : FromPure true P2 φ2] [Affine P1] :
    FromPure true iprop(P1 -∗ P2) (φ1 → φ2) where
  from_pure := by admit /- proof elided -/
end Iris.ProofMode

namespace Iris.ProofMode
instance fromPure_pure_wand_false (φ1 φ2 : Prop) [BI PROP] (P1 P2 : PROP)
    [h1 : IntoPure P1 φ1] [h2 : FromPure false P2 φ2] :
    FromPure false iprop(P1 -∗ P2) (φ1 → φ2) where
  from_pure := by admit /- proof elided -/
end Iris.ProofMode

namespace Iris.ProofMode
instance fromPure_persistently [BI PROP] (P : PROP) (a : Bool) (φ : Prop)
    [h : FromPure true P φ] : FromPure a iprop(<pers> P) φ where
  from_pure := affinelyIf_elim.trans <| persistently_pure.2.trans <|
    persistently_affinely.2.trans <| persistently_mono h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance fromPure_affinely_true (a : Bool) [BI PROP] (P : PROP) (φ : Prop)
    [h : FromPure a P φ] : FromPure true iprop(<affine> P) φ where
  from_pure := affinely_idem.2.trans <| affinely_mono <| affinely_affinelyIf.trans h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance fromPure_intuitionistically_true (a : Bool) [BI PROP] (P : PROP) (φ : Prop)
    [h : FromPure a P φ] : FromPure true iprop(□ P) φ where
  from_pure :=
    (intuitionistically_of_intuitionistic (P := iprop(<affine> ⌜φ⌝))).2.trans <|
    (intuitionistically_mono <| affinely_idem.2.trans <|
      affinely_mono <| affinely_affinelyIf).trans <|
    intuitionistically_affinely.1.trans <| intuitionistically_mono h.1
end Iris.ProofMode

namespace Iris.ProofMode
instance fromPure_absorbingly (a : Bool) [BI PROP] (P : PROP) (φ : Prop)
    [h : FromPure a P φ] : FromPure false iprop(<absorb> P) φ where
  from_pure := absorbingly_affinely_intro_of_persistent.trans <|
    absorbingly_mono <| affinely_affinelyIf.trans h.1
end Iris.ProofMode

namespace Prod
def mapAllM [Monad M] (f : α → M β) : α × α → M (β × β)
  | (x, y) => do return (← f x, ← f y)
end Prod

namespace Iris.ProofMode
@[delab app.Iris.ProofMode.Entails']
def delabIrisGoal : Delab := do
  let expr ← instantiateMVars <| ← getExpr

  
  let some { hyps, goal, .. } := parseIrisGoal? expr | failure

  
  let (_, hyps) ← delabHypotheses hyps ({}, #[])
  let goal ← unpackIprop (← delab goal)

  
  return ⟨← `(irisGoalStx| $hyps.reverse* ⊢ $goal:term)⟩
where
  delabHypotheses {u prop bi s} (hyps : @Hyps u prop bi s)
      (acc : NameMap Nat × Array (TSyntax ``irisHyp)) :
      DelabM (NameMap Nat × Array (TSyntax ``irisHyp)) := do
    match hyps with
    | .emp _ => pure acc
    | .hyp _ name _ p ty _ =>
      let mut (map, acc) := acc
      let (idx, name') ← if let some idx := map.find? name then
        pure (idx + 1, name.appendAfter <| if idx == 0 then "✝" else "✝" ++ idx.toSuperscriptString)
      else
        pure (0, name)
      let stx ← if isTrue p then
        `(irisHyp| □$(mkIdent name') : $(← unpackIprop (← delab ty)))
      else
        `(irisHyp| ∗$(mkIdent name') : $(← unpackIprop (← delab ty)))
      pure (map.insert name idx, acc.push stx)
    | .sep _ _ _ _ lhs rhs => delabHypotheses lhs (← delabHypotheses rhs acc)
end Iris.ProofMode

namespace Iris.ProofMode
@[delab app.Iris.ProofMode.HypMarker]
def delabHypMarker : Delab := do unpackIprop (← withAppArg delab)
end Iris.ProofMode

namespace Iris.Examples
abbrev FF0 : GFunctors := #[]
end Iris.Examples

namespace Iris.Examples
local instance : IsGFunctors FF0 := nofun

-- A proof with no resources
example (P Q : IProp FF0) : P ∗ Q ⊢ ⌜True⌝ :=
end Iris.Examples

namespace Iris.Examples
abbrev FF1 : GFunctors := #[COFE.constOF (Agree (LeibnizO String))]
end Iris.Examples

namespace Iris.Examples
abbrev γ : GId FF1 := ⟨0, Nat.zero_lt_succ _⟩
end Iris.Examples

namespace Iris.Examples
local instance : IsGFunctors FF1 := fun i => by admit /- proof elided -/
end Iris.Examples

namespace Iris.Examples
@[simp]
def MyAg (S : String) : Agree (LeibnizO String) := ⟨[⟨S⟩], by admit /- proof elided -/
⟩
end Iris.Examples

namespace Iris.Examples
@[simp]
def MyR (S : String) : IResUR FF1 := fun i _ => some (HγE i ▸ MyAg S)
end Iris.Examples

namespace Iris.Examples
def AgreeString (S : String) : IProp FF1 := UPred.ownM (MyR S)

example : AgreeString "I <3 iris-lean!" ⊢ (AgreeString "I don't :<" -∗ False) :=
end Iris.Examples

namespace Iris.ProofMode
structure RemoveHyp {prop : Q(Type u)} (bi : Q(BI $prop)) (e : Q($prop)) where
  (e' : Q($prop)) (hyps' : Hyps bi e') (out out' : Q($prop)) (p : Q(Bool))
  (eq : $out =Q iprop(□?$p $out'))
  (pf : Q($e ⊣⊢ $e' ∗ $out))
  deriving Inhabited
end Iris.ProofMode

namespace Iris.ProofMode
inductive RemoveHypCore {prop : Q(Type u)} (bi : Q(BI $prop)) (e : Q($prop)) (α : Type) where
  | none
  | one (a : α) (out' : Q($prop)) (p : Q(Bool)) (eq : $e =Q iprop(□?$p $out'))
  | main (a : α) (_ : RemoveHyp bi e)
end Iris.ProofMode

namespace Iris.ProofMode
def Hyps.removeCore : ∀ {e}, Hyps bi e → m (RemoveHypCore bi e α)
  | _, .emp _ => pure .none
  | e, h@(.hyp _ name uniq p ty _) => do
    if let some a ← check name uniq p ty then
      match matchBool p, rp with
      | .inl _, false =>
        have : $e =Q iprop(□ $ty) := ⟨⟩
        return .main a ⟨e, h, e, ty, q(true), ⟨⟩, q(intuitionistically_sep_dup)⟩
      | _, _ => return .one a ty p ⟨⟩
    else
      return .none
  | _, .sep _ elhs erhs _ lhs rhs => do
    match ← rhs.removeCore with
    | .one a out' p h =>
      return .main a ⟨elhs, lhs, erhs, out', p, h, q(.rfl)⟩
    | .main a ⟨_, rhs', out, out', p, h, pf⟩ =>
      let hyps' := .mkSep lhs rhs'
      return .main a ⟨_, hyps', out, out', p, h, q(remove_r $pf)⟩
    | .none => match ← lhs.removeCore with
      | .one a out' p h =>
        return .main a ⟨erhs, rhs, elhs, out', p, h, q(sep_comm)⟩
      | .main a ⟨_, lhs', out, out', p, h, pf⟩ =>
        let hyps' := .mkSep lhs' rhs
        return .main a ⟨_, hyps', out, out', p, h, q(remove_l $pf)⟩
      | .none => pure .none
end Iris.ProofMode

namespace Iris.ProofMode
def Hyps.removeG [Monad m] {prop : Q(Type u)} {bi : Q(BI $prop)} {e : Q(Prop)}
    (rp : Bool) (hyps : Hyps bi e)
    (check : Name → Name → Q(Bool) → Q($prop) → m (Option α)) :
    m (Option (α × RemoveHyp bi e)) := do
  match ← hyps.removeCore bi rp check with
  | .none => return none
  | .one a out' p h => return some ⟨a, _, .mkEmp bi, e, out', p, h, q(emp_sep_rev)⟩
  | .main a res => return some (a, res)
end Iris.ProofMode

namespace Iris.ProofMode
def Hyps.remove {prop : Q(Type u)} {bi : Q(BI $prop)} {e}
    (rp : Bool) (hyps : Hyps bi e) (uniq : Name) : RemoveHyp bi e :=
  match Id.run (hyps.removeG rp fun _ uniq' _ _ => if uniq == uniq' then some () else none) with
  | some (_, r) => r
  | none => panic! "variable not found"
end Iris.ProofMode

namespace Iris.Std
private def matchAlts' := leading_parser matchAlts
end Iris.Std

namespace Iris.Std
        def unexpand : Lean.PrettyPrinter.Unexpander
          $[| $p => $s]*)
    else
      `(@[app_unexpander $(mkIdent f)]
end Iris.Std

namespace Iris.Std
        def unexpand : Lean.PrettyPrinter.Unexpander
          $[| $p => $s]*
          | _ => throw ())
end Iris.Std

namespace Iris
class OFE (α : Type _) where
  Equiv : α → α → Prop
  Dist : Nat → α → α → Prop
  dist_eqv : Equivalence (Dist n)
  equiv_dist : Equiv x y ↔ ∀ n, Dist n x y
  dist_lt : Dist n x y → m < n → Dist m x y
end Iris

namespace Iris.OFE
instance [OFE α] : Trans OFE.Equiv OFE.Equiv (OFE.Equiv : α → α → Prop) where
  trans := Equiv.trans
end Iris.OFE

namespace Iris.OFE
instance [OFE α] {n : Nat} : Trans (OFE.Dist n) (OFE.Dist n) (OFE.Dist n : α → α → Prop) where
  trans := Dist.trans
end Iris.OFE

namespace Iris.OFE
class NonExpansive [OFE α] [OFE β] (f : α → β) where
  ne : ∀ ⦃n x₁ x₂⦄, x₁ ≡{n}≡ x₂ → f x₁ ≡{n}≡ f x₂
end Iris.OFE

namespace Iris.OFE
instance id_ne [OFE α] : NonExpansive (@id α) := ⟨fun _ _ _ h => h⟩
end Iris.OFE

namespace Iris.OFE
class NonExpansive₂ [OFE α] [OFE β] [OFE γ] (f : α → β → γ) where
  ne : ∀ ⦃n x₁ x₂⦄, x₁ ≡{n}≡ x₂ → ∀ ⦃y₁ y₂⦄, y₁ ≡{n}≡ y₂ → f x₁ y₁ ≡{n}≡ f x₂ y₂
end Iris.OFE

namespace Iris.OFE
def DistLater [OFE α] (n : Nat) (x y : α) : Prop := ∀ m, m < n → x ≡{m}≡ y
end Iris.OFE

namespace Iris.OFE
class Contractive [OFE α] [OFE β] (f : α → β) where
  distLater_dist : DistLater n x y → f x ≡{n}≡ f y
end Iris.OFE

namespace Iris.OFE
instance ne_of_contractive [OFE α] [OFE β] (f : α → β) [Contractive f] : NonExpansive f where
  ne := fun _ _ _ h => Contractive.distLater_dist (Dist.distLater h)
end Iris.OFE

namespace Iris.OFE
instance [OFE α] [OFE β] {x : β} : Contractive (fun _ : α => x) where
  distLater_dist := fun _ => Dist.rfl
end Iris.OFE

namespace Iris.OFE
def ofDiscrete (Equiv : α → α → Prop) (equiv_eqv : Equivalence Equiv) : OFE α where
  Equiv := Equiv
  Dist _ := Equiv
  dist_eqv := equiv_eqv
  equiv_dist := (forall_const _).symm
  dist_lt h _ := h
end Iris.OFE

namespace Iris.OFE
class DiscreteE {α : Type _} [OFE α] (x : α) : Prop where
  discrete : x ≡{0}≡ y → x ≡ y
end Iris.OFE

namespace Iris.OFE
class Discrete (α : Type _) [OFE α] where
  discrete_0 {x y : α} : x ≡{0}≡ y → x ≡ y
end Iris.OFE

namespace Iris.OFE
class Leibniz (α : Type _) [OFE α] where
  eq_of_eqv {x y : α} : x ≡ y → x = y
end Iris.OFE

namespace Iris.OFE
@[ext] structure Hom (α β : Type _) [OFE α] [OFE β] where
  f : α → β
  ne : NonExpansive f
end Iris.OFE

namespace Iris.OFE
instance [OFE α] [OFE β] : CoeFun (α -n> β) (fun _ => α → β) := ⟨Hom.f⟩
end Iris.OFE

namespace Iris.OFE
instance [OFE α] [OFE β] (f : α -n> β) : NonExpansive f := f.ne
end Iris.OFE

namespace Iris.OFE
protected def Hom.id [OFE α] : α -n> α where
  f := id
  ne.ne _ _ _ := id
end Iris.OFE

namespace Iris.OFE
protected def Hom.comp [OFE α] [OFE β] [OFE γ] (g : β -n> γ) (f : α -n> β) : α -n> γ where
  f := g.f ∘ f.f
  ne.1 _ _ _ h := g.ne.1 (f.ne.1 h)
end Iris.OFE

namespace Iris.OFE
@[ext] structure ContractiveHom (α β : Type _) [OFE α] [OFE β] extends Hom α β where
  [contractive : Contractive f]
  ne := ne_of_contractive f
end Iris.OFE

namespace Iris.OFE
instance [OFE α] [OFE β] : CoeFun (α -c> β) (fun _ => α → β) := ⟨fun x => x.toHom.f⟩
end Iris.OFE

namespace Iris.OFE
instance [OFE α] [OFE β] (f : α -c> β) : Contractive f := f.contractive
end Iris.OFE

namespace Iris.OFE
instance : OFE Unit where
  Equiv _ _ := True
  Dist _ _ _ := True
  dist_eqv := ⟨fun _ => ⟨⟩, id, fun _ => id⟩
  equiv_dist := by admit /- proof elided -/
end Iris.OFE

namespace Iris.OFE
instance [OFE α] : OFE (ULift α) where
  Equiv x y := x.down ≡ y.down
  Dist n x y := x.down ≡{n}≡ y.down
  dist_eqv := InvImage.equivalence dist_eqv
  equiv_dist := equiv_dist
  dist_lt := dist_lt
end Iris.OFE

namespace Iris.OFE
def uliftUpHom [OFE α] : α -n> ULift α where
  f := .up
  ne.1 _ _ _ := id
end Iris.OFE

namespace Iris.OFE
def uliftDownHom [OFE α] : ULift α -n> α where
  f := ULift.down
  ne.1 _ _ _ := id
end Iris.OFE

namespace Iris.OFE
def _root_.Option.Forall₂ (R : α → β → Prop) : Option α → Option β → Prop
  | none, none => True
  | some a, some b => R a b
  | _, _ => False
end Iris.OFE

namespace Iris.OFE
instance [OFE α] : OFE (Option α) where
  Equiv := Option.Forall₂ Equiv
  Dist n := Option.Forall₂ (Dist n)
  dist_eqv := Option.Forall₂.equivalence dist_eqv
  equiv_dist {x y} := by admit /- proof elided -/
end Iris.OFE

namespace Iris.OFE
instance [OFE α] [OFE.Discrete α] : OFE.Discrete (Option α) where
  discrete_0 {mx my} e :=
    match mx, my with
    | none,   none   => e
    | none,   some _ => e
    | some _, none   => e
    | some x, some y => show x ≡ y from discrete_0 e
end Iris.OFE

namespace Iris.OFE
instance [OFE α] [Leibniz α] : Leibniz (Option α) where
  eq_of_eqv {x y} H :=
    match x, y, H with
    | none, none, _ => rfl
    | some _, some _, h => congrArg some (Leibniz.eq_of_eqv h)
end Iris.OFE

namespace Iris.OFE
instance [OFE α] [Discrete α] : Discrete (Option α) where
  discrete_0 {x y} H :=
    match x, y with
    | none, none => H
    | some _, some _ => some_eqv_some.mpr (discrete_0 H)
end Iris.OFE

namespace Iris.OFE
instance OFE.Option.some.ne [OFE α] : OFE.NonExpansive (some : α → Option α) := ⟨fun _ _ _ => id⟩
end Iris.OFE

namespace Iris.OFE
instance Option.merge_ne [OFE α] {op : α → α → α} [NonExpansive₂ op] :
    NonExpansive₂ (Option.merge op) where
  ne n x1 x2 Hx y1 y2 Hy := by admit /- proof elided -/
end Iris.OFE

namespace Iris.OFE
abbrev OFEFun {α : Type _} (β : α → Type _) := ∀ a, OFE (β a)
end Iris.OFE

namespace Iris.OFE
instance [OFEFun (β : α → _)] : OFE ((x : α) → β x) where
  Equiv f g := ∀ x, f x ≡ g x
  Dist n f g := ∀ x, f x ≡{n}≡ g x
  dist_eqv := {
    refl _ _ := dist_eqv.refl _
    symm h _ := dist_eqv.symm (h _)
    trans h1 h2 _ := dist_eqv.trans (h1 _) (h2 _)
  }
  equiv_dist {_ _} := by admit /- proof elided -/
end Iris.OFE

namespace Iris.OFE
instance [OFE α] [OFE β] : OFE (α -n> β) where
  Equiv f g := f.f ≡ g.f
  Dist n f g := f.f ≡{n}≡ g.f
  dist_eqv := {
    refl _ := dist_eqv.refl _
    symm h := dist_eqv.symm h
    trans h1 h2 := dist_eqv.trans h1 h2
  }
  equiv_dist := equiv_dist
  dist_lt := dist_lt
end Iris.OFE

namespace Iris.OFE
instance [OFE α] [OFE β] : OFE (α -c> β) where
  Equiv f g := Equiv f.toHom g.toHom
  Dist n f g := Dist n f.toHom g.toHom
  dist_eqv := {
    refl _ := dist_eqv.refl _
    symm h := dist_eqv.symm h
    trans h1 h2 := dist_eqv.trans h1 h2
  }
  equiv_dist := equiv_dist
  dist_lt := dist_lt
end Iris.OFE

namespace Iris.OFE
def applyHom [OFEFun (β : α → _)] (x : α) : ((x : α) → β x) -n> β x where
  f f := f x
  ne.1 _ _ _ H := H x
end Iris.OFE

namespace Iris.OFE
def mapCodHom [OFEFun (β₁ : α → _)] [OFEFun β₂]
    (F : ∀ x, β₁ x -n> β₂ x) : ((x : α) → β₁ x) -n> ((x : α) → β₂ x) where
  f f x := F x (f x)
  ne.1 _ _ _ H x := (F x).ne.1 (H x)
end Iris.OFE

namespace Iris.OFE
instance [OFE α] [OFE β] : OFE (α × β) where
  Equiv a b := a.1 ≡ b.1 ∧ a.2 ≡ b.2
  Dist n a b := a.1 ≡{n}≡ b.1 ∧ a.2 ≡{n}≡ b.2
  dist_eqv := {
    refl _ := ⟨dist_eqv.refl _, dist_eqv.refl _⟩
    symm h := ⟨dist_eqv.symm h.1, dist_eqv.symm h.2⟩
    trans h1 h2 := ⟨dist_eqv.trans h1.1 h2.1, dist_eqv.trans h1.2 h2.2⟩
  }
  equiv_dist {_ _} := by admit /- proof elided -/
end Iris.OFE

namespace Iris.OFE
instance [OFE α] [OFE β] [Discrete α] [Discrete β] : Discrete (α × β) where
  discrete_0 H := by admit /- proof elided -/
end Iris.OFE

namespace Iris.OFE
@[ext] structure Iso (α β : Type _) [OFE α] [OFE β] where
  hom : α -n> β
  inv : β -n> α
  hom_inv : hom (inv x) ≡ x
  inv_hom : inv (hom x) ≡ x
end Iris.OFE

namespace Iris.OFE
instance [OFE α] [OFE β] : CoeFun (Iso α β) (fun _ => α -n> β) := ⟨Iso.hom⟩
end Iris.OFE

namespace Iris.OFE
instance [OFE α] [OFE β] (iso : Iso α β) : NonExpansive iso.hom := iso.hom.ne
end Iris.OFE

namespace Iris.OFE
instance [OFE α] [OFE β] (iso : Iso α β) : NonExpansive iso.inv := iso.inv.ne
end Iris.OFE

namespace Iris.OFE
def Iso.id [OFE α] : Iso α α where
  hom := Hom.id
  inv := Hom.id
  hom_inv := by admit /- proof elided -/
end Iris.OFE

namespace Iris.OFE
def Iso.symm [OFE α] [OFE β] (iso : Iso α β) : Iso β α where
  hom := iso.inv
  inv := iso.hom
  hom_inv := by admit /- proof elided -/
end Iris.OFE

namespace Iris.OFE
def Iso.comp [OFE α] [OFE β] [OFE γ] (iso1 : Iso β γ) (iso2 : Iso α β) : Iso α γ where
  hom := iso1.hom.comp iso2.hom
  inv := iso2.inv.comp iso1.inv
  hom_inv := by admit /- proof elided -/
end Iris.OFE

namespace Iris
structure Chain (α : Type _) [OFE α] where
  chain : Nat → α
  cauchy : n ≤ i → chain i ≡{n}≡ chain n
end Iris

namespace Iris
instance [OFE α] : CoeFun (Chain α) (fun _ => Nat → α) := ⟨Chain.chain⟩
end Iris

namespace Iris.Chain
def const [OFE α] (a : α) : Chain α where
  chain := fun _ => a
  cauchy _ := OFE.Dist.rfl
end Iris.Chain

namespace Iris.Chain
def map [OFE α] [OFE β] (f : α -n> β) (c : Chain α) : Chain β where
  chain n := f (c n)
  cauchy h := f.ne.1 (c.cauchy h)
end Iris.Chain

namespace Iris
def chain_option_some [OFE V] {c : Chain (Option V)} (H : c n = some v) :
    ∃ c' : Chain V, c = Chain.map ⟨some, OFE.Option.some.ne⟩ c' :=
end Iris

namespace Iris
class IsCOFE (α : Type _) [OFE α] where
  compl : Chain α → α
  conv_compl {c : Chain α} : compl c ≡{n}≡ c n
end Iris

namespace Iris.COFE
def ofDiscrete (Equiv : α → α → Prop) (equiv_eqv : Equivalence Equiv) : COFE α :=
  let _ := OFE.ofDiscrete Equiv equiv_eqv
  { compl := fun c => c 0
    conv_compl := fun {_ c} => equiv_eqv.2 (c.cauchy (Nat.zero_le _)) }
end Iris.COFE

namespace Iris.COFE
instance [COFE α] : COFE (ULift α) where
  compl c := ⟨compl (c.map uliftDownHom)⟩
  conv_compl := conv_compl
end Iris.COFE

namespace Iris.COFE
instance : COFE Unit where
  compl _ := ()
  conv_compl := ⟨⟩
end Iris.COFE

namespace Iris.COFE
abbrev IsCOFEFun {α : Type _} (β : α → Type _) [OFEFun β] := ∀ x : α, IsCOFE (β x)
end Iris.COFE

namespace Iris.COFE
instance {α : Type _} (β : α → Type _) [∀ x, COFE (β x)] : COFE ((x : α) → β x) where
  compl c x := compl (c.map (applyHom x))
  conv_compl _ := IsCOFE.conv_compl
end Iris.COFE

namespace Iris.COFE
abbrev OFunctorPre := ∀ α β [OFE α] [OFE β], Type _
end Iris.COFE

namespace Iris.COFE
class OFunctor (F : OFunctorPre) where
  
  
  
  cofe [OFE α] [OFE β] : OFE (F α β)
  map [OFE α₁] [OFE α₂] [OFE β₁] [OFE β₂] :
    (α₂ -n> α₁) → (β₁ -n> β₂) → F α₁ β₁ -n> F α₂ β₂
  map_ne [OFE α₁] [OFE α₂] [OFE β₁] [OFE β₂] :
    NonExpansive₂ (@map α₁ α₂ β₁ β₂ _ _ _ _)
  map_id [OFE α] [OFE β] (x : F α β) : map (@Hom.id α _) (@Hom.id β _) x ≡ x
  map_comp [OFE α₁] [OFE α₂] [OFE α₃] [OFE β₁] [OFE β₂] [OFE β₃]
    (f : α₂ -n> α₁) (g : α₃ -n> α₂) (f' : β₁ -n> β₂) (g' : β₂ -n> β₃) (x : F α₁ β₁) :
    map (f.comp g) (g'.comp f') x ≡ map g g' (map f f' x)
end Iris.COFE

namespace Iris.COFE
class OFunctorContractive (F : OFunctorPre) extends OFunctor F where
  map_contractive [OFE α₁] [OFE α₂] [OFE β₁] [OFE β₂] :
    Contractive (Function.uncurry (@map α₁ α₂ β₁ β₂ _ _ _ _))
end Iris.COFE

namespace Iris.COFE
abbrev constOF (B : Type) : OFunctorPre := fun _ _ _ _ => B
end Iris.COFE

namespace Iris.COFE
instance oFunctorConstOF [OFE B] : OFunctor (constOF B) where
  cofe := _
  map _ _ := ⟨id, id_ne⟩
  map_ne := by admit /- proof elided -/
end Iris.COFE

namespace Iris.COFE
instance OFunctor.constOF_contractive [OFE B] : OFunctorContractive (constOF B) where
  map_contractive.1 := by admit /- proof elided -/
end Iris.COFE

namespace Iris
@[ext] structure LeibnizO (α : Type _) where
  car : α
end Iris

namespace Iris
instance : COFE (LeibnizO α) := COFE.ofDiscrete _ Eq_Equivalence
end Iris

namespace Iris
instance : Leibniz (LeibnizO α) := ⟨(·)⟩
end Iris

namespace Iris
instance {α : Type _} : OFE.Discrete (LeibnizO α) := ⟨congrArg id⟩
end Iris

namespace Iris
instance {α : Type _} : OFE.Leibniz (LeibnizO α) := ⟨congrArg id⟩
end Iris

namespace Iris
abbrev DiscreteFunOF {C : Type _} (F : C → OFunctorPre) : OFunctorPre :=
  fun A B _ _ => (c : C) → F c A B
end Iris

namespace Iris
instance oFunctor_discreteFunOF {C} (F : C → OFunctorPre) [∀ c, OFunctor (F c)] :
    OFunctor (DiscreteFunOF F) where
  cofe := _
  map f₁ f₂ := mapCodHom fun c => OFunctor.map f₁ f₂
  map_ne.ne _ _ _ Hx _ _ Hy _ _ := by admit /- proof elided -/
end Iris

namespace Iris
def optionChain (c : Chain (Option α)) (x : α) : Chain α :=
end Iris

namespace Iris
instance isCOFE_option [IsCOFE α] : IsCOFE (Option α) where
  compl c := (c 0).map fun x => IsCOFE.compl (optionChain c x)
  conv_compl {n} c := by admit /- proof elided -/
end Iris

namespace Iris
def optionMap {α β : Type _} [OFE α] [OFE β] (f : α -n> β) : Option α -n> Option β :=
end Iris

namespace Iris
abbrev OptionOF (F : OFunctorPre) : OFunctorPre :=
  fun A B _ _ => Option (F A B)
end Iris

namespace Iris
instance oFunctorOption [OFunctor F] : OFunctor (OptionOF F) where
  cofe := _
  map f g := optionMap (OFunctor.map f g)
  map_ne.ne _ _ _ Hx _ _ Hy z := by admit /- proof elided -/
end Iris

namespace Iris
instance [OFunctorContractive F] : OFunctorContractive (OptionOF F) where
  map_contractive.1 H z := by admit /- proof elided -/
end Iris

namespace Iris
def LimitPreserving [COFE α] (P : α → Prop) : Prop :=
  ∀ (c : Chain α), (∀ n, P (c n)) → P (COFE.compl c)
end Iris

namespace Iris
def Fixpoint.chain [OFE α] [Inhabited α] (f : α → α) [Contractive f] : Chain α where
  chain n := Nat.repeat f (n + 1) default
  cauchy {n} := by admit /- proof elided -/
end Iris

namespace Iris
def fixpoint [COFE α] [Inhabited α] (f : α → α) [Contractive f] : α :=
  COFE.compl <| Fixpoint.chain f

nonrec abbrev OFE.ContractiveHom.fixpoint [COFE α] [Inhabited α] (f : α -c> α) : α := fixpoint f.f
end Iris

namespace Iris
instance OFE.ContractiveHom.fixpoint_ne [COFE α] [Inhabited α] :
    NonExpansive (ContractiveHom.fixpoint (α := α)) where
  ne n f1 f2 H := by admit /- proof elided -/
end Iris

namespace Iris
structure Later (A : Type u) : Type (u+1) where
  next :: car : A
end Iris

namespace Iris
instance isOFE_later [OFE A] : OFE (Later A) where
  Equiv x y := x.car ≡ y.car
  Dist n x y := DistLater n x.car y.car
  dist_eqv := ⟨fun _ => .rfl, .symm, .trans⟩
  equiv_dist := by admit /- proof elided -/
end Iris

namespace Iris
instance NextContractive {A : Type} [OFE A] : Contractive (@Later.next A) where
  distLater_dist := id
end Iris

namespace Iris
def laterChain [OFE A] (c : Chain (Later A)) : Chain A where
  chain n := (c (Nat.succ n)).car
  cauchy Hle := c.cauchy (Nat.succ_le_succ Hle) _ (Nat.lt_succ_self _)
end Iris

namespace Iris
instance isCOFE_later [OFE A] [IsCOFE A] : IsCOFE (Later A) where
  compl c := Later.next (IsCOFE.compl (laterChain c))
  conv_compl {n} c := by admit /- proof elided -/
end Iris

namespace Iris
def laterMap [OFE A] [OFE B] (f : A -n> B)  : Later A -n> Later B :=
end Iris

namespace Iris
abbrev LaterOF (F : OFunctorPre) : OFunctorPre :=
  fun A B _ _ => Later (F A B)
end Iris

namespace Iris
instance oFunctorLater [OFunctor F] : OFunctor (LaterOF F) where
  cofe := _
  map f g := laterMap (OFunctor.map f g)
  map_ne.ne _ _ _ Hx _ _ Hy _ _ := (OFunctor.map_ne.ne Hx Hy _).lt
  map_id _ := OFunctor.map_id _
  map_comp _ _ _ _ _ := OFunctor.map_comp ..
end Iris

namespace Iris
instance [OFunctorContractive F] : OFunctorContractive (LaterOF F) where
  map_contractive.1 H z m := Dist.lt <| by
    have := (OFunctorContractive.map_contractive (F := F)).distLater_dist H
    simp_all only [Dist, DistLater, Function.uncurry, OFunctor.map, laterMap]
end Iris

namespace Iris
instance [OFE α] {P : α → Prop} : OFE { x : α // P x } where
  Equiv := (·.val ≡ ·.val)
  Dist n := (·.val ≡{n}≡ ·.val)
  dist_eqv := {
    refl x := dist_eqv.refl x.val
    symm H := H.symm
    trans H1 H2 := H1.trans H2
  }
  equiv_dist := equiv_dist
  dist_lt := dist_lt
end Iris

namespace Iris.Instances.Data
class Disjoint (α : Type u) where
  disjoint : α → α → Prop
end Iris.Instances.Data

namespace Iris.BI
instance entails_trans [BI PROP] : Trans (α := PROP) Entails Entails Entails where
  trans h1 h2 := h1.trans h2
end Iris.BI

namespace Iris.BI
instance entails_antisymm [BI PROP] : Antisymmetric (α := PROP) BiEntails Entails where
  antisymm h1 h2 := ⟨h1, h2⟩
end Iris.BI

namespace Iris.BI
instance equiv_trans [BI PROP] : Trans (α := PROP) BiEntails BiEntails BiEntails where
  trans h1 h2 := h1.trans h2
end Iris.BI

namespace Iris.BI
instance [BI PROP] : Idempotent (α := PROP) BiEntails and := ⟨and_self⟩
end Iris.BI

namespace Iris.BI
instance [BI PROP] : Idempotent (α := PROP) BiEntails or := ⟨or_self⟩
end Iris.BI

namespace Iris.BI
instance [BI PROP] : Commutative (α := PROP) BiEntails and := ⟨and_comm⟩
end Iris.BI

namespace Iris.BI
instance [BI PROP] : Commutative (α := PROP) BiEntails or := ⟨or_comm⟩
end Iris.BI

namespace Iris.BI
instance [BI PROP] : LeftId (α := PROP) BiEntails iprop(True) and := ⟨true_and⟩
end Iris.BI

namespace Iris.BI
instance [BI PROP] : RightId (α := PROP) BiEntails iprop(True) and := ⟨and_true⟩
end Iris.BI

namespace Iris.BI
instance [BI PROP] : LeftId (α := PROP) BiEntails iprop(False) or := ⟨false_or⟩
end Iris.BI

namespace Iris.BI
instance [BI PROP] : RightId (α := PROP) BiEntails iprop(False) or := ⟨or_false⟩
end Iris.BI

namespace Iris.BI
instance [BI PROP] : LeftId (α := PROP) BiEntails iprop(True) and := ⟨true_and⟩
end Iris.BI

namespace Iris.BI
instance [BI PROP] : LawfulBigOp and (iprop(True) : PROP) BiEntails where
  refl := .rfl
  symm h := h.symm
  trans h1 h2 := h1.trans h2
  comm := and_comm
  assoc := and_assoc
  left_id := true_and
  congr_l := and_congr_l
end Iris.BI

namespace Iris.BI
instance [BI PROP] : Associative (α := PROP) BiEntails and := ⟨and_assoc⟩
end Iris.BI

namespace Iris.BI
instance [BI PROP] : Commutative (α := PROP) BiEntails sep := ⟨sep_comm⟩
end Iris.BI

namespace Iris.BI
instance [BI PROP] : Associative (α := PROP) BiEntails sep := ⟨sep_assoc⟩
end Iris.BI

namespace Iris.BI
instance [BI PROP] : LeftId (α := PROP) BiEntails emp sep := ⟨emp_sep⟩
end Iris.BI

namespace Iris.BI
instance [BI PROP] : RightId (α := PROP) BiEntails emp sep := ⟨sep_emp⟩
end Iris.BI

namespace Iris.BI
instance [BI PROP] : LawfulBigOp sep (emp : PROP) BiEntails where
  refl := .rfl
  symm h := h.symm
  trans h1 h2 := h1.trans h2
  comm := sep_comm
  assoc := sep_assoc
  left_id := emp_sep
  congr_l := sep_congr_l
end Iris.BI

namespace Iris.BI
instance emp_affine [BI PROP] : Affine (PROP := PROP) iprop(emp) where
  affine := .rfl
end Iris.BI

namespace Iris.BI
instance false_affine [BI PROP] : Affine (PROP := PROP) iprop(False) where
  affine := false_elim
end Iris.BI

namespace Iris.BI
instance and_affine_l [BI PROP] (P Q : PROP) [Affine P] : Affine iprop(P ∧ Q) where
  affine := and_elim_l.trans affine
end Iris.BI

namespace Iris.BI
instance and_affine_r [BI PROP] (P Q : PROP) [Affine Q] : Affine iprop(P ∧ Q) where
  affine := and_elim_r.trans affine
end Iris.BI

namespace Iris.BI
instance or_affine [BI PROP] (P Q : PROP) [Affine P] [Affine Q] : Affine iprop(P ∨ Q) where
  affine := or_elim affine affine
end Iris.BI

namespace Iris.BI
instance forall_affine [Inhabited α] [BI PROP] (Φ : α → PROP) [∀ x, Affine (Φ x)] :
    Affine iprop(∀ x, Φ x) where
  affine := (forall_elim default).trans affine
end Iris.BI

namespace Iris.BI
instance exists_affine [BI PROP] (Φ : α → PROP) [∀ x, Affine (Φ x)] : Affine iprop(∃ x, Φ x) where
  affine := exists_elim fun _ => affine
end Iris.BI

namespace Iris.BI
instance sep_affine [BI PROP] (P Q : PROP) [Affine P] [Affine Q] : Affine iprop(P ∗ Q) where
  affine := (sep_mono affine affine).trans sep_emp.1
end Iris.BI

namespace Iris.BI
instance affinely_affine [BI PROP] (P : PROP) : Affine iprop(<affine> P) where
  affine := affinely_elim_emp
end Iris.BI

namespace Iris.BI
instance absorbingly_absorbing [BI PROP] (P : PROP) : Absorbing iprop(<absorb> P) where
  absorbing := absorbingly_idem.1
end Iris.BI

namespace Iris.BI
instance pureAbsorbing (φ : Prop) [BI PROP] : Absorbing (PROP := PROP) iprop(⌜φ⌝) where
  absorbing := absorbingly_pure.1
end Iris.BI

namespace Iris.BI
instance pure_absorbing [BI PROP] (φ : Prop) : Absorbing iprop(⌜φ⌝ : PROP) where
  absorbing := absorbingly_pure.1
end Iris.BI

namespace Iris.BI
instance and_absorbing [BI PROP] (P Q : PROP) [Absorbing P] [Absorbing Q] :
    Absorbing iprop(P ∧ Q) where
  absorbing := absorbingly_and_1.trans (and_mono absorbing absorbing)
end Iris.BI

namespace Iris.BI
instance or_absorbing [BI PROP] (P Q : PROP) [Absorbing P] [Absorbing Q] :
    Absorbing iprop(P ∨ Q) where
  absorbing := absorbingly_or.1.trans (or_mono absorbing absorbing)
end Iris.BI

namespace Iris.BI
instance forall_absorbing [BI PROP] (Φ : α → PROP) [∀ x, Absorbing (Φ x)] :
    Absorbing iprop(∀ x, Φ x) where
  absorbing := absorbingly_forall_1.trans (forall_mono fun _ => absorbing)
end Iris.BI

namespace Iris.BI
instance exists_absorbing [BI PROP] (Φ : α → PROP) [∀ x, Absorbing (Φ x)] :
    Absorbing iprop(∃ x, Φ x) where
  absorbing := absorbingly_exists.1.trans (exists_mono fun _ => absorbing)
end Iris.BI

namespace Iris.BI
instance sep_absorbing_l [BI PROP] (P Q : PROP) [Absorbing P] : Absorbing iprop(P ∗ Q) where
  absorbing := absorbingly_sep_l.2.trans (sep_mono_l absorbing)
end Iris.BI

namespace Iris.BI
instance sep_absorbing_r [BI PROP] (P Q : PROP) [Absorbing Q] : Absorbing iprop(P ∗ Q) where
  absorbing := absorbingly_sep_r.2.trans (sep_mono_r absorbing)
end Iris.BI

namespace Iris.BI
instance (priority := default + 10) biaffine_absorbing [BI PROP] [BIAffine PROP]
    (P : PROP) : Absorbing P where
  absorbing := (sep_mono_l affine).trans emp_sep.1
end Iris.BI

namespace Iris.BI
instance wand_absorbing_l [BI PROP] (P Q : PROP) [Absorbing P] : Absorbing iprop(P -∗ Q) where
  absorbing := wand_intro' <| sep_assoc.2.trans <| (sep_mono_l sep_elim_l).trans wand_elim_r
end Iris.BI

namespace Iris.BI
instance wand_absorbing_r [BI PROP] (P Q : PROP) [Absorbing Q] : Absorbing iprop(P -∗ Q) where
  absorbing := absorbingly_wand_1.trans (wand_mono absorbingly_intro absorbing)
end Iris.BI

namespace Iris.BI
instance [BI PROP] [BIAffine PROP] : LeftId (α := PROP) BiEntails emp and := ⟨emp_and⟩
end Iris.BI

namespace Iris.BI
instance [BI PROP] [BIAffine PROP] : RightId (α := PROP) BiEntails emp and := ⟨and_emp⟩
end Iris.BI

namespace Iris.BI
instance [BI PROP] [BIAffine PROP] (P : PROP) : Absorbing P where
  absorbing := (sep_mono_l affine).trans emp_sep.1
end Iris.BI

namespace Iris.BI
instance [BI PROP] [BIAffine PROP] : LeftId (α := PROP) BiEntails iprop(True) sep := ⟨true_sep⟩
end Iris.BI

namespace Iris.BI
instance [BI PROP] [BIAffine PROP] : RightId (α := PROP) BiEntails iprop(True) sep := ⟨sep_true⟩
end Iris.BI

namespace Iris.BI
instance [BI PROP] [BIAffine PROP] : BIPositive PROP where
  affinely_sep_l := (affine_affinely _).1.trans (sep_mono_l (affine_affinely _).2)
end Iris.BI

namespace Iris.BI
instance persistently_persistent [BI PROP] (P : PROP) : Persistent iprop(<pers> P) where
  persistent := persistently_idem_2
end Iris.BI

namespace Iris.BI
instance persistently_absorbing [BI PROP] (P : PROP) : Absorbing iprop(<pers> P) where
  absorbing := absorbingly_persistently.1
end Iris.BI

namespace Iris.BI
instance pure_persistent (φ : Prop) [BI PROP] : Persistent (PROP := PROP) iprop(⌜φ⌝) where
  persistent := persistently_pure.2
end Iris.BI

namespace Iris.BI
instance emp_persistent [BI PROP] : Persistent (PROP := PROP) iprop(emp) where
  persistent := persistently_emp_intro
end Iris.BI

namespace Iris.BI
instance and_persistent [BI PROP] (P Q : PROP) [Persistent P] [Persistent Q] :
    Persistent iprop(P ∧ Q) where
  persistent := (and_mono persistent persistent).trans persistently_and.2
end Iris.BI

namespace Iris.BI
instance or_persistent [BI PROP] (P Q : PROP) [Persistent P] [Persistent Q] :
    Persistent iprop(P ∨ Q) where
  persistent := (or_mono persistent persistent).trans persistently_or.2
end Iris.BI

namespace Iris.BI
instance forall_persistent [BI PROP] [BIPersistentlyForall PROP] (Ψ : α → PROP)
    [h : ∀ x, Persistent (Ψ x)] : Persistent iprop(∀ x, Ψ x) :=
  sForall_persistent _ fun _ ⟨_, eq⟩ => eq ▸ h _
end Iris.BI

namespace Iris.BI
instance exists_persistent [BI PROP] (Ψ : α → PROP) [h : ∀ x, Persistent (Ψ x)] :
    Persistent iprop(∃ x, Ψ x) := sExists_persistent _ fun _ ⟨_, eq⟩ => eq ▸ h _
end Iris.BI

namespace Iris.BI
instance sep_persistent [BI PROP] (P Q : PROP) [Persistent P] [Persistent Q] :
    Persistent iprop(P ∗ Q) where
  persistent := (sep_mono persistent persistent).trans persistently_sep_2
end Iris.BI

namespace Iris.BI
instance affinely_persistent [BI PROP] (P : PROP) [Persistent P] : Persistent iprop(<affine> P) :=
  inferInstanceAs (Persistent iprop(_ ∧ _))
end Iris.BI

namespace Iris.BI
instance absorbingly_persistent [BI PROP] (P : PROP) [Persistent P] :
    Persistent iprop(<absorb> P) :=
  inferInstanceAs (Persistent iprop(_ ∗ _))
end Iris.BI

namespace Iris.BI
instance intuitionistically_affine [BI PROP] (P : PROP) : Affine iprop(□ P) :=
  inferInstanceAs (Affine iprop(<affine> _))
end Iris.BI

namespace Iris.BI
instance intuitionistically_persistent [BI PROP] (P : PROP) : Persistent iprop(□ P) :=
  inferInstanceAs (Persistent iprop(<affine> _))
end Iris.BI

namespace Iris.BI
instance affinelyIf_affine (p : Bool) [BI PROP] (P : PROP) [Affine P] :
    Affine iprop(<affine>?p P) :=
end Iris.BI

namespace Iris.BI
instance affinelyIf_persistent (p : Bool) [BI PROP] (P : PROP) [Persistent P] :
    Persistent iprop(<affine>?p P) :=
end Iris.BI

namespace Iris.BI
instance absorbinglyIf_persistent (p : Bool) [BI PROP] (P : PROP) [Persistent P] :
    Persistent iprop(<absorb>?p P) :=
end Iris.BI

namespace Iris.BI
instance persistentlyIf_absorbing [BI PROP] (P : PROP) (p : Bool) [Absorbing P] :
    Absorbing iprop(<pers>?p P) :=
end Iris.BI

namespace Iris.BI
instance intuitionisticallyIf_affine (p : Bool) [BI PROP] (P : PROP) [Affine P] :
    Affine iprop(□?p P) :=
end Iris.BI

namespace Iris.BI
instance imp_absorbing [BI PROP] (P Q : PROP) [Persistent P] [Absorbing P] [Absorbing Q] :
    Absorbing iprop(P → Q) where
  absorbing := imp_intro' <| persistent_and_affinely_sep_l.1.trans <| absorbingly_sep_r.1.trans <|
    (absorbingly_mono <| persistent_and_affinely_sep_l.2.trans imp_elim_r).trans absorbing
end Iris.BI

namespace Iris.BI
instance later_persistent [BI PROP] {P : PROP} [Persistent P] : Persistent iprop(▷ P) where
  persistent := (later_mono persistently_intro).trans later_persistently.mp
end Iris.BI

namespace Iris.BI
instance later_absorbing [BI PROP] {P : PROP} [Absorbing P] : Absorbing iprop(▷ P) where
  absorbing := later_absorbingly.mpr.trans <| later_mono absorbing
end Iris.BI

namespace Iris.ProofMode
macro "%" pat:icasesPat : icasesPat => `(icasesPat| ⌜$pat⌝)
end Iris.ProofMode

namespace Iris.ProofMode
macro "#" pat:icasesPat : icasesPat => `(icasesPat| □ $pat)
end Iris.ProofMode

namespace Iris.ProofMode
macro "*" pat:icasesPat : icasesPat => `(icasesPat| ∗ $pat)
end Iris.ProofMode

namespace Iris.ProofMode
inductive iCasesPat
  | one (name : TSyntax ``binderIdent)
  | clear
  | conjunction (args : List iCasesPat)
  | disjunction (args : List iCasesPat)
  | pure           (pat : iCasesPat)
  | intuitionistic (pat : iCasesPat)
  | spatial        (pat : iCasesPat)
  deriving Repr, Inhabited
end Iris.ProofMode

namespace Iris.ProofMode
partial def iCasesPat.parse (pat : TSyntax `icasesPat) : MacroM iCasesPat := do
  match go ⟨← expandMacros pat⟩ with
  | none => Macro.throwUnsupported
  | some pat => return pat
where
  go : TSyntax `icasesPat → Option iCasesPat
  | `(icasesPat| $name:binderIdent) => some <| .one name
  | `(icasesPat| -) => some <| .clear
  | `(icasesPat| ⟨$[$args],*⟩) => args.mapM goAlts |>.map (.conjunction ·.toList)
  | `(icasesPat| ⌜$pat⌝) => go pat |>.map .pure
  | `(icasesPat| □$pat) => go pat |>.map .intuitionistic
  | `(icasesPat| ∗$pat) => go pat |>.map .spatial
  | `(icasesPat| ($pat)) => goAlts pat
  | _ => none
  goAlts : TSyntax ``icasesPatAlts → Option iCasesPat
  | `(icasesPatAlts| $args|*) =>
    match args.getElems with
    | #[arg] => go arg
    | args   => args.mapM go |>.map (.disjunction ·.toList)
  | _ => none
end Iris.ProofMode

namespace Iris.BI
class BIAffine (PROP : Type _) [BI PROP] where
  affine (P : PROP) : Affine P
end Iris.BI

namespace Iris.BI
class BIPositive (PROP : Type _) [BI PROP] where
  affinely_sep_l {P Q : PROP} : <affine> (P ∗ Q) ⊢ <affine> P ∗ Q
end Iris.BI

namespace Iris.BI
class BILoeb (PROP : Type _) [BI PROP] where
  loeb_weak {P : PROP} : (▷ P ⊢ P) → True ⊢ P
end Iris.BI

namespace Iris.BI
class BILaterContractive (PROP : Type _) [BI PROP] extends OFE.Contractive later (α := PROP)
end Iris.BI

namespace Iris.BI
class BIPersistentlyForall (PROP : Type _) [BI PROP] where
  persistently_sForall_2 (Ψ : PROP → Prop) : (∀ p, ⌜Ψ p⌝ → <pers> p) ⊢ <pers> (sForall Ψ)
end Iris.BI

namespace Iris.ProofMode
def clearCore {prop : Q(Type u)} (_bi : Q(BI $prop)) (e e' out goal : Q($prop))
    (pf : Q($e ⊣⊢ $e' ∗ $out)) : MetaM Q(($e' ⊢ $goal) → $e ⊢ $goal) := do
  if out.isAppOfArity ``intuitionistically 3 then
    have out' : Q($prop) := out.appArg!
    have : $out =Q iprop(□ $out') := ⟨⟩
    pure q(clear_intuitionistic (Q := $goal) $pf)
  else
    let _ ← synthInstanceQ q(TCOr (Affine $out) (Absorbing $goal))
    pure q(clear_spatial $pf)
end Iris.ProofMode

namespace Iris.BI
class Persistent [BI PROP] (P : PROP) where
  persistent : P ⊢ <pers> P
end Iris.BI

namespace Iris.BI
class Affine [BI PROP] (P : PROP) where
  affine : P ⊢ emp
end Iris.BI

namespace Iris.BI
class Absorbing [BI PROP] (P : PROP) where
  absorbing : <absorb> P ⊢ P
end Iris.BI

namespace Iris.BI
class Intuitionistic [BI PROP] (P : PROP) where
  intuitionistic : P ⊢ □ P
end Iris.BI

namespace Iris.BI
class Timeless [BI PROP] (P : PROP) where
  timeless : ⊢ ▷ P ∨ ◇ P
end Iris.BI

namespace Iris.Instances.Classical
abbrev HeapProp (Val : Type _) := State Val → Prop
end Iris.Instances.Classical

namespace Iris.Instances.Classical
instance : BIBase (HeapProp Val) where
  Entails P Q      := ∀ σ, P σ → Q σ
  emp            σ := σ = ∅
  pure φ         _ := φ
  and P Q        σ := P σ ∧ Q σ
  or P Q         σ := P σ ∨ Q σ
  imp P Q        σ := P σ → Q σ
  sForall Ψ      σ := ∀ p, Ψ p → p σ
  sExists Ψ      σ := ∃ p, Ψ p ∧ p σ
  sep P Q        σ := ∃ σ1 σ2, σ = σ1 ∪ σ2 ∧ σ1 || σ2 ∧ P σ1 ∧ Q σ2
  wand P Q       σ := ∀ σ', σ || σ' → P σ' → Q (σ ∪ σ')
  persistently P _ := P ∅
  later P        σ := P σ
end Iris.Instances.Classical

namespace Iris.Instances.Classical
instance : Std.Preorder (Entails (PROP := HeapProp Val)) where
  refl := by admit /- proof elided -/
end Iris.Instances.Classical

namespace Iris.Instances.Classical
instance : COFE (HeapProp Val) := COFE.ofDiscrete Eq equivalence_eq
end Iris.Instances.Classical

namespace Iris.Instances.Classical
instance : BI (HeapProp Val) where
  entails_preorder := by admit /- proof elided -/
end Iris.Instances.Classical

namespace Iris.BI
class BIBase (PROP : Type u) where
  Entails : PROP → PROP → Prop
  emp : PROP
  pure : Prop → PROP
  and : PROP → PROP → PROP
  or : PROP → PROP → PROP
  imp : PROP → PROP → PROP
  sForall : (PROP → Prop) → PROP
  sExists : (PROP → Prop) → PROP
  sep : PROP → PROP → PROP
  wand : PROP → PROP → PROP
  persistently : PROP → PROP
  later : PROP → PROP
end Iris.BI

namespace Iris.BI.BIBase
def «forall» [BIBase PROP] {α : Sort _} (P : α → PROP) : PROP := sForall fun p => ∃ a, P a = p
end Iris.BI.BIBase

namespace Iris.BI.BIBase
def «exists» [BIBase PROP] {α : Sort _} (P : α → PROP) : PROP := sExists fun p => ∃ a, P a = p
end Iris.BI.BIBase

namespace Iris.BI.BIBase
macro:25 P:term:29 " ⊢ " Q:term:25 : term => ``(BIBase.Entails iprop($P) iprop($Q))

delab_rule BIBase.Entails
  | `($_ $P $Q) => do ``($(← unpackIprop P) ⊢ $(← unpackIprop Q))
end Iris.BI.BIBase

namespace Iris.BI.BIBase
macro "∃" xs:explicitBinders ", " b:term : term => do
  return ⟨← expandExplicitBinders ``BIBase.exists xs b⟩
end Iris.BI.BIBase

namespace Iris.BI.BIBase
def iff     [BIBase PROP] (P Q : PROP) : PROP := iprop((P → Q) ∧ (Q → P))
end Iris.BI.BIBase

namespace Iris.BI.BIBase
def wandIff [BIBase PROP] (P Q : PROP) : PROP := iprop((P -∗ Q) ∧ (Q -∗ P))
end Iris.BI.BIBase

namespace Iris.BI.BIBase
def affinely    [BIBase PROP] (P : PROP) : PROP := iprop(emp ∧ P)
end Iris.BI.BIBase

namespace Iris.BI.BIBase
def absorbingly [BIBase PROP] (P : PROP) : PROP := iprop(True ∗ P)
end Iris.BI.BIBase

namespace Iris.BI.BIBase
structure BiEntails [BIBase PROP] (P Q : PROP) where
  mp : P ⊢ Q
  mpr : Q ⊢ P
end Iris.BI.BIBase

namespace Iris.BI.BIBase
macro:25 "⊢ " P:term:25 : term => ``(emp ⊢ $P)
end Iris.BI.BIBase

namespace Iris.BI.BIBase
macro:25 P:term:29 " ⊣⊢ " Q:term:29 : term => ``(BiEntails iprop($P) iprop($Q))

delab_rule BIBase.Entails
  | `($_ iprop(emp) $P) => do ``(⊢ $(← unpackIprop P))

delab_rule BIBase.BiEntails
  | `($_ $P $Q) => do ``($(← unpackIprop P) ⊣⊢ $(← unpackIprop Q))
end Iris.BI.BIBase

namespace Iris.BI.BIBase
def intuitionistically [BIBase PROP] (P : PROP) : PROP := iprop(<affine> <pers> P)
end Iris.BI.BIBase

namespace Iris.BI.BIBase
def persistentlyIf [BIBase PROP] (p : Bool) (P : PROP) : PROP := iprop(if p then <pers> P else P)
end Iris.BI.BIBase

namespace Iris.BI.BIBase
def affinelyIf [BIBase PROP] (p : Bool) (P : PROP) : PROP := iprop(if p then <affine> P else P)
end Iris.BI.BIBase

namespace Iris.BI.BIBase
def absorbinglyIf [BIBase PROP] (p : Bool) (P : PROP) : PROP := iprop(if p then <absorb> P else P)
end Iris.BI.BIBase

namespace Iris.BI.BIBase
def intuitionisticallyIf [BIBase PROP] (p : Bool) (P : PROP) : PROP := iprop(if p then □ P else P)
end Iris.BI.BIBase

namespace Iris.BI.BIBase
def bigAnd [BIBase PROP] (Ps : List PROP) : PROP := bigOp and iprop(True) Ps
end Iris.BI.BIBase

namespace Iris.BI.BIBase
def bigOr [BIBase PROP] (Ps : List PROP) : PROP := bigOp or iprop(False) Ps
end Iris.BI.BIBase

namespace Iris.BI.BIBase
def bigSep [BIBase PROP] (Ps : List PROP) : PROP := bigOp sep iprop(emp) Ps
end Iris.BI.BIBase

namespace Iris.BI.BIBase
def laterN [BIBase PROP] (n : Nat) (P : PROP) : PROP :=
  match n with | .zero => P | .succ n' => later <| laterN n' P
end Iris.BI.BIBase

namespace Iris.BI.BIBase
def except0 [BIBase PROP] (P : PROP) := iprop(▷ False ∨ P)
end Iris.BI.BIBase

namespace Store
instance instOFE [Store T K V] [OFE V] : OFE T where
  Equiv s0 s1  := get s0 ≡ get s1
  Dist n s0 s1 := get s0 ≡{n}≡ get s1
  dist_eqv     := ⟨fun _ => .of_eq rfl, (·.symm), (·.trans ·)⟩
  equiv_dist   := equiv_dist
  dist_lt      := dist_lt
end Store

namespace Store
@[simp] def toMap [Store T K V] [OFE V] : T -n> (K → V) where
  f x := get x
  ne.1 {_ _ _} H k := H k
end Store

namespace Store
@[simp] def ofMap [Store T K V] [R : RepFunStore T K V] [OFE V] : {f : K → V // R.rep f} -n> T where
  f x := of_fun x
  ne.1 {_ _ _} H k := by admit /- proof elided -/
end Store

namespace Store
instance get_ne [Store T K V] [OFE V] (k : K) : NonExpansive (get · k : T → V) where
  ne {_ _ _} Ht := Ht k
end Store

namespace Store
instance [Store T K V] [OFE V] (k : K) : NonExpansive₂ (set · k · : T → V → T) where
  ne {_ _ _} Hv {_ _} Ht k' := by admit /- proof elided -/
end Store

namespace Store
instance [Heap T K V] [OFE V] (op : V → V → V) [NonExpansive₂ op] :
    NonExpansive₂ (merge (T := T) op) where
  ne _ {_ _} Ht {_ _} Hs k := by admit /- proof elided -/
end Store

namespace Store
instance [Store T1 K V1] [Store T2 K V2] [OFE V1] [OFE V2] (f : K → V1 → V2)
  [∀ k, NonExpansive (f k)] [HasStoreMap T1 T2 K V1 V2] : NonExpansive (dmap f : T1 → T2) where
  ne _ {_ _} H k := by admit /- proof elided -/
end Store

namespace Store
def chain [Store T K V] [OFE V] (k : K) (c : Chain T) : Chain V where
  chain i := get (c i) k
  cauchy Hni := c.cauchy Hni k
end Store

instance Heap.instCOFE [Heap T K V] [COFE V] : COFE T where
  compl c := hmap (fun _ => COFE.compl <| c.map ⟨_, Store.get_ne ·⟩) (c 0)
  conv_compl {_ c} k := by admit /- proof elided -/

namespace Store
@[simp] def op (s1 s2 : T) : T := merge (K := K) CMRA.op s1 s2
end Store

namespace Store
@[simp] def unit : T := empty
end Store

namespace Store
@[simp] def pcore (s : T) : Option T := some <| hmap (fun _ => CMRA.pcore) s
end Store

namespace Store
@[simp] def valid (s : T) : Prop := ∀ k, ✓ (get s k : Option V)
end Store

namespace Store
@[simp] def validN (n : Nat) (s : T) : Prop := ∀ k, ✓{n} (get s k : Option V)
end Store

namespace Store
instance instStoreCMRA : CMRA T where
  pcore := pcore
  op := op
  ValidN := validN
  Valid := valid
  op_ne.ne _ x1 x2 H i := by admit /- proof elided -/
end Store

namespace Store
instance instStoreUCMRA : UCMRA T where
  unit := unit
  unit_valid := by admit /- proof elided -/
end Store

namespace Heap
instance {m : T} [∀ x : V, CoreId x] : CoreId m where
  core_id i := by admit /- proof elided -/
end Heap

namespace Heap
instance [CoreId (x : V)] : CoreId (point (T := T) i (some x)) where
  core_id k := by admit /- proof elided -/
end Heap

namespace Heap
instance [H : Cancelable (some x)] : Cancelable (point (T := T) i (some x)) where
  cancelableN {n m1 m2} Hv He j := by admit /- proof elided -/
end Heap

namespace Heap
instance {m : T} [Hid : ∀ x : V, IdFree x] [Hc : ∀ x : V, Cancelable x] : Cancelable m where
  cancelableN {n m1 m2} Hv He i := by admit /- proof elided -/
end Heap

namespace Iris.ProofMode
class AsEmpValid1 (φ : semiOutParam Prop) {PROP : Type _} (P : PROP) [BI PROP] where
  as_emp_valid : φ ↔ ⊢ P
end Iris.ProofMode

namespace Iris.ProofMode
class AsEmpValid2 (φ : Prop) {PROP : outParam (Type _)} (P : outParam PROP) [BI PROP] where
  as_emp_valid : φ ↔ ⊢ P
end Iris.ProofMode

namespace Iris.ProofMode
def AsEmpValid1.to2 {φ : Prop} {PROP : Type _} {P : PROP} [BI PROP]
    [AsEmpValid1 φ P] : AsEmpValid2 φ P := ⟨AsEmpValid1.as_emp_valid⟩
end Iris.ProofMode

namespace Iris.ProofMode
def AsEmpValid2.to1 {φ : Prop} {PROP : Type _} {P : PROP} [BI PROP]
    [AsEmpValid2 φ P] : AsEmpValid1 φ P := ⟨AsEmpValid2.as_emp_valid⟩
end Iris.ProofMode

namespace Iris.ProofMode
class IntoEmpValid (φ : Prop) {PROP : outParam (Type _)} (P : outParam PROP) [BI PROP] where
  into_emp_valid : φ → ⊢ P
end Iris.ProofMode

namespace Iris.ProofMode
class FromImp [BI PROP] (P : PROP) (Q1 Q2 : outParam PROP) where
  from_imp : (Q1 → Q2) ⊢ P
end Iris.ProofMode

namespace Iris.ProofMode
class FromWand [BI PROP] (P : PROP) (Q1 Q2 : outParam PROP) where
  from_wand : (Q1 -∗ Q2) ⊢ P
end Iris.ProofMode

namespace Iris.ProofMode
class IntoWand [BI PROP] (p q : Bool) (R : PROP) (P Q : outParam PROP) where
  into_wand : □?p R ⊢ □?q P -∗ Q
end Iris.ProofMode

namespace Iris.ProofMode
class FromForall [BI PROP] (P : PROP) {α : outParam (Sort _)} (Ψ : outParam <| α → PROP) where
  from_forall : (∀ x, Ψ x) ⊢ P
end Iris.ProofMode

namespace Iris.ProofMode
class IntoForall [BI PROP] (P : PROP) {α : outParam (Sort _)} (Φ : outParam <| α → PROP) where
  into_forall : P ⊢ ∀ x, Φ x
end Iris.ProofMode

namespace Iris.ProofMode
class FromExists [BI PROP] (P : PROP) {α : outParam (Sort _)} (Φ : outParam <| α → PROP) where
  from_exists : (∃ x, Φ x) ⊢ P
end Iris.ProofMode

namespace Iris.ProofMode
class IntoExists [BI PROP] (P : PROP) {α : outParam (Sort _)} (Φ : outParam <| α → PROP) where
  into_exists : P ⊢ ∃ x, Φ x
end Iris.ProofMode

namespace Iris.ProofMode
class FromAnd [BI PROP] (P : PROP) (Q1 Q2 : outParam PROP) where
  from_and : Q1 ∧ Q2 ⊢ P
end Iris.ProofMode

namespace Iris.ProofMode
class IntoAnd (p : Bool) [BI PROP] (P : PROP) (Q1 Q2 : outParam PROP) where
  into_and : □?p P ⊢ □?p (Q1 ∧ Q2)
end Iris.ProofMode

namespace Iris.ProofMode
class FromSep [BI PROP] (P : PROP) (Q1 Q2 : outParam PROP) where
  from_sep : Q1 ∗ Q2 ⊢ P
end Iris.ProofMode

namespace Iris.ProofMode
class IntoSep [BI PROP] (P : PROP) (Q1 Q2 : outParam PROP) where
  into_sep : P ⊢ Q1 ∗ Q2
end Iris.ProofMode

namespace Iris.ProofMode
class FromOr [BI PROP] (P : PROP) (Q1 Q2 : outParam PROP) where
  from_or : Q1 ∨ Q2 ⊢ P
end Iris.ProofMode

namespace Iris.ProofMode
class IntoOr [BI PROP] (P : PROP) (Q1 Q2 : outParam PROP) where
  into_or : P ⊢ Q1 ∨ Q2
end Iris.ProofMode

namespace Iris.ProofMode
class IntoPersistently (p : Bool) [BI PROP] (P : PROP) (Q : outParam PROP) where
  into_persistently : <pers>?p P ⊢ <pers> Q
end Iris.ProofMode

namespace Iris.ProofMode
class FromAffinely [BI PROP] (P : outParam PROP) (Q : PROP) (p : Bool := true) where
  from_affinely : <affine>?p Q ⊢ P
end Iris.ProofMode

namespace Iris.ProofMode
class IntoAbsorbingly [BI PROP] (P : outParam PROP) (Q : PROP) where
  into_absorbingly : P ⊢ <absorb> Q
end Iris.ProofMode

namespace Iris.ProofMode
class FromAssumption (p : Bool) [BI PROP] (P : semiOutParam PROP) (Q : PROP) where
  from_assumption : □?p P ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
class IntoPure [BI PROP] (P : PROP) (φ : outParam Prop) where
  into_pure : P ⊢ ⌜φ⌝
end Iris.ProofMode

namespace Iris.ProofMode
class FromPure [BI PROP] (a : outParam Bool) (P : PROP) (φ : outParam Prop) where
  from_pure : <affine>?a ⌜φ⌝ ⊢ P
end Iris.ProofMode

namespace Iris.Instances.Data
inductive StateResult (α : Type _)
  | unknown
  | result (x : α)
  | conflict
end Iris.Instances.Data

namespace Iris.Instances.Data
abbrev State (Val : Type _) := Nat → StateResult Val
end Iris.Instances.Data

namespace Iris.Instances.Data
instance : EmptyCollection (State Val) where
  emptyCollection := fun _ => unknown
end Iris.Instances.Data

namespace Iris.Instances.Data
instance : HasSubset (State Val) where
  Subset a b := ∀ i x, a i = result x → b i = result x
end Iris.Instances.Data

namespace Iris.Instances.Data
instance : Union (State Val) where
  union a b := fun i =>
    match a i, b i with
    | unknown , unknown  => unknown
    | result x, unknown  => result x
    | unknown , result y => result y
    | _       , _        => conflict
end Iris.Instances.Data

namespace Iris.Instances.Data
instance : Disjoint (State Val) where
  disjoint a b := ∀ i, a i = unknown ∨ b i = unknown
end Iris.Instances.Data

namespace Iris
def Set (α : Type _) := α → Prop
end Iris

namespace Iris
def Set.univ {α : Type _} : Set α := fun _ => True
end Iris

namespace Iris
def Subset (x y : Set α) : Prop := ∀ a, x a → y a
end Iris

namespace Iris
def Disjoint (x y : Set α) : Prop := ∀ a, ¬(x a ∧ y a)
end Iris

namespace Iris
def union (x y : Set α) : Set α := fun a => x a ∨ y a
end Iris

namespace Iris
class BUpd (PROP : Type _) where
  bupd : PROP → PROP
end Iris

namespace Iris
class FUpd (PROP : Type _) (MASK : Type _) where
  fupd : Set MASK → Set MASK → PROP → PROP
end Iris

namespace Iris
class BIUpdate (PROP : Type _) [BI PROP] extends BUpd PROP where
  [bupd_ne : OFE.NonExpansive (BUpd.bupd (PROP := PROP))]
  intro {P : PROP} : iprop(P ⊢ |==> P)
  mono {P Q : PROP} : iprop(P ⊢ Q) → iprop(|==> P ⊢ |==> Q)
  trans {P : PROP} : iprop(|==> |==> P ⊢ |==> P)
  frame_r {P R : PROP} : iprop((|==> P) ∗ R ⊢ |==> (P ∗ R))
end Iris

namespace Iris
class BIFUpdate (PROP MASK : Type _) [BI PROP] extends FUpd PROP MASK where
  [ne {E1 E2 : Set MASK} : OFE.NonExpansive (FUpd.fupd E1 E2 (PROP := PROP))]
  subset {E1 E2 : Set MASK} : Subset E2 E1 → ⊢ |={E1, E2}=> |={E2, E1}=> (emp : PROP)
  except0 {E1 E2 : Set MASK} (P : PROP) : (◇ |={E1, E2}=> P) ⊢ |={E1, E2}=> P
  trans {E1 E2 E3 : Set MASK} (P : PROP) : (|={E1, E2}=> |={E2, E3}=> P) ⊢ |={E1, E3}=> P
  mask_frame_r' {E1 E2 Ef : Set MASK} (P : PROP) :
    Disjoint E1 Ef → (|={E1,E2}=> ⌜Disjoint E2 Ef⌝ → P) ⊢ |={union E1 Ef, union E2 Ef}=> P
  frame_r {E1 E2 : Set MASK} (P R : PROP) :
    iprop((|={E1, E2}=> P) ∗ R ⊢ |={E1, E2}=> P ∗ R)
end Iris

namespace Iris
class BIUpdateFUpdate (PROP : Type _) [BI PROP] [BIUpdate PROP] [BIFUpdate PROP MASK] where
  fupd_of_bupd {P : PROP} {E : Set MASK} : iprop(⊢ |==> P) → iprop(⊢ |={E}=> P)
end Iris

namespace Iris
class BIBUpdatePlainly (PROP : Type _) [BI PROP] [BIUpdate PROP] [BIPlainly PROP] where
  bupd_plainly {P : PROP} : iprop((|==> ■ P)) ⊢ P
end Iris

namespace Iris
class BIFUpdatePlainly (PROP MASK : Type _) [BI PROP] [BIFUpdate PROP MASK] [BIPlainly PROP] where
  fupd_plainly_keep_l (E E' : Set MASK) (P R : PROP) : (R ={E,E'}=∗ ■ P) ∗ R ⊢ |={E}=> P ∗ R
  fupd_plainly_later (E : Set MASK) (P : PROP) : (▷ |={E}=> ■ P) ⊢ |={E}=> ▷ ◇ P
  fupd_plainly_sForall_2 (E : Set MASK) (Φ : PROP → Prop) :
    (∀ p, ⌜Φ p⌝ → |={E}=> ■ p) ⊢ |={E}=> sForall Φ
end Iris

namespace Iris
instance {P : PROP} [Absorbing P] : Absorbing iprop(|==> P) :=
  ⟨bupd_frame_l.trans <| mono sep_elim_r⟩
end Iris

namespace Iris
instance {P : PROP} [Plain P] : Plain iprop(|==> P) :=
  ⟨(mono Plain.plain).trans <| (bupd_elim).trans <| BIPlainly.mono intro⟩
end Iris

namespace Iris
class Fraction (α : Type _) extends Add α where
   
  Proper : α → Prop
  add_comm : ∀ a b : α, a + b = b + a
  add_assoc : ∀ a b c : α, a + (b + c) = (a + b) + c
  add_left_cancel : ∀ {a b c : α}, a + b = a + c → b = c
   
  add_ne : ∀ {a b : α}, a ≠ b + a
  proper_add_mono_left : ∀ {a b : α}, Proper (a + b) → Proper a
end Iris

namespace Iris
class IsSplitFraction (α : Type _) [Fraction α] where
  split : α → α × α
  split_add {a : α} : (split a).1 + (split a).2 = a
end Iris

namespace Iris.Fraction
def Fractional [Fraction α] (a : α) : Prop := ∃ b, Proper (a + b)
end Iris.Fraction

namespace Iris.Fraction
def Whole [Fraction α] (a : α) : Prop := Proper a ∧ ¬Fractional a
end Iris.Fraction

namespace Iris
def Frac (α : Type _) := LeibnizO α
end Iris

namespace Iris
instance [Fraction α] : Coe (Frac α) α := ⟨(·.1)⟩
end Iris

namespace Iris
instance [Fraction α] : Coe α (Frac α) := ⟨(⟨·⟩)⟩
end Iris

namespace Iris
@[simp] instance : COFE (Frac α) := inferInstanceAs (COFE (LeibnizO α))
end Iris

namespace Iris
@[simp] instance [Fraction α] : Add (Frac α) := ⟨fun x y => x.1 + y.1⟩
end Iris

namespace Iris
instance : Leibniz (Frac α) := inferInstanceAs (Leibniz (LeibnizO α))
end Iris

namespace Iris
instance Frac_CMRA [Fraction α] : CMRA (Frac α) where
  pcore _ := none
  op := Add.add
  ValidN _ x := Proper x.1
  Valid x := Proper x.1
  op_ne {x} := ⟨fun _ _ _ => congrArg <| Add.add x⟩
  pcore_ne _ := (exists_eq_right'.mpr ·)
  validN_ne H Hp := H ▸ Hp
  valid_iff_validN := forall_const _ |>.symm
  validN_succ := (·)
  validN_op_left := proper_add_mono_left
  assoc := Equiv.of_eq <| by simp only [Add.add]; rw [add_assoc]
  comm := Equiv.of_eq <| by simp only [Add.add]; rw [add_comm]
  pcore_op_left := by admit /- proof elided -/
end Iris

namespace Iris
instance [Fraction α] : CMRA.Discrete (Frac α) where
  discrete_0 := id
  discrete_valid := id
end Iris

namespace Iris
instance [Fraction α] [CMRA α] {a : Frac α} (Hw : Whole a.1) : Exclusive a where
  exclusive0_l _ Hk := (not_exists.mp Hw.2) _ Hk
end Iris

namespace Iris
instance [Fraction α] {a : Frac α} : CMRA.Cancelable a where
  cancelableN {n x y} _ (H : a • x = a • y) := by admit /- proof elided -/
end Iris

namespace Iris
instance [Fraction α] {a : Frac α} : CMRA.IdFree a where
  id_free0_r b _ H := by admit /- proof elided -/
end Iris

namespace Iris
class UFraction (α : Type _) extends Fraction α, One α where
  
  
  
  
  one_whole : Fraction.Whole (1 : α)
end Iris

namespace Iris
class NumericFraction (α : Type _) extends One α, Add α, LE α, LT α where
  add_comm : ∀ a b : α, a + b = b + a
  add_assoc : ∀ a b c : α, a + (b + c) = (a + b) + c
  add_left_cancel : ∀ {a b c : α}, a + b = a + c → b = c
  le_def : ∀ {a b : α}, a ≤ b ↔ a = b ∨ a < b
  lt_def : ∀ {a b : α}, a < b ↔ ∃ c : α, a + c = b
  lt_irrefl : ∀ {a : α}, ¬a < a
end Iris

namespace Iris
@[simp] instance [NumericFraction T] : One (Frac T) := ⟨⟨One.one⟩⟩
end Iris

namespace Iris
@[simp] instance [NumericFraction T] : LE (Frac T) := ⟨(·.1 ≤ ·.1)⟩
end Iris

namespace Iris
@[simp] instance [NumericFraction T] : LT (Frac T) := ⟨(·.1 < ·.1)⟩
end Iris

namespace Iris
instance : UFraction α where
  Proper x := x ≤ 1
  add_comm := add_comm
  add_assoc := add_assoc
  add_left_cancel := add_left_cancel
  add_ne H := add_ne_self ((add_comm ..).trans H.symm)
  proper_add_mono_left := add_le_mono
  
  
  
  
  
  
  
  one_whole := by admit /- proof elided -/
end Iris

namespace Iris.ProofMode
instance : IsModal (PROP1 := PROP) persistently (.id rfl) .clear where
  spec_intuitionistic _ := persistent
  spec_spatial P := persistently_absorbing P
  emp := persistently_emp_2
  mono := (persistently_mono ·)
  sep := persistently_sep_2
end Iris.ProofMode

namespace Iris.ProofMode
instance : IsModal (PROP1 := PROP) affinely (.id rfl) (.forall rfl Affine) where
  spec_intuitionistic _ := affinely_intro .rfl
  spec_spatial _ _ := affinely_intro .rfl
  emp := affinely_intro .rfl
  mono := (affinely_mono ·)
  sep := affinely_sep_2
end Iris.ProofMode

namespace Iris.ProofMode
instance : IsModal (PROP1 := PROP) intuitionistically (.id rfl) .isEmpty where
  spec_intuitionistic _ := intuitionistic
  spec_spatial := trivial
  emp := intuitionistic
  mono := (intuitionistically_mono ·)
  sep := intuitionistically_sep_2
end Iris.ProofMode

namespace Iris.Std
def bigOp (f : PROP → PROP → PROP) (unit : PROP) : List PROP → PROP
  | []      => unit
  | [P]     => P
  | P :: Ps => f P (bigOp f unit Ps)
end Iris.Std

namespace Iris.Std
class LawfulBigOp (f : PROP → PROP → PROP) (unit : outParam PROP)
    (eq : outParam (PROP → PROP → Prop)) where
  refl : eq a a
  symm : eq a b → eq b a
  trans : eq a b → eq b c → eq a c
  comm : eq (f a b) (f b a)
  assoc : eq (f (f a b) c) (f a (f b c))
  left_id : eq (f unit a) a
  congr_l : eq a a' → eq (f a b) (f a' b)
end Iris.Std

namespace Iris
inductive DFrac (F : Type _) where
 
| own (f : F) : DFrac F
 
| discard : DFrac F
 
| ownDiscard (f : F) : DFrac F
end Iris

namespace Iris
@[simp] instance : COFE (DFrac F) := COFE.ofDiscrete _ Eq_Equivalence
end Iris

namespace Iris
instance : OFE.Leibniz (DFrac F) := ⟨(·)⟩
end Iris

namespace Iris
instance : OFE.Discrete (DFrac F) := ⟨congrArg id⟩
end Iris

namespace Iris
instance : Inhabited (DFrac F) := ⟨discard⟩
end Iris

namespace Iris
def valid : DFrac F → Prop
  | .own f        => Proper f
  | .discard      => True
  | .ownDiscard f => Fractional f
end Iris

namespace Iris
def pcore : DFrac F → Option (DFrac F)
  | own _        => none
  | .discard     => some discard
  | ownDiscard _ => some discard
end Iris

namespace Iris
def op : DFrac F → DFrac F → DFrac F
  | .discard, .discard => discard
  | own f, .discard
  | ownDiscard f, .discard
  | .discard, own f
  | .discard, ownDiscard f => ownDiscard f
  | own f, own f' => own (f + f')
  | own f, ownDiscard f'
  | ownDiscard f, own f'
  | ownDiscard f, ownDiscard f' => ownDiscard (f + f')
end Iris

namespace Iris
instance DFrac_CMRA : CMRA (DFrac F) where
  pcore := pcore
  op := op
  Valid := valid
  ValidN _ := valid
  op_ne := { ne _ _ _ := congrArg (op _) }
  pcore_ne {_} := by admit /- proof elided -/
end Iris

namespace Iris
instance : CMRA.Exclusive (own (1 : F)) :=
  own_whole_exclusive <| UFraction.one_whole
end Iris

namespace Iris
instance {f : F} : CMRA.Cancelable (own f) where
  cancelableN {_} := by admit /- proof elided -/
end Iris

namespace Iris
instance {f : F} : CMRA.IdFree (own f) where
  id_free0_r := by admit /- proof elided -/
end Iris

namespace Iris
instance : CMRA.Discrete (DFrac F) where
  discrete_valid {x} := by admit /- proof elided -/
end Iris

namespace Iris.ProofMode
structure SpecializeState {prop : Q(Type u)} (bi : Q(BI $prop)) (orig : Q($prop)) where
  (e : Q($prop)) (hyps : Hyps bi e) (b : Q(Bool)) (out : Q($prop))
  pf : Q($orig ⊢ $e ∗ □?$b $out)
end Iris.ProofMode

namespace Iris.ProofMode
def SpecializeState.process1 :
    @SpecializeState u prop bi orig → Term → TermElabM (SpecializeState bi orig)
  | { e, hyps, b, out, pf }, arg => do
    let uniq ← match arg with
      | `($x:ident) => try? (hyps.findWithInfo x)
      | _ => pure none
    if let some uniq := uniq then
      
      let ⟨e', hyps', out₁, out₁', b1, _, pf'⟩ := hyps.remove false uniq
      let b2 := if b1.constName! == ``true then b else q(false)
      have : $out₁ =Q iprop(□?$b1 $out₁') := ⟨⟩
      have : $b2 =Q ($b1 && $b) := ⟨⟩

      let out₂ ← mkFreshExprMVarQ prop
      let _ ← synthInstanceQ q(IntoWand $b $b1 $out $out₁' $out₂)
      let pf := q(specialize_wand $pf $pf')
      return { e := e', hyps := hyps', b := b2, out := out₂, pf }
    else
      
      let v ← mkFreshLevelMVar
      let α : Q(Sort v) ← mkFreshExprMVarQ q(Sort v)
      let Φ : Q($α → $prop) ← mkFreshExprMVarQ q($α → $prop)
      let _ ← synthInstanceQ q(IntoForall $out $Φ)
      let x ← elabTermEnsuringTypeQ (u := .succ .zero) arg α
      have out' : Q($prop) := Expr.headBeta q($Φ $x)
      have : $out' =Q $Φ $x := ⟨⟩
      return { e, hyps, b, out := out', pf := q(specialize_forall $pf $x) }
end Iris.ProofMode

namespace Iris.ProofMode
def Hyps.rename : ∀ {e}, Hyps bi e → Option (Hyps bi e)
  | _, .emp _ => none
  | _, .sep _ _ _ _ lhs rhs =>
    match rhs.rename with
    | some rhs' => some (.mkSep lhs rhs' _)
    | none => match lhs.rename with
      | some lhs' => some (.mkSep lhs' rhs _)
      | none => none
  | _, .hyp _ _ uniq p ty _ =>
    if oldUniq == uniq then some (Hyps.mkHyp bi new uniq p ty _) else none
end Iris.ProofMode

instance : Inhabited (QuotedDefEq a b) := ⟨⟨⟩⟩

namespace Iris.Std
instance : TCTrue := TCTrue.t
end Iris.Std

namespace Iris.Std
instance [t : T] : TCOr T U := @TCOr.l T U t
end Iris.Std

namespace Iris.Std
instance [u : U] : TCOr T U := @TCOr.r T U u
end Iris.Std

namespace Iris.Std
instance [t : T] : TCIte (no_index true) T U := TCIte.t (t := t)
end Iris.Std

namespace Iris.Std
instance [u : U] : TCIte (no_index false) T U := TCIte.e (u := u)

unif_hint (b : Bool) where
  |- false || b ≟ b
unif_hint (b : Bool) where
  |- true || b ≟ true
unif_hint (b : Bool) where
  |- false && b ≟ false
unif_hint (b : Bool) where
  |- true && b ≟ b
end Iris.Std

namespace Iris.Instances.Classical
def maps_to (l : Nat) (v : Val) : HeapProp Val :=
  fun state => state l = result v
end Iris.Instances.Classical

namespace Iris
class CMRA (α : Type _) extends OFE α where
  pcore : α → Option α
  op : α → α → α
  ValidN : Nat → α → Prop
  Valid : α → Prop

  op_ne : NonExpansive (op x)
  pcore_ne : x ≡{n}≡ y → pcore x = some cx →
    ∃ cy, pcore y = some cy ∧ cx ≡{n}≡ cy
  validN_ne : x ≡{n}≡ y → ValidN n x → ValidN n y

  valid_iff_validN : Valid x ↔ ∀ n, ValidN n x
  validN_succ : ValidN n.succ x → ValidN n x
  validN_op_left : ValidN n (op x y) → ValidN n x

  assoc : op x (op y z) ≡ op (op x y) z
  comm : op x y ≡ op y x

  pcore_op_left : pcore x = some cx → op cx x ≡ x
  pcore_idem : pcore x = some cx → pcore cx ≡ some cx
  pcore_op_mono : pcore x = some cx → ∀ y, ∃ cy, pcore (op x y) ≡ some (op cx cy)

  extend : ValidN n x → x ≡{n}≡ op y₁ y₂ →
    Σ' z₁ z₂, x ≡ op z₁ z₂ ∧ z₁ ≡{n}≡ y₁ ∧ z₂ ≡{n}≡ y₂
end Iris

namespace Iris.CMRA
def Included (x y : α) : Prop := ∃ z, y ≡ x • z
end Iris.CMRA

namespace Iris.CMRA
def IncludedN (n : Nat) (x y : α) : Prop := ∃ z, y ≡{n}≡ x • z
end Iris.CMRA

namespace Iris.CMRA
def op? [CMRA α] (x : α) : Option α → α
  | some y => x • y
  | none => x
end Iris.CMRA

namespace Iris.CMRA
class CoreId (x : α) where
  core_id : pcore x ≡ some x
end Iris.CMRA

namespace Iris.CMRA
class Exclusive (x : α) where
  exclusive0_l y : ¬✓{0} x • y
end Iris.CMRA

namespace Iris.CMRA
class Cancelable (x : α) where
  cancelableN : ✓{n} x • y → x • y ≡{n}≡ x • z → y ≡{n}≡ z
end Iris.CMRA

namespace Iris.CMRA
class IdFree (x : α) where
  id_free0_r y : ✓{0} x → ¬x • y ≡{0}≡ x
end Iris.CMRA

namespace Iris.CMRA
class IsTotal (α : Type _) [CMRA α] where
  total (x : α) : ∃ cx, pcore x = some cx
end Iris.CMRA

namespace Iris.CMRA
def core (x : α) := (pcore x).getD x
end Iris.CMRA

namespace Iris.CMRA
class Discrete (α : Type _) [CMRA α] extends OFE.Discrete α where
  discrete_valid {x : α} : ✓{0} x → ✓ x
end Iris.CMRA

namespace Iris
class UCMRA (α : Type _) extends CMRA α where
  unit : α
  unit_valid : ✓ unit
  unit_left_id : unit • x ≡ x
  pcore_unit : pcore unit ≡ some unit
end Iris

namespace Iris.CMRA
instance : NonExpansive (pcore (α := α)) where
  ne n x {y} e := by admit /- proof elided -/
end Iris.CMRA

namespace Iris.CMRA
instance : Trans Equiv (Included (α := α)) Included where
  trans := inc_of_eqv_of_inc
end Iris.CMRA

namespace Iris.CMRA
instance : Trans (Included (α := α)) Equiv Included where
  trans := inc_of_inc_of_eqv
end Iris.CMRA

namespace Iris.CMRA
instance {n : Nat} : Trans (IncludedN (α := α) n) (Dist n) (IncludedN n) where
  trans := incN_of_incN_of_dist
end Iris.CMRA

namespace Iris.CMRA
instance {n : Nat} : Trans (Dist (α := α) n) (IncludedN n) (IncludedN n) where
  trans := incN_of_dist_of_incN
end Iris.CMRA

namespace Iris.CMRA
instance : Trans (Included (α := α)) Included Included where
  trans := inc_trans
end Iris.CMRA

namespace Iris.CMRA
instance : Trans (IncludedN (α := α) n) (IncludedN n) (IncludedN n) where
  trans := incN_trans
end Iris.CMRA

namespace Iris.CMRA
instance (y : α) : CoreId (core y) := CoreId.of_pcore_eq_some (pcore_eq_core _)
end Iris.CMRA

namespace Iris.CMRA
instance discrete_op {x y : α} (Hv : ✓{0} x • y) [Hx : DiscreteE x] [Hy : DiscreteE y] :
    DiscreteE (x • y) where
  discrete h :=
    let ⟨_w, _t, wt, wx, ty⟩ := extend ((Dist.validN h).mp Hv) h.symm
    ((Hx.discrete wx.symm).op (Hy.discrete ty.symm)).trans wt.symm
end Iris.CMRA

namespace Iris.CMRA
instance cancelable_op {x y : α} [Cancelable x] [Cancelable y] : Cancelable (x • y) where
  cancelableN {n w _} v e :=
    have v1 : ✓{n} x • (y • w) := validN_ne op_assocN.symm v
    have v2 := validN_op_right v1
    cancelableN v2 <| cancelableN v1 <| op_assocN.trans <| e.trans op_assocN.symm
end Iris.CMRA

namespace Iris.CMRA
instance exclusive_cancelable {x : α} [Exclusive x] : Cancelable x where
  cancelableN v _ := absurd v not_valid_exclN_op_left
end Iris.CMRA

namespace Iris.CMRA
instance idFree_op_r {x y : α} [IdFree y] [Cancelable x] : IdFree (x • y) where
  id_free0_r z v h :=
    id_free0_r z (validN_op_right v) (cancelableN v (assoc.dist.trans h).symm).symm
end Iris.CMRA

namespace Iris.CMRA
instance idFree_op_l {x y : α} [IdFree x] [Cancelable y] : IdFree (x • y) :=
  comm.idFree.1 inferInstance
end Iris.CMRA

namespace Iris.CMRA
instance exclusive_idFree {x : α} [Exclusive x] : IdFree x where
  id_free0_r z v h := exclusive0_l z ((validN_iff h.symm).mp v)
end Iris.CMRA

namespace Iris.CMRA
instance unit_CoreId : CoreId (unit : α) where
  core_id := pcore_unit
end Iris.CMRA

namespace Iris.CMRA
instance unit_total : IsTotal α where
  total _ :=
    have ⟨y, hy, _⟩ := pcore_mono' inc_unit pcore_unit
    ⟨y, hy⟩
end Iris.CMRA

namespace Iris.CMRA
instance empty_cancelable : Cancelable (unit : α) where
  cancelableN {n w t} _ e := calc
    w ≡{n}≡ unit • w := unit_left_id.dist.symm
    _ ≡{n}≡ unit • t := e
    _ ≡{n}≡ t := unit_left_id.dist
end Iris.CMRA

namespace Iris.CMRA
@[ext] structure Hom (α β : Type _) [CMRA α] [CMRA β] extends OFE.Hom α β where
  protected validN {n x} : ✓{n} x → ✓{n} (f x)
  protected pcore x : (pcore x).map f ≡ pcore (f x)
  protected op x y : f (x • y) ≡ f x • f y
end Iris.CMRA

namespace Iris.CMRA
instance [CMRA β] : CoeFun (α -C> β) (fun _ => α → β) := ⟨fun F => F.f⟩
end Iris.CMRA

namespace Iris.CMRA
instance [CMRA β] : OFE (α -C> β) where
  Equiv f g := f.toHom ≡ g.toHom
  Dist n f g := f.toHom ≡{n}≡ g.toHom
  dist_eqv := {
    refl _ := dist_eqv.refl _
    symm h := dist_eqv.symm h
    trans h1 h2 := dist_eqv.trans h1 h2
  }
  equiv_dist := equiv_dist
  dist_lt := dist_lt
end Iris.CMRA

namespace Iris.CMRA
protected def Hom.id [CMRA α] : α -C> α where
  toHom := OFE.Hom.id
  validN := id
  pcore x := by admit /- proof elided -/
end Iris.CMRA

namespace Iris
class RFunctor (F : COFE.OFunctorPre) where
  
  
  
  [cmra [OFE α] [OFE β] : CMRA (F α β)]
  map [OFE α₁] [OFE α₂] [OFE β₁] [OFE β₂] :
    (α₂ -n> α₁) → (β₁ -n> β₂) → F α₁ β₁ -C> F α₂ β₂
  map_ne [OFE α₁] [OFE α₂] [OFE β₁] [OFE β₂] :
    NonExpansive₂ (@map α₁ α₂ β₁ β₂ _ _ _ _)
  map_id [OFE α] [OFE β] (x : F α β) : map (@Hom.id α _) (@Hom.id β _) x ≡ x
  map_comp [OFE α₁] [OFE α₂] [OFE α₃] [OFE β₁] [OFE β₂] [OFE β₃]
    (f : α₂ -n> α₁) (g : α₃ -n> α₂) (f' : β₁ -n> β₂) (g' : β₂ -n> β₃) (x : F α₁ β₁) :
    map (f.comp g) (g'.comp f') x ≡ map g g' (map f f' x)
end Iris

namespace Iris
class RFunctorContractive (F : COFE.OFunctorPre) extends (RFunctor F) where
  map_contractive [OFE α₁] [OFE α₂] [OFE β₁] [OFE β₂] :
    Contractive (Function.uncurry (@map α₁ α₂ β₁ β₂ _ _ _ _))
end Iris

namespace Iris
def RFunctor.ap [RFunctor F] [OFE T] := F T T
end Iris

namespace Iris
instance RFunctor.toOFunctor [R : RFunctor F] : COFE.OFunctor F where
  cofe       := RFunctor.cmra.toOFE
  map a b    := (RFunctor.map a b).toHom
  map_ne.ne  := RFunctor.map_ne.ne
  map_id     := RFunctor.map_id
  map_comp   := RFunctor.map_comp
end Iris

namespace Iris
instance RFunctorContractive.toOFunctorContractive
    [RFunctorContractive F] : COFE.OFunctorContractive F where
  map_contractive.1 := map_contractive.1
end Iris

namespace Iris
class URFunctor (F : COFE.OFunctorPre) where
  
  
  
  [cmra [OFE α] [OFE β] : UCMRA (F α β)]
  map [OFE α₁] [OFE α₂] [OFE β₁] [OFE β₂] :
    (α₂ -n> α₁) → (β₁ -n> β₂) → F α₁ β₁ -C> F α₂ β₂
  map_ne [OFE α₁] [OFE α₂] [OFE β₁] [OFE β₂] :
    NonExpansive₂ (@map α₁ α₂ β₁ β₂ _ _ _ _)
  map_id [OFE α] [OFE β] (x : F α β) : map (@Hom.id α _) (@Hom.id β _) x ≡ x
  map_comp [OFE α₁] [OFE α₂] [OFE α₃] [OFE β₁] [OFE β₂] [OFE β₃]
    (f : α₂ -n> α₁) (g : α₃ -n> α₂) (f' : β₁ -n> β₂) (g' : β₂ -n> β₃) (x : F α₁ β₁) :
    map (f.comp g) (g'.comp f') x ≡ map g g' (map f f' x)
end Iris

namespace Iris
class URFunctorContractive (F : COFE.OFunctorPre) extends URFunctor F where
  map_contractive [OFE α₁] [OFE α₂] [OFE β₁] [OFE β₂] :
    Contractive (Function.uncurry (@map α₁ α₂ β₁ β₂ _ _ _ _))
end Iris

namespace Iris
instance URFunctor.toRFunctor [UF : URFunctor F] : RFunctor F where
  cmra     := URFunctor.cmra.toCMRA
  map f g  := URFunctor.map f g
  map_ne   := URFunctor.map_ne
  map_id   := URFunctor.map_id
  map_comp := URFunctor.map_comp
end Iris

namespace Iris
instance URFunctorContractive.toRFunctorContractive
    [URFunctorContractive F] : RFunctorContractive F where
  map_contractive := map_contractive
end Iris

namespace Iris
instance COFE.OFunctor.constOF_RFunctor [CMRA B] : RFunctor (constOF B) where
  map f g := by admit /- proof elided -/
end Iris

namespace Iris
instance OFunctor.constOF_RFunctorContractive [CMRA B] :
    RFunctorContractive (COFE.constOF B) where
  map_contractive.1 := by admit /- proof elided -/
end Iris

namespace Iris
instance cmraDiscreteFunO {α : Type _} (β : α → Type _)
    [∀ x, CMRA (β x)] [∀ x, IsTotal (β x)] : CMRA (∀ x, β x) where
  pcore f := some fun x => core (f x)
  op f g x := f x • g x
  ValidN n f := ∀ x, ✓{n} f x
  Valid f := ∀ x, ✓ f x
  op_ne.ne _ _ _ H y := (H y).op_r
  pcore_ne {n f g _} H := by admit /- proof elided -/
end Iris

namespace Iris
instance ucmraDiscreteFunO {α : Type _} (β : α → Type _) [∀ x, UCMRA (β x)] : UCMRA (∀ x, β x) where
  unit _ := unit
  unit_valid _ := unit_valid
  unit_left_id _ := unit_left_id
  pcore_unit _ := core_eqv_self _
end Iris

namespace Iris
instance urFunctorDiscreteFunOF {C} (F : C → COFE.OFunctorPre) [∀ c, URFunctor (F c)] :
    URFunctor (DiscreteFunOF F) where
  map f g := {
    toHom := COFE.OFunctor.map f g
    validN hv _ := (URFunctor.map f g).validN (hv _)
    pcore _ _ := by admit /- proof elided -/
end Iris

namespace Iris
instance DiscreteFunOF_URFC {C} (F : C → COFE.OFunctorPre) [HURF : ∀ c, URFunctorContractive (F c)] :
    URFunctorContractive (DiscreteFunOF F) where
  map_contractive.1 h _ _ := URFunctorContractive.map_contractive.distLater_dist h _
end Iris

namespace Iris
@[simp] def optionCore (x : Option α) : Option α := x.bind pcore
end Iris

namespace Iris
@[simp] def optionOp (x y : Option α) : Option α :=
  match x, y with
  | some x', some y' => some (CMRA.op x' y')
  | none, _ => y
  | _, none => x
end Iris

namespace Iris
@[simp] def optionValidN (n : Nat) : Option α → Prop
  | some x => ✓{n} x
  | none => True
end Iris

namespace Iris
@[simp] def optionValid : Option α → Prop
  | some x => ✓ x
  | none => True
end Iris

namespace Iris
instance cmraOption : CMRA (Option α) where
  pcore x := some (optionCore x)
  op := optionOp
  ValidN := optionValidN
  Valid := optionValid
  op_ne.ne n x1 x2 H := by admit /- proof elided -/
end Iris

namespace Iris
instance ucmraOption : UCMRA (Option α) where
  unit := none
  unit_valid := by admit /- proof elided -/
end Iris

namespace Iris.Option
instance {a : α} [IdFree a] [Cancelable a] : Cancelable (some a) :=
end Iris.Option

namespace Iris.Option
instance {ma : Option α} [∀ a : α, IdFree a] [∀ a : α, Cancelable a] : Cancelable ma :=
end Iris.Option

namespace Iris.Option
instance [CMRA.Discrete α] : CMRA.Discrete (Option α) where
  discrete_valid {x} := by admit /- proof elided -/
end Iris.Option

namespace Iris
instance cmraUnit : CMRA Unit where
  pcore _ := some ()
  op _ _ := ()
  ValidN _ _ := True
  Valid _ := True
  op_ne.ne _ _ _ := id
  pcore_ne _ _ := ⟨(), rfl, .rfl⟩
  validN_ne _ := id
  valid_iff_validN := ⟨fun _ _ => ⟨⟩, fun _ => ⟨⟩⟩
  validN_succ := id
  validN_op_left := id
  assoc := .rfl
  comm := .rfl
  pcore_op_left _ := .rfl
  pcore_idem _ := .rfl
  pcore_op_mono _ _ := ⟨.unit, .rfl⟩
  extend _ _ := ⟨(), (), .rfl, .rfl, .rfl⟩
end Iris

namespace Iris.Prod
abbrev pcore (x : α × β) : Option (α × β) :=
  (CMRA.pcore x.fst).bind fun a =>
  (CMRA.pcore x.snd).bind fun b =>
  return (a, b)
end Iris.Prod

namespace Iris.Prod
abbrev op (x y : α × β) : α × β :=
  (x.1 • y.1, x.2 • y.2)
end Iris.Prod

namespace Iris.Prod
abbrev ValidN n (x : α × β) := ✓{n} x.fst ∧ ✓{n} x.snd
end Iris.Prod

namespace Iris.Prod
abbrev Valid (x : α × β) := ✓ x.fst ∧ ✓ x.snd
end Iris.Prod

namespace Iris.Prod
instance cmraProd : CMRA (α × β) where
  pcore := pcore
  op := op
  ValidN := ValidN
  Valid := Valid
  op_ne {x} :=
    { ne n y z h := dist_prod_ext (Dist.op_r $ dist_fst h) (Dist.op_r $ dist_snd h) }
  pcore_ne {n x y cx} h ph := by admit /- proof elided -/
end Iris.Prod

namespace Iris.Prod
instance [CMRA.Discrete α] [CMRA.Discrete β]: CMRA.Discrete (α × β) where
  discrete_valid := by admit /- proof elided -/
end Iris.Prod

namespace Iris
instance urFunctorOptionOF [RFunctor F] : URFunctor (OptionOF F) where
  cmra {α β} := ucmraOption
  map f g := {
    toHom := COFE.OFunctor.map f g
    validN := by admit /- proof elided -/
end Iris

namespace Iris
instance urFunctorContractiveOptionOF
    [RFunctorContractive F] : URFunctorContractive (OptionOF F) where
  map_contractive.1 := COFE.OFunctorContractive.map_contractive.1
end Iris

namespace Iris
abbrev GenMap := α → Option β
end Iris

namespace Iris
abbrev GenMapOF (C : Type _) (F : COFE.OFunctorPre) :=
  DiscreteFunOF fun (_ : C) => OptionOF F
end Iris

Nat in Init.Prelude

Or in Init.Prelude

Or.inl in Init.Prelude

Bool in Init.Prelude

Inhabited in Init.Prelude

Qq.QuotedDefEq in Qq.Typ

List in Init.Prelude

outParam in Init.Prelude

Monad in Init.Prelude

Nat.eq_or_lt_of_le in Init.Prelude

MonadExcept in Init.Prelude

Option in Init.Prelude

m in QqTest.matching

Lean.Elab.Tactic.TacticM in Lean.Elab.Tactic.Basic

Lean.Parser.Tactic.rwRule in Init.Tactics

Lean.TSyntax in Init.Prelude

Lean.Elab.throwUnsupportedSyntax in Lean.Elab.Exception

Array in Init.Prelude

Lean.Name in Init.Prelude

Lean.MVarId in Lean.Expr

Lean.Elab.Tactic.evalTactic in Lean.Elab.Tactic.Basic

Lean.Elab.Tactic.getMainGoal in Lean.Elab.Tactic.Basic

Lean.Elab.Tactic.withoutRecover in Lean.Elab.Tactic.Basic

Lean.Meta.saveState in Lean.Meta.Basic

Lean.Parser.Tactic.exact in Init.Tactics

Unit in Init.Prelude

Lean.Elab.Tactic.getUnsolvedGoals in Lean.Elab.Tactic.Basic

Lean.Elab.Tactic.setGoals in Lean.Elab.Tactic.Basic

Lean.Meta.withReducible in Lean.Meta.Basic

Lean.Expr in Lean.Expr

Lean.mkAppN in Lean.Expr

Lean.Expr.mdata in Lean.Expr

Lean.KVMap in Lean.Data.KVMap

Lean.mkMData in Lean.Expr

Eq in Init.Prelude

Equivalence in Init.Core

Lean.Parser.Term.leading_parser in Lean.Parser.Term

Lean.Parser.Term.matchAlts in Lean.Parser.Term

Lean.PrettyPrinter.Unexpander in Init.Prelude

Lean.mkIdent in Init.Meta.Defs

k in QqTest.matching

Equiv in Mathlib.Logic.Equiv.Defs

Trans in Init.Prelude

Option.merge in Init.Data.Option.Basic

String in Init.Prelude

Nat.le in Init.Prelude

Nat.zero in Init.Prelude

Ne in Init.Core

id in Init.Prelude

Lean.MonadQuotation in Init.Prelude

Lean.MonadRef in Init.Prelude

False.elim in Init.Prelude

And in Init.Prelude

Or.inr in Init.Prelude

And.elim in Init.Core

inferInstanceAs in Init.Prelude

Function.const in Init.Prelude

semiOutParam in Init.Prelude

Lean.Level in Lean.Level

Lean.Expr.isAppOfArity in Lean.Expr

Lean.LocalContext in Lean.LocalContext

Lean.Meta.MetaM in Lean.Meta.Basic

Lean.Syntax in Init.Prelude

Lean.Elab.withInfoContext' in Lean.Elab.InfoTree.Main

Lean.Expr.fvar in Lean.Expr

Lean.Expr.app in Lean.Expr

Lean.PrettyPrinter.Delaborator.Delab in Lean.PrettyPrinter.Delaborator.Basic

Lean.PrettyPrinter.Delaborator.SubExpr.getExpr in Lean.PrettyPrinter.Delaborator.SubExpr

Lean.PrettyPrinter.delab in Lean.PrettyPrinter.Delaborator.Basic

Lean.instantiateMVars in Lean.MetavarContext

Lean.NameMap in Lean.Data.NameMap.Basic

Lean.PrettyPrinter.Delaborator.DelabM in Lean.PrettyPrinter.Delaborator.Basic

Lean.PrettyPrinter.Delaborator.failure in Lean.PrettyPrinter.Delaborator.Basic

Lean.PrettyPrinter.Delaborator.SubExpr.withAppArg in Lean.PrettyPrinter.Delaborator.SubExpr

CoeFun in Init.Coe

InvImage in Init.Core

ULift in Init.Prelude

ULift.down in Init.Prelude

Nat.le_or_ge in Init.Data.Nat.Basic

Function.uncurry in Init.Data.Function

f₁ in QqTest.commandTest

f₂ in QqTest.commandTest

Option.map in Init.Prelude

Nat.succ in Init.Prelude

Dist in Mathlib.Topology.MetricSpace.Pseudo.Defs

Fin in Init.Prelude

GetElem in Init.GetElem

Inhabited.default in Init.Prelude

Fix in Mathlib.Control.Fix

Add in Init.Prelude

Coe in Init.Coe

Add.add in Init.Prelude

One in Init.Prelude

LE in Init.Prelude

LT in Init.Prelude

One.one in Init.Prelude

absurd in Init.Prelude

Option.le in Init.Data.Option.Basic

Option.elim in Init.Data.Option.Basic

Prod in Init.Prelude

Option.isSome in Init.Data.Option.Basic

Exists in Init.Core

propext in Init.Core

EmptyCollection in Init.Core

HasSubset in Init.Core

Union in Init.Core

EmptyCollection.emptyCollection in Init.Core

Union.union in Init.Core

Repr in Init.Data.Repr

Lean.MacroM in Init.Prelude

Lean.expandMacros in Init.Meta.Defs

Lean.Macro.throwUnsupported in Init.Prelude

Lean.Syntax.TSepArray in Init.Prelude

Lean.Expr.headBeta in Lean.Expr

Pure in Init.Prelude

Qq.mkFreshExprMVarQ in Qq.MetaM

Qq.synthInstanceQ in Qq.MetaM

Qq.withLocalDeclDQ in Qq.MetaM

Qq.assertDefEqQ in Qq.MetaM

Lean.mkFreshId in Init.Meta.Defs

Lean.throwError in Lean.Exception

Qq.inferTypeQ in Qq.MetaM

Id in Init.Control.Id

Id.run in Init.Control.Id

Lean.NameSet in Lean.Data.NameMap.Basic

Qq.elabTermEnsuringTypeQ in Qq.MetaM

Qq.Quoted in Qq.Typ

Qq.checkTypeQ in Qq.MetaM

IO in Init.System.IO

IO.Ref in Init.System.IO

Qq.push in Qq.Match

Lean.trace in Lean.Util.Trace

Qq.instantiateMVarsQ in Qq.MetaM

Lean.mkApp in Lean.Expr
</all_available_defs>

<all_available_lemmas>
namespace Iris
theorem mem_of_agree (x : Agree α) : ∃ a, a ∈ x.car
end Iris

namespace Iris
theorem Agree.dist_equiv : Equivalence (dist (α := α) n)
end Iris

namespace Iris
theorem Agree.equiv_def {x y : Agree α} : x ≡ y ↔ ∀ n, Agree.dist n x y
end Iris

namespace Iris
theorem Agree.dist_def {x y : Agree α} : x ≡{n}≡ y ↔ Agree.dist n x y
end Iris

namespace Iris
theorem Agree.validN_iff {x : Agree α} :
    x.validN n ↔ ∀ a ∈ x.car, ∀ b ∈ x.car, a ≡{n}≡ b
end Iris

namespace Iris
theorem Agree.op_comm {x y : Agree α} :  x.op y ≡ y.op x
end Iris

namespace Iris
theorem Agree.op_commN {x y : Agree α} :  x.op y ≡{n}≡ y.op x
end Iris

namespace Iris
theorem Agree.op_assoc {x y z : Agree α} :  x.op (y.op z) ≡ (x.op y).op z
end Iris

namespace Iris
theorem Agree.idemp {x : Agree α} : x.op x ≡ x
end Iris

namespace Iris
theorem Agree.validN_ne {x y : Agree α} : x ≡{n}≡ y → x.validN n → y.validN n
end Iris

namespace Iris
theorem Agree.op_ne {x : Agree α} : OFE.NonExpansive x.op
end Iris

namespace Iris
theorem liftRel_eq : liftRel (@Eq α) A B ↔ A = B
end Iris

namespace Iris.BI
theorem BIBase.Entails.trans [BI PROP] {P Q R : PROP} (h1 : P ⊢ Q) (h2 : Q ⊢ R) : P ⊢ R
end Iris.BI

namespace Iris.BI
@[simp] theorem BIBase.Entails.rfl [BI PROP] {P : PROP} : P ⊢ P
end Iris.BI

namespace Iris.BI
theorem BIBase.Entails.of_eq [BI PROP] {P Q : PROP} (h : P = Q) : P ⊢ Q
end Iris.BI

namespace Iris.BI
@[simp] theorem BIBase.BiEntails.rfl [BI PROP] {P : PROP} : P ⊣⊢ P
end Iris.BI

namespace Iris.BI
theorem BIBase.BiEntails.of_eq [BI PROP] {P Q : PROP} (h : P = Q) : P ⊣⊢ Q
end Iris.BI

namespace Iris.BI
theorem BIBase.BiEntails.symm [BI PROP] {P Q : PROP} (h : P ⊣⊢ Q) : Q ⊣⊢ P
end Iris.BI

namespace Iris.BI
theorem BIBase.BiEntails.trans [BI PROP] {P Q R : PROP} (h1 : P ⊣⊢ Q) (h2 : Q ⊣⊢ R) : P ⊣⊢ R
end Iris.BI

namespace Iris.Examples
theorem proof_example_1 [BI PROP] (P Q R : PROP) (Φ : α → PROP) :
  P ∗ Q ∗ □ R ⊢ □ (R -∗ ∃ x, Φ x) -∗ ∃ x, Φ x ∗ P ∗ Q
end Iris.Examples

namespace Iris.ProofMode
theorem assumption [BI PROP] {p : Bool} {P P' A Q : PROP} [inst : FromAssumption p A Q]
  [TCOr (Affine P') (Absorbing Q)] (h : P ⊣⊢ P' ∗ □?p A) : P ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem replaces_r [BI PROP] {K P Q Q' : PROP} (h : Replaces K Q Q') :
    Replaces K iprop(P ∗ Q) iprop(P ∗ Q')
end Iris.ProofMode

namespace Iris.ProofMode
theorem replaces_l [BI PROP] {K P P' Q : PROP} (h : Replaces K P P') :
    Replaces K iprop(P ∗ Q) iprop(P' ∗ Q)
end Iris.ProofMode

namespace Iris.ProofMode
theorem Replaces.apply [BI PROP] {P P' Q : PROP}
    (h : Replaces Q P P') (h_entails : P' ⊢ Q) : P ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem to_persistent_spatial [BI PROP] {P P' Q : PROP}
    [hP : IntoPersistently false P P'] [or : TCOr (Affine P) (Absorbing Q)] :
    Replaces Q P iprop(□ P')
end Iris.ProofMode

namespace Iris.ProofMode
theorem to_persistent_intuitionistic [BI PROP] {P P' Q : PROP}
    [hP : IntoPersistently true P P'] : Replaces Q iprop(□ P) iprop(□ P')
end Iris.ProofMode

namespace Iris.ProofMode
theorem from_affine [BI PROP] {p : Bool} {P P' Q : PROP} [hP : FromAffinely P' P p] :
    Replaces Q iprop(□?p P) P'
end Iris.ProofMode

namespace Iris
theorem LocalUpdate.id (x : α × α) : x ~l~> x
end Iris

namespace Iris
theorem LocalUpdate.equiv_left {x y : α × α} (z : α × α) (h : x ≡ y) : x ~l~> z → y ~l~> z
end Iris

namespace Iris
theorem LocalUpdate.equiv_right (x : α × α) {y z : α × α} (h : y ≡ z) : x ~l~> y → x ~l~> z
end Iris

namespace Iris
theorem LocalUpdate.exclusive [CMRA.Exclusive y] {x x' : α}
    (vx' : ✓ x') : (x, y) ~l~> (x', x')
end Iris

namespace Iris
theorem LocalUpdate.op {x y z : α}
    (h : ∀ n, ✓{n} x → ✓{n} (z • x)) : (x, y) ~l~> (z • x, z • y)
end Iris

namespace Iris
theorem LocalUpdate.op_discrete [CMRA.Discrete α] (x y z : α)
    (h : ✓ x → ✓ (z • x)) : (x, y) ~l~> (z • x, z • y)
end Iris

namespace Iris
theorem LocalUpdate.op_frame (x y x' y' yf : α)
    (h : (x, y) ~l~> (x', y')) : (x, y • yf) ~l~> (x', y' • yf)
end Iris

namespace Iris
theorem LocalUpdate.cancel (x y z : α) [CMRA.Cancelable x] : (x • y, x • z) ~l~> (y, z)
end Iris

namespace Iris
theorem LocalUpdate.replace (x y : α) [CMRA.IdFree x] (h : ✓ y) : (x, x) ~l~> (y, y)
end Iris

namespace Iris
theorem LocalUpdate.core_id (x y z : α) [CMRA.CoreId y] (inc : y ≼ x) : (x, z) ~l~> (x, z • y)
end Iris

namespace Iris
theorem LocalUpdate.discrete [CMRA.Discrete α] (x y x' y' : α) :
    (x, y) ~l~> (x', y') ↔ ∀ mz, ✓ x → x ≡ y •? mz → (✓ x' ∧ x' ≡ y' •? mz)
end Iris

namespace Iris
theorem LocalUpdate.valid0 {x y x' y' : α}
    (h : ✓{0} x → ✓{0} y → some y ≼{0} some x → (x, y) ~l~> (x', y')) :
    (x, y) ~l~> (x', y')
end Iris

namespace Iris
theorem LocalUpdate.valid [CMRA.Discrete α] {x y x' y' : α}
    (h : ✓ x → ✓ y → some y ≼ some x → (x, y) ~l~> (x', y')) : (x, y) ~l~> (x', y')
end Iris

namespace Iris
theorem LocalUpdate.total_valid0 [CMRA.IsTotal α] {x y x' y' : α}
    (h : ✓{0} x → ✓{0} y → y ≼{0} x → (x, y) ~l~> (x', y')) : (x, y) ~l~> (x', y')
end Iris

namespace Iris
theorem LocalUpdate.total_valid [CMRA.IsTotal α] [CMRA.Discrete α] {x y x' y' : α}
    (h : ✓ x → ✓ y → y ≼ x → (x, y) ~l~> (x', y')) : (x, y) ~l~> (x', y')
end Iris

namespace Iris
theorem local_update_unital {x y x' y' : α} :
    (x, y) ~l~> (x', y') ↔ ∀ n z, ✓{n} x → x ≡{n}≡ y • z → (✓{n} x' ∧ x' ≡{n}≡ y' • z)
end Iris

namespace Iris
theorem local_update_unital_discrete [CMRA.Discrete α] (x y x' y' : α) :
    (x, y) ~l~> (x', y') ↔ ∀ z, ✓ x → x ≡ y • z → (✓ x' ∧ x' ≡ y' • z)
end Iris

namespace Iris
theorem cancel_local_update_unit (x y : α) [CMRA.Cancelable x] : (x • y, x) ~l~> (y, CMRA.unit)
end Iris

namespace Iris
theorem LocalUpdate.unit {x y x' y' : Unit} : (x, y) ~l~> (x', y')
end Iris

namespace Iris
theorem LocalUpdate.discrete_fun {β : α → Type _} [∀ x, UCMRA (β x)]
    {f g f' g' : ∀ x, β x} (h : ∀ x : α, (f x, g x) ~l~> (f' x, g' x)) :
    (f, g) ~l~> (f', g')
end Iris

namespace Iris
theorem LocalUpdate.prod {x y x' y' : α × β}
    (hl : (x.1, y.1) ~l~> (x'.1, y'.1)) (hr : (x.2, y.2) ~l~> (x'.2, y'.2)) :
    (x, y) ~l~> (x', y')
end Iris

namespace Iris
theorem LocalUpdate.prod' {x1 y1 x1' y1' : α} {x2 y2 x2' y2' : β}
    (hl : (x1, y1) ~l~> (x1', y1')) (hr : (x2, y2) ~l~> (x2', y2')) :
    ((x1, x2), (y1, y2)) ~l~> ((x1', x2'), (y1', y2'))
end Iris

namespace Iris
theorem LocalUpdate.prod_1 {x1 y1 x1' y1' : α} (x2 y2 : β)
    (h : (x1, y1) ~l~> (x1', y1')) : ((x1, x2), (y1, y2)) ~l~> ((x1', x2), (y1', y2))
end Iris

namespace Iris
theorem LocalUpdate.prod_2 (x1 y1 : α) {x2 y2 x2' y2' : β}
    (h : (x2, y2) ~l~> (x2', y2')) : ((x1, x2), (y1, y2)) ~l~> ((x1, x2'), (y1, y2'))
end Iris

namespace Iris
theorem LocalUpdate.option {x y x' y' : α}
    (h : (x, y) ~l~> (x', y')) : (some x, some y) ~l~> (some x', some y')
end Iris

namespace Iris
theorem LocalUpdate.option_none {α} [UCMRA α] {x x' y' : α}
    (h : (x, CMRA.unit) ~l~> (x', y')) : (some x, none) ~l~> (some x', some y')
end Iris

namespace Iris
theorem LocalUpdate.alloc_option {x : α} (y : Option α)
    (vx : ✓ x) : (none, y) ~l~> (some x, some x)
end Iris

namespace Iris
theorem LocalUpdate.delete_option (x : Option α) (y : α) [CMRA.Exclusive y] :
    (x, some y) ~l~> (none, none)
end Iris

namespace Iris
theorem LocalUpdate.delete_option_cancelable
    (mx : Option α) [CMRA.Cancelable mx] : (mx, mx) ~l~> (none, none)
end Iris

namespace Iris.ProofMode
theorem pure_assumption [BI PROP] {P A Q : PROP} (h_P : ⊢ A)
    [inst : FromAssumption true A Q] [TCOr (Affine P) (Absorbing Q)] :
    P ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem assumption_l [BI PROP] {P Q R : PROP} [Affine Q] (h : P ⊢ R) : P ∗ Q ⊢ R
end Iris.ProofMode

namespace Iris.ProofMode
theorem assumption_r [BI PROP] {P Q R : PROP} [Affine P] (h : Q ⊢ R) : P ∗ Q ⊢ R
end Iris.ProofMode

namespace Iris.ProofMode
theorem exfalso [BI PROP] {P Q : PROP} (h : P ⊢ False) : P ⊢ Q
end Iris.ProofMode

namespace Iris
theorem uPred_ne {P : UPred M} {n} {m₁ m₂} (H : m₁ ≡{n}≡ m₂) : P n m₁ ↔ P n m₂
end Iris

namespace Iris
theorem uPred_proper {P : UPred M} {n} {m₁ m₂} (H : m₁ ≡ m₂) : P n m₁ ↔ P n m₂
end Iris

namespace Iris
theorem uPred_holds_ne {P Q : UPred M} {n₁ n₂ x}
    (HPQ : P ≡{n₂}≡ Q) (Hn : n₂ ≤ n₁) (Hx : ✓{n₂} x) (HQ : Q n₁ x) : P n₂ x
end Iris

namespace Iris.COFE.OFunctor.Fix.Impl
theorem down_up : ∀ {k} x, down F k (up F k x) ≡ x
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor.Fix.Impl
theorem up_down {k} (x) : up F (k+1) (down F (k+1) x) ≡{k}≡ x
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor.Fix.Impl
theorem downN_upN {k} (x : A F k) : ∀ {i}, downN F i (upN F i x) ≡ x
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor.Fix.Impl
protected theorem Tower.up (X : Tower F) : up F (k+1) (X (k+1)) ≡{k}≡ X (k+2)
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor.Fix.Impl
protected theorem Tower.upN (X : Tower F) : ∀ i, upN F i (X (k+1)) ≡{k}≡ X (k+1+i)
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor.Fix.Impl
protected theorem Tower.downN (X : Tower F) : ∀ i, downN F i (X (k+i)) ≡ X k
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor.Fix.Impl
theorem eqToHom_up {k k'} {x : A F k} (e : k = k') :
    eqToHom (congrArg Nat.succ e) (up F k x) = up F k' (eqToHom e x)
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor.Fix.Impl
theorem down_eqToHom {k k'} {x : A F (k+1)} (e : k = k') :
    down F k' (eqToHom (congrArg Nat.succ e) x) = eqToHom e (down F k x)
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor.Fix.Impl
theorem Tower.embed_up (x : A F k) :
    Tower.embed (k+1) (up F k x) ≡ Tower.embed k x
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor.Fix.Impl
theorem Tower.embed_self (X : Tower F) :
    Tower.embed (k+1) (X (k+1)) ≡{k}≡ X
end Iris.COFE.OFunctor.Fix.Impl

namespace Iris.COFE.OFunctor
theorem Fix.fold_unfold (X : Fix F) : Fix.fold (Fix.unfold X) ≡ X
end Iris.COFE.OFunctor

namespace Iris.COFE.OFunctor
theorem Fix.unfold_fold (X : F (Fix F) (Fix F)) : Fix.unfold (Fix.fold X) ≡ X
end Iris.COFE.OFunctor

namespace Iris.BI
theorem affinely_plainly_elim : <affine> ■ P ⊢ P
end Iris.BI

namespace Iris.BI
theorem persistently_elim_plainly : <pers> ■ P ⊣⊢ ■ P
end Iris.BI

namespace Iris.BI
theorem plainly_forall_2 {Ψ : α → PROP} : (∀ a, ■ (Ψ a)) ⊢ ■ (∀ a, Ψ a)
end Iris.BI

namespace Iris.BI
theorem plainly_persistently_elim : ■ <pers> P ⊣⊢ ■ P
end Iris.BI

namespace Iris.BI
theorem absorbingly_elim_plainly : <absorb> ■ P ⊣⊢ ■ P
end Iris.BI

namespace Iris.BI
theorem plainly_and_sep_elim : ■ P ∧ Q ⊢ (emp ∧ P) ∗ Q
end Iris.BI

namespace Iris.BI
theorem plainly_and_sep_assoc : ■ P ∧ (Q ∗ R) ⊣⊢ (■ P ∧ Q) ∗ R
end Iris.BI

namespace Iris.BI
theorem plainly_and_emp_elim : emp ∧ ■ P ⊢ P
end Iris.BI

namespace Iris.BI
theorem plainly_into_absorbingly : ■ P ⊢ <absorb> P
end Iris.BI

namespace Iris.BI
theorem plainly_elim [Absorbing P] : ■ P ⊢ P
end Iris.BI

namespace Iris.BI
theorem plainly_idemp : ■ ■ P ⊣⊢ ■ P
end Iris.BI

namespace Iris.BI
theorem plainly_intro' (H : ■ P ⊢ Q) : ■ P ⊢ ■ Q
end Iris.BI

namespace Iris.BI
theorem plainly_pure {φ} : ■ ⌜φ⌝ ⊣⊢ (⌜φ⌝ : PROP)
end Iris.BI

namespace Iris.BI
theorem plainly_forall {Ψ : α → PROP} : ■ (∀ a, Ψ a) ⊣⊢ ∀ a, ■ (Ψ a)
end Iris.BI

namespace Iris.BI
theorem plainly_exists_2 {α : Sort _} {Ψ : α → PROP} : (∃ a, ■ (Ψ a)) ⊢ ■ (∃ a, Ψ a)
end Iris.BI

namespace Iris.BI
theorem plainly_exists_1 [BIPlainlyExists PROP] {Ψ : α → PROP} :
    ■ (∃ a, Ψ a) ⊢ ∃ a, ■ (Ψ a)
end Iris.BI

namespace Iris.BI
theorem plainly_exists [BIPlainlyExists PROP] {Ψ : α → PROP} : ■ (∃ a, Ψ a) ⊣⊢ ∃ a, ■ (Ψ a)
end Iris.BI

namespace Iris.BI
theorem plainly_and : ■ (P ∧ Q) ⊣⊢ ■ P ∧ ■ Q
end Iris.BI

namespace Iris.BI
theorem plainly_or_2 : ■ P ∨ ■ Q ⊢ ■ (P ∨ Q)
end Iris.BI

namespace Iris.BI
theorem plainly_or [BIPlainlyExists PROP] : ■ (P ∨ Q) ⊣⊢ ■ P ∨ ■ Q
end Iris.BI

namespace Iris.BI
theorem plainly_impl : ■ (P → Q) ⊢ ■ P → ■ Q
end Iris.BI

namespace Iris.BI
theorem plainly_emp_2 : (emp : PROP) ⊢ ■ emp
end Iris.BI

namespace Iris.BI
theorem plainly_sep_dup : ■ P ⊣⊢ ■ P ∗ ■ P
end Iris.BI

namespace Iris.BI
theorem plainly_and_sep_l_1 : ■ P ∧ Q ⊢ ■ P ∗ Q
end Iris.BI

namespace Iris.BI
theorem plainly_and_sep_r_1 : P ∧ ■ Q ⊢ P ∗ ■ Q
end Iris.BI

namespace Iris.BI
theorem plainly_true_emp : ■ True ⊣⊢ ■ (emp : PROP)
end Iris.BI

namespace Iris.BI
theorem plainly_and_sep : ■ (P ∧ Q) ⊢ ■ (P ∗ Q)
end Iris.BI

namespace Iris.BI
theorem plainly_affinely_elim : ■ <affine> P ⊣⊢ ■ P
end Iris.BI

namespace Iris.BI
theorem intuitionistically_plainly_elim : □ ■ P ⊢ □ P
end Iris.BI

namespace Iris.BI
theorem intuitionistically_plainly : □ ■ P ⊢ ■ □ P
end Iris.BI

namespace Iris.BI
theorem and_sep_plainly : ■ P ∧ ■ Q ⊣⊢ ■ P ∗ ■ Q
end Iris.BI

namespace Iris.BI
theorem plainly_sep_2 : ■ P ∗ ■ Q ⊢ ■ (P ∗ Q)
end Iris.BI

namespace Iris.BI
theorem plainly_sep [BIPositive PROP] : ■ (P ∗ Q) ⊣⊢ ■ P ∗ ■ Q
end Iris.BI

namespace Iris.BI
theorem plainly_wand : ■ (P -∗ Q) ⊢ ■ P -∗ ■ Q
end Iris.BI

namespace Iris.BI
theorem plainly_entails_l (H : P ⊢ ■ Q) : P ⊢ ■ Q ∗ P
end Iris.BI

namespace Iris.BI
theorem plainly_entails_r (H : P ⊢ ■ Q) : P ⊢ P ∗ ■ Q
end Iris.BI

namespace Iris.BI
theorem plainly_impl_wand_2 : ■ (P -∗ Q) ⊢ ■ (P → Q)
end Iris.BI

namespace Iris.BI
theorem impl_wand_plainly_2 : (■ P -∗ Q) ⊢ (■ P → Q)
end Iris.BI

namespace Iris.BI
theorem impl_wand_affinely_plainly : (■ P → Q) ⊣⊢ (<affine> ■ P -∗ Q)
end Iris.BI

namespace Iris.BI
theorem persistently_wand_affinely_plainly [BIPersistentlyImplPlainly PROP] :
    (<affine> ■ P -∗ <pers> Q) ⊢ <pers> (<affine> ■ P -∗ Q)
end Iris.BI

namespace Iris.BI
theorem plainly_wand_affinely_plainly : (<affine> ■ P -∗ ■ Q) ⊢ ■ (<affine> ■ P -∗ Q)
end Iris.BI

namespace Iris.BI
theorem plainly_emp : ■ emp ⊣⊢ (emp : PROP)
end Iris.BI

namespace Iris.BI
theorem plainly_and_sep_l : ■ P ∧ Q ⊣⊢ ■ P ∗ Q
end Iris.BI

namespace Iris.BI
theorem plainly_and_sep_r : P ∧ ■ Q ⊣⊢ P ∗ ■ Q
end Iris.BI

namespace Iris.BI
theorem plainly_impl_wand : ■ (P → Q) ⊣⊢ ■ (P -∗ Q)
end Iris.BI

namespace Iris.BI
theorem impl_wand_plainly : (■ P → Q) ⊣⊢ (■ P -∗ Q)
end Iris.BI

namespace Iris.ProofMode
theorem from_and_intro [BI PROP] {P Q A1 A2 : PROP} [inst : FromAnd Q A1 A2]
    (h1 : P ⊢ A1) (h2 : P ⊢ A2) : P ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem split_es [BI PROP] {Q Q1 Q2 : PROP} (h : Q ⊣⊢ Q1 ∗ Q2) : emp ∗ Q ⊣⊢ Q1 ∗ Q2
end Iris.ProofMode

namespace Iris.ProofMode
theorem split_ls [BI PROP] {P Q Q1 Q2 : PROP} (h : Q ⊣⊢ Q1 ∗ Q2) : P ∗ Q ⊣⊢ (P ∗ Q1) ∗ Q2
end Iris.ProofMode

namespace Iris.ProofMode
theorem split_rs [BI PROP] {P Q Q1 Q2 : PROP} (h : Q ⊣⊢ Q1 ∗ Q2) : P ∗ Q ⊣⊢ Q1 ∗ (P ∗ Q2)
end Iris.ProofMode

namespace Iris.ProofMode
theorem split_se [BI PROP] {P P1 P2 : PROP} (h : P ⊣⊢ P1 ∗ P2) : P ∗ emp ⊣⊢ P1 ∗ P2
end Iris.ProofMode

namespace Iris.ProofMode
theorem split_sl [BI PROP] {P Q P1 P2 : PROP} (h : P ⊣⊢ P1 ∗ P2) : P ∗ Q ⊣⊢ (P1 ∗ Q) ∗ P2
end Iris.ProofMode

namespace Iris.ProofMode
theorem split_sr [BI PROP] {P Q P1 P2 : PROP} (h : P ⊣⊢ P1 ∗ P2) : P ∗ Q ⊣⊢ P1 ∗ (P2 ∗ Q)
end Iris.ProofMode

namespace Iris.ProofMode
theorem split_ss [BI PROP] {P Q P1 P2 Q1 Q2 : PROP}
    (h1 : P ⊣⊢ P1 ∗ P2) (h2 : Q ⊣⊢ Q1 ∗ Q2) : P ∗ Q ⊣⊢ (P1 ∗ Q1) ∗ (P2 ∗ Q2)
end Iris.ProofMode

namespace Iris.ProofMode
theorem sep_split [BI PROP] {P P1 P2 Q Q1 Q2 : PROP} [inst : FromSep Q Q1 Q2]
    (h : P ⊣⊢ P1 ∗ P2) (h1 : P1 ⊢ Q1) (h2 : P2 ⊢ Q2) : P ⊢ Q
end Iris.ProofMode

theorem Store.get_set [Store T K V] {t : T} {k k' : K} {v : V} :
    get (set t k v) k' = if k = k' then v else get t k'

theorem IsoFunStore.ext [Store T K V] [IsoFunStore T K V] {t1 t2 : T}
    (H : ∀ k, get t1 k = get t2 k) : t1 = t2

theorem IsoFunStore.store_eq_of_Equiv [Store T K V] [IsoFunStore T K V] {t1 t2 : T}
    (H : Store.Equiv t1 t2) : t1 = t2

theorem hmap_alloc [Heap T K V] {t : T} (H : get t k = some v) : get (hmap f t) k = f k v

theorem hmap_unalloc [Heap T K V] {t : T} (H : get t k = none) : get (hmap f t) k = none

theorem Heap.point_get_eq [Heap T K V] (H : k = k') : get (point k v : T) k' = v

theorem Heap.point_get_ne [Heap T K V] (H : k ≠ k') : get (point k v : T) k' = none

theorem Heap.get_point [Heap T K V] {k k' : K} {v : Option V} :
    get (point k v : T) k' = if k = k' then v else .none

namespace Iris.ProofMode
theorem pure_elim_spatial [BI PROP] {P P' A Q : PROP} {φ : Prop}
    [hA : IntoPure A φ] [or : TCOr (Affine A) (Absorbing Q)]
    (h : P ⊣⊢ P' ∗ A) (h_entails : φ → P' ⊢ Q) : P ⊢ Q :=
  h.1.trans <| match or with
end Iris.ProofMode

namespace Iris.ProofMode
theorem pure_elim_intuitionistic [BI PROP] {P P' A Q : PROP} {φ : Prop}
    [IntoPure A φ] (h : P ⊣⊢ P' ∗ □ A) (h' : φ → P' ⊢ Q) : P ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem pure_intro_affine [BI PROP] {Q : PROP} {φ : Prop}
    [h : FromPure true Q φ] [Affine P] (hφ : φ) : P ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem pure_intro_spatial [BI PROP] {Q : PROP} {φ : Prop}
    [h : FromPure false Q φ] (hφ : φ) : P ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem from_or_l [BI PROP] {P Q A1 A2 : PROP} [inst : FromOr Q A1 A2]
    (h1 : P ⊢ A1) : P ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem from_or_r [BI PROP] {P Q A1 A2 : PROP} [inst : FromOr Q A1 A2]
    (h1 : P ⊢ A2) : P ⊢ Q
end Iris.ProofMode

namespace Iris
theorem Excl.dist_eqv [OFE α] {n} : Equivalence (Excl.Dist (α := α) n)
end Iris

namespace Iris
theorem excl_included [OFE α] {x y : Excl α} : x ≼ y ↔ y = invalid
end Iris

namespace Iris
theorem excl_includedN [OFE α] {x y : Excl α} (n) : x ≼{n} y ↔ y = invalid
end Iris

namespace Iris
theorem invalid_included [OFE α] (ea : Excl α) : ea ≼ invalid
end Iris

namespace Iris
theorem excl_map_id : map id x = x
end Iris

namespace Iris
theorem excl_map_compose (f : α → β) (g : β → γ) :
    map (g ∘ f) x = map g (map f x)
end Iris

namespace Iris
theorem excl_map_ext [OFE α] [OFE β] (f g : α → β) (h : ∀ x, f x ≡ g x) : map f x ≡ map g x
end Iris

namespace Iris
theorem excl_map_ne [OFE α] [OFE β] (f : α -n> β) : NonExpansive (map f)
end Iris

namespace UPred
theorem uPred_entails_lim {cP cQ : Chain (UPred M)} (H : ∀ n, cP n ⊢ cQ n) :
    IsCOFE.compl cP ⊢ IsCOFE.compl cQ
end UPred

namespace UPred
theorem ownM_valid (m : M) : ownM m ⊢ cmraValid m
end UPred

namespace UPred
theorem ownM_op (m1 m2 : M) : ownM (m1 • m2) ⊣⊢ ownM m1 ∗ ownM m2
end UPred

namespace UPred
theorem ownM_always_invalid_elim (m : M) (H : ∀ n, ¬✓{n} m) : (cmraValid m : UPred M) ⊢ False
end UPred

namespace UPred
theorem intuitionistically_ownM_core (m : M) : ownM m ⊢ □ ownM (CMRA.core m)
end UPred

namespace UPred
theorem ownM_unit P : P ⊢ □ ownM (CMRA.unit : M)
end UPred

namespace UPred
theorem cmra_valid_intro P [CMRA A] (a : A) : ✓ a → P ⊢ (cmraValid a : UPred M)
end UPred

namespace UPred
theorem cmra_valid_elim [CMRA A] (a : A) : (cmraValid a : UPred M) ⊢ ⌜ ✓{0} a ⌝
end UPred

namespace UPred
theorem cmra_valid_weaken [CMRA A] (a b : A) : (cmraValid (a • b) : UPred M) ⊢ cmraValid a
end UPred

namespace UPred
theorem valid_entails [CMRA A] [CMRA B] {a : A} {b : B} (Himp : ∀ n, ✓{n} a → ✓{n} b) :
    (cmraValid a : UPred M) ⊢ cmraValid b
end UPred

namespace UPred
theorem pure_soundness : iprop(True ⊢ (⌜P⌝ : UPred M)) → P
end UPred

namespace UPred
theorem later_soundness : iprop(True ⊢ ▷ P) → iprop((True : UPred M) ⊢ P)
end UPred

namespace UPred
theorem persistently_ownM_core (a : M) : ownM a ⊢ <pers> ownM (CMRA.core a)
end UPred

namespace UPred
theorem bupd_ownM_updateP (x : M) (Φ : M → Prop) :
  (x ~~>: Φ) → ownM x ⊢ |==> ∃ y, ⌜Φ y⌝ ∧ ownM y
end UPred

namespace UPred
theorem cmraValid_intro [CMRA A] {P : UPred M} (a : A) (Ha : ✓ a) : P ⊢ cmraValid a
end UPred

namespace UPred
theorem cmraValid_elim [CMRA A] (a : A) : (cmraValid a : UPred M) ⊢ iprop(⌜ ✓{0} a ⌝)
end UPred

namespace UPred
theorem plainly_cmra_cmraValid_1 [CMRA A] (a : A) :
    (cmraValid a : UPred M) ⊢ ■ cmraValid a
end UPred

namespace UPred
theorem cmra_cmraValid_weaken [CMRA A] (a b : A) :
    (cmraValid (a • b) : UPred M) ⊢ cmraValid a
end UPred

namespace UPred
theorem cmraValid_entails [CMRA A] [CMRA B] {a : A} {b : B} (Hv : ∀ n, ✓{n} a → ✓{n} b) :
    (cmraValid a : UPred M) ⊢ cmraValid b
end UPred

namespace Iris.ProofMode
theorem false_elim_spatial [BI PROP] {P Q : PROP} : P ∗ False ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem false_elim_intuitionistic [BI PROP] {P Q : PROP} : P ∗ □ False ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem sep_emp_intro_spatial [BI PROP] {P Q : PROP} (h : P ⊢ Q) : P ∗ emp ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem sep_emp_intro_intuitionistic [BI PROP] {P Q : PROP}
    (h : P ⊢ Q) : P ∗ □ emp ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem exists_elim_spatial [BI PROP] {P A Q : PROP} {Φ : α → PROP} [inst : IntoExists A Φ]
    (h : ∀ a, P ∗ Φ a ⊢ Q) : P ∗ A ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem exists_elim_intuitionistic [BI PROP] {P A Q : PROP} {Φ : α → PROP} [IntoExists A Φ]
    (h : ∀ a, P ∗ □ Φ a ⊢ Q) : P ∗ □ A ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem sep_and_elim_l [BI PROP] {P A Q A1 A2 : PROP} [inst : IntoAnd p A A1 A2]
    (h : P ∗ □?p A1 ⊢ Q) : P ∗ □?p A ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem and_elim_l_spatial [BI PROP] {P A Q A1 A2 : PROP} [IntoAnd false A A1 A2]
    (h : P ∗ A1 ⊢ Q) : P ∗ A ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem and_elim_l_intuitionistic [BI PROP] {P A Q A1 A2 : PROP} [IntoAnd true A A1 A2]
    (h : P ∗ □ A1 ⊢ Q) : P ∗ □ A ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem sep_and_elim_r [BI PROP] {P A Q A1 A2 : PROP} [inst : IntoAnd p A A1 A2]
    (h : P ∗ □?p A2 ⊢ Q) : P ∗ □?p A ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem and_elim_r_spatial [BI PROP] {P A Q A1 A2 : PROP} [IntoAnd false A A1 A2]
    (h : P ∗ A2 ⊢ Q) : P ∗ A ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem and_elim_r_intuitionistic [BI PROP] {P A Q A1 A2 : PROP} [IntoAnd true A A1 A2]
    (h : P ∗ □ A2 ⊢ Q) : P ∗ □ A ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem sep_elim_spatial [BI PROP] {P A Q A1 A2 : PROP} [inst : IntoSep A A1 A2]
    (h : P ∗ A1 ⊢ A2 -∗ Q) : P ∗ A ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem and_elim_intuitionistic [BI PROP] {P A Q A1 A2 : PROP} [inst : IntoAnd true A A1 A2]
    (h : P ∗ □ A1 ⊢ □ A2 -∗ Q) : P ∗ □ A ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem or_elim_spatial [BI PROP] {P A Q A1 A2 : PROP} [inst : IntoOr A A1 A2]
    (h1 : P ∗ A1 ⊢ Q) (h2 : P ∗ A2 ⊢ Q) : P ∗ A ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem or_elim_intuitionistic [BI PROP] {P A Q A1 A2 : PROP} [IntoOr A A1 A2]
    (h1 : P ∗ □ A1 ⊢ Q) (h2 : P ∗ □ A2 ⊢ Q) : P ∗ □ A ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem intuitionistic_elim_spatial [BI PROP] {A A' Q : PROP}
    [IntoPersistently false A A'] [TCOr (Affine A) (Absorbing Q)]
    (h : P ∗ □ A' ⊢ Q) : P ∗ A ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem intuitionistic_elim_intuitionistic [BI PROP] {A A' Q : PROP} [IntoPersistently true A A']
    (h : P ∗ □ A' ⊢ Q) : P ∗ □ A ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem spatial_elim_spatial [BI PROP] {A A' Q : PROP} [FromAffinely A' A false]
    (h : P ∗ A' ⊢ Q) : P ∗ A ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem spatial_elim_intuitionistic [BI PROP] {A A' Q : PROP} [FromAffinely A' A true]
    (h : P ∗ A' ⊢ Q) : P ∗ □ A ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem of_emp_sep [BI PROP] {A Q : PROP} (h : A ⊢ Q) : emp ∗ A ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem apply [BI PROP] {P Q1 Q2 R : PROP}
    (h : P ⊢ Q1) [inst : IntoWand false false R Q1 Q2] : P ∗ R ⊢ Q2
end Iris.ProofMode

namespace Iris.ProofMode
theorem rec_apply [BI PROP] {P Q P' Q' Q1 Q2 R : PROP}
    (h1 : P ⊣⊢ P' ∗ Q') (h2 : Q' ⊢ Q1) (h3 : P' ∗ Q2 ⊢ R)
    [IntoWand false false Q Q1 Q2] : P ∗ Q ⊢ R
end Iris.ProofMode

namespace Iris.ProofMode
theorem apply_lean [BI PROP] {P Q R : PROP} (h1 : ⊢ Q) (h2 : P ∗ Q ⊢ R) : P ⊢ R
end Iris.ProofMode

namespace Iris.ProofMode
theorem apply_forall [BI PROP] (x : α) (P : α → PROP) {Q : PROP}
    [H1 : IntoForall Q P] (H2 : E ⊢ E' ∗ Q) : E ⊢ E' ∗ P x
end Iris.ProofMode

namespace Iris
theorem mem_of_agree (x : Agree α) : ∃ a, a ∈ x.car
end Iris

namespace Iris
theorem Agree.dist_equiv : Equivalence (dist (α := α) n)
end Iris

namespace Iris
theorem Agree.equiv_def {x y : Agree α} : x ≡ y ↔ ∀ n, Agree.dist n x y
end Iris

namespace Iris
theorem Agree.dist_def {x y : Agree α} : x ≡{n}≡ y ↔ Agree.dist n x y
end Iris

namespace Iris
theorem Agree.validN_iff {x : Agree α} :
    x.validN n ↔ ∀ a ∈ x.car, ∀ b ∈ x.car, a ≡{n}≡ b
end Iris

namespace Iris
theorem Agree.op_comm {x y : Agree α} :  x.op y ≡ y.op x
end Iris

namespace Iris
theorem Agree.op_commN {x y : Agree α} :  x.op y ≡{n}≡ y.op x
end Iris

namespace Iris
theorem Agree.op_assoc {x y z : Agree α} :  x.op (y.op z) ≡ (x.op y).op z
end Iris

namespace Iris
theorem Agree.idemp {x : Agree α} : x.op x ≡ x
end Iris

namespace Iris
theorem Agree.validN_ne {x y : Agree α} : x ≡{n}≡ y → x.validN n → y.validN n
end Iris

namespace Iris
theorem Agree.op_ne {x : Agree α} : OFE.NonExpansive x.op
end Iris

namespace Iris
theorem Agree.op_ne₂ : OFE.NonExpansive₂ (Agree.op (α := α))
end Iris

namespace Iris
theorem Agree.op_invN {x y : Agree α} : (x.op y).validN n → x ≡{n}≡ y
end Iris

namespace Iris
theorem Agree.op_inv {x y : Agree α} : (x.op y).valid → x ≡ y
end Iris

namespace Iris
theorem Agree.op_def {x y : Agree α} : x • y = x.op y
end Iris

namespace Iris
theorem Agree.validN_def {x : Agree α} : ✓{n} x ↔ x.validN n
end Iris

namespace Iris
theorem Agree.valid_def {x : Agree α} : ✓ x ↔ x.valid
end Iris

namespace Iris
theorem Agree.toAgree_injN {a b : α} : toAgree a ≡{n}≡ toAgree b → a ≡{n}≡ b
end Iris

namespace Iris
theorem Agree.toAgree_inj {a b : α} : toAgree a ≡ toAgree b → a ≡ b
end Iris

namespace Iris
theorem Agree.toAgree_uninjN {x : Agree α} : ✓{n} x → ∃ a, toAgree a ≡{n}≡ x
end Iris

namespace Iris
theorem Agree.toAgree_uninj {x : Agree α} : ✓ x → ∃ a, toAgree a ≡ x
end Iris

namespace Iris
theorem Agree.includedN {x y : Agree α} : x ≼{n} y ↔ y ≡{n}≡ y • x
end Iris

namespace Iris
theorem Agree.included {x y : Agree α} : x ≼ y ↔ y ≡ y • x
end Iris

namespace Iris
theorem Agree.valid_includedN {x y : Agree α} : ✓{n} y → x ≼{n} y → x ≡{n}≡ y
end Iris

namespace Iris
theorem Agree.valid_included {x y : Agree α} : ✓ y → x ≼ y → x ≡ y
end Iris

namespace Iris
@[simp]
theorem Agree.toAgree_includedN {a b : α} : toAgree a ≼{n} toAgree b ↔ a ≡{n}≡ b
end Iris

namespace Iris
@[simp]
theorem Agree.toAgree_included {a b : α} : toAgree a ≼ toAgree b ↔ a ≡ b
end Iris

namespace Iris
@[simp]
theorem Agree.toAgree_included_L [OFE.Leibniz α] {a b : α} :
    toAgree a ≼ toAgree b ↔ a = b
end Iris

namespace Iris
theorem Agree.toAgree_op_validN_iff_dist {a b : α} :
    ✓{n} (toAgree a • toAgree b) ↔ a ≡{n}≡ b
end Iris

namespace Iris
theorem Agree.toAgree_op_valid_iff_equiv {a : α} : ✓ (toAgree a • toAgree b) ↔ a ≡ b
end Iris

namespace Iris
theorem toAgree_op_valid_iff_eq [OFE.Leibniz α] {a : α} :
    ✓ (toAgree a • toAgree b) ↔ a = b
end Iris

namespace Iris
theorem Agree.agree_map_ext {g : α → β} [OFE.NonExpansive g] (heq : ∀ a, f a ≡ g a) :
    map f x ≡ map g x
end Iris

namespace Iris.ProofMode
theorem pose [BI PROP] {P Q R : PROP}
    (H1 : P ∗ Q ⊢ R) (H2 : ⊢ Q) : P ⊢ R
end Iris.ProofMode

namespace Iris.ProofMode
theorem pose_forall [BI PROP] (x : α) (P : α → PROP) {Q : PROP}
    [H1 : IntoForall Q P] (H2 : ⊢ Q) : ⊢ P x
end Iris.ProofMode

namespace Iris
theorem UpdateP.equiv_left {P : α → Prop} {x y : α} (e : x ≡ y) (u : x ~~>: P) : y ~~>: P
end Iris

namespace Iris
theorem Update.equiv_left {x y z : α} (e : x ≡ y) (u : x ~~> z) : y ~~> z
end Iris

namespace Iris
theorem Update.equiv_right {x y z : α} (e : y ≡ z) (u : x ~~> y) : x ~~> z
end Iris

namespace Iris
theorem Update.of_updateP {x y : α} (h : x ~~>: (y = ·)) : x ~~> y
end Iris

namespace Iris
theorem UpdateP.of_update {x y : α} (h : x ~~> y) : x ~~>: (y = ·)
end Iris

namespace Iris
theorem UpdateP.id {P : α → Prop} {x} (h : P x) : x ~~>: P
end Iris

namespace Iris
theorem Update.id {x : α} : x ~~> x
end Iris

namespace Iris
theorem Update.trans {x y z : α} (uxy : x ~~> y) (uyz : y ~~> z) : x ~~> z
end Iris

namespace Iris
theorem UpdateP.trans {x : α} (ux : x ~~>: P) (upq : ∀ y, P y → y ~~>: Q) : x ~~>: Q
end Iris

namespace Iris
theorem Update.transP {x y : α} (uxy : x ~~> y) (uyq : y ~~>: Q) : x ~~>: Q
end Iris

namespace Iris
theorem UpdateP.weaken {x : α} (uxp : x ~~>: P) (pq : ∀ y, P y → Q y) : x ~~>: Q
end Iris

namespace Iris
theorem Update.exclusive {x y : α} [CMRA.Exclusive x] (vy : ✓ y) : x ~~> y
end Iris

namespace Iris
theorem UpdateP.op {P Q R : α → Prop} {x y}
    (uxp : x ~~>: P) (uyq : y ~~>: Q) (pqr : ∀z w, P z → Q w → R (z • w)) : x • y ~~>: R
end Iris

namespace Iris
theorem UpdateP.op' {P Q : α → Prop} {x y : α} (uxp : x ~~>: P) (uyq : y ~~>: Q) :
    (x • y : α) ~~>: λ t ↦ ∃ z w, t = (z • w : α) ∧ P z ∧ Q w
end Iris

namespace Iris
theorem Update.op {x₁ x₂ y₁ y₂ : α} (xy₁ : x₁ ~~> y₁) (xy₂ : x₂ ~~> y₂) : x₁ • x₂ ~~> y₁ • y₂
end Iris

namespace Iris
theorem Update.op_l {x y : α} : x • y ~~> x
end Iris

namespace Iris
theorem Update.op_r {x y : α} : x • y ~~> y
end Iris

namespace Iris
theorem Update.included {x y : α} : x ≼ y → y ~~> x
end Iris

namespace Iris
theorem Update.valid0 {x y : α} : (✓{0} x → x ~~> y) → x ~~> y
end Iris

namespace Iris
theorem UpdateP.total [CMRA.IsTotal α] :
    x ~~>: P ↔ ∀ (n : Nat) (z : α), ✓{n} (x • z) → ∃ y, P y ∧ ✓{n} (y • z)
end Iris

namespace Iris
theorem Update.total [CMRA.IsTotal α] :
    x ~~> y ↔ ∀ (n : Nat) (z : α), ✓{n} (x • z) → ✓{n} (y • z)
end Iris

namespace Iris
theorem UpdateP.discrete [CMRA.Discrete α] :
    x ~~>: P ↔ ∀ (mz : Option α), ✓ (x •? mz) → ∃ y, P y ∧ ✓ (y •? mz)
end Iris

namespace Iris
theorem Update.discrete [CMRA.Discrete α] {x y : α} :
    x ~~> y ↔ ∀ (mz : Option α), ✓ (x •? mz) → ✓ (y •? mz)
end Iris

namespace Iris
theorem UpdateP.discrete_total [CMRA.Discrete α] [CMRA.IsTotal α] :
    x ~~>: P ↔ ∀ (z : α), ✓ (x • z) → ∃ y, P y ∧ ✓ (y • z)
end Iris

namespace Iris
theorem Update.discrete_total [CMRA.Discrete α] [CMRA.IsTotal α] :
    x ~~> y ↔ ∀ (z : α), ✓ (x • z) → ✓ (y • z)
end Iris

namespace Iris
theorem UpdateP.iso
    (gf : ∀ x, g (f x) ≡ x)
    (g_op : ∀ y1 y2, g (y1 • y2) ≡ g y1 • g y2)
    (g_validN : ∀ n y, ✓{n} (g y) ↔ ✓{n} y)
    (uyp : y ~~>: P)
    (pq : ∀ y', P y' → Q (g y')) :
    g y ~~>: Q
end Iris

namespace Iris
theorem UpdateP.iso'
    (gf : ∀ x, g (f x) ≡ x)
    (g_op : ∀ y1 y2, g (y1 • y2) ≡ g y1 • g y2)
    (g_validN : ∀ n y, ✓{n} (g y) ↔ ✓{n} y)
    (uyp : y ~~>: P) :
    g y ~~>: λ x ↦ ∃ y, x = g y ∧ P y
end Iris

namespace Iris
theorem Update.lift_updateP (x y : β)
    (H : ∀ P, x ~~>: P → g x ~~>: λ a' ↦ ∃ b', a' = g b' ∧ P b')
    (uxy : x ~~> y) : g x ~~> g y
end Iris

namespace Iris
theorem UpdateP.prod {P : α → Prop} {Q : β → Prop} {R : α × β → Prop} {x : α × β}
    (uxp : x.fst ~~>: P) (uxq : x.snd ~~>: Q) (pq : ∀ a b, P a → Q b → R (a, b)) :
    x ~~>: R
end Iris

namespace Iris
theorem UpdateP.prod' (P : α → Prop) (Q : β → Prop) (x : α × β)
    (uxp : x.fst ~~>: P) (uxq : x.snd ~~>: Q) : x ~~>: λ y ↦ P (y.fst) ∧ Q (y.snd)
end Iris

namespace Iris
theorem Update.prod (x : α × β) (uxy₁ : x.fst ~~> y.fst) (uxy₂ : x.snd ~~> y.snd) : x ~~> y
end Iris

namespace Iris
theorem UpdateP.option {P : α → Prop} {Q : Option α → Prop} {x : α}
    (uxp : x ~~>: P) (pq : ∀ y, P y → Q (some y)) : some x ~~>: Q
end Iris

namespace Iris
theorem UpdateP.option' (P : α → Prop) (x : α) (uxp : x ~~>: P) : some x ~~>: Option.rec False P
end Iris

namespace Iris
theorem Update.option (x y : α) (uxy : x ~~> y) : some x ~~> some y
end Iris

namespace Iris.ProofMode
theorem imp_intro_drop [BI PROP] {P Q A1 A2 : PROP} [inst : FromImp Q A1 A2] (h : P ⊢ A2) : P ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem from_forall_intro [BI PROP] {P Q : PROP} {Φ : α → PROP} [inst : FromForall Q Φ]
    (h : ∀ a, P ⊢ Φ a) : P ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem imp_intro_intuitionistic [BI PROP] {P Q A1 A2 B : PROP}
    [FromImp Q A1 A2] [inst : IntoPersistently false A1 B] (h : P ∗ □ B ⊢ A2) : P ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem wand_intro_intuitionistic [BI PROP] {P Q A1 A2 B : PROP}
    [FromWand Q A1 A2] [inst : IntoPersistently false A1 B] [or : TCOr (Affine A1) (Absorbing A2)]
    (h : P ∗ □ B ⊢ A2) : P ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem imp_intro_spatial [BI PROP] {P Q A1 A2 B : PROP}
    [FromImp Q A1 A2] [inst : FromAffinely B A1] [or : TCOr (Persistent A1) (Intuitionistic P)]
    (h : P ∗ B ⊢ A2) : P ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem wand_intro_spatial [BI PROP] {P Q A1 A2 : PROP}
    [FromWand Q A1 A2] (h : P ∗ A1 ⊢ A2) : P ⊢ Q
end Iris.ProofMode

namespace Iris.Tests
theorem start_stop [BI PROP] (Q : PROP) (H : Q ⊢ Q) : Q ⊢ Q
end Iris.Tests

namespace Iris.Tests.rename
theorem rename [BI PROP] (Q : PROP) : Q ⊢ Q
end Iris.Tests.rename

namespace Iris.Tests.rename
theorem rename_by_type [BI PROP] (Q : PROP) : □ P ∗ Q ⊢ Q
end Iris.Tests.rename

namespace Iris.Tests.rename
theorem rename_twice [BI PROP] (Q : PROP) : Q ⊢ Q
end Iris.Tests.rename

namespace Iris.Tests.rename
theorem rename_id [BI PROP] (Q : PROP) : Q ⊢ Q
end Iris.Tests.rename

namespace Iris.Tests.clear
theorem intuitionistic [BI PROP] (Q : PROP) : □ P ⊢ Q -∗ Q
end Iris.Tests.clear

namespace Iris.Tests.clear
theorem spatial [BI PROP] (Q : PROP) : <affine> P ⊢ Q -∗ Q
end Iris.Tests.clear

namespace Iris.Tests.intro
theorem spatial [BI PROP] (Q : PROP) : Q ⊢ Q
end Iris.Tests.intro

namespace Iris.Tests.intro
theorem intuitionistic [BI PROP] (Q : PROP) : □ Q ⊢ Q
end Iris.Tests.intro

namespace Iris.Tests.intro
theorem as_intuitionistic [BI PROP] (Q : PROP) : <affine> <pers> Q ⊢ Q
end Iris.Tests.intro

namespace Iris.Tests.intro
theorem as_intuitionistic_in_spatial [BI PROP] (Q : PROP) : ⊢ <pers> Q → Q
end Iris.Tests.intro

namespace Iris.Tests.intro
theorem drop [BI PROP] (Q : PROP) : ⊢ P → Q -∗ Q
end Iris.Tests.intro

namespace Iris.Tests.intro
theorem drop_after [BI PROP] (Q : PROP) : ⊢ Q -∗ P → Q
end Iris.Tests.intro

namespace Iris.Tests.intro
theorem «forall» [BI PROP] : ⊢ ∀ x, ⌜x = 0⌝ → (⌜x = 0⌝ : PROP)
end Iris.Tests.intro

namespace Iris.Tests.intro
theorem pure [BI PROP] [BIAffine PROP] (Q : PROP) : ⊢ ⌜φ⌝ -∗ Q -∗ Q
end Iris.Tests.intro

namespace Iris.Tests.intro
theorem pattern [BI PROP] (Q : PROP) : □ (P1 ∨ P2) ∗ Q ⊢ Q
end Iris.Tests.intro

namespace Iris.Tests.intro
theorem multiple_spatial [BI PROP] (Q : PROP) : ⊢ <affine> P -∗ Q -∗ Q
end Iris.Tests.intro

namespace Iris.Tests.intro
theorem multiple_intuitionistic [BI PROP] (Q : PROP) : ⊢ □ P -∗ □ Q -∗ Q
end Iris.Tests.intro

namespace Iris.Tests.intro
theorem multiple_patterns [BI PROP] (Q : PROP) : ⊢ □ (P1 ∧ P2) -∗ Q ∨ Q -∗ Q
end Iris.Tests.intro

namespace Iris.Tests
theorem id [BI PROP] : ⊢ (∃ x, x : PROP)
end Iris.Tests

namespace Iris.Tests
theorem f [BI PROP] : ⊢ (∃ (_x : Nat), True ∨ False : PROP)
end Iris.Tests

namespace Iris.Tests
theorem pure [BI PROP] : ⊢ (⌜∃ x, x ∨ False⌝ : PROP)
end Iris.Tests

namespace Iris.Tests.exact
theorem exact [BI PROP] (Q : PROP) : Q ⊢ Q
end Iris.Tests.exact

namespace Iris.Tests.exact
theorem def_eq [BI PROP] (Q : PROP) : <affine> <pers> Q ⊢ □ Q
end Iris.Tests.exact

namespace Iris.Tests.exact
theorem intuitionistic [BI PROP] (Q : PROP) : □ Q ⊢ Q
end Iris.Tests.exact

namespace Iris.Tests.assumption
theorem exact [BI PROP] (Q : PROP) : Q ⊢ Q
end Iris.Tests.assumption

namespace Iris.Tests.assumption
theorem from_assumption [BI PROP] (Q : PROP) : <affine> <pers> Q ⊢ □ Q
end Iris.Tests.assumption

namespace Iris.Tests.assumption
theorem intuitionistic [BI PROP] (Q : PROP) : □ Q ⊢ Q
end Iris.Tests.assumption

namespace Iris.Tests.assumption
theorem lean [BI PROP] (Q : PROP) (H : ⊢ Q) : <affine> P ⊢ Q
end Iris.Tests.assumption

namespace Iris.Tests.assumption
theorem lean_pure [BI PROP] (Q : PROP) : <affine> ⌜⊢ Q⌝ ⊢ Q
end Iris.Tests.assumption

namespace Iris.Tests.apply
theorem exact [BI PROP] (Q : PROP) : Q ⊢ Q
end Iris.Tests.apply

namespace Iris.Tests.apply
theorem apply [BI PROP] (P Q : PROP) : ⊢ P -∗ (P -∗ Q) -∗ Q
end Iris.Tests.apply

namespace Iris.Tests.apply
theorem multiple [BI PROP] (P Q R : PROP) : ⊢ P -∗ Q -∗ (P -∗ Q -∗ R) -∗ R
end Iris.Tests.apply

namespace Iris.Tests.apply
theorem multiple' [BI PROP] (P Q R S : PROP) : ⊢ (P -∗ Q) -∗ P -∗ R -∗ (Q -∗ R -∗ S) -∗ S
end Iris.Tests.apply

namespace Iris.Tests.apply
theorem exact_intuitionistic [BI PROP] (Q : PROP) : □ Q ⊢ Q
end Iris.Tests.apply

namespace Iris.Tests.apply
theorem apply_intuitionistic [BI PROP] (P Q : PROP) : ⊢ □ P -∗ (P -∗ Q) -∗ Q
end Iris.Tests.apply

namespace Iris.Tests.apply
theorem multiple_intuitionistic [BI PROP] (P Q R : PROP) : ⊢ □ P -∗ Q -∗ □ (P -∗ Q -∗ □ R) -∗ R
end Iris.Tests.apply

namespace Iris.Tests.apply
theorem later [BI PROP] (P Q : PROP) : ⊢ (▷ P -∗ Q) -∗ P -∗ Q
end Iris.Tests.apply

namespace Iris.Tests.apply
theorem affine [BI PROP] [BIAffine PROP] (P Q : PROP) : ⊢ (P → Q) -∗ <pers> P -∗ Q
end Iris.Tests.apply

namespace Iris.Tests.apply
theorem later_affine [BI PROP] [BIAffine PROP] (P Q : PROP) : ⊢ (▷ P → Q) -∗ P -∗ Q
end Iris.Tests.apply

namespace Iris.Tests.apply
theorem exact_lean [BI PROP] (Q : PROP) (H : ⊢ Q) : ⊢ Q
end Iris.Tests.apply

namespace Iris.Tests.apply
theorem exact_lean' [BI PROP] (Q : PROP) : Q ⊢ (emp ∗ Q) ∗ emp
end Iris.Tests.apply

namespace Iris.Tests.apply
theorem exact_lean'' [BI PROP] (Q : PROP) (H : 0 = 0 → ⊢ Q) : ⊢ Q
end Iris.Tests.apply

namespace Iris.Tests.apply
theorem apply_lean [BI PROP] (P Q : PROP) (H : P ⊢ Q) (HP : ⊢ P) : ⊢ Q
end Iris.Tests.apply

namespace Iris.Tests.apply
theorem apply_lean' [BI PROP] (P Q : PROP) (H : ⊢ P -∗ Q) (HP : ⊢ P) : ⊢ Q
end Iris.Tests.apply

namespace Iris.Tests.apply
theorem apply_lean'' [BI PROP] (P Q : PROP) (H1 : P ⊢ Q) (H2 : Q ⊢ R) : P ⊢ R
end Iris.Tests.apply

namespace Iris.Tests.apply
theorem multiple_lean [BI PROP] (P Q R : PROP) (H : P ⊢ Q -∗ R) (HP : ⊢ P) : ⊢ Q -∗ R
end Iris.Tests.apply

namespace Iris.Tests.apply
theorem multiple_lean' [BI PROP] (P Q R : PROP) (H : P ∗ Q ⊢ R) (HP : ⊢ P) : ⊢ Q -∗ R
end Iris.Tests.apply

namespace Iris.Tests.apply
theorem exact_forall [BI PROP] (P : α → PROP) (a : α) (H : ⊢ ∀ x, P x) : ⊢ P a
end Iris.Tests.apply

namespace Iris.Tests.apply
theorem exact_forall' [BI PROP] (P : α → PROP) (a : α) (H : ∀ x, ⊢ P x) : ⊢ P a
end Iris.Tests.apply

namespace Iris.Tests.apply
theorem apply_forall [BI PROP] (P Q : α → PROP) (a b : α) (H : ⊢ ∀ x, ∀ y, P x -∗ Q y) : P a ⊢ Q b
end Iris.Tests.apply

namespace Iris.Tests.apply
theorem apply_forall' [BI PROP] (P Q : α → PROP) (a b : α) : (∀ x, ∀ y, P x -∗ Q y) ⊢ P a -∗ Q b
end Iris.Tests.apply

namespace Iris.Tests.apply
theorem apply_forall_intuitionistic [BI PROP] (P Q : α → PROP) (a b : α) (H : ⊢ □ ∀ x, ∀ y, P x -∗ Q y) : P a ⊢ Q b
end Iris.Tests.apply

namespace Iris.Tests.apply
theorem apply_forall_intuitionistic' [BI PROP] (P Q : α → PROP) (a b : α) : (□ ∀ x, ∀ y, P x -∗ Q y) ⊢ P a -∗ Q b
end Iris.Tests.apply

namespace Iris.Tests.pose
theorem exact_lean [BI PROP] (Q : PROP) (H : ⊢ Q) : ⊢ Q
end Iris.Tests.pose

namespace Iris.Tests.pose
theorem apply_lean [BI PROP] (P Q : PROP) (H : P ⊢ Q) : ⊢ P -∗ Q
end Iris.Tests.pose

namespace Iris.Tests.pose
theorem apply_forall [BI PROP] (P Q : α → PROP) (a b : α) (H : ⊢ ∀ x, ∀ y, P x -∗ Q y) : P a ⊢ Q b
end Iris.Tests.pose

namespace Iris.Tests.pose
theorem apply_forall_intuitionistic [BI PROP] (P Q : α → PROP) (a b : α) (H : ⊢ □ ∀ x, ∀ y, P x -∗ Q y) : P a ⊢ Q b
end Iris.Tests.pose

namespace Iris.Tests.exfalso
theorem false_intro [BI PROP] (Q : PROP) : False ⊢ Q
end Iris.Tests.exfalso

namespace Iris.Tests.exfalso
theorem false [BI PROP] (P : PROP) : □ P ⊢ False -∗ Q
end Iris.Tests.exfalso

namespace Iris.Tests.exfalso
theorem pure [BI PROP] (P : PROP) (HF : False) : ⊢ P
end Iris.Tests.exfalso

namespace Iris.Tests.pure
theorem move [BI PROP] (Q : PROP) : <affine> ⌜φ⌝ ⊢ Q -∗ Q
end Iris.Tests.pure

namespace Iris.Tests.pure
theorem move_multiple [BI PROP] (Q : PROP) : <affine> ⌜φ1⌝ ⊢ <affine> ⌜φ2⌝ -∗ Q -∗ Q
end Iris.Tests.pure

namespace Iris.Tests.pure
theorem move_conjunction [BI PROP] (Q : PROP) : (⌜φ1⌝ ∧ <affine> ⌜φ2⌝) ⊢ Q -∗ Q
end Iris.Tests.pure

namespace Iris.Tests.intuitionistic
theorem move [BI PROP] (P : PROP) : □ P ⊢ Q -∗ Q
end Iris.Tests.intuitionistic

namespace Iris.Tests.intuitionistic
theorem move_multiple [BI PROP] (P : PROP) : □ P ⊢ □ Q -∗ Q
end Iris.Tests.intuitionistic

namespace Iris.Tests.intuitionistic
theorem move_twice [BI PROP] (P : PROP) : □ P ⊢ Q -∗ Q
end Iris.Tests.intuitionistic

namespace Iris.Tests.spatial
theorem move [BI PROP] (P : PROP) : □ P ⊢ □ Q -∗ Q
end Iris.Tests.spatial

namespace Iris.Tests.spatial
theorem move_multiple [BI PROP] (P : PROP) : □ P ⊢ □ Q -∗ Q
end Iris.Tests.spatial

namespace Iris.Tests.spatial
theorem move_twice [BI PROP] (P : PROP) : □ P ⊢ □ Q -∗ Q
end Iris.Tests.spatial

namespace Iris.Tests.empintro
theorem simple [BI PROP] : ⊢ (emp : PROP)
end Iris.Tests.empintro

namespace Iris.Tests.empintro
theorem affine_env [BI PROP] (P : PROP) : <affine> P ⊢ emp
end Iris.Tests.empintro

namespace Iris.Tests.pureintro
theorem simple [BI PROP] : ⊢ (⌜True⌝ : PROP)
end Iris.Tests.pureintro

namespace Iris.Tests.pureintro
theorem or [BI PROP] : ⊢ True ∨ (False : PROP)
end Iris.Tests.pureintro

namespace Iris.Tests.pureintro
theorem with_proof [BI PROP] (H : A → B) (P Q : PROP) : <affine> P ⊢ <pers> Q → ⌜A⌝ → ⌜B⌝
end Iris.Tests.pureintro

namespace Iris.Tests.specialize
theorem wand_spatial [BI PROP] (Q : PROP) : P ⊢ (P -∗ Q) -∗ Q
end Iris.Tests.specialize

namespace Iris.Tests.specialize
theorem wand_intuitionistic [BI PROP] (Q : PROP) : □ P ⊢ □ (P -∗ Q) -∗ □ Q
end Iris.Tests.specialize

namespace Iris.Tests.specialize
theorem wand_intuitionistic_overwrite [BI PROP] (Q : PROP) : □ P ⊢ □ (□ P -∗ Q) -∗ □ Q
end Iris.Tests.specialize

namespace Iris.Tests.specialize
theorem wand_intuitionistic_required [BI PROP] (Q : PROP) : □ P ⊢ □ (□ P -∗ Q) -∗ □ Q
end Iris.Tests.specialize

namespace Iris.Tests.specialize
theorem wand_intuitionistic_spatial [BI PROP] (Q : PROP) : □ P ⊢ (P -∗ Q) -∗ Q
end Iris.Tests.specialize

namespace Iris.Tests.specialize
theorem wand_intuitionistic_required_spatial [BI PROP] (Q : PROP) : □ P ⊢ (□ P -∗ Q) -∗ Q
end Iris.Tests.specialize

namespace Iris.Tests.specialize
theorem wand_spatial_intuitionistic [BI PROP] (Q : PROP) : P ⊢ □ (P -∗ Q) -∗ Q
end Iris.Tests.specialize

namespace Iris.Tests.specialize
theorem wand_spatial_multiple [BI PROP] (Q : PROP) : ⊢ P1 -∗ P2 -∗ (P1 -∗ P2 -∗ Q) -∗ Q
end Iris.Tests.specialize

namespace Iris.Tests.specialize
theorem wand_intuitionistic_multiple [BI PROP] (Q : PROP) :
    ⊢ □ P1 -∗ □ P2 -∗ □ (P1 -∗ □ P2 -∗ Q) -∗ □ Q
end Iris.Tests.specialize

namespace Iris.Tests.specialize
theorem wand_multiple [BI PROP] (Q : PROP) :
    ⊢ P1 -∗ □ P2 -∗ P3 -∗ □ (P1 -∗ P2 -∗ P3 -∗ Q) -∗ Q
end Iris.Tests.specialize

namespace Iris.Tests.specialize
theorem forall_spatial [BI PROP] (Q : Nat → PROP) : ⊢ (∀ x, Q x) -∗ Q (y + 1)
end Iris.Tests.specialize

namespace Iris.Tests.specialize
theorem forall_intuitionistic [BI PROP] (Q : Nat → PROP) : ⊢ □ (∀ x, Q x) -∗ □ Q y
end Iris.Tests.specialize

namespace Iris.Tests.specialize
theorem forall_intuitionistic_overwrite [BI PROP] (Q : Nat → PROP) : ⊢ □ (∀ x, Q x) -∗ □ Q y
end Iris.Tests.specialize

namespace Iris.Tests.specialize
theorem forall_spatial_intuitionistic [BI PROP] (Q : Nat → PROP) : ⊢ (∀ x, □ Q x) -∗ □ Q y
end Iris.Tests.specialize

namespace Iris.Tests.specialize
theorem forall_spatial_multiple [BI PROP] (Q : Nat → Nat → PROP) :
    ⊢ (∀ x, ∀ y, Q x y) -∗ Q x y
end Iris.Tests.specialize

namespace Iris.Tests.specialize
theorem forall_intuitionistic_multiple [BI PROP] (Q : Nat → Nat → PROP) :
    ⊢ □ (∀ x, ∀ y, Q x y) -∗ □ Q x y
end Iris.Tests.specialize

namespace Iris.Tests.specialize
theorem forall_multiple [BI PROP] (Q : Nat → Nat → PROP) : ⊢ (∀ x, □ (∀ y, Q x y)) -∗ □ Q x y
end Iris.Tests.specialize

namespace Iris.Tests.specialize
theorem multiple [BI PROP] (Q : Nat → PROP) :
    ⊢ □ P1 -∗ P2 -∗ (□ P1 -∗ (∀ x, P2 -∗ Q x)) -∗ Q y
end Iris.Tests.specialize

namespace Iris.Tests.split
theorem and [BI PROP] (Q : PROP) : Q ⊢ Q ∧ Q
end Iris.Tests.split

namespace Iris.Tests.split
theorem sep_left [BI PROP] [BIAffine PROP] (Q : PROP) : ⊢ P -∗ Q -∗ R -∗ P ∗ Q
end Iris.Tests.split

namespace Iris.Tests.split
theorem sep_right [BI PROP] [BIAffine PROP] (Q : PROP) : ⊢ P -∗ Q -∗ R -∗ P ∗ Q
end Iris.Tests.split

namespace Iris.Tests.split
theorem sep_left_all [BI PROP] [BIAffine PROP] (Q : PROP) : ⊢ P -∗ □ Q -∗ R -∗ P ∗ Q
end Iris.Tests.split

namespace Iris.Tests.split
theorem sep_right_all [BI PROP] [BIAffine PROP] (Q : PROP) : ⊢ □ P -∗ Q -∗ R -∗ P ∗ Q
end Iris.Tests.split

namespace Iris.Tests.leftright
theorem left [BI PROP] (P : PROP) : P ⊢ P ∨ Q
end Iris.Tests.leftright

namespace Iris.Tests.leftright
theorem right [BI PROP] (Q : PROP) : Q ⊢ P ∨ Q
end Iris.Tests.leftright

namespace Iris.Tests.leftright
theorem complex [BI PROP] (P Q : PROP) : ⊢ P -∗ Q -∗ P ∗ (R ∨ Q ∨ R)
end Iris.Tests.leftright

namespace Iris.Tests.cases
theorem rename [BI PROP] (P : PROP) : P ⊢ P
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem clear [BI PROP] (P Q : PROP) : ⊢ P -∗ <affine> Q -∗ P
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem and [BI PROP] (Q : PROP) : □ (P1 ∧ P2 ∧ Q) ⊢ Q
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem and_intuitionistic [BI PROP] (Q : PROP) : □ P ∧ Q ⊢ Q
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem and_persistent_left [BI PROP] (Q : PROP) : <pers> Q ∧ <affine> P ⊢ Q
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem and_persistent_right [BI PROP] (Q : PROP) : Q ∧ <pers> P ⊢ Q
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem sep [BI PROP] [BIAffine PROP] (Q : PROP) : P1 ∗ P2 ∗ Q ⊢ Q
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem disjunction [BI PROP] (Q : PROP) : Q ⊢ <affine> (P1 ∨ P2 ∨ P3) -∗ Q
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem conjunction_and_disjunction [BI PROP] [BIAffine PROP] (Q : PROP) :
    (P11 ∨ P12 ∨ P13) ∗ P2 ∗ (P31 ∨ P32 ∨ P33) ∗ Q ⊢ Q
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem move_to_pure [BI PROP] (Q : PROP) : ⊢ <affine> ⌜⊢ Q⌝ -∗ Q
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem move_to_pure_ascii [BI PROP] (Q : PROP) : ⊢ <affine> ⌜⊢ Q⌝ -∗ Q
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem move_to_intuitionistic [BI PROP] (Q : PROP) : ⊢ □ Q -∗ Q
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem move_to_intuitionistic_ascii [BI PROP] (Q : PROP) : ⊢ □ Q -∗ Q
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem move_to_spatial [BI PROP] (Q : PROP) : ⊢ □ Q -∗ Q
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem move_to_spatial_ascii [BI PROP] (Q : PROP) : ⊢ □ Q -∗ Q
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem move_to_pure_conjunction [BI PROP] (Q : PROP) : ⊢ <affine> ⌜φ⌝ ∗ Q -∗ Q
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem move_to_pure_disjunction [BI PROP] (Q : PROP) :
    ⊢ <affine> ⌜φ1⌝ ∨ <affine> ⌜φ2⌝ -∗ Q -∗ Q
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem move_to_intuitionistic_conjunction [BI PROP] (Q : PROP) : ⊢ □ P ∗ Q -∗ Q
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem move_to_intuitionistic_disjunction [BI PROP] (Q : PROP) : ⊢ □ Q ∨ Q -∗ Q
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem move_to_spatial_conjunction [BI PROP] (Q : PROP) : ⊢ □ (P ∧ Q) -∗ Q
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem move_to_spatial_disjunction [BI PROP] (Q : PROP) : ⊢ □ (Q ∨ Q) -∗ Q
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem move_to_intuitionistic_and_back_conjunction [BI PROP] (Q : PROP) : ⊢ □ (P ∧ Q) -∗ Q
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem move_to_intuitionistic_and_back_disjunction [BI PROP] (Q : PROP) : ⊢ □ (Q ∨ Q) -∗ Q
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem conjunction_clear [BI PROP] [BIAffine PROP] (Q : PROP) : Q ∗ P ⊢ Q
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem disjunction_clear [BI PROP] [BIAffine PROP] (Q : PROP) : Q ⊢ P1 ∨ P2 -∗ Q
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem and_destruct_spatial_right [BI PROP] (Q : PROP) : P ∧ Q ⊢ Q
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem and_destruct_spatial_left [BI PROP] (Q : PROP) : Q ∧ P ⊢ Q
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem and_clear_spatial_multiple [BI PROP] (Q : PROP) : P1 ∧ P2 ∧ Q ∧ P3 ⊢ Q
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem and_destruct_intuitionistic_right [BI PROP] (Q : PROP) : □ (P ∧ Q) ⊢ Q
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem and_destruct_intuitionistic_left [BI PROP] (Q : PROP) : □ (Q ∧ P) ⊢ Q
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem and_clear_intuitionistic_multiple [BI PROP] (Q : PROP) : □ (P1 ∧ P2 ∧ Q ∧ P3) ⊢ Q
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem «exists» [BI PROP] (Q : Nat → PROP) : (∃ x, Q x) ⊢ ∃ x, Q x ∨ False
end Iris.Tests.cases

namespace Iris.Tests.cases
theorem exists_intuitionistic [BI PROP] (Q : Nat → PROP) : □ (∃ x, Q x) ⊢ ∃ x, □ Q x ∨ False
end Iris.Tests.cases

namespace Iris.Examples
theorem HγE  (i : GId FF1) : i = γ
end Iris.Examples

namespace Iris.Examples
theorem HγLookup : FF1[γ] = COFE.constOF (Agree (LeibnizO String))
end Iris.Examples

namespace Iris.Examples
theorem MyR_always_invalid (S₁ S₂ : String) (Hne : S₁ ≠ S₂) (n : Nat) : ¬✓{n} MyR S₁ • MyR S₂
end Iris.Examples

namespace Iris.ProofMode
theorem remove_l [BI PROP] {P P' Q R : PROP} (h : P ⊣⊢ P' ∗ R) :
    P ∗ Q ⊣⊢ (P' ∗ Q) ∗ R
end Iris.ProofMode

namespace Iris.ProofMode
theorem remove_r [BI PROP] {P Q Q' R : PROP} (h : Q ⊣⊢ Q' ∗ R) :
    P ∗ Q ⊣⊢ (P ∗ Q') ∗ R
end Iris.ProofMode

namespace Iris.ProofMode
theorem intuitionistically_sep_dup [BI PROP] {P : PROP} : □ P ⊣⊢ □ P ∗ □ P
end Iris.ProofMode

namespace Iris.ProofMode
theorem sep_emp_rev [BI PROP] {P : PROP} : P ⊣⊢ P ∗ emp
end Iris.ProofMode

namespace Iris.ProofMode
theorem emp_sep_rev [BI PROP] {P : PROP} : P ⊣⊢ emp ∗ P
end Iris.ProofMode

namespace Iris.OFE
theorem Dist.of_eq [OFE α] {x y : α} : x = y → x ≡{n}≡ y
end Iris.OFE

namespace Iris.OFE
@[simp, refl] theorem Equiv.rfl [OFE α] {x : α} : x ≡ x
end Iris.OFE

namespace Iris.OFE
theorem Equiv.of_eq [OFE α] {x y : α} : x = y → x ≡ y
end Iris.OFE

namespace Iris.OFE
theorem NonExpansive.eqv [OFE α] [OFE β] {f : α → β} [NonExpansive f]
    ⦃x₁ x₂⦄ (h : x₁ ≡ x₂) : f x₁ ≡ f x₂
end Iris.OFE

namespace Iris.OFE
theorem NonExpansive₂.eqv [OFE α] [OFE β] [OFE γ] {f : α → β → γ} [NonExpansive₂ f]
    ⦃x₁ x₂⦄ (hx : x₁ ≡ x₂) ⦃y₁ y₂⦄ (hy : y₁ ≡ y₂) : f x₁ y₁ ≡ f x₂ y₂
end Iris.OFE

namespace Iris.OFE
@[simp, refl] theorem DistLater.rfl [OFE α] {n} {x : α} : DistLater n x x
end Iris.OFE

namespace Iris.OFE
theorem distLater_eqv [OFE α] {n} : Equivalence (α := α) (DistLater n)
end Iris.OFE

namespace Iris.OFE
theorem Dist.distLater [OFE α] {n} {x y : α} (h : x ≡{n}≡ y) : DistLater n x y
end Iris.OFE

namespace Iris.OFE
theorem DistLater.dist_lt [OFE α] {m n} {x y : α} (h : DistLater n x y) (hm : m < n) : x ≡{m}≡ y
end Iris.OFE

namespace Iris.OFE
theorem Contractive.eqv [OFE α] [OFE β] (f : α → β) [Contractive f] ⦃x y : α⦄ (h : x ≡ y) :
    f x ≡ f y
end Iris.OFE

namespace Iris.OFE
theorem Discrete.discrete [OFE α] [Discrete α] {n} {x y : α} (h : x ≡{n}≡ y) : x ≡ y
end Iris.OFE

namespace Iris.OFE
theorem Discrete.discrete_n [OFE α] [Discrete α] {n} {x y : α} (h : x ≡{0}≡ y) : x ≡{n}≡ y
end Iris.OFE

namespace Iris.OFE
@[simp] theorem Leibniz.leibniz [OFE α] [Leibniz α] {x y : α} : x ≡ y ↔ x = y
end Iris.OFE

namespace Iris.OFE
@[simp] theorem Hom.id_apply [OFE α] {x} : (Hom.id : α -n> α) x = x
end Iris.OFE

namespace Iris.OFE
@[simp] theorem Hom.comp_apply [OFE α] [OFE β] [OFE γ] {g : β -n> γ} {f : α -n> β} {x} :
    (g.comp f) x = g (f x)
end Iris.OFE

namespace Iris.OFE
@[simp] theorem Hom.id_comp [OFE α] [OFE β] {f : α -n> β} : Hom.id.comp f = f
end Iris.OFE

namespace Iris.OFE
@[simp] theorem Hom.comp_id [OFE α] [OFE β] {f : α -n> β} : f.comp Hom.id = f
end Iris.OFE

namespace Iris.OFE
theorem Hom.comp_assoc [OFE α] [OFE β] [OFE γ] [OFE δ]
    (h : γ -n> δ) (g : β -n> γ) (f : α -n> β) : (h.comp g).comp f = h.comp (g.comp f)
end Iris.OFE

namespace Iris.OFE
theorem InvImage.equivalence {α : Sort u} {β : Sort v}
    {r : β → β → Prop} {f : α → β} (H : Equivalence r) : Equivalence (InvImage r f)
end Iris.OFE

namespace Iris.OFE
theorem _root_.Option.Forall₂.equivalence {R : α → α → Prop}
    (H : Equivalence R) : Equivalence (Option.Forall₂ R)
end Iris.OFE

namespace Iris.OFE
@[simp] theorem some_eqv_some [OFE α] {x y : α} : (some x ≡ some y) ↔ x ≡ y
end Iris.OFE

namespace Iris.OFE
@[simp] theorem not_some_eqv_none [OFE α] {x : α} : ¬some x ≡ none
end Iris.OFE

namespace Iris.OFE
@[simp] theorem not_none_eqv_some [OFE α] {x : α} : ¬none ≡ some x
end Iris.OFE

namespace Iris.OFE
@[simp] theorem some_dist_some [OFE α] {n} {x y : α} : (some x ≡{n}≡ some y) ↔ x ≡{n}≡ y
end Iris.OFE

namespace Iris.OFE
@[simp] theorem not_some_dist_none [OFE α] {n} {x : α} : ¬some x ≡{n}≡ none
end Iris.OFE

namespace Iris.OFE
@[simp] theorem not_none_dist_some [OFE α] {n} {x : α} : ¬none ≡{n}≡ some x
end Iris.OFE

namespace Iris.OFE
theorem equiv_some [OFE α] {o : Option α} {y : α} (e : o ≡ some y) :
    ∃ z, o = some z ∧ z ≡ y
end Iris.OFE

namespace Iris.OFE
theorem equiv_none [OFE α] {o : Option α} : o ≡ none ↔ o = none
end Iris.OFE

namespace Iris.OFE
theorem dist_some [OFE α] {n mx y} (h : mx ≡{n}≡ some y) :
    ∃ z : α, mx = some z ∧ y ≡{n}≡ z :=
  suffices hh : ∀ mx my y, mx ≡{n}≡ my → my = some y → ∃ t, mx = some t ∧ t ≡{n}≡ y from
    (hh mx (some y) _ h rfl).elim (fun t h => ⟨t, h.left, h.right.symm⟩)
  fun mx _ y e1 e2 =>
    match mx with
end Iris.OFE

namespace Iris.OFE
theorem Option.some_is_discrete [OFE α] {a : α} (Ha : DiscreteE a) : DiscreteE (some a)
end Iris.OFE

namespace Iris.OFE
theorem Option.none_is_discrete [OFE α] : DiscreteE (none : Option α)
end Iris.OFE

namespace Iris.OFE
theorem equiv_fst [OFE α] [OFE β] {x y : α × β} (h : x ≡ y) : x.fst ≡ y.fst
end Iris.OFE

namespace Iris.OFE
theorem equiv_snd [OFE α] [OFE β] {x y : α × β} (h : x ≡ y) : x.snd ≡ y.snd
end Iris.OFE

namespace Iris.OFE
theorem equiv_prod_ext [OFE α] [OFE β] {x₁ x₂ : α} {y₁ y₂ : β}
    (ex : x₁ ≡ x₂) (ey : y₁ ≡ y₂) : (x₁, y₁) ≡ (x₂, y₂)
end Iris.OFE

namespace Iris.OFE
theorem dist_fst {n} [OFE α] [OFE β] {x y : α × β} (h : x ≡{n}≡ y) : x.fst ≡{n}≡ y.fst
end Iris.OFE

namespace Iris.OFE
theorem dist_snd {n} [OFE α] [OFE β] {x y : α × β} (h : x ≡{n}≡ y) : x.snd ≡{n}≡ y.snd
end Iris.OFE

namespace Iris.OFE
theorem dist_prod_ext {n} [OFE α] [OFE β] {x₁ x₂ : α} {y₁ y₂ : β}
    (ex : x₁ ≡{n}≡ x₂) (ey : y₁ ≡{n}≡ y₂) : (x₁, y₁) ≡{n}≡ (x₂, y₂)
end Iris.OFE

namespace Iris.OFE
theorem prod.is_discrete [OFE α] [OFE β] {a : α} {b : β} (Ha : DiscreteE a) (Hb : DiscreteE b) :
    DiscreteE (a, b)
end Iris.OFE

namespace Iris.OFE
@[simp] theorem Iso.hom_inv_dist [OFE α] [OFE β] (iso : Iso α β) {n} {x} :
    iso.hom (iso.inv x) ≡{n}≡ x
end Iris.OFE

namespace Iris.OFE
@[simp] theorem Iso.inv_hom_dist [OFE α] [OFE β] (iso : Iso α β) {n} {x} :
    iso.inv (iso.hom x) ≡{n}≡ x
end Iris.OFE

namespace Iris.OFE
theorem Iso.hom_eqv [OFE α] [OFE β] (iso : Iso α β) ⦃x y⦄ :
    x ≡ y ↔ iso.hom x ≡ iso.hom y
end Iris.OFE

namespace Iris.OFE
theorem Iso.inv_eqv [OFE α] [OFE β] (iso : Iso α β) ⦃x y⦄ :
    x ≡ y ↔ iso.inv x ≡ iso.inv y
end Iris.OFE

namespace Iris.OFE
theorem Iso.hom_dist [OFE α] [OFE β] (iso : Iso α β) {n} ⦃x y⦄ :
    x ≡{n}≡ y ↔ iso.hom x ≡{n}≡ iso.hom y
end Iris.OFE

namespace Iris.OFE
theorem Iso.inv_dist [OFE α] [OFE β] (iso : Iso α β) {n} ⦃x y⦄ :
    x ≡{n}≡ y ↔ iso.inv x ≡{n}≡ iso.inv y
end Iris.OFE

namespace Iris.OFE
@[simp] theorem Iso.id_apply [OFE α] {x} : ((Iso.id : Iso α α) : α -n> α) x = x
end Iris.OFE

namespace Iris.Chain
@[simp] theorem const_apply [OFE α] {a : α} {n} : const a n = a
end Iris.Chain

namespace Iris.Chain
@[simp] theorem map_apply [OFE α] [OFE β] {f : α -n> β} {c : Chain α} {n} :
    map f c n = f (c n)
end Iris.Chain

namespace Iris.Chain
@[simp] theorem map_id [OFE α] {c : Chain α} : map (Hom.id : α -n> α) c = c
end Iris.Chain

namespace Iris.Chain
theorem map_comp [OFE α] [OFE β] [OFE γ] {f : α -n> β} {g : β -n> γ} {c : Chain α} :
    map (g.comp f) c = map g (map f c)
end Iris.Chain

namespace Iris
theorem chain_none_const [OFE V] {c : Chain (Option V)} (H : c n = none) :
    c = Chain.const none
end Iris

namespace Iris.COFE
theorem conv_compl' [COFE α] {c : Chain α} {n i} (h : n ≤ i) : compl c ≡{n}≡ c i
end Iris.COFE

namespace Iris.COFE
theorem compl_map [COFE α] [COFE β] (f : α -n> β) (c : Chain α) :
    compl (Chain.map f c) ≡ f (compl c)
end Iris.COFE

namespace Iris.COFE
@[simp] theorem compl_const [COFE α] (a : α) : compl (Chain.const a) ≡ a
end Iris.COFE

namespace Iris.COFE
@[simp] theorem discrete_cofe_compl [COFE α] [OFE.Discrete α] (c : Chain α) : compl c ≡ c 0
end Iris.COFE

namespace Iris
theorem Eq_Equivalence {α : Type _} : Equivalence (@Eq α)
end Iris

namespace Iris
theorem LeibnizO.eqv_inj {x y : α} (H : LeibnizO.mk x ≡ LeibnizO.mk y) : x = y
end Iris

namespace Iris
theorem LeibnizO.dist_inj {x y : α} {n} (H : LeibnizO.mk x ≡{n}≡ LeibnizO.mk y) : x = y
end Iris

namespace Iris
theorem LimitPreserving.const [COFE α] {P : Prop} : LimitPreserving fun (_ : α) => P
end Iris

namespace Iris
theorem LimitPreserving.discrete [COFE α] {P : α → Prop} :
    (∀ {x y : α}, x ≡{0}≡ y → (P x → P y)) → LimitPreserving P
end Iris

namespace Iris
theorem LimitPreserving.and [COFE α] {P Q : α → Prop}  (HP : LimitPreserving P)
    (HQ : LimitPreserving Q) : LimitPreserving fun a => P a ∧ Q a
end Iris

namespace Iris
theorem LimitPreserving.forall [COFE α] (P : β → α → Prop) (Hlim : ∀ y, LimitPreserving (P y)) :
    LimitPreserving (∀ y, P y ·)
end Iris

namespace Iris
theorem LimitPreserving.impl [COFE α] (P1 P2 : α → Prop)
    (HP1 : ∀ {x y : α}, x ≡{0}≡ y → P1 x → P1 y)
    (Hcompl : LimitPreserving P2) :
    LimitPreserving (fun x => P1 x → P2 x)
end Iris

namespace Iris
theorem LimitPreserving.equiv [COFE α] [COFE β] (f g : α -n> β) :
    LimitPreserving (fun x => f x ≡ g x)
end Iris

namespace Iris.BI
theorem and_elim_l' [BI PROP] {P Q R : PROP} (h : P ⊢ R) : P ∧ Q ⊢ R
end Iris.BI

namespace Iris.BI
theorem and_elim_r' [BI PROP] {P Q R : PROP} (h : Q ⊢ R) : P ∧ Q ⊢ R
end Iris.BI

namespace Iris.BI
theorem or_intro_l' [BI PROP] {P Q R : PROP} (h : P ⊢ Q) : P ⊢ Q ∨ R
end Iris.BI

namespace Iris.BI
theorem or_intro_r' [BI PROP] {P Q R : PROP} (h : P ⊢ R) : P ⊢ Q ∨ R
end Iris.BI

namespace Iris.BI
theorem and_symm [BI PROP] {P Q : PROP} : P ∧ Q ⊢ Q ∧ P
end Iris.BI

namespace Iris.BI
theorem or_symm [BI PROP] {P Q : PROP} : P ∨ Q ⊢ Q ∨ P
end Iris.BI

namespace Iris.BI
theorem imp_intro' [BI PROP] {P Q R : PROP} (h : Q ∧ P ⊢ R) : P ⊢ Q → R
end Iris.BI

namespace Iris.BI
theorem mp [BI PROP] {P Q R : PROP} (h1 : P ⊢ Q → R) (h2 : P ⊢ Q) : P ⊢ R
end Iris.BI

namespace Iris.BI
theorem imp_elim' [BI PROP] {P Q R : PROP} (h : Q ⊢ P → R) : P ∧ Q ⊢ R
end Iris.BI

namespace Iris.BI
theorem imp_elim_l [BI PROP] {P Q : PROP} : (P → Q) ∧ P ⊢ Q
end Iris.BI

namespace Iris.BI
theorem imp_elim_r [BI PROP] {P Q : PROP} : P ∧ (P → Q) ⊢ Q
end Iris.BI

namespace Iris.BI
theorem false_elim [BI PROP] {P : PROP} : False ⊢ P
end Iris.BI

namespace Iris.BI
theorem true_intro [BI PROP] {P : PROP} : P ⊢ True
end Iris.BI

namespace Iris.BI
@[rw_mono_rule]
theorem and_mono [BI PROP] {P P' Q Q' : PROP} (h1 : P ⊢ Q) (h2 : P' ⊢ Q') : P ∧ P' ⊢ Q ∧ Q'
end Iris.BI

namespace Iris.BI
theorem and_mono_l [BI PROP] {P P' Q : PROP} (h : P ⊢ P') : P ∧ Q ⊢ P' ∧ Q
end Iris.BI

namespace Iris.BI
theorem and_mono_r [BI PROP] {P Q Q' : PROP} (h : Q ⊢ Q') : P ∧ Q ⊢ P ∧ Q'
end Iris.BI

namespace Iris.BI
@[rw_mono_rule]
theorem and_congr [BI PROP] {P P' Q Q' : PROP} (h1 : P ⊣⊢ Q) (h2 : P' ⊣⊢ Q') : P ∧ P' ⊣⊢ Q ∧ Q'
end Iris.BI

namespace Iris.BI
theorem and_congr_l [BI PROP] {P P' Q : PROP} (h : P ⊣⊢ P') : P ∧ Q ⊣⊢ P' ∧ Q
end Iris.BI

namespace Iris.BI
theorem and_congr_r [BI PROP] {P Q Q' : PROP} (h : Q ⊣⊢ Q') : P ∧ Q ⊣⊢ P ∧ Q'
end Iris.BI

namespace Iris.BI
@[rw_mono_rule]
theorem or_mono [BI PROP] {P P' Q Q' : PROP} (h1 : P ⊢ Q) (h2 : P' ⊢ Q') : P ∨ P' ⊢ Q ∨ Q'
end Iris.BI

namespace Iris.BI
theorem or_mono_l [BI PROP] {P P' Q : PROP} (h : P ⊢ P') : P ∨ Q ⊢ P' ∨ Q
end Iris.BI

namespace Iris.BI
theorem or_mono_r [BI PROP] {P Q Q' : PROP} (h : Q ⊢ Q') : P ∨ Q ⊢ P ∨ Q'
end Iris.BI

namespace Iris.BI
@[rw_mono_rule]
theorem or_congr [BI PROP] {P P' Q Q' : PROP} (h1 : P ⊣⊢ Q) (h2 : P' ⊣⊢ Q') : P ∨ P' ⊣⊢ Q ∨ Q'
end Iris.BI

namespace Iris.BI
theorem or_congr_l [BI PROP] {P P' Q : PROP} (h : P ⊣⊢ P') : P ∨ Q ⊣⊢ P' ∨ Q
end Iris.BI

namespace Iris.BI
theorem or_congr_r [BI PROP] {P Q Q' : PROP} (h : Q ⊣⊢ Q') : P ∨ Q ⊣⊢ P ∨ Q'
end Iris.BI

namespace Iris.BI
@[rw_mono_rule]
theorem imp_mono [BI PROP] {P P' Q Q' : PROP} (h1 : Q ⊢ P) (h2 : P' ⊢ Q') : (P → P') ⊢ Q → Q'
end Iris.BI

namespace Iris.BI
theorem imp_mono_l [BI PROP] {P P' Q : PROP} (h : P' ⊢ P) : (P → Q) ⊢ (P' → Q)
end Iris.BI

namespace Iris.BI
theorem imp_mono_r [BI PROP] {P Q Q' : PROP} (h : Q ⊢ Q') : (P → Q) ⊢ (P → Q')
end Iris.BI

namespace Iris.BI
@[rw_mono_rule]
theorem imp_congr [BI PROP] {P P' Q Q' : PROP}
    (h1 : P ⊣⊢ Q) (h2 : P' ⊣⊢ Q') : (P → P') ⊣⊢ (Q → Q')
end Iris.BI

namespace Iris.BI
theorem imp_congr_l [BI PROP] {P P' Q : PROP} (h : P ⊣⊢ P') : (P → Q) ⊣⊢ (P' → Q)
end Iris.BI

namespace Iris.BI
theorem imp_congr_r [BI PROP] {P Q Q' : PROP} (h : Q ⊣⊢ Q') : (P → Q) ⊣⊢ (P → Q')
end Iris.BI

namespace Iris.BI
theorem forall_ne [BI PROP] {Φ Ψ : α → PROP} (h : ∀ a, Φ a ≡{n}≡ Ψ a) :
    iprop(∀ a, Φ a) ≡{n}≡ iprop(∀ a, Ψ a)
end Iris.BI

namespace Iris.BI
theorem forall_intro [BI PROP] {P : PROP} {Ψ : α → PROP} (h : ∀ a, P ⊢ Ψ a) : P ⊢ ∀ a, Ψ a
end Iris.BI

namespace Iris.BI
theorem forall_elim [BI PROP] {Ψ : α → PROP} (a : α) : (∀ a, Ψ a) ⊢ Ψ a
end Iris.BI

namespace Iris.BI
@[rw_mono_rule]
theorem forall_mono [BI PROP] {Φ Ψ : α → PROP} (h : ∀ a, Φ a ⊢ Ψ a) : (∀ a, Φ a) ⊢ ∀ a, Ψ a
end Iris.BI

namespace Iris.BI
@[rw_mono_rule]
theorem forall_congr [BI PROP] {Φ Ψ : α → PROP} (h : ∀ a, Φ a ⊣⊢ Ψ a) : (∀ a, Φ a) ⊣⊢ ∀ a, Ψ a
end Iris.BI

namespace Iris.BI
theorem exists_ne [BI PROP] {Φ Ψ : α → PROP} (h : ∀ a, Φ a ≡{n}≡ Ψ a) :
    iprop(∃ a, Φ a) ≡{n}≡ iprop(∃ a, Ψ a)
end Iris.BI

namespace Iris.BI
theorem exists_intro [BI PROP] {Ψ : α → PROP} (a : α) : Ψ a ⊢ ∃ a, Ψ a
end Iris.BI

namespace Iris.BI
theorem exists_elim [BI PROP] {Φ : α → PROP} {Q : PROP} (h : ∀ a, Φ a ⊢ Q) : (∃ a, Φ a) ⊢ Q
end Iris.BI

namespace Iris.BI
@[rw_mono_rule]
theorem exists_mono [BI PROP] {Φ Ψ : α → PROP} (h : ∀ a, Φ a ⊢ Ψ a) : (∃ a, Φ a) ⊢ ∃ a, Ψ a
end Iris.BI

namespace Iris.BI
@[rw_mono_rule]
theorem exists_congr [BI PROP] {Φ Ψ : α → PROP} (h : ∀ a, Φ a ⊣⊢ Ψ a) : (∃ a, Φ a) ⊣⊢ ∃ a, Ψ a
end Iris.BI

namespace Iris.BI
theorem and_self [BI PROP] {P : PROP} : P ∧ P ⊣⊢ P
end Iris.BI

namespace Iris.BI
theorem or_self [BI PROP] {P : PROP} : P ∨ P ⊣⊢ P
end Iris.BI

namespace Iris.BI
theorem and_comm [BI PROP] {P Q : PROP} : P ∧ Q ⊣⊢ Q ∧ P
end Iris.BI

namespace Iris.BI
theorem or_comm [BI PROP] {P Q : PROP} : P ∨ Q ⊣⊢ Q ∨ P
end Iris.BI

namespace Iris.BI
theorem true_and [BI PROP] {P : PROP} : True ∧ P ⊣⊢ P
end Iris.BI

namespace Iris.BI
theorem and_true [BI PROP] {P : PROP} : P ∧ True ⊣⊢ P
end Iris.BI

namespace Iris.BI
theorem false_and [BI PROP] {P : PROP} : False ∧ P ⊣⊢ False
end Iris.BI

namespace Iris.BI
theorem and_false [BI PROP] {P : PROP} : P ∧ False ⊣⊢ False
end Iris.BI

namespace Iris.BI
theorem true_or [BI PROP] {P : PROP} : True ∨ P ⊣⊢ True
end Iris.BI

namespace Iris.BI
theorem or_true [BI PROP] {P : PROP} : P ∨ True ⊣⊢ True
end Iris.BI

namespace Iris.BI
theorem false_or [BI PROP] {P : PROP} : False ∨ P ⊣⊢ P
end Iris.BI

namespace Iris.BI
theorem or_false [BI PROP] {P : PROP} : P ∨ False ⊣⊢ P
end Iris.BI

namespace Iris.BI
theorem and_assoc [BI PROP] {P Q R : PROP} : (P ∧ Q) ∧ R ⊣⊢ P ∧ Q ∧ R
end Iris.BI

namespace Iris.BI
theorem or_assoc [BI PROP] {P Q R : PROP} : (P ∨ Q) ∨ R ⊣⊢ P ∨ Q ∨ R
end Iris.BI

namespace Iris.BI
theorem true_imp [BI PROP] {P : PROP} : (True → P) ⊣⊢ P
end Iris.BI

namespace Iris.BI
theorem imp_self [BI PROP] {P Q : PROP} : Q ⊢ P → P
end Iris.BI

namespace Iris.BI
theorem imp_trans [BI PROP] {P Q R : PROP} : (P → Q) ∧ (Q → R) ⊢ P → R
end Iris.BI

namespace Iris.BI
theorem false_imp [BI PROP] {P : PROP} : (False → P) ⊣⊢ True
end Iris.BI

namespace Iris.BI
theorem and_left_comm [BI PROP] {P Q R : PROP} : P ∧ Q ∧ R ⊣⊢ Q ∧ P ∧ R
end Iris.BI

namespace Iris.BI
theorem and_or_l [BI PROP] {P Q R : PROP} : P ∧ (Q ∨ R) ⊣⊢ P ∧ Q ∨ P ∧ R
end Iris.BI

namespace Iris.BI
theorem and_exists_l [BI PROP] {P : PROP} {Ψ : α → PROP} : P ∧ (∃ a, Ψ a) ⊣⊢ ∃ a, P ∧ Ψ a
end Iris.BI

namespace Iris.BI
theorem or_eq_ite [BI PROP] {P Q : PROP} : P ∨ Q ⊣⊢ ∃ (b : Bool), if b then P else Q
end Iris.BI

namespace Iris.BI
theorem exists_intro' [BI PROP] {P : PROP} {Ψ : α → PROP} (a : α) (h : P ⊢ Ψ a) : P ⊢ ∃ a, Ψ a
end Iris.BI

namespace Iris.BI
theorem sep_mono_l [BI PROP] {P P' Q : PROP} (h : P ⊢ P') : P ∗ Q ⊢ P' ∗ Q
end Iris.BI

namespace Iris.BI
theorem sep_mono_r [BI PROP] {P Q Q' : PROP} (h : Q ⊢ Q') : P ∗ Q ⊢ P ∗ Q'
end Iris.BI

namespace Iris.BI
@[rw_mono_rule]
theorem sep_congr [BI PROP] {P P' Q Q' : PROP} (h1 : P ⊣⊢ Q) (h2 : P' ⊣⊢ Q') :
    (P ∗ P') ⊣⊢ (Q ∗ Q')
end Iris.BI

namespace Iris.BI
theorem sep_congr_l [BI PROP] {P P' Q : PROP} (h : P ⊣⊢ P') : P ∗ Q ⊣⊢ P' ∗ Q
end Iris.BI

namespace Iris.BI
theorem sep_congr_r [BI PROP] {P Q Q' : PROP} (h : Q ⊣⊢ Q') : P ∗ Q ⊣⊢ P ∗ Q'
end Iris.BI

namespace Iris.BI
@[rw_mono_rule]
theorem wand_mono [BI PROP] {P P' Q Q' : PROP} (h1 : Q ⊢ P) (h2 : P' ⊢ Q') :
    (P -∗ P') ⊢ Q -∗ Q'
end Iris.BI

namespace Iris.BI
theorem wand_mono_l [BI PROP] {P P' Q : PROP} (h : P' ⊢ P) : (P -∗ Q) ⊢ P' -∗ Q
end Iris.BI

namespace Iris.BI
theorem wand_mono_r [BI PROP] {P Q Q' : PROP} (h : Q ⊢ Q') : (P -∗ Q) ⊢ P -∗ Q'
end Iris.BI

namespace Iris.BI
@[rw_mono_rule]
theorem wand_congr [BI PROP] {P P' Q Q' : PROP} (h1 : P ⊣⊢ Q) (h2 : P' ⊣⊢ Q') :
    (P -∗ P') ⊣⊢ (Q -∗ Q')
end Iris.BI

namespace Iris.BI
theorem wand_congr_l [BI PROP] {P P' Q : PROP} (h : P ⊣⊢ P') : (P -∗ Q) ⊣⊢ (P' -∗ Q)
end Iris.BI

namespace Iris.BI
theorem wand_congr_r [BI PROP] {P Q Q' : PROP} (h : Q ⊣⊢ Q') : (P -∗ Q) ⊣⊢ (P -∗ Q')
end Iris.BI

namespace Iris.BI
theorem sep_comm [BI PROP] {P Q : PROP} : P ∗ Q ⊣⊢ Q ∗ P
end Iris.BI

namespace Iris.BI
theorem sep_assoc [BI PROP] {P Q R : PROP} : (P ∗ Q) ∗ R ⊣⊢ P ∗ Q ∗ R
end Iris.BI

namespace Iris.BI
theorem sep_left_comm [BI PROP] {P Q R : PROP} : P ∗ Q ∗ R ⊣⊢ Q ∗ P ∗ R
end Iris.BI

namespace Iris.BI
theorem sep_right_comm [BI PROP] {P Q R : PROP} : (P ∗ Q) ∗ R ⊣⊢ (P ∗ R) ∗ Q
end Iris.BI

namespace Iris.BI
theorem sep_sep_sep_comm [BI PROP] {P Q R S : PROP} : (P ∗ Q) ∗ (R ∗ S) ⊣⊢ (P ∗ R) ∗ (Q ∗ S)
end Iris.BI

namespace Iris.BI
theorem sep_emp [BI PROP] {P : PROP} : P ∗ emp ⊣⊢ P
end Iris.BI

namespace Iris.BI
theorem true_sep_2 [BI PROP] {P : PROP} : P ⊢ True ∗ P
end Iris.BI

namespace Iris.BI
theorem wand_intro' [BI PROP] {P Q R : PROP} (h : Q ∗ P ⊢ R) : P ⊢ Q -∗ R
end Iris.BI

namespace Iris.BI
theorem wand_elim' [BI PROP] {P Q R : PROP} (h : Q ⊢ P -∗ R) : P ∗ Q ⊢ R
end Iris.BI

namespace Iris.BI
theorem wand_elim_l [BI PROP] {P Q : PROP} : (P -∗ Q) ∗ P ⊢ Q
end Iris.BI

namespace Iris.BI
theorem wand_elim_r [BI PROP] {P Q : PROP} : P ∗ (P -∗ Q) ⊢ Q
end Iris.BI

namespace Iris.BI
theorem sep_or_l [BI PROP] {P Q R : PROP} : P ∗ (Q ∨ R) ⊣⊢ (P ∗ Q) ∨ (P ∗ R)
end Iris.BI

namespace Iris.BI
theorem sep_or_r [BI PROP] {P Q R : PROP} : (P ∨ Q) ∗ R ⊣⊢ (P ∗ R) ∨ (Q ∗ R)
end Iris.BI

namespace Iris.BI
theorem sep_exists_l [BI PROP] {P : PROP} {Ψ : α → PROP} : P ∗ (∃ a, Ψ a) ⊣⊢ ∃ a, P ∗ Ψ a
end Iris.BI

namespace Iris.BI
theorem sep_exists_r [BI PROP] {Φ : α → PROP} {Q : PROP} : (∃ a, Φ a) ∗ Q ⊣⊢ ∃ a, Φ a ∗ Q
end Iris.BI

namespace Iris.BI
theorem wand_rfl [BI PROP] {P : PROP} : ⊢ P -∗ P
end Iris.BI

namespace Iris.BI
@[rw_mono_rule]
theorem wandIff_congr [BI PROP] {P P' Q Q' : PROP} (h1 : P ⊣⊢ Q) (h2 : P' ⊣⊢ Q') :
    (P ∗-∗ P') ⊣⊢ (Q ∗-∗ Q')
end Iris.BI

namespace Iris.BI
theorem wandIff_congr_l [BI PROP] {P P' Q : PROP} (h : P ⊣⊢ P') : (P ∗-∗ Q) ⊣⊢ (P' ∗-∗ Q)
end Iris.BI

namespace Iris.BI
theorem wandIff_congr_r [BI PROP] {P Q Q' : PROP} (h : Q ⊣⊢ Q') : (P ∗-∗ Q) ⊣⊢ (P ∗-∗ Q')
end Iris.BI

namespace Iris.BI
theorem wandIff_refl [BI PROP] {P : PROP} : ⊢ P ∗-∗ P
end Iris.BI

namespace Iris.BI
theorem wand_entails [BI PROP] {P Q : PROP} (h : ⊢ P -∗ Q) : P ⊢ Q
end Iris.BI

namespace Iris.BI
theorem entails_wand [BI PROP] {P Q : PROP} (h : P ⊢ Q) : ⊢ P -∗ Q
end Iris.BI

namespace Iris.BI
theorem equiv_wandIff [BI PROP] {P Q : PROP} (h : P ⊣⊢ Q) : ⊢ P ∗-∗ Q
end Iris.BI

namespace Iris.BI
theorem wandIff_equiv [BI PROP] {P Q : PROP} (h : ⊢ P ∗-∗ Q) : P ⊣⊢ Q
end Iris.BI

namespace Iris.BI
theorem pure_elim [BI PROP] (φ : Prop) {Q R : PROP} (h1 : Q ⊢ ⌜φ⌝) (h2 : φ → Q ⊢ R) : Q ⊢ R
end Iris.BI

namespace Iris.BI
theorem pure_mono [BI PROP] {φ1 φ2 : Prop} (h : φ1 → φ2) : ⌜φ1⌝ ⊢ (⌜φ2⌝ : PROP)
end Iris.BI

namespace Iris.BI
theorem pure_congr [BI PROP] {φ1 φ2 : Prop} (h : φ1 ↔ φ2) : ⌜φ1⌝ ⊣⊢ (⌜φ2⌝ : PROP)
end Iris.BI

namespace Iris.BI
theorem pure_elim_l [BI PROP] {φ : Prop} {Q R : PROP} (h : φ → Q ⊢ R) : ⌜φ⌝ ∧ Q ⊢ R
end Iris.BI

namespace Iris.BI
theorem pure_elim_r [BI PROP] {φ : Prop} {Q R : PROP} (h : φ → Q ⊢ R) : Q ∧ ⌜φ⌝ ⊢ R
end Iris.BI

namespace Iris.BI
theorem pure_true [BI PROP] {φ : Prop} (h : φ) : ⌜φ⌝ ⊣⊢ (True : PROP)
end Iris.BI

namespace Iris.BI
theorem pure_and [BI PROP] {φ1 φ2 : Prop} : ⌜φ1⌝ ∧ (⌜φ2⌝ : PROP) ⊣⊢ ⌜φ1 ∧ φ2⌝
end Iris.BI

namespace Iris.BI
theorem pure_or [BI PROP] {φ1 φ2 : Prop} : ⌜φ1⌝ ∨ (⌜φ2⌝ : PROP) ⊣⊢ ⌜φ1 ∨ φ2⌝
end Iris.BI

namespace Iris.BI
theorem pure_imp_2 [BI PROP] {φ1 φ2 : Prop} : ⌜φ1 → φ2⌝ ⊢ (⌜φ1⌝ → ⌜φ2⌝ : PROP)
end Iris.BI

namespace Iris.BI
theorem pure_imp [BI PROP] {φ1 φ2 : Prop} : (⌜φ1⌝ → ⌜φ2⌝ : PROP) ⊣⊢ ⌜φ1 → φ2⌝
end Iris.BI

namespace Iris.BI
theorem pure_forall_2 [BI PROP] {φ : α → Prop} : ⌜∀ x, φ x⌝ ⊢ ∀ x, (⌜φ x⌝ : PROP)
end Iris.BI

namespace Iris.BI
theorem pure_forall [BI PROP] {φ : α → Prop} : (∀ x, (⌜φ x⌝ : PROP)) ⊣⊢ ⌜∀ x, φ x⌝
end Iris.BI

namespace Iris.BI
theorem pure_exists [BI PROP] {φ : α → Prop} : (∃ x, ⌜φ x⌝ : PROP) ⊣⊢ ⌜∃ x, φ x⌝
end Iris.BI

namespace Iris.BI
theorem affinely_ne [BI PROP] : OFE.NonExpansive (@affinely PROP _)
end Iris.BI

namespace Iris.BI
@[rw_mono_rule]
theorem affinely_congr [BI PROP] {P P' : PROP} (h : P ⊣⊢ P') :
    <affine> P ⊣⊢ <affine> P'
end Iris.BI

namespace Iris.BI
theorem affinely_elim_emp [BI PROP] {P : PROP} : <affine> P ⊢ emp
end Iris.BI

namespace Iris.BI
theorem affinely_elim [BI PROP] {P : PROP} : <affine> P ⊢ P
end Iris.BI

namespace Iris.BI
@[rw_mono_rule]
theorem affinely_mono [BI PROP] {P Q : PROP} : (P ⊢ Q) → <affine> P ⊢ <affine> Q
end Iris.BI

namespace Iris.BI
theorem affinely_idem [BI PROP] {P : PROP} : <affine> <affine> P ⊣⊢ <affine> P
end Iris.BI

namespace Iris.BI
theorem affinely_intro' [BI PROP] {P Q : PROP} (h : P ⊢ <affine> Q) :
    <affine> P ⊢ <affine> Q
end Iris.BI

namespace Iris.BI
theorem affinely_false [BI PROP] : <affine> False ⊣⊢ (False : PROP)
end Iris.BI

namespace Iris.BI
theorem affinely_emp [BI PROP] : <affine> emp ⊣⊢ (emp : PROP)
end Iris.BI

namespace Iris.BI
theorem affinely_or [BI PROP] {P Q : PROP} : <affine> (P ∨ Q) ⊣⊢ <affine> P ∨ <affine> Q
end Iris.BI

namespace Iris.BI
theorem affinely_and [BI PROP] {P Q : PROP} : <affine> (P ∧ Q) ⊣⊢ <affine> P ∧ <affine> Q
end Iris.BI

namespace Iris.BI
theorem affinely_sep_2 [BI PROP] {P Q : PROP} : <affine> P ∗ <affine> Q ⊢ <affine> (P ∗ Q)
end Iris.BI

namespace Iris.BI
theorem affinely_sep_r [BI PROP] [BIPositive PROP] {P Q : PROP} :
    <affine> (P ∗ Q) ⊢ P ∗ <affine> Q
end Iris.BI

namespace Iris.BI
theorem affinely_sep [BI PROP] [BIPositive PROP] {P Q : PROP} :
    <affine> (P ∗ Q) ⊣⊢ <affine> P ∗ <affine> Q
end Iris.BI

namespace Iris.BI
theorem affinely_forall_1 [BI PROP] {Φ : α → PROP} : <affine> (∀ a, Φ a) ⊢ ∀ a, <affine> (Φ a)
end Iris.BI

namespace Iris.BI
theorem affinely_exists [BI PROP] {Φ : α → PROP} : <affine> (∃ a, Φ a) ⊣⊢ ∃ a, <affine> (Φ a)
end Iris.BI

namespace Iris.BI
theorem affinely_true [BI PROP] : <affine> True ⊣⊢ (emp : PROP)
end Iris.BI

namespace Iris.BI
theorem affinely_and_l [BI PROP] {P Q : PROP} : <affine> P ∧ Q ⊣⊢ <affine> (P ∧ Q)
end Iris.BI

namespace Iris.BI
theorem affinely_and_r [BI PROP] {P Q : PROP} : P ∧ <affine> Q ⊣⊢ <affine> (P ∧ Q)
end Iris.BI

namespace Iris.BI
theorem affinely_and_lr [BI PROP] {P Q : PROP} : <affine> P ∧ Q ⊣⊢ P ∧ <affine> Q
end Iris.BI

namespace Iris.BI
theorem affine_mono [BI PROP] {P Q : PROP} (h : P ⊢ Q) [Affine Q] : Affine P
end Iris.BI

namespace Iris.BI
theorem absorbingly_ne [BI PROP] : OFE.NonExpansive (@absorbingly PROP _)
end Iris.BI

namespace Iris.BI
@[rw_mono_rule]
theorem absorbingly_congr [BI PROP] {P P' : PROP} (h : P ⊣⊢ P') :
    <absorb> P ⊣⊢ <absorb> P'
end Iris.BI

namespace Iris.BI
theorem absorbingly_intro [BI PROP] {P : PROP} : P ⊢ <absorb> P
end Iris.BI

namespace Iris.BI
@[rw_mono_rule]
theorem absorbingly_mono [BI PROP] {P Q : PROP} : (P ⊢ Q) → <absorb> P ⊢ <absorb> Q
end Iris.BI

namespace Iris.BI
theorem absorbingly_idem [BI PROP] {P : PROP} : <absorb> <absorb> P ⊣⊢ <absorb> P
end Iris.BI

namespace Iris.BI
theorem absorbingly_pure {φ : Prop} [BI PROP] : <absorb> ⌜φ⌝ ⊣⊢ (⌜φ⌝ : PROP)
end Iris.BI

namespace Iris.BI
theorem absorbingly_true [BI PROP] : <absorb> True ⊣⊢ (True : PROP)
end Iris.BI

namespace Iris.BI
theorem absorbingly_or [BI PROP] {P Q : PROP} : <absorb> (P ∨ Q) ⊣⊢ <absorb> P ∨ <absorb> Q
end Iris.BI

namespace Iris.BI
theorem absorbingly_and_1 [BI PROP] {P Q : PROP} : <absorb> (P ∧ Q) ⊢ <absorb> P ∧ <absorb> Q
end Iris.BI

namespace Iris.BI
theorem absorbingly_forall_1 [BI PROP] {Φ : α → PROP} : <absorb> (∀ a, Φ a) ⊢ ∀ a, <absorb> (Φ a)
end Iris.BI

namespace Iris.BI
theorem absorbingly_exists [BI PROP] {Φ : α → PROP} :
    <absorb> (∃ a, Φ a) ⊣⊢ ∃ a, <absorb> (Φ a)
end Iris.BI

namespace Iris.BI
theorem absorbingly_sep [BI PROP] {P Q : PROP} : <absorb> (P ∗ Q) ⊣⊢ <absorb> P ∗ <absorb> Q
end Iris.BI

namespace Iris.BI
theorem absorbingly_emp [BI PROP] : <absorb> (emp : PROP) ⊣⊢ True
end Iris.BI

namespace Iris.BI
theorem absorbingly_wand_1 [BI PROP] {P Q : PROP} : <absorb> (P -∗ Q) ⊢ <absorb> P -∗ <absorb> Q
end Iris.BI

namespace Iris.BI
theorem absorbingly_sep_l [BI PROP] {P Q : PROP} : <absorb> P ∗ Q ⊣⊢ <absorb> (P ∗ Q)
end Iris.BI

namespace Iris.BI
theorem absorbingly_sep_r [BI PROP] {P Q : PROP} : P ∗ <absorb> Q ⊣⊢ <absorb> (P ∗ Q)
end Iris.BI

namespace Iris.BI
theorem absorbingly_sep_lr [BI PROP] {P Q : PROP} : <absorb> P ∗ Q ⊣⊢ P ∗ <absorb> Q
end Iris.BI

namespace Iris.BI
theorem affinely_absorbingly [BI PROP] [BIPositive PROP] {P : PROP} :
    <affine> <absorb> P ⊣⊢ <affine> P
end Iris.BI

namespace Iris.BI
theorem affine_affinely [BI PROP] (P : PROP) [Affine P] : <affine> P ⊣⊢ P
end Iris.BI

namespace Iris.BI
theorem biaffine_iff_true_emp [BI PROP] : BIAffine PROP ↔ (True : PROP) ⊢ emp
end Iris.BI

namespace Iris.BI
theorem biaffine_of_true_affine [BI PROP] [Affine (iprop(True) : PROP)] : BIAffine PROP
end Iris.BI

namespace Iris.BI
theorem absorbing_absorbingly [BI PROP] {P : PROP} [Absorbing P] : <absorb> P ⊣⊢ P
end Iris.BI

namespace Iris.BI
theorem absorbing_of_emp_absorbing [BI PROP] [Absorbing (emp : PROP)] (P : PROP) : Absorbing P
end Iris.BI

namespace Iris.BI
theorem sep_elim_l [BI PROP] {P Q : PROP} : [TCOr (Affine Q) (Absorbing P)] → P ∗ Q ⊢ P
end Iris.BI

namespace Iris.BI
theorem sep_elim_r [BI PROP] {P Q : PROP} [TCOr (Affine P) (Absorbing Q)] : P ∗ Q ⊢ Q
end Iris.BI

namespace Iris.BI
theorem sep_and [BI PROP] {P Q : PROP}
    [TCOr (Affine P) (Absorbing Q)] [TCOr (Affine Q) (Absorbing P)] : P ∗ Q ⊢ P ∧ Q
end Iris.BI

namespace Iris.BI
theorem affinely_intro [BI PROP] {P Q : PROP} [Affine P] (h : P ⊢ Q) : P ⊢ <affine> Q
end Iris.BI

namespace Iris.BI
theorem emp_and [BI PROP] {P : PROP} [Affine P] : emp ∧ P ⊣⊢ P
end Iris.BI

namespace Iris.BI
theorem and_emp [BI PROP] {P : PROP} [Affine P] : P ∧ emp ⊣⊢ P
end Iris.BI

namespace Iris.BI
theorem emp_or [BI PROP] {P : PROP} [Affine P] : emp ∨ P ⊣⊢ emp
end Iris.BI

namespace Iris.BI
theorem or_emp [BI PROP] {P : PROP} [Affine P] : P ∨ emp ⊣⊢ emp
end Iris.BI

namespace Iris.BI
theorem true_emp [BI PROP] [h : BIAffine PROP] : (True : PROP) ⊣⊢ emp
end Iris.BI

namespace Iris.BI
theorem true_sep [BI PROP] {P : PROP} [Absorbing P] : True ∗ P ⊣⊢ P
end Iris.BI

namespace Iris.BI
theorem sep_true [BI PROP] {P : PROP} [Absorbing P] : P ∗ True ⊣⊢ P
end Iris.BI

namespace Iris.BI
theorem imp_wand_1 [BI PROP] [BIAffine PROP] {P Q : PROP} : (P → Q) ⊢ P -∗ Q
end Iris.BI

namespace Iris.BI
theorem pure_sep [BI PROP] {φ1 φ2 : Prop} : ⌜φ1⌝ ∗ (⌜φ2⌝ : PROP) ⊣⊢ ⌜φ1 ∧ φ2⌝
end Iris.BI

namespace Iris.BI
theorem pure_wand_2 [BI PROP] {φ1 φ2 : Prop} : ⌜φ1 → φ2⌝ ⊢ (⌜φ1⌝ -∗ (⌜φ2⌝ : PROP))
end Iris.BI

namespace Iris.BI
theorem pure_wand [BI PROP] {φ1 φ2 : Prop} : (⌜φ1⌝ -∗ (⌜φ2⌝ : PROP)) ⊣⊢ ⌜φ1 → φ2⌝
end Iris.BI

namespace Iris.BI
@[rw_mono_rule]
theorem persistently_congr [BI PROP] {P P' : PROP} (h : P ⊣⊢ P') :
    <pers> P ⊣⊢ <pers> P'
end Iris.BI

namespace Iris.BI
theorem persistently_absorb_r [BI PROP] {P Q : PROP} : P ∗ <pers> Q ⊢ <pers> Q
end Iris.BI

namespace Iris.BI
theorem absorbingly_persistently [BI PROP] {P : PROP} : <absorb> <pers> P ⊣⊢ <pers> P
end Iris.BI

namespace Iris.BI
theorem persistently_forall_1 [BI PROP] {Ψ : α → PROP} : <pers> (∀ a, Ψ a) ⊢ ∀ a, <pers> (Ψ a)
end Iris.BI

namespace Iris.BI
theorem persistently_forall [BI PROP] [h : BIPersistentlyForall PROP] {Ψ : α → PROP} :
    <pers> (∀ a, Ψ a) ⊣⊢ ∀ a, <pers> (Ψ a)
end Iris.BI

namespace Iris.BI
theorem persistently_exists [BI PROP] {Ψ : α → PROP} : <pers> (∃ a, Ψ a) ⊣⊢ ∃ a, <pers> (Ψ a)
end Iris.BI

namespace Iris.BI
theorem persistently_and [BI PROP] {P Q : PROP} : <pers> (P ∧ Q) ⊣⊢ <pers> P ∧ <pers> Q
end Iris.BI

namespace Iris.BI
theorem persistently_ite {p : Bool} [BI PROP] {P Q : PROP} :
    iprop(<pers> if p then P else Q) = iprop(if p then <pers> P else <pers> Q)
end Iris.BI

namespace Iris.BI
theorem persistently_or [BI PROP] {P Q : PROP} : <pers> (P ∨ Q) ⊣⊢ <pers> P ∨ <pers> Q
end Iris.BI

namespace Iris.BI
theorem persistently_imp_1 [BI PROP] {P Q : PROP} : <pers> (P → Q) ⊢ (<pers> P → <pers> Q)
end Iris.BI

namespace Iris.BI
theorem persistently_emp_intro [BI PROP] {P : PROP} : P ⊢ <pers> emp
end Iris.BI

namespace Iris.BI
theorem persistently_emp [BI PROP] : <pers> (emp : PROP) ⊣⊢ True
end Iris.BI

namespace Iris.BI
theorem persistently_true [BI PROP] : <pers> (True : PROP) ⊣⊢ True
end Iris.BI

namespace Iris.BI
theorem persistently_affinely [BI PROP] {P : PROP} : <pers> <affine> P ⊣⊢ <pers> P
end Iris.BI

namespace Iris.BI
theorem persistently_and_affinely_sep [BI PROP] {P Q : PROP} : <pers> P ∧ Q ⊢ <affine> P ∗ Q
end Iris.BI

namespace Iris.BI
theorem persistently_and_sep_assoc [BI PROP] {P Q R : PROP} :
    <pers> P ∧ (Q ∗ R) ⊣⊢ (<pers> P ∧ Q) ∗ R
end Iris.BI

namespace Iris.BI
theorem intuitionistically_elim [BI PROP] {P : PROP} : □ P ⊢ P
end Iris.BI

namespace Iris.BI
theorem absorbingly_of_persistently [BI PROP] {P : PROP} : <pers> P ⊢ <absorb> P
end Iris.BI

namespace Iris.BI
theorem persistently_elim [BI PROP] {P : PROP} [Absorbing P] : <pers> P ⊢ P
end Iris.BI

namespace Iris.BI
theorem persistently_idem [BI PROP] {P : PROP} : <pers> <pers> P ⊣⊢ <pers> P
end Iris.BI

namespace Iris.BI
theorem persistently_intro' [BI PROP] {P Q : PROP} (h : <pers> P ⊢ Q) : <pers> P ⊢ <pers> Q
end Iris.BI

namespace Iris.BI
theorem persistently_pure {φ : Prop} [BI PROP] : <pers> ⌜φ⌝ ⊣⊢ (⌜φ⌝ : PROP)
end Iris.BI

namespace Iris.BI
theorem persistently_and_imp_sep [BI PROP] {P Q : PROP} : <pers> P ∧ Q ⊢ <pers> P ∗ Q
end Iris.BI

namespace Iris.BI
theorem and_persistently_imp_sep [BI PROP] {P Q : PROP} : P ∧ <pers> Q ⊢ P ∗ <pers> Q
end Iris.BI

namespace Iris.BI
theorem persistently_sep_persistently [BI PROP] {P : PROP} : <pers> P ∗ <pers> P ⊣⊢ <pers> P
end Iris.BI

namespace Iris.BI
theorem persistently_and_sep [BI PROP] {P Q : PROP} : <pers> (P ∧ Q) ⊢ <pers> (P ∗ Q)
end Iris.BI

namespace Iris.BI
theorem persistently_and_persistently_sep [BI PROP] {P Q : PROP} :
    <pers> P ∧ <pers> Q ⊣⊢ <pers> P ∗ <pers> Q
end Iris.BI

namespace Iris.BI
theorem persistently_sep_2 [BI PROP] {P Q : PROP} : <pers> P ∗ <pers> Q ⊢ <pers> (P ∗ Q)
end Iris.BI

namespace Iris.BI
theorem persistently_sep [BI PROP] [BIPositive PROP] {P Q : PROP} :
    <pers> (P ∗ Q) ⊣⊢ <pers> P ∗ <pers> Q
end Iris.BI

namespace Iris.BI
theorem self_sep_persistently [BI PROP] {P : PROP} : P ∗ <pers> P ⊣⊢ <pers> P
end Iris.BI

namespace Iris.BI
theorem affinely_sep_persistently [BI PROP] {P : PROP} : <affine> P ∗ <pers> P ⊣⊢ <pers> P
end Iris.BI

namespace Iris.BI
theorem persistently_wand_1 [BI PROP] {P Q : PROP} : <pers> (P -∗ Q) ⊢ (<pers> P -∗ <pers> Q)
end Iris.BI

namespace Iris.BI
theorem persistently_entails_l [BI PROP] {P Q : PROP} (h : P ⊢ <pers> Q) : P ⊢ <pers> Q ∗ P
end Iris.BI

namespace Iris.BI
theorem persistently_entails_r [BI PROP] {P Q : PROP} (h : P ⊢ <pers> Q) : P ⊢ P ∗ <pers> Q
end Iris.BI

namespace Iris.BI
theorem persistently_imp_wand_2 [BI PROP] {P Q : PROP} : <pers> (P -∗ Q) ⊢ <pers> (P → Q)
end Iris.BI

namespace Iris.BI
theorem imp_wand_persistently_2 [BI PROP] {P Q : PROP} : (<pers> P -∗ Q) ⊢ (<pers> P → Q)
end Iris.BI

namespace Iris.BI
theorem persistently_emp' [BI PROP] [BIAffine PROP] : <pers> (emp : PROP) ⊣⊢ emp
end Iris.BI

namespace Iris.BI
theorem persistently_and_iff_sep [BI PROP] [BIAffine PROP] {P Q : PROP} :
    <pers> P ∧ Q ⊣⊢ <pers> P ∗ Q
end Iris.BI

namespace Iris.BI
theorem and_persistently_iff_sep [BI PROP] [BIAffine PROP] {P Q : PROP} :
    P ∧ <pers> Q ⊣⊢ P ∗ <pers> Q
end Iris.BI

namespace Iris.BI
theorem persistently_imp_wand [BI PROP] [BIAffine PROP] {P Q : PROP} :
    <pers> (P → Q) ⊣⊢ <pers> (P -∗ Q)
end Iris.BI

namespace Iris.BI
theorem imp_wand_persistently [BI PROP] [BIAffine PROP] {P Q : PROP} :
    (<pers> P → Q) ⊣⊢ (<pers> P -∗ Q)
end Iris.BI

namespace Iris.BI
theorem wand_iff_exists_persistently [BI PROP] [BIAffine PROP] {P Q : PROP} :
    (P -∗ Q) ⊣⊢ ∃ R, R ∗ <pers> (P ∗ R → Q)
end Iris.BI

namespace Iris.BI
theorem persistently_and_emp {P : PROP} [BI PROP] : <pers> P ⊣⊢ <pers> (emp ∧ P)
end Iris.BI

namespace Iris.BI
theorem persistently_and_sep_elim_emp {P Q : PROP} [BI PROP] : <pers> P ∧ Q ⊢ (emp ∧ P) ∗ Q
end Iris.BI

namespace Iris.BI
theorem persistently_and_emp_elim {P : PROP} [BI PROP] : emp ∧ <pers> P ⊢ P
end Iris.BI

namespace Iris.BI
theorem sForall_persistent [BI PROP] [h : BIPersistentlyForall PROP] (Ψ : PROP → Prop)
    (H : ∀ p, Ψ p → Persistent p) : Persistent iprop(sForall Ψ)
end Iris.BI

namespace Iris.BI
theorem sExists_persistent [BI PROP] (Ψ : PROP → Prop)
    (H : ∀ p, Ψ p → Persistent p) : Persistent iprop(sExists Ψ)
end Iris.BI

namespace Iris.BI
theorem intuitionistically_ne [BI PROP] : OFE.NonExpansive (@intuitionistically PROP _)
end Iris.BI

namespace Iris.BI
@[rw_mono_rule]
theorem intuitionistically_congr [BI PROP] {P Q : PROP} (h : P ⊣⊢ Q) : □ P ⊣⊢ □ Q
end Iris.BI

namespace Iris.BI
@[rw_mono_rule]
theorem intuitionistically_mono [BI PROP] {P Q : PROP} (h : P ⊢ Q) : □ P ⊢ □ Q
end Iris.BI

namespace Iris.BI
theorem intuitionistically_def [BI PROP] {P : PROP} : iprop(□ P) = iprop(<affine> <pers> P)
end Iris.BI

namespace Iris.BI
theorem intuitionistically_elim_emp [BI PROP] {P : PROP} : □ P ⊢ emp
end Iris.BI

namespace Iris.BI
theorem intuitionistically_emp [BI PROP] : □ emp ⊣⊢ (emp : PROP)
end Iris.BI

namespace Iris.BI
theorem intuitionistically_false [BI PROP] : □ False ⊣⊢ (False : PROP)
end Iris.BI

namespace Iris.BI
theorem intuitionistically_true [BI PROP] : □ True ⊣⊢ (emp : PROP)
end Iris.BI

namespace Iris.BI
theorem intuitionistically_and [BI PROP] {P Q : PROP} : □ (P ∧ Q) ⊣⊢ □ P ∧ □ Q
end Iris.BI

namespace Iris.BI
theorem intuitionistically_forall_1 [BI PROP] {Φ : α → PROP} : □ (∀ x, Φ x) ⊢ ∀ x, □ Φ x
end Iris.BI

namespace Iris.BI
theorem intuitionistically_or [BI PROP] {P Q : PROP} : □ (P ∨ Q) ⊣⊢ □ P ∨ □ Q
end Iris.BI

namespace Iris.BI
theorem intuitionistically_exists [BI PROP] {Φ : α → PROP} : □ (∃ x, Φ x) ⊣⊢ ∃ x, □ Φ x
end Iris.BI

namespace Iris.BI
theorem intuitionistically_sep_2 [BI PROP] {P Q : PROP} : □ P ∗ □ Q ⊢ □ (P ∗ Q)
end Iris.BI

namespace Iris.BI
theorem intuitionistically_sep [BI PROP] [BIPositive PROP] {P Q : PROP} : □ (P ∗ Q) ⊣⊢ □ P ∗ □ Q
end Iris.BI

namespace Iris.BI
theorem intuitionistically_idem [BI PROP] {P : PROP} : □ □ P ⊣⊢ □ P
end Iris.BI

namespace Iris.BI
theorem intuitionistically_intro' [BI PROP] {P Q : PROP} (h : □ P ⊢ Q) : □ P ⊢ □ Q
end Iris.BI

namespace Iris.BI
theorem persistently_of_intuitionistically [BI PROP] {P : PROP} : □ P ⊢ <pers> P
end Iris.BI

namespace Iris.BI
theorem intuitionistically_persistently [BI PROP] {P : PROP} : □ <pers> P ⊣⊢ □ P
end Iris.BI

namespace Iris.BI
theorem intuitionistically_of_intuitionistic [BI PROP] {P : PROP} [Affine P] [Persistent P] :
    □ P ⊣⊢ P
end Iris.BI

namespace Iris.BI
theorem affinely_of_intuitionistically [BI PROP] {P : PROP} : □ P ⊢ <affine> P
end Iris.BI

namespace Iris.BI
theorem intuitionistically_affinely [BI PROP] {P : PROP} : □ <affine> P ⊣⊢ □ P
end Iris.BI

namespace Iris.BI
theorem persistently_and_intuitionistically_sep_l [BI PROP] {P Q : PROP} :
    <pers> P ∧ Q ⊣⊢ □ P ∗ Q
end Iris.BI

namespace Iris.BI
theorem persistently_and_intuitionistically_sep_r [BI PROP] {P Q : PROP} :
    P ∧ <pers> Q ⊣⊢ P ∗ □ Q
end Iris.BI

namespace Iris.BI
theorem and_sep_intuitionistically [BI PROP] {P Q : PROP} : □ P ∧ □ Q ⊣⊢ □ P ∗ □ Q
end Iris.BI

namespace Iris.BI
theorem intuitionistically_and_sep [BI PROP] {P Q : PROP} : □ (P ∧ Q) ⊣⊢ □ P ∗ □ Q
end Iris.BI

namespace Iris.BI
theorem intuitionistically_sep_idem [BI PROP] {P : PROP} : □ P ∗ □ P ⊣⊢ □ P
end Iris.BI

namespace Iris.BI
theorem intuitionistically_wand [BI PROP] {P Q : PROP} : (□ P -∗ Q) ⊣⊢ (<pers> P → Q)
end Iris.BI

namespace Iris.BI
theorem affinely_self_sep_intuitionistically [BI PROP] {P : PROP} :
    <affine> (P ∗ □ P) ⊣⊢ □ P
end Iris.BI

namespace Iris.BI
theorem intuitionistically_imp_wand_2 [BI PROP] {P Q : PROP} : □ (P -∗ Q) ⊢ □ (P → Q)
end Iris.BI

namespace Iris.BI
theorem imp_iff_exists_persistently [BI PROP] [BIAffine PROP] {P Q : PROP} :
    (P → Q) ⊣⊢ ∃ R, R ∧ <pers> (P ∧ R -∗ Q)
end Iris.BI

namespace Iris.BI
theorem intuitionistically_iff_persistently [BI PROP] [BIAffine PROP]
    {P : PROP} : □ P ⊣⊢ <pers> P
end Iris.BI

namespace Iris.BI
@[simp] theorem affinelyIf_false [BI PROP] (P : PROP) : iprop(<affine>?false P) = P
end Iris.BI

namespace Iris.BI
@[simp] theorem affinelyIf_true [BI PROP] (P : PROP) :
    iprop(<affine>?true P) = iprop(<affine> P)
end Iris.BI

namespace Iris.BI
theorem affinelyIf_ne {p : Bool} [BI PROP] : OFE.NonExpansive (affinelyIf (PROP := PROP) p)
end Iris.BI

namespace Iris.BI
@[rw_mono_rule]
theorem affinelyIf_mono {p : Bool} [BI PROP] {P Q : PROP}
    (h : P ⊢ Q) : <affine>?p P ⊢ <affine>?p Q
end Iris.BI

namespace Iris.BI
@[rw_mono_rule]
theorem affinelyIf_congr {p : Bool} [BI PROP] {P Q : PROP} (h : P ⊣⊢ Q) :
    <affine>?p P ⊣⊢ <affine>?p Q
end Iris.BI

namespace Iris.BI
theorem affinelyIf_flag_mono {p q : Bool} [BI PROP] {P : PROP} (h : q → p) :
    <affine>?p P ⊢ <affine>?q P
end Iris.BI

namespace Iris.BI
theorem affinelyIf_elim {p : Bool} [BI PROP] {P : PROP} : <affine>?p P ⊢ P
end Iris.BI

namespace Iris.BI
theorem affinely_affinelyIf {p : Bool} [BI PROP] {P : PROP} : <affine> P ⊢ <affine>?p P
end Iris.BI

namespace Iris.BI
theorem affinelyIf_intro' {p : Bool} [BI PROP] {P Q : PROP} :
    (P ⊢ <affine>?p Q) → <affine>?p P ⊢ <affine>?p Q
end Iris.BI

namespace Iris.BI
theorem affinelyIf_emp {p : Bool} [BI PROP] : (<affine>?p emp : PROP) ⊣⊢ emp
end Iris.BI

namespace Iris.BI
theorem affinelyIf_and {p : Bool} [BI PROP] {P Q : PROP} :
    <affine>?p (P ∧ Q) ⊣⊢ <affine>?p P ∧ <affine>?p Q
end Iris.BI

namespace Iris.BI
theorem affinelyIf_or {p : Bool} [BI PROP] {P Q : PROP} :
    <affine>?p (P ∨ Q) ⊣⊢ <affine>?p P ∨ <affine>?p Q
end Iris.BI

namespace Iris.BI
theorem affinelyIf_exists {p : Bool} [BI PROP] {Ψ : α → PROP} :
    <affine>?p (∃ a, Ψ a) ⊣⊢ ∃ a, <affine>?p (Ψ a)
end Iris.BI

namespace Iris.BI
theorem affinelyIf_forall_1 {p : Bool} [BI PROP] {Ψ : α → PROP} :
    <affine>?p (∀ a, Ψ a) ⊢ ∀ a, <affine>?p (Ψ a)
end Iris.BI

namespace Iris.BI
theorem affinelyIf_sep_2 {p : Bool} [BI PROP] {P Q : PROP} :
    <affine>?p P ∗ <affine>?p Q ⊢ <affine>?p (P ∗ Q)
end Iris.BI

namespace Iris.BI
theorem affinelyIf_sep {p : Bool} [BI PROP] [BIPositive PROP] {P Q : PROP} :
    <affine>?p (P ∗ Q) ⊣⊢ <affine>?p P ∗ <affine>?p Q
end Iris.BI

namespace Iris.BI
theorem affinelyIf_idem {p : Bool} [BI PROP] [BIPositive PROP] {P : PROP} :
    <affine>?p <affine>?p P ⊣⊢ <affine>?p P
end Iris.BI

namespace Iris.BI
theorem affinelyIf_and_l {p : Bool} [BI PROP] {P Q : PROP} :
    <affine>?p P ∧ Q ⊣⊢ <affine>?p (P ∧ Q)
end Iris.BI

namespace Iris.BI
theorem affinelyIf_and_r {p : Bool} [BI PROP] {P Q : PROP} :
    P ∧ <affine>?p Q ⊣⊢ <affine>?p (P ∧ Q)
end Iris.BI

namespace Iris.BI
theorem affinelyIf_and_lr {p : Bool} [BI PROP] {P Q : PROP} :
    <affine>?p P ∧ Q ⊣⊢ P ∧ <affine>?p Q
end Iris.BI

namespace Iris.BI
@[simp] theorem absorbinglyIf_false [BI PROP] (P : PROP) : iprop(<absorb>?false P) = P
end Iris.BI

namespace Iris.BI
@[simp] theorem absorbinglyIf_true [BI PROP] (P : PROP) :
    iprop(<absorb>?true P) = iprop(<absorb> P)
end Iris.BI

namespace Iris.BI
theorem absorbinglyIf_ne {p : Bool} [BI PROP] : OFE.NonExpansive (absorbinglyIf (PROP := PROP) p)
end Iris.BI

namespace Iris.BI
@[rw_mono_rule]
theorem absorbinglyIf_mono {p : Bool} [BI PROP] {P Q : PROP} (h : P ⊢ Q) :
    <absorb>?p P ⊢ <absorb>?p Q
end Iris.BI

namespace Iris.BI
@[rw_mono_rule]
theorem absorbinglyIf_congr {p : Bool} [BI PROP] {P Q : PROP} (h : P ⊣⊢ Q) :
    <absorb>?p P ⊣⊢ <absorb>?p Q
end Iris.BI

namespace Iris.BI
theorem absorbingly_of_absorbinglyIf {p : Bool} [BI PROP] {P : PROP} : <absorb>?p P ⊢ <absorb> P
end Iris.BI

namespace Iris.BI
theorem absorbinglyIf_intro {p : Bool} [BI PROP] {P : PROP} : P ⊢ <absorb>?p P
end Iris.BI

namespace Iris.BI
theorem absorbinglyIf_flag_mono {p q : Bool} [BI PROP] {P : PROP} (h : p → q) :
    <absorb>?p P ⊢ <absorb>?q P
end Iris.BI

namespace Iris.BI
theorem absorbinglyIf_idem {p : Bool} [BI PROP] {P : PROP} :
    <absorb>?p <absorb>?p P ⊣⊢ <absorb>?p P
end Iris.BI

namespace Iris.BI
theorem absorbinglyIf_pure {p : Bool} [BI PROP] {φ : Prop} : (<absorb>?p ⌜φ⌝ : PROP) ⊣⊢ ⌜φ⌝
end Iris.BI

namespace Iris.BI
theorem absorbinglyIf_or {p : Bool} [BI PROP] {P Q : PROP} :
    <absorb>?p (P ∨ Q) ⊣⊢ <absorb>?p P ∨ <absorb>?p Q
end Iris.BI

namespace Iris.BI
theorem absorbinglyIf_and_1 {p : Bool} [BI PROP] {P Q : PROP} :
    <absorb>?p (P ∧ Q) ⊢ <absorb>?p P ∧ <absorb>?p Q
end Iris.BI

namespace Iris.BI
theorem absorbinglyIf_forall_1 {p : Bool} [BI PROP] {Φ : α → PROP} :
    <absorb>?p (∀ a, Φ a) ⊢ ∀ a, <absorb>?p (Φ a)
end Iris.BI

namespace Iris.BI
theorem absorbinglyIf_exists {p : Bool} [BI PROP] {Φ : α → PROP} :
    <absorb>?p (∃ a, Φ a) ⊣⊢ ∃ a, <absorb>?p (Φ a)
end Iris.BI

namespace Iris.BI
theorem absorbinglyIf_sep {p : Bool} [BI PROP] {P Q : PROP} :
    <absorb>?p (P ∗ Q) ⊣⊢ <absorb>?p P ∗ <absorb>?p Q
end Iris.BI

namespace Iris.BI
theorem absorbinglyIf_wand_1 {p : Bool} [BI PROP] {P Q : PROP} :
    <absorb>?p (P -∗ Q) ⊢ (<absorb>?p P -∗ <absorb>?p Q)
end Iris.BI

namespace Iris.BI
theorem absorbinglyIf_sep_l {p : Bool} [BI PROP] {P Q : PROP} :
    <absorb>?p P ∗ Q ⊣⊢ <absorb>?p (P ∗ Q)
end Iris.BI

namespace Iris.BI
theorem absorbinglyIf_sep_r {p : Bool} [BI PROP] {P Q : PROP} :
    P ∗ <absorb>?p Q ⊣⊢ <absorb>?p (P ∗ Q)
end Iris.BI

namespace Iris.BI
theorem absorbinglyIf_sep_lr {p : Bool} [BI PROP] {P Q : PROP} :
    <absorb>?p P ∗ Q ⊣⊢ P ∗ <absorb>?p Q
end Iris.BI

namespace Iris.BI
theorem affinelyIf_absorbinglyIf {p : Bool} [BI PROP] [BIPositive PROP] {P : PROP} :
    <affine>?p <absorb>?p P ⊣⊢ <affine>?p P
end Iris.BI

namespace Iris.BI
@[simp] theorem persistentlyIf_false [BI PROP] (P : PROP) : iprop(<pers>?false P) = P
end Iris.BI

namespace Iris.BI
@[simp] theorem persistentlyIf_true [BI PROP] (P : PROP) :
    iprop(<pers>?true P) = iprop(<pers> P)
end Iris.BI

namespace Iris.BI
theorem persistentlyIf_ne {p : Bool} [BI PROP] :
    OFE.NonExpansive (persistentlyIf (PROP := PROP) p)
end Iris.BI

namespace Iris.BI
@[rw_mono_rule]
theorem persistentlyIf_mono {p : Bool} [BI PROP] {P Q : PROP} (h : P ⊢ Q) :
    <pers>?p P ⊢ <pers>?p Q
end Iris.BI

namespace Iris.BI
@[rw_mono_rule]
theorem persistentlyIf_congr {p : Bool} [BI PROP] {P Q : PROP} (h : P ⊣⊢ Q) :
    <pers>?p P ⊣⊢ <pers>?p Q
end Iris.BI

namespace Iris.BI
theorem persistentlyIf_pure {p : Bool} [BI PROP] {φ : Prop} : (<pers>?p ⌜φ⌝ : PROP) ⊣⊢ ⌜φ⌝
end Iris.BI

namespace Iris.BI
theorem persistentlyIf_and {p : Bool} [BI PROP] {P Q : PROP} :
    <pers>?p (P ∧ Q) ⊣⊢ <pers>?p P ∧ <pers>?p Q
end Iris.BI

namespace Iris.BI
theorem persistentlyIf_or {p : Bool} [BI PROP] {P Q : PROP} :
    <pers>?p (P ∨ Q) ⊣⊢ <pers>?p P ∨ <pers>?p Q
end Iris.BI

namespace Iris.BI
theorem persistentlyIf_forall_1 {p : Bool} [BI PROP] {Φ : α → PROP} :
    <pers>?p (∀ a, Φ a) ⊢ ∀ a, <pers>?p (Φ a)
end Iris.BI

namespace Iris.BI
theorem persistentlyIf_exists {p : Bool} [BI PROP] {Φ : α → PROP} :
    <pers>?p (∃ a, Φ a) ⊣⊢ ∃ a, <pers>?p (Φ a)
end Iris.BI

namespace Iris.BI
theorem persistentlyIf_sep_2 {p : Bool} [BI PROP] {P Q : PROP} :
    <pers>?p P ∗ <pers>?p Q ⊢ <pers>?p (P ∗ Q)
end Iris.BI

namespace Iris.BI
theorem persistentlyIf_sep {p : Bool} [BI PROP] [BIPositive PROP] {P Q : PROP} :
    <pers>?p (P ∗ Q) ⊣⊢ <pers>?p P ∗ <pers>?p Q
end Iris.BI

namespace Iris.BI
theorem persistentlyIf_idem {p : Bool} [BI PROP] [BIPositive PROP] {P : PROP} :
    <pers>?p <pers>?p P ⊣⊢ <pers>?p P
end Iris.BI

namespace Iris.BI
theorem persistentlyIf_persistently {p : Bool} [BI PROP] {P : PROP} :
    <pers>?p <pers> P ⊣⊢ <pers> P
end Iris.BI

namespace Iris.BI
theorem persistentlyIf_intutitionistically {p : Bool} [BI PROP] {P : PROP} :
    <pers>?p □ P ⊢ <pers> P
end Iris.BI

namespace Iris.BI
@[simp] theorem intuitionisticallyIf_false' [BI PROP] (P : PROP) : iprop(□?false P) = P
end Iris.BI

namespace Iris.BI
@[simp] theorem intuitionisticallyIf_true [BI PROP] (P : PROP) : iprop(□?true P) = iprop(□ P)
end Iris.BI

namespace Iris.BI
theorem intuitionisticallyIf_ne {p : Bool} [BI PROP] :
    OFE.NonExpansive (intuitionisticallyIf (PROP := PROP) p)
end Iris.BI

namespace Iris.BI
@[rw_mono_rule]
theorem intuitionisticallyIf_mono {p : Bool} [BI PROP] {P Q : PROP} (h : P ⊢ Q) : □?p P ⊢ □?p Q
end Iris.BI

namespace Iris.BI
@[rw_mono_rule]
theorem intuitionisticallyIf_congr {p : Bool} [BI PROP] {P Q : PROP}
    (h : P ⊣⊢ Q) : □?p P ⊣⊢ □?p Q
end Iris.BI

namespace Iris.BI
theorem intuitionisticallyIf_flag_mono {p q : Bool} [BI PROP] {P : PROP} (h : q → p) :
    □?p P ⊢ □?q P
end Iris.BI

namespace Iris.BI
theorem intuitionisticallyIf_elim {p : Bool} [BI PROP] {P : PROP} : □?p P ⊢ P
end Iris.BI

namespace Iris.BI
theorem intuitionisticallyIf_of_intuitionistically (p : Bool) [BI PROP] {P : PROP} : □ P ⊢ □?p P
end Iris.BI

namespace Iris.BI
theorem intuitionisticallyIf_intro' {p : Bool} [BI PROP] {P Q : PROP} :
    (□?p P ⊢ Q) → □?p P ⊢ □?p Q
end Iris.BI

namespace Iris.BI
theorem intuitionisticallyIf_emp {p : Bool} [BI PROP] : (□?p emp : PROP) ⊣⊢ emp
end Iris.BI

namespace Iris.BI
theorem intuitionisticallyIf_false {p : Bool} [BI PROP] : (□?p False : PROP) ⊣⊢ False
end Iris.BI

namespace Iris.BI
theorem intuitionisticallyIf_and {p : Bool} [BI PROP] {P Q : PROP} : □?p (P ∧ Q) ⊣⊢ □?p P ∧ □?p Q
end Iris.BI

namespace Iris.BI
theorem intuitionisticallyIf_or (p : Bool) [BI PROP] {P Q : PROP} : □?p (P ∨ Q) ⊣⊢ □?p P ∨ □?p Q
end Iris.BI

namespace Iris.BI
theorem intuitionisticallyIf_exists {p : Bool} [BI PROP] {Ψ : α → PROP} :
    (□?p ∃ a, Ψ a) ⊣⊢ ∃ a, □?p Ψ a
end Iris.BI

namespace Iris.BI
theorem intuitionisticallyIf_sep_2 {p : Bool} [BI PROP] {P Q : PROP} :
    □?p P ∗ □?p Q ⊢ □?p (P ∗ Q)
end Iris.BI

namespace Iris.BI
theorem intuitionisticallyIf_sep {p : Bool} [BI PROP] [BIPositive PROP] {P Q : PROP} :
    □?p (P ∗ Q) ⊣⊢ □?p P ∗ □?p Q
end Iris.BI

namespace Iris.BI
theorem intuitionisticallyIf_idem {p : Bool} [BI PROP] {P : PROP} : □?p □?p P ⊣⊢ □?p P
end Iris.BI

namespace Iris.BI
theorem intuitionisticallyIf_def' {p : Bool} [BI PROP] {P : PROP} :
    iprop(□?p P) = iprop(<affine>?p <pers>?p P)
end Iris.BI

namespace Iris.BI
theorem intuitionisticallyIf_comm {p q : Bool} [BI PROP] {P : PROP} :
    iprop(□?p □?q P) = iprop(□?q □?p P)
end Iris.BI

namespace Iris.BI
theorem intuitionisticallyIf_comm' {p q : Bool} [BI PROP] {P : PROP} :
    □?p □?q P ⊣⊢ □?q □?p P
end Iris.BI

namespace Iris.BI
theorem intuitionisticallyIf_affinely {p : Bool} [BI PROP] {P : PROP} :
    □?p <affine> P ⊣⊢ <affine> □?p P
end Iris.BI

namespace Iris.BI
theorem intuitionisticallyIf_intutitionistically {p : Bool} [BI PROP] {P : PROP} : □?p □ P ⊣⊢ □ P
end Iris.BI

namespace Iris.BI
theorem affinelyIf_of_intuitionisticallyIf {p : Bool} [BI PROP] {P : PROP} : □?p P ⊢ <affine>?p P
end Iris.BI

namespace Iris.BI
theorem persistent_congr [BI PROP] {P Q : PROP} (H : P ⊣⊢ Q) : Persistent P ↔ Persistent Q
end Iris.BI

namespace Iris.BI
theorem persistently_intro [BI PROP] {P : PROP} [Persistent P] : P ⊢ <pers> P
end Iris.BI

namespace Iris.BI
theorem persistently_iff [BI PROP] {P : PROP} [Persistent P] [Absorbing P] :
    <pers> P ⊣⊢ P
end Iris.BI

namespace Iris.BI
theorem persistently_intro'' [BI PROP] {P : PROP} [Persistent P] (h : P ⊢ Q) : P ⊢ <pers> Q
end Iris.BI

namespace Iris.BI
theorem persistent_and_affinely_sep_l_1 [BI PROP] {P Q : PROP} [Persistent P] :
    P ∧ Q ⊢ <affine> P ∗ Q
end Iris.BI

namespace Iris.BI
theorem persistent_and_affinely_sep_r_1 [BI PROP] {P Q : PROP} [Persistent Q] :
    P ∧ Q ⊢ P ∗ <affine> Q
end Iris.BI

namespace Iris.BI
theorem persistent_and_affinely_sep_l [BI PROP] {P Q : PROP} [Persistent P] [Absorbing P] :
    P ∧ Q ⊣⊢ <affine> P ∗ Q
end Iris.BI

namespace Iris.BI
theorem persistent_and_affinely_sep_r [BI PROP] {P Q : PROP} [Persistent Q] [Absorbing Q] :
    P ∧ Q ⊣⊢ P ∗ <affine> Q
end Iris.BI

namespace Iris.BI
theorem persistent_and_sep_1 [BI PROP] {P Q : PROP} :
    [TCOr (Persistent P) (Persistent Q)] → P ∧ Q ⊢ P ∗ Q
end Iris.BI

namespace Iris.BI
theorem absorbingly_intuitionistically [BI PROP] {P : PROP} : <absorb> □ P ⊣⊢ <pers> P
end Iris.BI

namespace Iris.BI
theorem absorbingly_affinely_intro_of_persistent [BI PROP] {P : PROP} [Persistent P] :
    P ⊢ <absorb> <affine> P
end Iris.BI

namespace Iris.BI
theorem bigOp_sep_nil [BI PROP] : iprop([∗] []) ⊣⊢ (emp : PROP)
end Iris.BI

namespace Iris.BI
theorem bigOp_and_nil [BI PROP] : iprop([∧] []) ⊣⊢ (True : PROP)
end Iris.BI

namespace Iris.BI
theorem bigOp_sep_cons [BI PROP] {P : PROP} {Ps : List PROP} :
    [∗] (P :: Ps) ⊣⊢ P ∗ [∗] Ps
end Iris.BI

namespace Iris.BI
theorem bigOp_and_cons [BI PROP] {P : PROP} {Ps : List PROP} :
    [∧] (P :: Ps) ⊣⊢ P ∧ [∧] Ps
end Iris.BI

namespace Iris.BI
theorem and_forall_bool [BI PROP] {P Q : PROP} :
    P ∧ Q ⊣⊢ «forall» (fun b : Bool => if b then P else Q)
end Iris.BI

namespace Iris.BI
theorem or_exists_bool [BI PROP] {P Q : PROP} :
    P ∨ Q ⊣⊢ «exists» (fun b : Bool => if b then P else Q)
end Iris.BI

namespace Iris.BI
theorem later_congr [BI PROP] {P Q : PROP} (h : P ⊣⊢ Q) : ▷ P ⊣⊢ ▷ Q
end Iris.BI

namespace Iris.BI
theorem later_true [BI PROP] : (▷ True ⊣⊢ (True : PROP))
end Iris.BI

namespace Iris.BI
theorem later_emp [BI PROP] [BIAffine PROP] : (▷ emp ⊣⊢ (emp : PROP))
end Iris.BI

namespace Iris.BI
theorem later_forall_2 [BI PROP] {α} {Φ : α → PROP} : (∀ a, ▷ Φ a) ⊢ ▷ ∀ a, Φ a
end Iris.BI

namespace Iris.BI
theorem later_forall [BI PROP] {Φ : α → PROP} :
    ▷ (∀ a, Φ a) ⊣⊢ (∀ a, ▷ Φ a)
end Iris.BI

namespace Iris.BI
theorem later_exists_2 [BI PROP] {Φ : α → PROP} :
    (∃ a, ▷ Φ a) ⊢ ▷ (∃ a, Φ a)
end Iris.BI

namespace Iris.BI
theorem later_exists_false [BI PROP] {Φ : α → PROP} :
    (▷ ∃ a, Φ a) ⊢ ▷ False ∨ ∃ a, ▷ Φ a
end Iris.BI

namespace Iris.BI
theorem later_exists [BI PROP] [Inhabited α] {Φ : α → PROP} :
    (∃ a, ▷ Φ a) ⊣⊢ ▷ (∃ a, Φ a)
end Iris.BI

namespace Iris.BI
theorem later_and [BI PROP] {P Q : PROP} : ▷ (P ∧ Q) ⊣⊢ ▷ P ∧ ▷ Q
end Iris.BI

namespace Iris.BI
theorem later_or [BI PROP] {P Q : PROP} : ▷ (P ∨ Q) ⊣⊢ ▷ P ∨ ▷ Q
end Iris.BI

namespace Iris.BI
theorem later_impl [BI PROP] {P Q : PROP} : ▷ (P → Q) ⊢ ▷ P → ▷ Q
end Iris.BI

namespace Iris.BI
theorem later_wand [BI PROP] {P Q : PROP} : ▷ (P -∗ Q) ⊢ ▷ P -∗ ▷ Q
end Iris.BI

namespace Iris.BI
theorem later_iff [BI PROP] {P Q : PROP} : ▷ (P ↔ Q) ⊢ (▷ P ↔ ▷ Q)
end Iris.BI

namespace Iris.BI
theorem later_wand_iff [BI PROP] {P Q : PROP} : ▷ (P ∗-∗ Q) ⊢ ▷ P ∗-∗ ▷ Q
end Iris.BI

namespace Iris.BI
theorem later_affinely_2 [BI PROP] {P : PROP} : <affine> ▷ P ⊢ ▷ <affine> P
end Iris.BI

namespace Iris.BI
theorem later_intuitionistically_2 [BI PROP] {P : PROP} : □ ▷ P ⊢ ▷ □ P
end Iris.BI

namespace Iris.BI
theorem later_intuitionisticallyIf_2 [BI PROP] {P : PROP} : □?p ▷ P ⊢ ▷ □?p P
end Iris.BI

namespace Iris.BI
theorem later_absorbingly [BI PROP] {P : PROP} : ▷ <absorb> P ⊣⊢ <absorb> ▷ P
end Iris.BI

namespace Iris.BI
theorem later_affinely [BI PROP] [BIAffine PROP] {P : PROP} : <affine> ▷ P ⊣⊢ ▷ <affine> P
end Iris.BI

namespace Iris.BI
theorem later_intuitionistically [BI PROP] [BIAffine PROP] {P : PROP} : □ ▷ P ⊣⊢ ▷ □ P
end Iris.BI

namespace Iris.BI
theorem later_intuitionisticallyIf [BI PROP] [BIAffine PROP] {P : PROP} : □?p ▷ P ⊣⊢ ▷ □?p P
end Iris.BI

namespace Iris.BI
theorem entails_impl_true [BI PROP] {P Q : PROP} :
    (P ⊢ Q) ↔ iprop((True : PROP) ⊢ (P → Q))
end Iris.BI

namespace Iris.BI
theorem loeb [BI PROP] [BILoeb PROP] {P : PROP} : (▷ P → P) ⊢ P
end Iris.BI

namespace Iris.BI
theorem loeb_weak_of_strong [BI PROP] {P : PROP} (H : ∀ P : PROP, (▷ P → P) ⊢ P)
    (H' : ▷ P ⊢ P) : True ⊢ P
end Iris.BI

namespace Iris.BI
theorem loeb_wand_intuitionistically [BI PROP] [BILoeb PROP] {P : PROP} :
    □ (□ ▷ P -∗ P) ⊢ P
end Iris.BI

namespace Iris.BI
theorem loeb_wand [BI PROP] [BILoeb PROP] {P : PROP} : □ (▷ P -∗ P) ⊢ P
end Iris.BI

namespace Iris.ProofMode
theorem clear_spatial [BI PROP] {P P' A Q : PROP} [TCOr (Affine A) (Absorbing Q)]
    (h_rem : P ⊣⊢ P' ∗ A) (h : P' ⊢ Q) : P ⊢ Q
end Iris.ProofMode

namespace Iris.ProofMode
theorem clear_intuitionistic [BI PROP] {P P' A Q : PROP}
    (h_rem : P ⊣⊢ P' ∗ □ A) (h : P' ⊢ Q) : P ⊢ Q
end Iris.ProofMode

namespace Store
theorem eqv_of_Equiv [OFE V] [Store T K V] {t1 t2 : T} (H : Store.Equiv t1 t2) : t1 ≡ t2
end Store

namespace Store
theorem chain_get [Store T K V] [OFE V] (k : K) (c : Chain T) :
    (chain k c) i = get (c i) k
end Store

namespace Store
theorem lookup_incN {n} {m1 m2 : T} :
    (∃ (z : T), m2 ≡{n}≡ op m1 z) ↔
    ∀ i, (∃ z, (get m2 i) ≡{n}≡ (get m1 i) • z)
end Store

namespace Store
theorem lookup_inc {m1 m2 : T} :
    (∃ (z : T), m2 ≡ op m1 z) ↔
    ∀ i, (∃ z, (get m2 i) ≡ (get m1 i) • z)
end Store

namespace Heap
theorem validN_get_validN {m : T} (Hv : ✓{n} m) (He : get m i ≡{n}≡ some x) : ✓{n} x
end Heap

namespace Heap
theorem valid_get_valid {m : T} (Hv : ✓ m) (He : get m i ≡ some x) : ✓ x
end Heap

namespace Heap
theorem set_validN {m : T} (Hx : ✓{n} x) (Hm : ✓{n} m) : ✓{n} (set m i x)
end Heap

namespace Heap
theorem set_valid {m : T} (Hx : ✓ x) (Hm : ✓ m) : ✓ (set m i x)
end Heap

namespace Heap
theorem point_valid_iff : ✓ (point i x : T) ↔ ✓ x
end Heap

namespace Heap
theorem point_validN_iff : ✓{n} (point i x : T) ↔ ✓{n} x
end Heap

namespace Heap
theorem delete_validN {m : T} (Hv : ✓{n} m) : ✓{n} (delete m i)
end Heap

namespace Heap
theorem delete_valid {m : T} (Hv : ✓ m) : ✓ (delete m i)
end Heap

namespace Heap
theorem set_equiv_point_op_point {m : T} (Hemp : get m i = none) : Equiv (set m i x) (point i x • m)
end Heap

namespace Heap
theorem set_eq_point_op_point [IsoFunStore T K (Option V)] {m : T} (Hemp : get m i = none) :
    set m i x = point i x • m
end Heap

namespace Heap
theorem core_point_equiv {i : K} {x : V} {cx} (Hpcore : pcore x = some cx) :
    Equiv (T := T) (core <| point i (some x)) (point i (some cx))
end Heap

namespace Heap
theorem point_core_eq [IsoFunStore T K (Option V)] {i : K} {x : V} {cx} (Hpcore : pcore x = some cx) :
    core (point (T := T) i (some x)) = point i (some cx)
end Heap

namespace Heap
theorem point_core_eqv {i : K} {x : V} {cx} (Hpcore : pcore x ≡ some cx) :
    core (point (T := T) i (some x)) ≡ point i (some cx)
end Heap

namespace Heap
theorem point_core_total [IsTotal V] {i : K} {x : V} :
    Equiv (core <| point (T := T) i (some x)) ((point i (some (core x))))
end Heap

namespace Heap
theorem point_core_total_eq [IsTotal V] [IsoFunStore T K (Option V)] {i : K} {x : V} :
    core (point (T := T) i (some x)) = point i (some (core x))
end Heap

namespace Heap
theorem point_op_point {i : K} {x y : V} :
    Equiv ((point (T := T) i (some x)) • (point i (some y))) ((point i (some (x • y))))
end Heap

namespace Heap
theorem point_op_point_eq [IsoFunStore T K (Option V)] {i : K} {x y : V} :
    (point (T := T) i (some x)) • (point i (some y)) = (point i (some (x • y)))
end Heap

namespace Heap
theorem point_incN_iff {m : T} :
    (point (T := T) i (some x)) ≼{n} m ↔ ∃ y, (get m i ≡{n}≡ some y) ∧ some x ≼{n} some y
end Heap

namespace Heap
theorem point_inc_iff {m : T} :
    (point i (T := T) (some x)) ≼ m ↔ ∃ y, (get m i ≡ some y) ∧ some x ≼ some y
end Heap

namespace Heap
theorem exclusive_point_inc_iff {m : T} (He : Exclusive x) (Hv : ✓ m) :
    (point i (T := T) (some x)) ≼ m ↔ (get m i ≡ some x)
end Heap

namespace Heap
theorem point_inc_point_iff : (point i (T := T) (some x)) ≼ (point i (some y)) ↔ some x ≼ some y
end Heap

namespace Heap
theorem total_point_inc_point_iff [IsTotal V] : (point i (T := T) (some x)) ≼ (point i (some y)) ↔ x ≼ y
end Heap

namespace Heap
theorem point_inc_point_mono (Hinc : x ≼ y) : (point (T := T) i (some x)) ≼ (point i (some y))
end Heap

namespace Heap
theorem set_op_equiv {m1 m2 : T} :
    Equiv ((set (V := Option V) (m1 • m2) i (x • y))) (set m1 i x • set m2 i y)
end Heap

namespace Heap
theorem set_op_eq [IsoFunStore T K (Option V)] {m1 m2 : T} :
    (set (V := Option V) (m1 • m2) i (x • y)) = (set m1 i x • set m2 i y)
end Heap

namespace Heap
theorem disjoint_op_equiv_union {m1 m2 : T} (Hd : Set.Disjoint (dom m1) (dom m2)) :
    Equiv (m1 • m2) (union m1 m2)
end Heap

namespace Heap
theorem disjoint_op_eq_union [IsoFunStore T K (Option V)] {m1 m2 : T} (H : Set.Disjoint (dom m1) (dom m2)) :
    m1 • m2 = Heap.union m1 m2
end Heap

namespace Heap
theorem valid0_disjoint_dom {m1 m2 : T} (Hv : ✓{0} (m1 • m2)) (H : ∀ {k x}, get m1 k = some x → Exclusive x) :
    Set.Disjoint (dom m1) (dom m2)
end Heap

namespace Heap
theorem valid_disjoint_dom {m1 m2 : T} (Hv : ✓ (m1 • m2)) (H : ∀ {k x}, get m1 k = some x → Exclusive x) :
    Set.Disjoint (dom m1) (dom m2)
end Heap

namespace Heap
theorem dom_op_union (m1 m2 : T) : dom (m1 • m2) = Set.Union (dom m1) (dom m2)
end Heap

namespace Heap
theorem inc_dom_inc {m1 m2 : T} (Hinc : m1 ≼ m2) : Set.Included (dom m1) (dom m2)
end Heap

namespace Iris.ProofMode
theorem as_emp_valid_1 [BI PROP] (P : PROP) [AsEmpValid1 φ P] : φ → ⊢ P
end Iris.ProofMode

namespace Iris.ProofMode
theorem as_emp_valid_2 [BI PROP] (φ : Prop) [AsEmpValid2 φ (P : PROP)] : (⊢ P) → φ
end Iris.ProofMode

namespace Iris.Instances.Data
theorem empty_union {s : State Val} : s = ∅ ∪ s
end Iris.Instances.Data

namespace Iris.Instances.Data
theorem union_comm {a b : State Val} : a ∪ b = b ∪ a
end Iris.Instances.Data

namespace Iris.Instances.Data
theorem union_assoc {a b c : State Val} : (a ∪ b) ∪ c = a ∪ (b ∪ c)
end Iris.Instances.Data

namespace Iris.Instances.Data
theorem empty_disjoint {s : State Val} : ∅ |
end Iris.Instances.Data

namespace Iris.Instances.Data
theorem disjoint_comm {a b : State Val} : a |
end Iris.Instances.Data

namespace Iris.Instances.Data
theorem disjoint_assoc {a b c : State Val} : a ∪ b |
end Iris.Instances.Data

namespace Iris.Instances.Data
theorem disjoint_union {a b c : State Val} : a |
end Iris.Instances.Data

namespace Iris
theorem bupd_frame_l {P Q : PROP} : iprop(P ∗ |==> Q ⊢ |==> (P ∗ Q))
end Iris

namespace Iris
theorem bupd_wand_l {P Q : PROP} : iprop((P -∗ Q) ∗ (|==> P) ⊢ |==> Q)
end Iris

namespace Iris
theorem bupd_wand_r {P Q : PROP} : iprop((|==> P) ∗ (P -∗ Q) ⊢ |==> Q)
end Iris

namespace Iris
theorem bupd_sep {P Q : PROP} : iprop((|==> P) ∗ (|==> Q) ⊢ |==> (P ∗ Q))
end Iris

namespace Iris
theorem bupd_idem {P : PROP} : iprop((|==> |==> P) ⊣⊢ |==> P)
end Iris

namespace Iris
theorem bupd_or {P Q: PROP} : iprop((|==> P) ∨ (|==> Q) ⊢ |==> (P ∨ Q))
end Iris

namespace Iris
theorem bupd_and {P Q : PROP} : iprop((|==> (P ∧ Q)) ⊢ (|==> P) ∧ (|==> Q))
end Iris

namespace Iris
theorem bupd_exist {A : Type} {Φ : A → PROP} : (∃ x : A, |==> Φ x) ⊢ |==> ∃ x : A, Φ x
end Iris

namespace Iris
theorem bupd_forall {A : Type} {Φ : A → PROP} :
    iprop(|==> «forall» fun x : A => Φ x) ⊢ «forall» fun x : A => iprop(|==> Φ x)
end Iris

namespace Iris
theorem bupd_except0 {P : PROP} : iprop(◇ (|==> P) ⊢ (|==> ◇ P))
end Iris

namespace Iris
theorem bupd_elim {P : PROP} [Plain P] : |==> P ⊢ P
end Iris

namespace Iris
theorem bupd_plain_forall {A : Type} (Φ : A → PROP) [∀ x, Plain (Φ x)] :
    (|==> ∀ x, Φ x) ⊣⊢ (∀ x, |==> Φ x)
end Iris

namespace Iris.Fraction
theorem Proper.fractional_or_whole {a : α} (H : Proper a) : Fractional a ∨ Whole a
end Iris.Fraction

namespace Iris.Fraction
theorem Fractional.not_whole {a : α} (H : Fractional a) : ¬Whole a
end Iris.Fraction

namespace Iris.Fraction
theorem Whole.not_fractional {a : α} (H : Whole a) : ¬Fractional a
end Iris.Fraction

namespace Iris.Fraction
theorem add_right_cancel {a b c : α} (H : b + a = c + a) : b = c
end Iris.Fraction

namespace Iris.Fraction
theorem Fractional.proper {a : α} : Fractional a → Proper a
end Iris.Fraction

namespace Iris.Fraction
theorem Fractional.of_add_left {a a' : α} (H : Fractional (a + a')) : Fractional a
end Iris.Fraction

namespace Iris.Fraction
theorem Fractional.of_add_right {a a' : α} (H : Fractional (a + a')) : Fractional a'
end Iris.Fraction

namespace Iris
theorem le_rfl {a : α} : a ≤ a
end Iris

namespace Iris
theorem lt_trans {a b c : α} : a < b → b < c → a < c
end Iris

namespace Iris
theorem le_trans {a b c : α} : a ≤ b → b ≤ c → a ≤ c
end Iris

namespace Iris
theorem add_le_mono {a b c : α} : a + b ≤ c → a ≤ c
end Iris

namespace Iris
theorem lt_le {a b : α} : a < b → a ≤ b
end Iris

namespace Iris
theorem add_ne_self {a b : α} : a + b ≠ a
end Iris

namespace Iris
theorem not_add_lt_self {a b : α} : ¬a + b < a
end Iris

namespace Iris
theorem not_add_le_self {a b : α} : ¬ a + b ≤ a
end Iris

namespace Iris
theorem Frac.inc_iff_lt {p q : Frac α} : p ≼ q ↔ p < q
end Iris

namespace Iris
theorem Frac.le_of_inc {p q : Frac α} (H : p ≼ q) : p ≤ q
end Iris

theorem equivalence_eq : Equivalence (@Eq α)

namespace Iris.Std
theorem LawfulBigOp.right_id [LawfulBigOp (PROP := PROP) f unit eq] : eq (f a unit) a
end Iris.Std

namespace Iris.Std
theorem LawfulBigOp.congr_r [LawfulBigOp (PROP := PROP) f unit eq]
    (h : eq b b') : eq (f a b) (f a b')
end Iris.Std

namespace Iris.Std
theorem bigOp_nil {f : PROP → PROP → PROP} {unit : PROP} : bigOp f unit [] = unit
end Iris.Std

namespace Iris.Std
theorem bigOp_cons {f : PROP → PROP → PROP} {unit : PROP} [LawfulBigOp f unit eq] :
    eq (bigOp f unit (P :: Ps)) (f P (bigOp f unit Ps))
end Iris.Std

namespace Iris.ProofMode
theorem exists_intro' [BI PROP] {Φ : α → PROP} {P Q : PROP} [inst : FromExists Q Φ]
    (a : α) (h : P ⊢ Φ a) : P ⊢ Q
end Iris.ProofMode

namespace Iris
theorem own_whole_exclusive {w : F} (Hw : Whole w) : CMRA.Exclusive (own w)
end Iris

namespace Iris
theorem valid_own_one : ✓ own (One.one : F)
end Iris

namespace Iris
theorem valid_op_own {dq : DFrac F} {q : F} : ✓ dq • own q → Fractional q
end Iris

namespace Iris
theorem valid_own_op {dq : DFrac F} {q : F} : ✓ own q • dq → Fractional q
end Iris

namespace Iris
theorem valid_discard : ✓ (discard : DFrac F)
end Iris

namespace Iris
theorem valid_own_op_discard {q : F} : ✓ own q • discard ↔ Fractional q
end Iris

namespace Iris
theorem DFrac.is_discrete {q : DFrac F} : OFE.DiscreteE q
end Iris

namespace Iris
theorem DFrac.update_discard {dq : DFrac F} : dq ~~> .discard
end Iris

namespace Iris
theorem DFrac.update_acquire [IsSplitFraction F] :
    (.discard : DFrac F) ~~>: fun k => ∃ q, k = .own q
end Iris

namespace Nat
theorem eq_of_not_lt_not_lt {a b : Nat} : ¬(a < b) → ¬(b < a) → a = b
end Nat

namespace Iris.ProofMode
theorem specialize_wand [BI PROP] {q p : Bool} {A1 A2 A3 Q P1 P2 : PROP}
    (h1 : A1 ⊢ A2 ∗ □?q Q) (h2 : A2 ⊣⊢ A3 ∗ □?p P1)
    [inst : IntoWand q p Q P1 P2] : A1 ⊢ A3 ∗ □?(p && q) P2
end Iris.ProofMode

namespace Iris.ProofMode
theorem specialize_forall [BI PROP] {p : Bool} {A1 A2 P : PROP} {α : Sort _} {Φ : α → PROP}
    [inst : IntoForall P Φ] (h : A1 ⊢ A2 ∗ □?p P) (a : α) : A1 ⊢ A2 ∗ □?p (Φ a)
end Iris.ProofMode

namespace Iris
theorem pcore_op_mono_of_core_op_mono [OFE α] (op : α → α → α) (pcore : α → Option α)
    (h : (∀ x cx y : α, (∃ z, y ≡ op x z) → pcore x = some cx →
      ∃ cy, pcore y = some cy ∧ ∃ z, cy ≡ op cx z))
    (x cx) (e : pcore x = some cx) (y) : ∃ cy, pcore (op x y) ≡ some (op cx cy)
end Iris

namespace Iris.CMRA
theorem coreId_of_eqv {x₁ x₂ : α} (e : x₁ ≡ x₂) (h : CoreId x₁) : CoreId x₂
end Iris.CMRA

namespace Iris.CMRA
theorem coreId_iff {x₁ x₂ : α} (e : x₁ ≡ x₂) : CoreId x₁ ↔ CoreId x₂
end Iris.CMRA

namespace Iris.CMRA
theorem op_right_eqv (x : α) {y z : α} (e : y ≡ z) : x • y ≡ x • z
end Iris.CMRA

namespace Iris.CMRA
theorem _root_.Iris.OFE.Equiv.op_r {x y z : α} : y ≡ z → x • y ≡ x • z
end Iris.CMRA

namespace Iris.CMRA
theorem op_right_dist (x : α) {y z : α} (e : y ≡{n}≡ z) : x • y ≡{n}≡ x • z
end Iris.CMRA

namespace Iris.CMRA
theorem _root_.Iris.OFE.Dist.op_r {x y z : α} : y ≡{n}≡ z → x • y ≡{n}≡ x • z
end Iris.CMRA

namespace Iris.CMRA
theorem op_commN {x y : α} : x • y ≡{n}≡ y • x
end Iris.CMRA

namespace Iris.CMRA
theorem op_assocN {x y z : α} : x • (y • z) ≡{n}≡ (x • y) • z
end Iris.CMRA

namespace Iris.CMRA
theorem op_left_eqv {x y : α} (z : α) (e : x ≡ y) : x • z ≡ y • z
end Iris.CMRA

namespace Iris.CMRA
theorem _root_.Iris.OFE.Equiv.op_l {x y z : α} : x ≡ y → x • z ≡ y • z
end Iris.CMRA

namespace Iris.CMRA
theorem op_left_dist {x y : α} (z : α) (e : x ≡{n}≡ y) : x • z ≡{n}≡ y • z
end Iris.CMRA

namespace Iris.CMRA
theorem _root_.Iris.OFE.Dist.op_l {x y z : α} : x ≡{n}≡ y → x • z ≡{n}≡ y • z
end Iris.CMRA

namespace Iris.CMRA
theorem _root_.Iris.OFE.Dist.op {x x' y y' : α}
    (ex : x ≡{n}≡ x') (ey : y ≡{n}≡ y') : x • y ≡{n}≡ x' • y'
end Iris.CMRA

namespace Iris.CMRA
theorem op_eqv {x x' y y' : α} (ex : x ≡ x') (ey : y ≡ y') : x • y ≡ x' • y'
end Iris.CMRA

namespace Iris.CMRA
theorem _root_.Iris.OFE.Equiv.op : (x : α) ≡ x' → y ≡ y' → x • y ≡ x' • y'
end Iris.CMRA

namespace Iris.CMRA
theorem op_proper2 {x₁ x₂ y₁ y₂ : α} (H1 : x₁ ≡ x₂) (H2 : y₁ ≡ y₂) : x₁ • y₁ ≡ x₂ • y₂
end Iris.CMRA

namespace Iris.CMRA
theorem _root_.Iris.OFE.Dist.opM {x₁ x₂ : α} {y₁ y₂ : Option α}
    (H1 : x₁ ≡{n}≡ x₂) (H2 : y₁ ≡{n}≡ y₂) : x₁ •? y₁ ≡{n}≡ x₂ •? y₂
end Iris.CMRA

namespace Iris.CMRA
theorem _root_.Iris.OFE.Equiv.opM {x₁ x₂ : α} {y₁ y₂ : Option α}
    (H1 : x₁ ≡ x₂) (H2 : y₁ ≡ y₂) : x₁ •? y₁ ≡ x₂ •? y₂
end Iris.CMRA

namespace Iris.CMRA
theorem opM_left_eqv {x y : α} (z : Option α) (e : x ≡ y) : x •? z ≡ y •? z
end Iris.CMRA

namespace Iris.CMRA
theorem opM_right_eqv (x : α) {y z : Option α} (e : y ≡ z) : x •? y ≡ x •? z
end Iris.CMRA

namespace Iris.CMRA
theorem opM_left_dist {n} {x y : α} (z : Option α) (e : x ≡{n}≡ y) : x •? z ≡{n}≡ y •? z
end Iris.CMRA

namespace Iris.CMRA
theorem opM_right_dist {n} (x : α) {y z : Option α} (e : y ≡{n}≡ z) : x •? y ≡{n}≡ x •? z
end Iris.CMRA

namespace Iris.CMRA
theorem op_opM_assoc (x y : α) (mz : Option α) : (x • y) •? mz ≡ x • (y •? mz)
end Iris.CMRA

namespace Iris.CMRA
theorem op_opM_assoc_dist (x y : α) (mz : Option α) : (x • y) •? mz ≡{n}≡ x • (y •? mz)
end Iris.CMRA

namespace Iris.CMRA
theorem Valid.validN : ✓ (x : α) → ✓{n} x
end Iris.CMRA

namespace Iris.CMRA
theorem valid_mapN {x y : α} (f : ∀ n, ✓{n} x → ✓{n} y) (v : ✓ x) : ✓ y
end Iris.CMRA

namespace Iris.CMRA
theorem validN_of_eqv {x y : α} : x ≡ y → ✓{n} x → ✓{n} y
end Iris.CMRA

namespace Iris.CMRA
theorem validN_iff {x y : α} (e : x ≡{n}≡ y) : ✓{n} x ↔ ✓{n} y
end Iris.CMRA

namespace Iris.CMRA
theorem _root_.Iris.OFE.Dist.validN : (x : α) ≡{n}≡ y → (✓{n} x ↔ ✓{n} y)
end Iris.CMRA

namespace Iris.CMRA
theorem valid_of_eqv {x y : α} : x ≡ y → ✓ x → ✓ y
end Iris.CMRA

namespace Iris.CMRA
theorem valid_iff {x y : α} (e : x ≡ y) : ✓ x ↔ ✓ y
end Iris.CMRA

namespace Iris.CMRA
theorem _root_.Iris.OFE.Equiv.valid : (x : α) ≡ y → (✓ x ↔ ✓ y)
end Iris.CMRA

namespace Iris.CMRA
theorem validN_of_le {n n'} {x : α} : n' ≤ n → ✓{n} x → ✓{n'} x
end Iris.CMRA

namespace Iris.CMRA
theorem valid0_of_validN {n} {x : α} : ✓{n} x → ✓{0} x
end Iris.CMRA

namespace Iris.CMRA
theorem validN_op_right {n} {x y : α} : ✓{n} (x • y) → ✓{n} y
end Iris.CMRA

namespace Iris.CMRA
theorem valid_op_right (x y : α) : ✓ (x • y) → ✓ y
end Iris.CMRA

namespace Iris.CMRA
theorem valid_op_left {x y : α} : ✓ (x • y) → ✓ x
end Iris.CMRA

namespace Iris.CMRA
theorem validN_opM {x : α} {my : Option α} : ✓{n} (x •? my) → ✓{n} x
end Iris.CMRA

namespace Iris.CMRA
theorem valid_opM {x : α} {my : Option α} : ✓ (x •? my) → ✓ x
end Iris.CMRA

namespace Iris.CMRA
theorem validN_op_opM_left {mz : Option α} : ✓{n} (x • y : α) •? mz → ✓{n} x •? mz
end Iris.CMRA

namespace Iris.CMRA
theorem validN_op_opM_right {mz : Option α} (h : ✓{n} (x • y : α) •? mz) : ✓{n} y •? mz
end Iris.CMRA

namespace Iris.CMRA
theorem pcore_proper {x y : α} (cx : α) (e : x ≡ y) (ps : pcore x = some cx)
    : ∃ cy, pcore y = some cy ∧ cx ≡ cy
end Iris.CMRA

namespace Iris.CMRA
theorem pcore_proper' {x y : α} (e : x ≡ y) : pcore x ≡ pcore y
end Iris.CMRA

namespace Iris.CMRA
theorem pcore_op_left' {x : α} {cx} (e : pcore x ≡ some cx) : cx • x ≡ x
end Iris.CMRA

namespace Iris.CMRA
theorem pcore_op_right {x : α} {cx} (e : pcore x = some cx) : x • cx ≡ x
end Iris.CMRA

namespace Iris.CMRA
theorem pcore_op_right' {x : α} {cx} (e : pcore x ≡ some cx) : x • cx ≡ x
end Iris.CMRA

namespace Iris.CMRA
theorem pcore_idem' {x : α} {cx} (e : pcore x ≡ some cx) : pcore cx ≡ some cx
end Iris.CMRA

namespace Iris.CMRA
theorem pcore_op_self {x : α} {cx} (e : pcore x = some cx) : cx • cx ≡ cx
end Iris.CMRA

namespace Iris.CMRA
theorem pcore_op_self' {x : α} {cx} (e : pcore x ≡ some cx) : cx • cx ≡ cx
end Iris.CMRA

namespace Iris.CMRA
theorem pcore_validN {n} {x : α} {cx} (e : pcore x = some cx) (v : ✓{n} x) : ✓{n} cx
end Iris.CMRA

namespace Iris.CMRA
theorem pcore_valid {x : α} {cx} (e : pcore x = some cx) : ✓ x → ✓ cx
end Iris.CMRA

namespace Iris.CMRA
theorem not_valid_exclN_op_left {n} {x : α} [Exclusive x] {y} : ¬✓{n} (x • y)
end Iris.CMRA

namespace Iris.CMRA
theorem not_valid_exclN_op_right {n} {x : α} [Exclusive x] {y} : ¬✓{n} (y • x)
end Iris.CMRA

namespace Iris.CMRA
theorem not_valid_excl_op_left {x : α} [Exclusive x] {y} : ¬✓ (x • y)
end Iris.CMRA

namespace Iris.CMRA
theorem not_excl_op_right {x : α} [Exclusive x] {y} : ¬✓ (y • x)
end Iris.CMRA

namespace Iris.CMRA
theorem none_of_excl_valid_op {n} {x : α} [Exclusive x] {my} : ✓{n} (x •? my) → my = none
end Iris.CMRA

namespace Iris.CMRA
theorem not_valid_of_exclN_inc {n} {x : α} [Exclusive x] {y} : x ≼{n} y → ¬✓{n} y
end Iris.CMRA

namespace Iris.CMRA
theorem not_valid_of_excl_inc {x : α} [Exclusive x] {y} : x ≼ y → ¬✓ y
end Iris.CMRA

namespace Iris.CMRA
theorem Exclusive.of_eqv {x₁ x₂ : α} (e : x₁ ≡ x₂) (h : Exclusive x₁) : Exclusive x₂
end Iris.CMRA

namespace Iris.CMRA
theorem exclusive_iff {x₁ x₂ : α} (e : x₁ ≡ x₂) : Exclusive x₁ ↔ Exclusive x₂
end Iris.CMRA

namespace Iris.CMRA
theorem _root_.Iris.OFE.Dist.exclusive {x₁ x₂ : α} : x₁ ≡ x₂ → (Exclusive x₁ ↔ Exclusive x₂)
end Iris.CMRA

namespace Iris.CMRA
theorem inc_of_eqv_of_inc (e : (a : α) ≡ b) : b ≼ c → a ≼ c
end Iris.CMRA

namespace Iris.CMRA
theorem inc_of_inc_of_eqv : (a : α) ≼ b → b ≡ c → a ≼ c
end Iris.CMRA

namespace Iris.CMRA
theorem incN_of_incN_of_dist : (a : α) ≼{n} b → b ≡{n}≡ c → a ≼{n} c
end Iris.CMRA

namespace Iris.CMRA
theorem incN_of_dist_of_incN (e : (a : α) ≡{n}≡ b) : b ≼{n} c → a ≼{n} c
end Iris.CMRA

namespace Iris.CMRA
theorem incN_of_inc (n) {x y : α} : x ≼ y → x ≼{n} y
end Iris.CMRA

namespace Iris.CMRA
theorem Included.incN {n} {x y : α} : x ≼ y → x ≼{n} y
end Iris.CMRA

namespace Iris.CMRA
theorem inc_iff_left (e : (a : α) ≡ b) : a ≼ c ↔ b ≼ c
end Iris.CMRA

namespace Iris.CMRA
theorem _root_.Iris.OFE.Equiv.inc_l : (a : α) ≡ b → (a ≼ c ↔ b ≼ c)
end Iris.CMRA

namespace Iris.CMRA
theorem inc_iff_right (e : (b : α) ≡ c) : a ≼ b ↔ a ≼ c
end Iris.CMRA

namespace Iris.CMRA
theorem _root_.Iris.OFE.Equiv.inc_r : (b : α) ≡ c → (a ≼ b ↔ a ≼ c)
end Iris.CMRA

namespace Iris.CMRA
theorem inc_iff (ea : (a : α) ≡ a') (eb : (b : α) ≡ b') : a ≼ b ↔ a' ≼ b'
end Iris.CMRA

namespace Iris.CMRA
theorem _root_.Iris.OFE.Equiv.inc : (a : α) ≡ a' → b ≡ b' → (a ≼ b ↔ a' ≼ b')
end Iris.CMRA

namespace Iris.CMRA
theorem incN_iff_left (e : (a : α) ≡{n}≡ b) : a ≼{n} c ↔ b ≼{n} c
end Iris.CMRA

namespace Iris.CMRA
theorem _root_.Iris.OFE.Dist.incN_l : (a : α) ≡{n}≡ b → (a ≼{n} c ↔ b ≼{n} c)
end Iris.CMRA

namespace Iris.CMRA
theorem incN_iff_right (e : (b : α) ≡{n}≡ c) : a ≼{n} b ↔ a ≼{n} c
end Iris.CMRA

namespace Iris.CMRA
theorem _root_.Iris.OFE.Dist.incN_r : (b : α) ≡{n}≡ c → (a ≼{n} b ↔ a ≼{n} c)
end Iris.CMRA

namespace Iris.CMRA
theorem incN_iff (ea : (a : α) ≡{n}≡ a') (eb : (b : α) ≡{n}≡ b') : a ≼{n} b ↔ a' ≼{n} b'
end Iris.CMRA

namespace Iris.CMRA
theorem _root_.Iris.OFE.Dist.incN :
    (a : α) ≡{n}≡ a' → b ≡{n}≡ b' → (a ≼{n} b ↔ a' ≼{n} b')
end Iris.CMRA

namespace Iris.CMRA
theorem inc_trans {x y z : α} : x ≼ y → y ≼ z → x ≼ z
end Iris.CMRA

namespace Iris.CMRA
theorem Included.trans : (x : α) ≼ y → y ≼ z → x ≼ z
end Iris.CMRA

namespace Iris.CMRA
theorem incN_trans {x y z : α} : x ≼{n} y → y ≼{n} z → x ≼{n} z
end Iris.CMRA

namespace Iris.CMRA
theorem IncludedN.trans : (x : α) ≼{n} y → y ≼{n} z → x ≼{n} z
end Iris.CMRA

namespace Iris.CMRA
theorem valid_of_inc {x y : α} : x ≼ y → ✓ y → ✓ x
end Iris.CMRA

namespace Iris.CMRA
theorem validN_of_incN {n} {x y : α} : x ≼{n} y → ✓{n} y → ✓{n} x
end Iris.CMRA

namespace Iris.CMRA
theorem IncludedN.validN {n} {x y : α} : x ≼{n} y → ✓{n} y → ✓{n} x
end Iris.CMRA

namespace Iris.CMRA
theorem validN_of_inc {n} {x y : α} : x ≼ y → ✓{n} y → ✓{n} x
end Iris.CMRA

namespace Iris.CMRA
theorem Included.validN {n} {x y : α} : x ≼ y → ✓{n} y → ✓{n} x
end Iris.CMRA

namespace Iris.CMRA
theorem incN_of_incN_le {n n'} {x y : α} (l1 : n' ≤ n) : x ≼{n} y → x ≼{n'} y
end Iris.CMRA

namespace Iris.CMRA
theorem inc0_of_incN {n} {x y : α} : x ≼{n} y → x ≼{0} y
end Iris.CMRA

namespace Iris.CMRA
theorem IncludedN.le {n n'} {x y : α} : n' ≤ n → x ≼{n} y → x ≼{n'} y
end Iris.CMRA

namespace Iris.CMRA
theorem incN_of_incN_succ {n} {x y : α} : x ≼{n.succ} y → x ≼{n} y
end Iris.CMRA

namespace Iris.CMRA
theorem IncludedN.succ {n} {x y : α} : x ≼{n.succ} y → x ≼{n} y
end Iris.CMRA

namespace Iris.CMRA
theorem incN_op_left (n) (x y : α) : x ≼{n} x • y
end Iris.CMRA

namespace Iris.CMRA
theorem inc_op_left (x y : α) : x ≼ x • y
end Iris.CMRA

namespace Iris.CMRA
theorem inc_op_right (x y : α) : y ≼ x • y
end Iris.CMRA

namespace Iris.CMRA
theorem incN_op_right (n) (x y : α) : y ≼{n} x • y
end Iris.CMRA

namespace Iris.CMRA
theorem pcore_mono {x y : α} : x ≼ y → pcore x = some cx → ∃ cy, pcore y = some cy ∧ cx ≼ cy
end Iris.CMRA

namespace Iris.CMRA
theorem pcore_mono' {x y : α} {cx} (le : x ≼ y) (e : pcore x ≡ some cx) :
    ∃ cy, pcore y = some cy ∧ cx ≼ cy
end Iris.CMRA

namespace Iris.CMRA
theorem pcore_monoN' {n} {x y : α} {cx} :
    x ≼{n} y → pcore x ≡{n}≡ some cx → ∃ cy, pcore y = some cy ∧ cx ≼{n} cy
end Iris.CMRA

namespace Iris.CMRA
theorem pcore_inc_self {x : α} {cx} (e : pcore x = some cx) : cx ≼ x
end Iris.CMRA

namespace Iris.CMRA
theorem op_mono_right {x y} (z : α) : x ≼ y → z • x ≼ z • y
end Iris.CMRA

namespace Iris.CMRA
theorem op_monoN_right {n x y} (z : α) : x ≼{n} y → z • x ≼{n} z • y
end Iris.CMRA

namespace Iris.CMRA
theorem op_monoN_left {n x y} (z : α) (h : x ≼{n} y) : x • z ≼{n} y • z
end Iris.CMRA

namespace Iris.CMRA
theorem op_mono_left {x y} (z : α) (h : x ≼ y) : x • z ≼ y • z
end Iris.CMRA

namespace Iris.CMRA
theorem op_monoN {n} {x x' y y' : α} (hx : x ≼{n} x') (hy : y ≼{n} y') : x • y ≼{n} x' • y'
end Iris.CMRA

namespace Iris.CMRA
theorem op_mono {x x' y y' : α} (hx : x ≼ x') (hy : y ≼ y') : x • y ≼ x' • y'
end Iris.CMRA

namespace Iris.CMRA
theorem op_self (x : α) [CoreId x] : x • x ≡ x
end Iris.CMRA

namespace Iris.CMRA
theorem op_core_right_of_inc {x y : α} [CoreId x] : x ≼ y → x • y ≡ y
end Iris.CMRA

namespace Iris.CMRA
theorem included_dist_l {n} {x1 x2 x1' : α} :
    x1 ≼ x2 → x1' ≡{n}≡ x1 → ∃ x2', x1' ≼ x2' ∧ x2' ≡{n}≡ x2
end Iris.CMRA

namespace Iris.CMRA
theorem op_core_left_of_inc {x y : α} [CoreId x] (le : x ≼ y) : y • x ≡ y
end Iris.CMRA

namespace Iris.CMRA
theorem CoreId.of_pcore_eq_some {x y : α} (e : pcore x = some y) : CoreId y
end Iris.CMRA

namespace Iris.CMRA
theorem pcore_eq_core (x : α) : pcore x = some (core x)
end Iris.CMRA

namespace Iris.CMRA
theorem op_core (x : α) : x • core x ≡ x
end Iris.CMRA

namespace Iris.CMRA
theorem core_op (x : α) : core x • x ≡ x
end Iris.CMRA

namespace Iris.CMRA
theorem op_core_dist (x : α) : x • core x ≡{n}≡ x
end Iris.CMRA

namespace Iris.CMRA
theorem core_op_dist (x : α) : core x • x ≡{n}≡ x
end Iris.CMRA

namespace Iris.CMRA
theorem core_op_core {x : α} : core x • core x ≡ core x
end Iris.CMRA

namespace Iris.CMRA
theorem validN_core {n} {x : α} (v : ✓{n} x) : ✓{n} core x
end Iris.CMRA

namespace Iris.CMRA
theorem valid_core {x : α} (v : ✓ x) : ✓ core x
end Iris.CMRA

namespace Iris.CMRA
theorem core_ne : NonExpansive (core : α → α)
end Iris.CMRA

namespace Iris.CMRA
theorem _root_.Iris.OFE.Dist.core :
  ∀ {n} {x₁ x₂ : α}, x₁ ≡{n}≡ x₂ → core x₁ ≡{n}≡ core x₂
end Iris.CMRA

namespace Iris.CMRA
theorem _root_.Iris.OFE.Equiv.core : ∀ {x₁ x₂ : α}, x₁ ≡ x₂ → core x₁ ≡ core x₂
end Iris.CMRA

namespace Iris.CMRA
theorem core_eqv_self (x : α) [CoreId x] : core (x : α) ≡ x
end Iris.CMRA

namespace Iris.CMRA
theorem coreId_iff_core_eqv_self : CoreId (x : α) ↔ core x ≡ x
end Iris.CMRA

namespace Iris.CMRA
theorem core_idem (x : α) : core (core x) ≡ core x
end Iris.CMRA

namespace Iris.CMRA
theorem inc_refl (x : α) : x ≼ x
end Iris.CMRA

namespace Iris.CMRA
@[refl] theorem Included.rfl {x : α} : x ≼ x
end Iris.CMRA

namespace Iris.CMRA
theorem incN_refl (x : α) : x ≼{n} x
end Iris.CMRA

namespace Iris.CMRA
@[refl] theorem IncludedN.rfl {x : α} : x ≼{n} x
end Iris.CMRA

namespace Iris.CMRA
theorem core_inc_self {x : α} [CoreId x] : core x ≼ x
end Iris.CMRA

namespace Iris.CMRA
theorem core_incN_core {n} {x y : α} (inc : x ≼{n} y) : core x ≼{n} core y
end Iris.CMRA

namespace Iris.CMRA
theorem core_op_mono (x y : α) : core x ≼ core (x • y)
end Iris.CMRA

namespace Iris.CMRA
theorem core_mono {x y : α} (Hinc : x ≼ y) : core x ≼ core y
end Iris.CMRA

namespace Iris.CMRA
theorem discrete_inc_l {x y : α} [HD : DiscreteE x] (Hv : ✓{0} y) (Hle : x ≼{0} y) : x ≼ y
end Iris.CMRA

namespace Iris.CMRA
theorem discrete_inc_r {x y : α} [HD : DiscreteE y] : x ≼{0} y → x ≼ y
end Iris.CMRA

namespace Iris.CMRA
theorem valid_iff_validN' [Discrete α] (n) {x : α} : ✓ x ↔ ✓{n} x
end Iris.CMRA

namespace Iris.CMRA
theorem valid_0_iff_validN [Discrete α] (n) {x : α} : ✓{0} x ↔ ✓{n} x
end Iris.CMRA

namespace Iris.CMRA
theorem inc_iff_incN [OFE.Discrete α] (n) {x y : α} : x ≼ y ↔ x ≼{n} y
end Iris.CMRA

namespace Iris.CMRA
theorem inc_0_iff_incN [OFE.Discrete α] (n) {x y : α} : x ≼{0} y ↔ x ≼{n} y
end Iris.CMRA

namespace Iris.CMRA
theorem cancelable {x y z : α} [Cancelable x] (v : ✓(x • y)) (e : x • y ≡ x • z) : y ≡ z
end Iris.CMRA

namespace Iris.CMRA
theorem discrete_cancelable {x : α} [Discrete α]
    (H : ∀ {y z : α}, ✓(x • y) → x • y ≡ x • z → y ≡ z) : Cancelable x
end Iris.CMRA

namespace Iris.CMRA
theorem Cancelable.of_eqv {x₁ x₂ : α} (e : x₁ ≡ x₂) (h : Cancelable x₁) : Cancelable x₂
end Iris.CMRA

namespace Iris.CMRA
theorem cancelable_iff {x₁ x₂ : α} (e : x₁ ≡ x₂) : Cancelable x₁ ↔ Cancelable x₂
end Iris.CMRA

namespace Iris.CMRA
theorem _root_.Iris.OFE.Equiv.cancelable {x₁ x₂ : α} : x₁ ≡ x₂ → (Cancelable x₁ ↔ Cancelable x₂)
end Iris.CMRA

namespace Iris.CMRA
theorem op_opM_cancel_dist {x y z : α} [Cancelable x]
    (vxy : ✓{n} x • y) (h : x • y ≡{n}≡ (x • z) •? mw) : y ≡{n}≡ z •? mw
end Iris.CMRA

namespace Iris.CMRA
theorem IdFree.of_dist {x₁ x₂ : α} {n} (e : x₁ ≡{n}≡ x₂) (h : IdFree x₁) : IdFree x₂
end Iris.CMRA

namespace Iris.CMRA
theorem _root_.Iris.OFE.Dist.idFree {x₁ x₂ : α} (e : x₁ ≡{n}≡ x₂) : IdFree x₁ ↔ IdFree x₂
end Iris.CMRA

namespace Iris.CMRA
theorem IdFree.of_eqv {x₁ x₂ : α} (e : x₁ ≡ x₂) (h : IdFree x₁) : IdFree x₂
end Iris.CMRA

namespace Iris.CMRA
theorem idFree_iff {x₁ x₂ : α} (e : x₁ ≡ x₂) : IdFree x₁ ↔ IdFree x₂
end Iris.CMRA

namespace Iris.CMRA
theorem _root_.Iris.OFE.Equiv.idFree {x₁ x₂ : α} : x₁ ≡ x₂ → (IdFree x₁ ↔ IdFree x₂)
end Iris.CMRA

namespace Iris.CMRA
theorem id_freeN_r {n n'} {x : α} [IdFree x] {y} (v : ✓{n} x) : ¬(x • y ≡{n'}≡ x)
end Iris.CMRA

namespace Iris.CMRA
theorem id_freeN_l {n n'} {x : α} [IdFree x] {y} (v : ✓{n} x) : ¬(y • x ≡{n'}≡ x)
end Iris.CMRA

namespace Iris.CMRA
theorem id_free_r {x : α} [IdFree x] {y} (v : ✓x) : ¬(x • y ≡ x)
end Iris.CMRA

namespace Iris.CMRA
theorem id_free_l {x : α} [IdFree x] {y} (v : ✓ x) : ¬(y • x ≡ x)
end Iris.CMRA

namespace Iris.CMRA
theorem discrete_id_free {x : α} [Discrete α] (H : ∀ y, ✓ x → ¬(x • y ≡ x)) : IdFree x
end Iris.CMRA

namespace Iris.CMRA
theorem unit_validN {n} : ✓{n} (unit : α)
end Iris.CMRA

namespace Iris.CMRA
theorem incN_unit {n} {x : α} : unit ≼{n} x
end Iris.CMRA

namespace Iris.CMRA
theorem inc_unit {x : α} : unit ≼ x
end Iris.CMRA

namespace Iris.CMRA
theorem unit_left_id_dist {n} (x : α) : unit • x ≡{n}≡ x
end Iris.CMRA

namespace Iris.CMRA
theorem unit_right_id {x : α} : x • unit ≡ x
end Iris.CMRA

namespace Iris.CMRA
theorem unit_right_id_dist (x : α) : x • unit ≡{n}≡ x
end Iris.CMRA

namespace Iris.CMRA
theorem _root_.Iris.OFE.Dist.to_incN {n} {x y : α} (H : x ≡{n}≡ y) : x ≼{n} y
end Iris.CMRA

namespace Iris.CMRA
theorem assoc_L {x y z : α} : x • (y • z) = (x • y) • z
end Iris.CMRA

namespace Iris.CMRA
theorem comm_L {x y : α} : x • y = y • x
end Iris.CMRA

namespace Iris.CMRA
theorem pcore_op_left_L {x cx : α} (h : pcore x = some cx) : cx • x = x
end Iris.CMRA

namespace Iris.CMRA
theorem pcore_idem_L {x cx : α} (h : pcore x = some cx) : pcore cx = some cx
end Iris.CMRA

namespace Iris.CMRA
theorem op_opM_assoc_L {x y : α} {mz} : (x • y) •? mz = x • (y •? mz)
end Iris.CMRA

namespace Iris.CMRA
theorem pcore_op_right_L {x cx : α} (h : pcore x = some cx) : x • cx = x
end Iris.CMRA

namespace Iris.CMRA
theorem pcore_op_self_L {x cx : α} (h : pcore x = some cx) : cx • cx = cx
end Iris.CMRA

namespace Iris.CMRA
theorem core_id_dup_L {x : α} [CoreId x] : x • x = x
end Iris.CMRA

namespace Iris.CMRA
theorem op_core_L {x : α} [IsTotal α] : x • core x = x
end Iris.CMRA

namespace Iris.CMRA
theorem core_op_L {x : α} [IsTotal α] : core x • x = x
end Iris.CMRA

namespace Iris.CMRA
theorem core_idem_L {x : α} [IsTotal α] : core (core x) = core x
end Iris.CMRA

namespace Iris.CMRA
theorem core_op_core_L {x : α} [IsTotal α] : core x • core x = core x
end Iris.CMRA

namespace Iris.CMRA
theorem coreId_iff_core_eq_self {x : α} [IsTotal α] : CoreId x ↔ core x = x
end Iris.CMRA

namespace Iris.CMRA
theorem core_eq_self {x : α} [IsTotal α] [c : CoreId x] : core x = x
end Iris.CMRA

namespace Iris.CMRA
theorem unit_left_id_L {x : α} : unit • x = x
end Iris.CMRA

namespace Iris.CMRA
theorem unit_right_id_L {x : α} : x • unit = x
end Iris.CMRA

namespace Iris.CMRA
protected theorem Hom.eqv [CMRA β] (f : α -C> β) {x₁ x₂ : α} (X : x₁ ≡ x₂) : f x₁ ≡ f x₂
end Iris.CMRA

namespace Iris.CMRA
protected theorem Hom.core [CMRA β] (f : α -C> β) {x : α} : core (f x) ≡ f (core x)
end Iris.CMRA

namespace Iris.CMRA
protected theorem Hom.mono [CMRA β] (f : α -C> β) {x₁ x₂ : α} : x₁ ≼ x₂ → f x₁ ≼ f x₂
end Iris.CMRA

namespace Iris.CMRA
protected theorem Hom.monoN [CMRA β] (f : α -C> β) n {x₁ x₂ : α} : x₁ ≼{n} x₂ → f x₁ ≼{n} f x₂
end Iris.CMRA

namespace Iris.CMRA
protected theorem Hom.valid [CMRA β] (f : α -C> β) {x : α} (H : ✓ x) : ✓ f x
end Iris.CMRA

namespace Iris.Option
theorem equiv_of_some_equiv_some {x y : α} (H : some x ≡ some y) : x ≡ y
end Iris.Option

namespace Iris.Option
theorem dist_of_some_dist_some {n} {x y : α} (H : some x ≡{n}≡ some y) : x ≡{n}≡ y
end Iris.Option

namespace Iris.Option
theorem op_some_opM_assoc {x y : α} {mz : Option α} : (x • y) •? mz ≡ x •? (some y • mz)
end Iris.Option

namespace Iris.Option
theorem some_op_opM {a : α} {ma : Option α} : some a • ma = some (a •? ma)
end Iris.Option

namespace Iris.Option
theorem opM_opM_assoc {x : α} {y z : Option α} : (x •? y) •? z ≡ x •? (y • z)
end Iris.Option

namespace Iris.Option
theorem op_some_opM_assoc_dist {x y : α} {mz : Option α} : (x • y) •? mz ≡{n}≡ x •? (some y • mz)
end Iris.Option

namespace Iris.Option
theorem some_inc_some_of_dist_opM {mz : Option α} (H : x ≡{n}≡ y •? mz) : some y ≼{n} some x
end Iris.Option

namespace Iris.Option
theorem inc_of_some_inc_some [IsTotal α] {x y : α} (H : some y ≼ some x) : y ≼ x :=
  let ⟨mz, hmz⟩ := H
  match mz with
end Iris.Option

namespace Iris.Option
theorem some_incN_some_iff_some [IsTotal α] {x y : α} : some y ≼{n} some x → y ≼{n} x
end Iris.Option

namespace Iris.Option
theorem exists_op_some_eqv_some (x : Option α) (y : α) : ∃ z, x • some y ≡ some z
end Iris.Option

namespace Iris.Option
theorem exists_op_some_dist_some {n} (x : Option α) (y : α) : ∃ z, x • some y ≡{n}≡ some z
end Iris.Option

namespace Iris.Option
theorem not_valid_some_exclN_op_left {n} {x : α} [Exclusive x] {y : α} : ¬✓{n} (some x • some y)
end Iris.Option

namespace Iris.Option
theorem validN_op_unit {n} {x : Option α} (vx : ✓{n} x) : ✓{n} x • unit
end Iris.Option

namespace Iris.Option
theorem inc_iff {ma mb : Option α} :
    ma ≼ mb ↔ ma = none ∨ ∃ a b, ma = some a ∧ mb = some b ∧ (a ≡ b ∨ a ≼ b)
end Iris.Option

namespace Iris.Option
theorem incN_iff {ma mb : Option α} :
    ma ≼{n} mb ↔ ma = none ∨ ∃ a b, ma = some a ∧ mb = some b ∧ (a ≡{n}≡ b ∨ a ≼{n} b)
end Iris.Option

namespace Iris.Option
theorem inc_iff_isTotal [IsTotal α] {ma mb : Option α} :
    ma ≼ mb ↔ ma = none ∨ ∃ a b, ma = some a ∧ mb = some b ∧ a ≼ b
end Iris.Option

namespace Iris.Option
theorem incN_iff_isTotal [IsTotal α] {ma mb : Option α} :
    ma ≼{n} mb ↔ ma = none ∨ ∃ a b, ma = some a ∧ mb = some b ∧ a ≼{n} b
end Iris.Option

namespace Iris.Option
theorem some_incN_some_iff {a b : α} : some a ≼{n} some b ↔ a ≡{n}≡ b ∨ a ≼{n} b
end Iris.Option

namespace Iris.Option
theorem some_inc_some_iff {a b : α} : some a ≼ some b ↔ a ≡ b ∨ a ≼ b
end Iris.Option

namespace Iris.Option
theorem eqv_of_inc_exclusive [Exclusive (a : α)] {b : α} (H : some a ≼ some b) (Hv : ✓ b) :
     a ≡ b
end Iris.Option

namespace Iris.Option
theorem dist_of_inc_exclusive [Exclusive (a : α)] {b : α} (H : some a ≼{n} some b) (Hv : ✓{n} b)  :
    a ≡{n}≡ b
end Iris.Option

namespace Iris.Option
theorem some_inc_some_iff_isTotal [IsTotal α] {a b : α} : some a ≼ some b ↔ a ≼ b
end Iris.Option

namespace Iris.Option
theorem some_incN_some_iff_isTotal [IsTotal α] {a b : α} : some a ≼{n} some b ↔ a ≼{n} b
end Iris.Option

namespace Iris.Option
theorem validN_of_incN_validN {a b : α} (Hv : ✓{n} a) (Hinc : some b ≼{n} some a) : ✓{n} b
end Iris.Option

namespace Iris.Option
theorem valid_of_inc_valid {a b : α} (Hv : ✓ a) (Hinc : some b ≼ some a) : ✓ b
end Iris.Option

namespace Iris.Option
theorem some_inc_some_iff_opM {a b : α} : some a ≼ some b ↔ ∃ mc, b ≡ a •? mc
end Iris.Option

namespace Iris.Option
theorem some_incN_some_iff_opM {a b : α} : some a ≼{n} some b ↔ ∃ mc, b ≡{n}≡ a •? mc
end Iris.Option

namespace Iris.Prod
theorem valid_fst {x : α × β} (h : ✓ x) : ✓ x.fst
end Iris.Prod

namespace Iris.Prod
theorem valid_snd {x : α × β} (h : ✓ x) : ✓ x.snd
end Iris.Prod

namespace Iris.Prod
theorem validN_fst {n} {x : α × β} (h : ✓{n} x) : ✓{n} x.fst
end Iris.Prod

namespace Iris.Prod
theorem validN_snd {n} {x : α × β} (h : ✓{n} x) : ✓{n} x.snd
end Iris.Prod

congrArg in Init.Prelude
</all_available_lemmas>

<local_ctx>
namespace Iris

class OFE (α : Type _) where
  Equiv : α → α → Prop
  Dist : Nat → α → α → Prop
  dist_eqv : Equivalence (Dist n)
  equiv_dist : Equiv x y ↔ ∀ n, Dist n x y
  dist_lt : Dist n x y → m < n → Dist m x y

open OFE

scoped infix:40 " ≡ " => OFE.Equiv

scoped notation:40 x " ≡{" n "}≡ " y:41 => OFE.Dist n x y

namespace OFE

theorem Dist.lt [OFE α] {m n} {x y : α} : x ≡{n}≡ y → m < n → x ≡{m}≡ y

theorem Dist.le [OFE α] {m n} {x y : α} (h : x ≡{n}≡ y) (h' : m ≤ n) : x ≡{m}≡ y

@[simp, refl] theorem Dist.rfl [OFE α] {n} {x : α} : x ≡{n}≡ x

@[symm] theorem Dist.symm [OFE α] {n} {x : α} : x ≡{n}≡ y → y ≡{n}≡ x

theorem Dist.trans [OFE α] {n} {x : α} : x ≡{n}≡ y → y ≡{n}≡ z → x ≡{n}≡ z

theorem Dist.of_eq [OFE α] {x y : α} : x = y → x ≡{n}≡ y

theorem equiv_eqv [ofe : OFE α] : Equivalence ofe.Equiv

@[simp, refl] theorem Equiv.rfl [OFE α] {x : α} : x ≡ x

@[symm] theorem Equiv.symm [OFE α] {x : α} : x ≡ y → y ≡ x

theorem Equiv.trans [OFE α] {x : α} : x ≡ y → y ≡ z → x ≡ z

theorem Equiv.dist [OFE α] {x : α} : x ≡ y → x ≡{n}≡ y

theorem Equiv.of_eq [OFE α] {x y : α} : x = y → x ≡ y

instance [OFE α] : Trans OFE.Equiv OFE.Equiv (OFE.Equiv : α → α → Prop) where
  trans := Equiv.trans

instance [OFE α] {n : Nat} : Trans (OFE.Dist n) (OFE.Dist n) (OFE.Dist n : α → α → Prop) where
  trans := Dist.trans

class NonExpansive [OFE α] [OFE β] (f : α → β) where
  ne : ∀ ⦃n x₁ x₂⦄, x₁ ≡{n}≡ x₂ → f x₁ ≡{n}≡ f x₂

instance id_ne [OFE α] : NonExpansive (@id α) := ⟨fun _ _ _ h => h⟩

theorem NonExpansive.eqv [OFE α] [OFE β] {f : α → β} [NonExpansive f]
    ⦃x₁ x₂⦄ (h : x₁ ≡ x₂) : f x₁ ≡ f x₂

class NonExpansive₂ [OFE α] [OFE β] [OFE γ] (f : α → β → γ) where
  ne : ∀ ⦃n x₁ x₂⦄, x₁ ≡{n}≡ x₂ → ∀ ⦃y₁ y₂⦄, y₁ ≡{n}≡ y₂ → f x₁ y₁ ≡{n}≡ f x₂ y₂

theorem NonExpansive₂.eqv [OFE α] [OFE β] [OFE γ] {f : α → β → γ} [NonExpansive₂ f]
    ⦃x₁ x₂⦄ (hx : x₁ ≡ x₂) ⦃y₁ y₂⦄ (hy : y₁ ≡ y₂) : f x₁ y₁ ≡ f x₂ y₂

def DistLater [OFE α] (n : Nat) (x y : α) : Prop := ∀ m, m < n → x ≡{m}≡ y

@[simp, refl] theorem DistLater.rfl [OFE α] {n} {x : α} : DistLater n x x

@[symm] theorem DistLater.symm [OFE α] {n} {x : α} (h : DistLater n x y) : DistLater n y x

theorem DistLater.trans [OFE α] {n} {x : α} (h1 : DistLater n x y) (h2 : DistLater n y z) :
    DistLater n x z

theorem distLater_eqv [OFE α] {n} : Equivalence (α := α) (DistLater n)

theorem Dist.distLater [OFE α] {n} {x y : α} (h : x ≡{n}≡ y) : DistLater n x y

theorem DistLater.dist_lt [OFE α] {m n} {x y : α} (h : DistLater n x y) (hm : m < n) : x ≡{m}≡ y

@[simp] theorem distLater_zero [OFE α] {x y : α} : DistLater 0 x y

theorem distLater_succ [OFE α] {n} {x y : α} : DistLater n.succ x y ↔ x ≡{n}≡ y

class Contractive [OFE α] [OFE β] (f : α → β) where
  distLater_dist : DistLater n x y → f x ≡{n}≡ f y

@[simp] theorem Contractive.zero [OFE α] [OFE β] (f : α → β) [Contractive f] {x y} :
    f x ≡{0}≡ f y

theorem Contractive.succ [OFE α] [OFE β] (f : α → β) [Contractive f] {n x y}
    (h : x ≡{n}≡ y) : f x ≡{n.succ}≡ f y

instance ne_of_contractive [OFE α] [OFE β] (f : α → β) [Contractive f] : NonExpansive f where
  ne := fun _ _ _ h => Contractive.distLater_dist (Dist.distLater h)

theorem Contractive.eqv [OFE α] [OFE β] (f : α → β) [Contractive f] ⦃x y : α⦄ (h : x ≡ y) :
    f x ≡ f y

instance [OFE α] [OFE β] {x : β} : Contractive (fun _ : α => x) where
  distLater_dist := fun _ => Dist.rfl

def ofDiscrete (Equiv : α → α → Prop) (equiv_eqv : Equivalence Equiv) : OFE α where
  Equiv := Equiv
  Dist _ := Equiv
  dist_eqv := equiv_eqv
  equiv_dist := (forall_const _).symm
  dist_lt h _ := h

class DiscreteE {α : Type _} [OFE α] (x : α) : Prop where
  discrete : x ≡{0}≡ y → x ≡ y

class Discrete (α : Type _) [OFE α] where
  discrete_0 {x y : α} : x ≡{0}≡ y → x ≡ y

theorem Discrete.discrete [OFE α] [Discrete α] {n} {x y : α} (h : x ≡{n}≡ y) : x ≡ y

theorem Discrete.discrete_n [OFE α] [Discrete α] {n} {x y : α} (h : x ≡{0}≡ y) : x ≡{n}≡ y

class Leibniz (α : Type _) [OFE α] where
  eq_of_eqv {x y : α} : x ≡ y → x = y

@[simp] theorem Leibniz.leibniz [OFE α] [Leibniz α] {x y : α} : x ≡ y ↔ x = y

@[ext] structure Hom (α β : Type _) [OFE α] [OFE β] where
  f : α → β
  ne : NonExpansive f

@[inherit_doc]
infixr:25 " -n> " => Hom

instance [OFE α] [OFE β] : CoeFun (α -n> β) (fun _ => α → β) := ⟨Hom.f⟩

instance [OFE α] [OFE β] (f : α -n> β) : NonExpansive f := f.ne

protected def Hom.id [OFE α] : α -n> α where
  f := id
  ne.ne _ _ _ := id

protected def Hom.comp [OFE α] [OFE β] [OFE γ] (g : β -n> γ) (f : α -n> β) : α -n> γ where
  f := g.f ∘ f.f
  ne.1 _ _ _ h := g.ne.1 (f.ne.1 h)

@[simp] theorem Hom.id_apply [OFE α] {x} : (Hom.id : α -n> α) x = x

@[simp] theorem Hom.comp_apply [OFE α] [OFE β] [OFE γ] {g : β -n> γ} {f : α -n> β} {x} :
    (g.comp f) x = g (f x)

@[simp] theorem Hom.id_comp [OFE α] [OFE β] {f : α -n> β} : Hom.id.comp f = f

@[simp] theorem Hom.comp_id [OFE α] [OFE β] {f : α -n> β} : f.comp Hom.id = f

theorem Hom.comp_assoc [OFE α] [OFE β] [OFE γ] [OFE δ]
    (h : γ -n> δ) (g : β -n> γ) (f : α -n> β) : (h.comp g).comp f = h.comp (g.comp f)

@[ext] structure ContractiveHom (α β : Type _) [OFE α] [OFE β] extends Hom α β where
  [contractive : Contractive f]
  ne := ne_of_contractive f

infixr:25 " -c> " => ContractiveHom

instance [OFE α] [OFE β] : CoeFun (α -c> β) (fun _ => α → β) := ⟨fun x => x.toHom.f⟩

instance [OFE α] [OFE β] (f : α -c> β) : Contractive f := f.contractive

theorem InvImage.equivalence {α : Sort u} {β : Sort v}
    {r : β → β → Prop} {f : α → β} (H : Equivalence r) : Equivalence (InvImage r f)

instance : OFE Unit where
  Equiv _ _ := True
  Dist _ _ _ := True
  dist_eqv := ⟨fun _ => ⟨⟩, id, fun _ => id⟩
  equiv_dist := by admit /- proof elided -/

instance [OFE α] : OFE (ULift α) where
  Equiv x y := x.down ≡ y.down
  Dist n x y := x.down ≡{n}≡ y.down
  dist_eqv := InvImage.equivalence dist_eqv
  equiv_dist := equiv_dist
  dist_lt := dist_lt

def uliftUpHom [OFE α] : α -n> ULift α where
  f := .up
  ne.1 _ _ _ := id

def uliftDownHom [OFE α] : ULift α -n> α where
  f := ULift.down
  ne.1 _ _ _ := id

def _root_.Option.Forall₂ (R : α → β → Prop) : Option α → Option β → Prop
  | none, none => True
  | some a, some b => R a b
  | _, _ => False

theorem _root_.Option.Forall₂.equivalence {R : α → α → Prop}
    (H : Equivalence R) : Equivalence (Option.Forall₂ R)

instance [OFE α] : OFE (Option α) where
  Equiv := Option.Forall₂ Equiv
  Dist n := Option.Forall₂ (Dist n)
  dist_eqv := Option.Forall₂.equivalence dist_eqv
  equiv_dist {x y} := by admit /- proof elided -/

instance [OFE α] [OFE.Discrete α] : OFE.Discrete (Option α) where
  discrete_0 {mx my} e :=
    match mx, my with
    | none,   none   => e
    | none,   some _ => e
    | some _, none   => e
    | some x, some y => show x ≡ y from discrete_0 e

@[simp] theorem some_eqv_some [OFE α] {x y : α} : (some x ≡ some y) ↔ x ≡ y

@[simp] theorem not_some_eqv_none [OFE α] {x : α} : ¬some x ≡ none

@[simp] theorem not_none_eqv_some [OFE α] {x : α} : ¬none ≡ some x

@[simp] theorem some_dist_some [OFE α] {n} {x y : α} : (some x ≡{n}≡ some y) ↔ x ≡{n}≡ y

@[simp] theorem not_some_dist_none [OFE α] {n} {x : α} : ¬some x ≡{n}≡ none

@[simp] theorem not_none_dist_some [OFE α] {n} {x : α} : ¬none ≡{n}≡ some x

theorem equiv_some [OFE α] {o : Option α} {y : α} (e : o ≡ some y) :
    ∃ z, o = some z ∧ z ≡ y

theorem equiv_none [OFE α] {o : Option α} : o ≡ none ↔ o = none

theorem dist_some [OFE α] {n mx y} (h : mx ≡{n}≡ some y) :
    ∃ z : α, mx = some z ∧ y ≡{n}≡ z :=
  suffices hh : ∀ mx my y, mx ≡{n}≡ my → my = some y → ∃ t, mx = some t ∧ t ≡{n}≡ y from
    (hh mx (some y) _ h rfl).elim (fun t h => ⟨t, h.left, h.right.symm⟩)
  fun mx _ y e1 e2 =>
    match mx with

instance [OFE α] [Leibniz α] : Leibniz (Option α) where
  eq_of_eqv {x y} H :=
    match x, y, H with
    | none, none, _ => rfl
    | some _, some _, h => congrArg some (Leibniz.eq_of_eqv h)

instance [OFE α] [Discrete α] : Discrete (Option α) where
  discrete_0 {x y} H :=
    match x, y with
    | none, none => H
    | some _, some _ => some_eqv_some.mpr (discrete_0 H)

instance OFE.Option.some.ne [OFE α] : OFE.NonExpansive (some : α → Option α) := ⟨fun _ _ _ => id⟩

theorem Option.some_is_discrete [OFE α] {a : α} (Ha : DiscreteE a) : DiscreteE (some a)

theorem Option.none_is_discrete [OFE α] : DiscreteE (none : Option α)

instance Option.merge_ne [OFE α] {op : α → α → α} [NonExpansive₂ op] :
    NonExpansive₂ (Option.merge op) where
  ne n x1 x2 Hx y1 y2 Hy := by admit /- proof elided -/

abbrev OFEFun {α : Type _} (β : α → Type _) := ∀ a, OFE (β a)

instance [OFEFun (β : α → _)] : OFE ((x : α) → β x) where
  Equiv f g := ∀ x, f x ≡ g x
  Dist n f g := ∀ x, f x ≡{n}≡ g x
  dist_eqv := {
    refl _ _ := dist_eqv.refl _
    symm h _ := dist_eqv.symm (h _)
    trans h1 h2 _ := dist_eqv.trans (h1 _) (h2 _)
  }
  equiv_dist {_ _} := by admit /- proof elided -/

instance [OFE α] [OFE β] : OFE (α -n> β) where
  Equiv f g := f.f ≡ g.f
  Dist n f g := f.f ≡{n}≡ g.f
  dist_eqv := {
    refl _ := dist_eqv.refl _
    symm h := dist_eqv.symm h
    trans h1 h2 := dist_eqv.trans h1 h2
  }
  equiv_dist := equiv_dist
  dist_lt := dist_lt

instance [OFE α] [OFE β] : OFE (α -c> β) where
  Equiv f g := Equiv f.toHom g.toHom
  Dist n f g := Dist n f.toHom g.toHom
  dist_eqv := {
    refl _ := dist_eqv.refl _
    symm h := dist_eqv.symm h
    trans h1 h2 := dist_eqv.trans h1 h2
  }
  equiv_dist := equiv_dist
  dist_lt := dist_lt

def applyHom [OFEFun (β : α → _)] (x : α) : ((x : α) → β x) -n> β x where
  f f := f x
  ne.1 _ _ _ H := H x

def mapCodHom [OFEFun (β₁ : α → _)] [OFEFun β₂]
    (F : ∀ x, β₁ x -n> β₂ x) : ((x : α) → β₁ x) -n> ((x : α) → β₂ x) where
  f f x := F x (f x)
  ne.1 _ _ _ H x := (F x).ne.1 (H x)

instance [OFE α] [OFE β] : OFE (α × β) where
  Equiv a b := a.1 ≡ b.1 ∧ a.2 ≡ b.2
  Dist n a b := a.1 ≡{n}≡ b.1 ∧ a.2 ≡{n}≡ b.2
  dist_eqv := {
    refl _ := ⟨dist_eqv.refl _, dist_eqv.refl _⟩
    symm h := ⟨dist_eqv.symm h.1, dist_eqv.symm h.2⟩
    trans h1 h2 := ⟨dist_eqv.trans h1.1 h2.1, dist_eqv.trans h1.2 h2.2⟩
  }
  equiv_dist {_ _} := by admit /- proof elided -/

theorem equiv_fst [OFE α] [OFE β] {x y : α × β} (h : x ≡ y) : x.fst ≡ y.fst

theorem equiv_snd [OFE α] [OFE β] {x y : α × β} (h : x ≡ y) : x.snd ≡ y.snd

theorem equiv_prod_ext [OFE α] [OFE β] {x₁ x₂ : α} {y₁ y₂ : β}
    (ex : x₁ ≡ x₂) (ey : y₁ ≡ y₂) : (x₁, y₁) ≡ (x₂, y₂)

theorem dist_fst {n} [OFE α] [OFE β] {x y : α × β} (h : x ≡{n}≡ y) : x.fst ≡{n}≡ y.fst

theorem dist_snd {n} [OFE α] [OFE β] {x y : α × β} (h : x ≡{n}≡ y) : x.snd ≡{n}≡ y.snd

theorem dist_prod_ext {n} [OFE α] [OFE β] {x₁ x₂ : α} {y₁ y₂ : β}
    (ex : x₁ ≡{n}≡ x₂) (ey : y₁ ≡{n}≡ y₂) : (x₁, y₁) ≡{n}≡ (x₂, y₂)

theorem prod.is_discrete [OFE α] [OFE β] {a : α} {b : β} (Ha : DiscreteE a) (Hb : DiscreteE b) :
    DiscreteE (a, b)

instance [OFE α] [OFE β] [Discrete α] [Discrete β] : Discrete (α × β) where
  discrete_0 H := by admit /- proof elided -/

@[ext] structure Iso (α β : Type _) [OFE α] [OFE β] where
  hom : α -n> β
  inv : β -n> α
  hom_inv : hom (inv x) ≡ x
  inv_hom : inv (hom x) ≡ x

instance [OFE α] [OFE β] : CoeFun (Iso α β) (fun _ => α -n> β) := ⟨Iso.hom⟩

instance [OFE α] [OFE β] (iso : Iso α β) : NonExpansive iso.hom := iso.hom.ne

instance [OFE α] [OFE β] (iso : Iso α β) : NonExpansive iso.inv := iso.inv.ne

@[simp] theorem Iso.hom_inv_dist [OFE α] [OFE β] (iso : Iso α β) {n} {x} :
    iso.hom (iso.inv x) ≡{n}≡ x

@[simp] theorem Iso.inv_hom_dist [OFE α] [OFE β] (iso : Iso α β) {n} {x} :
    iso.inv (iso.hom x) ≡{n}≡ x

theorem Iso.hom_eqv [OFE α] [OFE β] (iso : Iso α β) ⦃x y⦄ :
    x ≡ y ↔ iso.hom x ≡ iso.hom y

theorem Iso.inv_eqv [OFE α] [OFE β] (iso : Iso α β) ⦃x y⦄ :
    x ≡ y ↔ iso.inv x ≡ iso.inv y

theorem Iso.hom_dist [OFE α] [OFE β] (iso : Iso α β) {n} ⦃x y⦄ :
    x ≡{n}≡ y ↔ iso.hom x ≡{n}≡ iso.hom y

theorem Iso.inv_dist [OFE α] [OFE β] (iso : Iso α β) {n} ⦃x y⦄ :
    x ≡{n}≡ y ↔ iso.inv x ≡{n}≡ iso.inv y

def Iso.id [OFE α] : Iso α α where
  hom := Hom.id
  inv := Hom.id
  hom_inv := by admit /- proof elided -/

@[simp] theorem Iso.id_apply [OFE α] {x} : ((Iso.id : Iso α α) : α -n> α) x = x

def Iso.symm [OFE α] [OFE β] (iso : Iso α β) : Iso β α where
  hom := iso.inv
  inv := iso.hom
  hom_inv := by admit /- proof elided -/

def Iso.comp [OFE α] [OFE β] [OFE γ] (iso1 : Iso β γ) (iso2 : Iso α β) : Iso α γ where
  hom := iso1.hom.comp iso2.hom
  inv := iso2.inv.comp iso1.inv
  hom_inv := by admit /- proof elided -/

end OFE

structure Chain (α : Type _) [OFE α] where
  chain : Nat → α
  cauchy : n ≤ i → chain i ≡{n}≡ chain n

instance [OFE α] : CoeFun (Chain α) (fun _ => Nat → α) := ⟨Chain.chain⟩

namespace Chain

def const [OFE α] (a : α) : Chain α where
  chain := fun _ => a
  cauchy _ := OFE.Dist.rfl

@[simp] theorem const_apply [OFE α] {a : α} {n} : const a n = a

def map [OFE α] [OFE β] (f : α -n> β) (c : Chain α) : Chain β where
  chain n := f (c n)
  cauchy h := f.ne.1 (c.cauchy h)

@[simp] theorem map_apply [OFE α] [OFE β] {f : α -n> β} {c : Chain α} {n} :
    map f c n = f (c n)

@[simp] theorem map_id [OFE α] {c : Chain α} : map (Hom.id : α -n> α) c = c

theorem map_comp [OFE α] [OFE β] [OFE γ] {f : α -n> β} {g : β -n> γ} {c : Chain α} :
    map (g.comp f) c = map g (map f c)

end Chain

theorem chain_none_const [OFE V] {c : Chain (Option V)} (H : c n = none) :
    c = Chain.const none

def chain_option_some [OFE V] {c : Chain (Option V)} (H : c n = some v) :
    ∃ c' : Chain V, c = Chain.map ⟨some, OFE.Option.some.ne⟩ c' :=

class IsCOFE (α : Type _) [OFE α] where
  compl : Chain α → α
  conv_compl {c : Chain α} : compl c ≡{n}≡ c n

namespace COFE

theorem conv_compl' [COFE α] {c : Chain α} {n i} (h : n ≤ i) : compl c ≡{n}≡ c i

theorem compl_map [COFE α] [COFE β] (f : α -n> β) (c : Chain α) :
    compl (Chain.map f c) ≡ f (compl c)

@[simp] theorem compl_const [COFE α] (a : α) : compl (Chain.const a) ≡ a

@[simp] theorem discrete_cofe_compl [COFE α] [OFE.Discrete α] (c : Chain α) : compl c ≡ c 0

def ofDiscrete (Equiv : α → α → Prop) (equiv_eqv : Equivalence Equiv) : COFE α :=
  let _ := OFE.ofDiscrete Equiv equiv_eqv
  { compl := fun c => c 0
    conv_compl := fun {_ c} => equiv_eqv.2 (c.cauchy (Nat.zero_le _)) }

instance [COFE α] : COFE (ULift α) where
  compl c := ⟨compl (c.map uliftDownHom)⟩
  conv_compl := conv_compl

instance : COFE Unit where
  compl _ := ()
  conv_compl := ⟨⟩

abbrev IsCOFEFun {α : Type _} (β : α → Type _) [OFEFun β] := ∀ x : α, IsCOFE (β x)

instance {α : Type _} (β : α → Type _) [∀ x, COFE (β x)] : COFE ((x : α) → β x) where
  compl c x := compl (c.map (applyHom x))
  conv_compl _ := IsCOFE.conv_compl

abbrev OFunctorPre := ∀ α β [OFE α] [OFE β], Type _

class OFunctor (F : OFunctorPre) where
  
  
  
  cofe [OFE α] [OFE β] : OFE (F α β)
  map [OFE α₁] [OFE α₂] [OFE β₁] [OFE β₂] :
    (α₂ -n> α₁) → (β₁ -n> β₂) → F α₁ β₁ -n> F α₂ β₂
  map_ne [OFE α₁] [OFE α₂] [OFE β₁] [OFE β₂] :
    NonExpansive₂ (@map α₁ α₂ β₁ β₂ _ _ _ _)
  map_id [OFE α] [OFE β] (x : F α β) : map (@Hom.id α _) (@Hom.id β _) x ≡ x
  map_comp [OFE α₁] [OFE α₂] [OFE α₃] [OFE β₁] [OFE β₂] [OFE β₃]
    (f : α₂ -n> α₁) (g : α₃ -n> α₂) (f' : β₁ -n> β₂) (g' : β₂ -n> β₃) (x : F α₁ β₁) :
    map (f.comp g) (g'.comp f') x ≡ map g g' (map f f' x)

class OFunctorContractive (F : OFunctorPre) extends OFunctor F where
  map_contractive [OFE α₁] [OFE α₂] [OFE β₁] [OFE β₂] :
    Contractive (Function.uncurry (@map α₁ α₂ β₁ β₂ _ _ _ _))

abbrev constOF (B : Type) : OFunctorPre := fun _ _ _ _ => B

instance oFunctorConstOF [OFE B] : OFunctor (constOF B) where
  cofe := _
  map _ _ := ⟨id, id_ne⟩
  map_ne := by admit /- proof elided -/

instance OFunctor.constOF_contractive [OFE B] : OFunctorContractive (constOF B) where
  map_contractive.1 := by admit /- proof elided -/

end COFE

@[ext] structure LeibnizO (α : Type _) where
  car : α

theorem Eq_Equivalence {α : Type _} : Equivalence (@Eq α)

instance : COFE (LeibnizO α) := COFE.ofDiscrete _ Eq_Equivalence

instance : Leibniz (LeibnizO α) := ⟨(·)⟩

instance {α : Type _} : OFE.Discrete (LeibnizO α) := ⟨congrArg id⟩

instance {α : Type _} : OFE.Leibniz (LeibnizO α) := ⟨congrArg id⟩

theorem LeibnizO.eqv_inj {x y : α} (H : LeibnizO.mk x ≡ LeibnizO.mk y) : x = y

theorem LeibnizO.dist_inj {x y : α} {n} (H : LeibnizO.mk x ≡{n}≡ LeibnizO.mk y) : x = y

section DiscreteFunOF

open COFE

abbrev DiscreteFunOF {C : Type _} (F : C → OFunctorPre) : OFunctorPre :=
  fun A B _ _ => (c : C) → F c A B

instance oFunctor_discreteFunOF {C} (F : C → OFunctorPre) [∀ c, OFunctor (F c)] :
    OFunctor (DiscreteFunOF F) where
  cofe := _
  map f₁ f₂ := mapCodHom fun c => OFunctor.map f₁ f₂
  map_ne.ne _ _ _ Hx _ _ Hy _ _ := by admit /- proof elided -/

end DiscreteFunOF

section Option

variable [OFE α]

def optionChain (c : Chain (Option α)) (x : α) : Chain α :=

instance isCOFE_option [IsCOFE α] : IsCOFE (Option α) where
  compl c := (c 0).map fun x => IsCOFE.compl (optionChain c x)
  conv_compl {n} c := by admit /- proof elided -/

def optionMap {α β : Type _} [OFE α] [OFE β] (f : α -n> β) : Option α -n> Option β :=

end Option

section OptionOF

open COFE

abbrev OptionOF (F : OFunctorPre) : OFunctorPre :=
  fun A B _ _ => Option (F A B)

variable (F : OFunctorPre)

instance oFunctorOption [OFunctor F] : OFunctor (OptionOF F) where
  cofe := _
  map f g := optionMap (OFunctor.map f g)
  map_ne.ne _ _ _ Hx _ _ Hy z := by admit /- proof elided -/

instance [OFunctorContractive F] : OFunctorContractive (OptionOF F) where
  map_contractive.1 H z := by admit /- proof elided -/

end OptionOF

section Fixpoint

def LimitPreserving [COFE α] (P : α → Prop) : Prop :=
  ∀ (c : Chain α), (∀ n, P (c n)) → P (COFE.compl c)

theorem LimitPreserving.const [COFE α] {P : Prop} : LimitPreserving fun (_ : α) => P

theorem LimitPreserving.discrete [COFE α] {P : α → Prop} :
    (∀ {x y : α}, x ≡{0}≡ y → (P x → P y)) → LimitPreserving P

theorem LimitPreserving.and [COFE α] {P Q : α → Prop}  (HP : LimitPreserving P)
    (HQ : LimitPreserving Q) : LimitPreserving fun a => P a ∧ Q a

theorem LimitPreserving.forall [COFE α] (P : β → α → Prop) (Hlim : ∀ y, LimitPreserving (P y)) :
    LimitPreserving (∀ y, P y ·)

theorem LimitPreserving.impl [COFE α] (P1 P2 : α → Prop)
    (HP1 : ∀ {x y : α}, x ≡{0}≡ y → P1 x → P1 y)
    (Hcompl : LimitPreserving P2) :
    LimitPreserving (fun x => P1 x → P2 x)

theorem LimitPreserving.equiv [COFE α] [COFE β] (f g : α -n> β) :
    LimitPreserving (fun x => f x ≡ g x)

def Fixpoint.chain [OFE α] [Inhabited α] (f : α → α) [Contractive f] : Chain α where
  chain n := Nat.repeat f (n + 1) default
  cauchy {n} := by admit /- proof elided -/

def fixpoint [COFE α] [Inhabited α] (f : α → α) [Contractive f] : α :=
  COFE.compl <| Fixpoint.chain f

nonrec abbrev OFE.ContractiveHom.fixpoint [COFE α] [Inhabited α] (f : α -c> α) : α := fixpoint f.f

theorem fixpoint_unfold [COFE α] [Inhabited α] (f : α -c> α) :
    fixpoint f ≡ f (fixpoint f)

theorem fixpoint_unique [COFE α] [Inhabited α] {f : α -c> α} {x : α} (H : x ≡ f x) :
    x ≡ fixpoint f

instance OFE.ContractiveHom.fixpoint_ne [COFE α] [Inhabited α] :
    NonExpansive (ContractiveHom.fixpoint (α := α)) where
  ne n f1 f2 H := by admit /- proof elided -/
</local_ctx>

<target_theorem>
@[elab_as_elim]
theorem OFE.ContractiveHom.fixpoint_ind [COFE α] [Inhabited α] (f : α -c> α)
    (P : α → Prop) (HProper : ∀ A B : α, A ≡ B → P A → P B) (x : α) (Hbase : P x)
    (Hind : ∀ x, P x → P (f x)) (Hlim : LimitPreserving P) :
    P f.fixpoint :=
</target_theorem>

