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>
@[ext]
structure Agree where
  car : List α
  not_nil : car ≠ []

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

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)

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 -/

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

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

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

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)

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 -/

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

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

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

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

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)

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

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

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

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

abbrev Relation (α : Type _) := α → α → Prop

class Reflexive (R : Relation α) where
  refl {x : α} : R x x

class Transitive (R : Relation α) where
  trans {x y z : α} : R x y → R y z → R x z

class Preorder (R : Relation α) extends Reflexive R, Transitive R

class Idempotent (R : Relation α) (f : α → α → α) where
  idem {x : α} : R (f x x) x

class Commutative (R : Relation α) (f : β → β → α) where
  comm {x y : β} : R (f x y) (f y x)

class LeftId (R : Relation α) (i : α) (f : α → α → α) where
  left_id {x : α} : R (f i x) x

class RightId (R : Relation α) (i : α) (f : α → α → α) where
  right_id {x : α} : R (f x i) x

class Associative (R : Relation α) (f : α → α → α) where
  assoc {x y z : α} : R (f (f x y) z) (f x (f y z))

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

def Replaces [BI PROP] (K A B : PROP) := (B -∗ K) ⊢ (A -∗ K)

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'))

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

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

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

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

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

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

@[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))

@[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)

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)

instance [BI PROP] : IsModal (PROP1 := PROP) id (.id rfl) (.id rfl) :=

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"

inductive AssumptionFastPath (prop : Q(Type u)) (bi : Q(BI $prop)) (Q : Q($prop)) where
  | absorbing (_ : Q(Absorbing $Q))
  | biAffine (_ : Q(BIAffine $prop))

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)

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))

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

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

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

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

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

@[match_pattern] def nameAnnotation := `name

@[match_pattern] def uniqAnnotation := `uniq

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

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

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

instance : Inhabited (Hyps bi s) := ⟨.emp ⟨⟩⟩

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

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

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

def isTrue (p : Q(Bool)) : Bool := p.constName! == ``true

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

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, ⟨⟩⟩

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 ⟨⟩

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 ⟨⟩⟩

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

abbrev Entails' [BI PROP] : PROP → PROP → Prop := Entails

structure IrisGoal where
  u : Level
  prop : Q(Type u)
  bi : Q(BI $prop)
  e : Q($prop)
  hyps : Hyps bi e
  goal : Q($prop)

def isIrisGoal (expr : Expr) : Bool := isAppOfArity expr ``Entails' 4

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 }

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

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

def HypMarker {PROP : Type _} (_A : PROP) : Prop := True

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? })

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

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

@[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

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

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

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

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 -/

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

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

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

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

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

def A (n : Nat) : Type u := (A' F n).1

instance instA' (n) : COFE (A' F n).1 := (A' F n).2

instance instA (n) : COFE (A F n) := (A' F n).2

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

def down : ∀ k, A F (k+1) -n> A F k
  | 0 => ⟨fun _ => ⟨()⟩, ⟨fun _ _ _ _ => .rfl⟩⟩
  | k+1 => map (up k) (down k)

@[ext] structure Tower : Type u where
  val k : A F k
  protected down {k} : down F k (val (k+1)) ≡ val k

instance : CoeFun (Tower F) (fun _ => ∀ k, A F k) := ⟨Tower.val⟩

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 -/

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

instance : COFE (Tower F) where
  compl c := by admit /- proof elided -/

def upN {k} : ∀ n, A F k -n> A F (k + n)
  | 0 => .id
  | n+1 => (up F (k + n)).comp (upN n)

def downN {k} : ∀ n, A F (k + n) -n> A F k
  | 0 => .id
  | n+1 => (downN n).comp (down F (k + n))

instance (k : Nat) : NonExpansive (fun X : Tower F => X.val k) := ⟨fun _ _ _ => (· _)⟩

def Tower.proj (k) : Tower F -n> A F k := ⟨(· k), ⟨fun _ _ _ => (· _)⟩⟩

def eqToHom (e : i = k) : A F i -n> A F k := e ▸ .id

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)

protected def Tower.embed (k) : A F k -n> Tower F :=

instance : Inhabited (Tower F) := ⟨Tower.embed 0 ⟨()⟩⟩

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 -/

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 -/

def Fix : Type u := Tower F

instance : Inhabited (Fix F) := inferInstanceAs (Inhabited (Tower F))

instance : COFE (Fix F) := inferInstanceAs (COFE (Tower F))

def Fix.iso : OFE.Iso (F (Fix F) (Fix F)) (Fix F) := Tower.iso

def Fix.fold : F (Fix F) (Fix F) -n> Fix F := Fix.iso.hom

def Fix.unfold : Fix F -n> F (Fix F) (Fix F) := Fix.iso.inv

class Plainly (PROP : Type _) where
  plainly : PROP → PROP

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

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

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

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

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

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

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))

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)

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⟩

inductive splitSide where
| splitLeft | splitRight

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!]

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)

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))

inductive Excl α where
  | excl : α → Excl α
  | invalid : Excl α

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

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

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

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

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

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

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

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

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

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

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

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 -/

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

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

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

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

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

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

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 -/

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

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

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

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⟩

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)

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 -/

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

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⟩

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

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 -/

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 -/

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

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

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 -/

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 -/

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

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

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

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 -/

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

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

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

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

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')

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

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

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

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

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

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

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

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

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

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

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 -/

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

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

def GFunctors := Array COFE.OFunctorPre

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

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

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

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

def GName := LeibnizO Nat

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

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

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

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

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

abbrev IProp := UPred (IResUR FF)

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))

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)

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 ⟨⟩))

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)

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)

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'))

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'))

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

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

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'⟩

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}"

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⟩

inductive RewriteModifier
  | single
  | all

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

inductive RewriteDirection
  | forward
  | reverse

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

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

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

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

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

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

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

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

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

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

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

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

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

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)

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 -/

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

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

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

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 -/

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

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

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

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

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

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

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

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⟩

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)

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"

macro:max "iprop(" P:term " : " t:term ")" : term => `((iprop($P) : $t))

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)

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

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

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

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

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

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

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

structure PMTerm where
  term : Term
  terms : List Term
  spats : List SpecPat
  deriving Repr, Inhabited

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)

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)

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

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

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

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

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

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

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

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

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

instance intoEmpValid_emp_entails [BI PROP] (P : PROP) : IntoEmpValid (⊢ P) iprop(P) where
  into_emp_valid := id

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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 -/

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 -/

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

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

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

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

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

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

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

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

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)

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

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 -/

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

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

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

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)

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)

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)

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)

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

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

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

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

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

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

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

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

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

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)

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)

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)

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)

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

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

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

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

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

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

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

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

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

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

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

instance fromAffinely_affine [BI PROP] (P : PROP) [Affine P] : FromAffinely P P true where
  from_affinely := affinely_elim

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

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

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

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

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

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

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

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

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)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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)

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)

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 -/

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 -/

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 -/

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

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

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

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

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

@[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)

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

abbrev FF0 : GFunctors := #[]

local instance : IsGFunctors FF0 := nofun

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

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

abbrev γ : GId FF1 := ⟨0, Nat.zero_lt_succ _⟩

local instance : IsGFunctors FF1 := fun i => by admit /- proof elided -/

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

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

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

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

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

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)

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

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)

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"

private def matchAlts' := leading_parser matchAlts

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

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

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

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⟩

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₂

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

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

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

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

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

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

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)

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

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

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

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

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

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⟩

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 -/

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

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

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 -/

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

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

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

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

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

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 -/

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

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

instance : Leibniz (LeibnizO α) := ⟨(·)⟩

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

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

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 -/

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 β :=

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

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 -/

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

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

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

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

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 -/

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

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 _)

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 -/

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

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

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 ..

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]

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

class Disjoint (α : Type u) where
  disjoint : α → α → Prop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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)

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)

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

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

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)

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)

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

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

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)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

macro "%" pat:icasesPat : icasesPat => `(icasesPat| ⌜$pat⌝)

macro "#" pat:icasesPat : icasesPat => `(icasesPat| □ $pat)

macro "*" pat:icasesPat : icasesPat => `(icasesPat| ∗ $pat)

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

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

class BIAffine (PROP : Type _) [BI PROP] where
  affine (P : PROP) : Affine P

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

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

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

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

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)

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

class Affine [BI PROP] (P : PROP) where
  affine : P ⊢ emp

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

class Intuitionistic [BI PROP] (P : PROP) where
  intuitionistic : P ⊢ □ P

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

abbrev HeapProp (Val : Type _) := State Val → Prop

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 σ

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

instance : COFE (HeapProp Val) := COFE.ofDiscrete Eq equivalence_eq

instance : BI (HeapProp Val) where
  entails_preorder := by admit /- proof elided -/

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

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

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

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))

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

def iff     [BIBase PROP] (P Q : PROP) : PROP := iprop((P → Q) ∧ (Q → P))

def wandIff [BIBase PROP] (P Q : PROP) : PROP := iprop((P -∗ Q) ∧ (Q -∗ P))

def affinely    [BIBase PROP] (P : PROP) : PROP := iprop(emp ∧ P)

def absorbingly [BIBase PROP] (P : PROP) : PROP := iprop(True ∗ P)

structure BiEntails [BIBase PROP] (P Q : PROP) where
  mp : P ⊢ Q
  mpr : Q ⊢ P

macro:25 "⊢ " P:term:25 : term => ``(emp ⊢ $P)

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))

def intuitionistically [BIBase PROP] (P : PROP) : PROP := iprop(<affine> <pers> P)

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

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

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

def intuitionisticallyIf [BIBase PROP] (p : Bool) (P : PROP) : PROP := iprop(if p then □ P else P)

def bigAnd [BIBase PROP] (Ps : List PROP) : PROP := bigOp and iprop(True) Ps

def bigOr [BIBase PROP] (Ps : List PROP) : PROP := bigOp or iprop(False) Ps

def bigSep [BIBase PROP] (Ps : List PROP) : PROP := bigOp sep iprop(emp) Ps

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

def except0 [BIBase PROP] (P : PROP) := iprop(▷ False ∨ P)

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

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

@[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 -/

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

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

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 -/

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 -/

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

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 -/

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

@[simp] def unit : T := empty

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

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

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

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

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

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

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

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

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 -/

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

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

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

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

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

class FromImp [BI PROP] (P : PROP) (Q1 Q2 : outParam PROP) where
  from_imp : (Q1 → Q2) ⊢ P

class FromWand [BI PROP] (P : PROP) (Q1 Q2 : outParam PROP) where
  from_wand : (Q1 -∗ Q2) ⊢ P

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

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

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

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

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

class FromAnd [BI PROP] (P : PROP) (Q1 Q2 : outParam PROP) where
  from_and : Q1 ∧ Q2 ⊢ P

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

class FromSep [BI PROP] (P : PROP) (Q1 Q2 : outParam PROP) where
  from_sep : Q1 ∗ Q2 ⊢ P

class IntoSep [BI PROP] (P : PROP) (Q1 Q2 : outParam PROP) where
  into_sep : P ⊢ Q1 ∗ Q2

class FromOr [BI PROP] (P : PROP) (Q1 Q2 : outParam PROP) where
  from_or : Q1 ∨ Q2 ⊢ P

class IntoOr [BI PROP] (P : PROP) (Q1 Q2 : outParam PROP) where
  into_or : P ⊢ Q1 ∨ Q2

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

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

class IntoAbsorbingly [BI PROP] (P : outParam PROP) (Q : PROP) where
  into_absorbingly : P ⊢ <absorb> Q

class FromAssumption (p : Bool) [BI PROP] (P : semiOutParam PROP) (Q : PROP) where
  from_assumption : □?p P ⊢ Q

class IntoPure [BI PROP] (P : PROP) (φ : outParam Prop) where
  into_pure : P ⊢ ⌜φ⌝

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

inductive StateResult (α : Type _)
  | unknown
  | result (x : α)
  | conflict

abbrev State (Val : Type _) := Nat → StateResult Val

instance : EmptyCollection (State Val) where
  emptyCollection := fun _ => unknown

instance : HasSubset (State Val) where
  Subset a b := ∀ i x, a i = result x → b i = result x

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

instance : Disjoint (State Val) where
  disjoint a b := ∀ i, a i = unknown ∨ b i = unknown

def Set (α : Type _) := α → Prop

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

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

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

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

class BUpd (PROP : Type _) where
  bupd : PROP → PROP

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

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))

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)

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)

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

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 Φ

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

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

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

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

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

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

def Frac (α : Type _) := LeibnizO α

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

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

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

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

instance : Leibniz (Frac α) := inferInstanceAs (Leibniz (LeibnizO α))

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 -/

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

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

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

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

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

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

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

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

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

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 -/

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

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

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

def bigOp (f : PROP → PROP → PROP) (unit : PROP) : List PROP → PROP
  | []      => unit
  | [P]     => P
  | P :: Ps => f P (bigOp f unit Ps)

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)

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

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

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

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

instance : Inhabited (DFrac F) := ⟨discard⟩

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

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

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')

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 -/

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

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

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

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

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)

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) }

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

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

instance : TCTrue := TCTrue.t

instance [t : T] : TCOr T U := @TCOr.l T U t

instance [u : U] : TCOr T U := @TCOr.r T U u

instance [t : T] : TCIte (no_index true) T U := TCIte.t (t := t)

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

def maps_to (l : Nat) (v : Val) : HeapProp Val :=
  fun state => state l = result v

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₂

def Included (x y : α) : Prop := ∃ z, y ≡ x • z

def IncludedN (n : Nat) (x y : α) : Prop := ∃ z, y ≡{n}≡ x • z

def op? [CMRA α] (x : α) : Option α → α
  | some y => x • y
  | none => x

class CoreId (x : α) where
  core_id : pcore x ≡ some x

class Exclusive (x : α) where
  exclusive0_l y : ¬✓{0} x • y

class Cancelable (x : α) where
  cancelableN : ✓{n} x • y → x • y ≡{n}≡ x • z → y ≡{n}≡ z

class IdFree (x : α) where
  id_free0_r y : ✓{0} x → ¬x • y ≡{0}≡ x

class IsTotal (α : Type _) [CMRA α] where
  total (x : α) : ∃ cx, pcore x = some cx

def core (x : α) := (pcore x).getD x

class Discrete (α : Type _) [CMRA α] extends OFE.Discrete α where
  discrete_valid {x : α} : ✓{0} x → ✓ x

class UCMRA (α : Type _) extends CMRA α where
  unit : α
  unit_valid : ✓ unit
  unit_left_id : unit • x ≡ x
  pcore_unit : pcore unit ≡ some unit

instance : NonExpansive (pcore (α := α)) where
  ne n x {y} e := by admit /- proof elided -/

instance : Trans Equiv (Included (α := α)) Included where
  trans := inc_of_eqv_of_inc

instance : Trans (Included (α := α)) Equiv Included where
  trans := inc_of_inc_of_eqv

instance {n : Nat} : Trans (IncludedN (α := α) n) (Dist n) (IncludedN n) where
  trans := incN_of_incN_of_dist

instance {n : Nat} : Trans (Dist (α := α) n) (IncludedN n) (IncludedN n) where
  trans := incN_of_dist_of_incN

instance : Trans (Included (α := α)) Included Included where
  trans := inc_trans

instance : Trans (IncludedN (α := α) n) (IncludedN n) (IncludedN n) where
  trans := incN_trans

instance (y : α) : CoreId (core y) := CoreId.of_pcore_eq_some (pcore_eq_core _)

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

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

instance exclusive_cancelable {x : α} [Exclusive x] : Cancelable x where
  cancelableN v _ := absurd v not_valid_exclN_op_left

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

instance idFree_op_l {x y : α} [IdFree x] [Cancelable y] : IdFree (x • y) :=
  comm.idFree.1 inferInstance

instance exclusive_idFree {x : α} [Exclusive x] : IdFree x where
  id_free0_r z v h := exclusive0_l z ((validN_iff h.symm).mp v)

instance unit_CoreId : CoreId (unit : α) where
  core_id := pcore_unit

instance unit_total : IsTotal α where
  total _ :=
    have ⟨y, hy, _⟩ := pcore_mono' inc_unit pcore_unit
    ⟨y, hy⟩

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

@[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

instance [CMRA β] : CoeFun (α -C> β) (fun _ => α → β) := ⟨fun F => F.f⟩

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

protected def Hom.id [CMRA α] : α -C> α where
  toHom := OFE.Hom.id
  validN := id
  pcore x := by admit /- proof elided -/

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)

class RFunctorContractive (F : COFE.OFunctorPre) extends (RFunctor F) where
  map_contractive [OFE α₁] [OFE α₂] [OFE β₁] [OFE β₂] :
    Contractive (Function.uncurry (@map α₁ α₂ β₁ β₂ _ _ _ _))

def RFunctor.ap [RFunctor F] [OFE T] := F T T

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

instance RFunctorContractive.toOFunctorContractive
    [RFunctorContractive F] : COFE.OFunctorContractive F where
  map_contractive.1 := map_contractive.1

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)

class URFunctorContractive (F : COFE.OFunctorPre) extends URFunctor F where
  map_contractive [OFE α₁] [OFE α₂] [OFE β₁] [OFE β₂] :
    Contractive (Function.uncurry (@map α₁ α₂ β₁ β₂ _ _ _ _))

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

instance URFunctorContractive.toRFunctorContractive
    [URFunctorContractive F] : RFunctorContractive F where
  map_contractive := map_contractive

instance COFE.OFunctor.constOF_RFunctor [CMRA B] : RFunctor (constOF B) where
  map f g := by admit /- proof elided -/

instance OFunctor.constOF_RFunctorContractive [CMRA B] :
    RFunctorContractive (COFE.constOF B) where
  map_contractive.1 := by admit /- proof elided -/

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 -/

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 _

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 -/

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 _

@[simp] def optionCore (x : Option α) : Option α := x.bind pcore

@[simp] def optionOp (x y : Option α) : Option α :=
  match x, y with
  | some x', some y' => some (CMRA.op x' y')
  | none, _ => y
  | _, none => x

@[simp] def optionValidN (n : Nat) : Option α → Prop
  | some x => ✓{n} x
  | none => True

@[simp] def optionValid : Option α → Prop
  | some x => ✓ x
  | none => True

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 -/

instance ucmraOption : UCMRA (Option α) where
  unit := none
  unit_valid := by admit /- proof elided -/

instance {a : α} [IdFree a] [Cancelable a] : Cancelable (some a) :=

instance {ma : Option α} [∀ a : α, IdFree a] [∀ a : α, Cancelable a] : Cancelable ma :=

instance [CMRA.Discrete α] : CMRA.Discrete (Option α) where
  discrete_valid {x} := by admit /- proof elided -/

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⟩

abbrev pcore (x : α × β) : Option (α × β) :=
  (CMRA.pcore x.fst).bind fun a =>
  (CMRA.pcore x.snd).bind fun b =>
  return (a, b)

abbrev op (x y : α × β) : α × β :=
  (x.1 • y.1, x.2 • y.2)

abbrev ValidN n (x : α × β) := ✓{n} x.fst ∧ ✓{n} x.snd

abbrev Valid (x : α × β) := ✓ x.fst ∧ ✓ x.snd

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 -/

instance [CMRA.Discrete α] [CMRA.Discrete β]: CMRA.Discrete (α × β) where
  discrete_valid := by admit /- proof elided -/

instance urFunctorOptionOF [RFunctor F] : URFunctor (OptionOF F) where
  cmra {α β} := ucmraOption
  map f g := {
    toHom := COFE.OFunctor.map f g
    validN := by admit /- proof elided -/

instance urFunctorContractiveOptionOF
    [RFunctorContractive F] : URFunctorContractive (OptionOF F) where
  map_contractive.1 := COFE.OFunctorContractive.map_contractive.1

abbrev GenMap := α → Option β

abbrev GenMapOF (C : Type _) (F : COFE.OFunctorPre) :=
  DiscreteFunOF fun (_ : C) => OptionOF F

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>
theorem Agree.dist_equiv : Equivalence (dist (α := α) n)

theorem Agree.dist_def {x y : Agree α} : x ≡{n}≡ y ↔ Agree.dist n x y

theorem Agree.op_comm {x y : Agree α} :  x.op y ≡ y.op x

theorem Agree.op_commN {x y : Agree α} :  x.op y ≡{n}≡ y.op x

theorem Agree.op_assoc {x y z : Agree α} :  x.op (y.op z) ≡ (x.op y).op z

theorem Agree.idemp {x : Agree α} : x.op x ≡ x

theorem Agree.validN_ne {x y : Agree α} : x ≡{n}≡ y → x.validN n → y.validN n

theorem Agree.op_ne {x : Agree α} : OFE.NonExpansive x.op

theorem liftRel_eq : liftRel (@Eq α) A B ↔ A = B

theorem BIBase.Entails.trans [BI PROP] {P Q R : PROP} (h1 : P ⊢ Q) (h2 : Q ⊢ R) : P ⊢ R

@[simp] theorem BIBase.Entails.rfl [BI PROP] {P : PROP} : P ⊢ P

theorem BIBase.Entails.of_eq [BI PROP] {P Q : PROP} (h : P = Q) : P ⊢ Q

@[simp] theorem BIBase.BiEntails.rfl [BI PROP] {P : PROP} : P ⊣⊢ P

theorem BIBase.BiEntails.of_eq [BI PROP] {P Q : PROP} (h : P = Q) : P ⊣⊢ Q

theorem BIBase.BiEntails.symm [BI PROP] {P Q : PROP} (h : P ⊣⊢ Q) : Q ⊣⊢ P

theorem BIBase.BiEntails.trans [BI PROP] {P Q R : PROP} (h1 : P ⊣⊢ Q) (h2 : Q ⊣⊢ R) : P ⊣⊢ R

theorem proof_example_1 [BI PROP] (P Q R : PROP) (Φ : α → PROP) :
  P ∗ Q ∗ □ R ⊢ □ (R -∗ ∃ x, Φ x) -∗ ∃ x, Φ x ∗ P ∗ Q

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

theorem replaces_r [BI PROP] {K P Q Q' : PROP} (h : Replaces K Q Q') :
    Replaces K iprop(P ∗ Q) iprop(P ∗ Q')

theorem replaces_l [BI PROP] {K P P' Q : PROP} (h : Replaces K P P') :
    Replaces K iprop(P ∗ Q) iprop(P' ∗ Q)

theorem Replaces.apply [BI PROP] {P P' Q : PROP}
    (h : Replaces Q P P') (h_entails : P' ⊢ Q) : P ⊢ Q

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')

theorem to_persistent_intuitionistic [BI PROP] {P P' Q : PROP}
    [hP : IntoPersistently true P P'] : Replaces Q iprop(□ P) iprop(□ P')

theorem from_affine [BI PROP] {p : Bool} {P P' Q : PROP} [hP : FromAffinely P' P p] :
    Replaces Q iprop(□?p P) P'

theorem LocalUpdate.id (x : α × α) : x ~l~> x

theorem LocalUpdate.equiv_left {x y : α × α} (z : α × α) (h : x ≡ y) : x ~l~> z → y ~l~> z

theorem LocalUpdate.equiv_right (x : α × α) {y z : α × α} (h : y ≡ z) : x ~l~> y → x ~l~> z

theorem LocalUpdate.exclusive [CMRA.Exclusive y] {x x' : α}
    (vx' : ✓ x') : (x, y) ~l~> (x', x')

theorem LocalUpdate.op {x y z : α}
    (h : ∀ n, ✓{n} x → ✓{n} (z • x)) : (x, y) ~l~> (z • x, z • y)

theorem LocalUpdate.op_discrete [CMRA.Discrete α] (x y z : α)
    (h : ✓ x → ✓ (z • x)) : (x, y) ~l~> (z • x, z • y)

theorem LocalUpdate.op_frame (x y x' y' yf : α)
    (h : (x, y) ~l~> (x', y')) : (x, y • yf) ~l~> (x', y' • yf)

theorem LocalUpdate.cancel (x y z : α) [CMRA.Cancelable x] : (x • y, x • z) ~l~> (y, z)

theorem LocalUpdate.replace (x y : α) [CMRA.IdFree x] (h : ✓ y) : (x, x) ~l~> (y, y)

theorem LocalUpdate.core_id (x y z : α) [CMRA.CoreId y] (inc : y ≼ x) : (x, z) ~l~> (x, z • y)

theorem LocalUpdate.discrete [CMRA.Discrete α] (x y x' y' : α) :
    (x, y) ~l~> (x', y') ↔ ∀ mz, ✓ x → x ≡ y •? mz → (✓ x' ∧ x' ≡ y' •? mz)

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')

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')

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')

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')

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)

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)

theorem cancel_local_update_unit (x y : α) [CMRA.Cancelable x] : (x • y, x) ~l~> (y, CMRA.unit)

theorem LocalUpdate.unit {x y x' y' : Unit} : (x, y) ~l~> (x', y')

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')

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')

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'))

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))

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'))

theorem LocalUpdate.option {x y x' y' : α}
    (h : (x, y) ~l~> (x', y')) : (some x, some y) ~l~> (some x', some y')

theorem LocalUpdate.option_none {α} [UCMRA α] {x x' y' : α}
    (h : (x, CMRA.unit) ~l~> (x', y')) : (some x, none) ~l~> (some x', some y')

theorem LocalUpdate.alloc_option {x : α} (y : Option α)
    (vx : ✓ x) : (none, y) ~l~> (some x, some x)

theorem LocalUpdate.delete_option (x : Option α) (y : α) [CMRA.Exclusive y] :
    (x, some y) ~l~> (none, none)

theorem LocalUpdate.delete_option_cancelable
    (mx : Option α) [CMRA.Cancelable mx] : (mx, mx) ~l~> (none, none)

theorem pure_assumption [BI PROP] {P A Q : PROP} (h_P : ⊢ A)
    [inst : FromAssumption true A Q] [TCOr (Affine P) (Absorbing Q)] :
    P ⊢ Q

theorem assumption_l [BI PROP] {P Q R : PROP} [Affine Q] (h : P ⊢ R) : P ∗ Q ⊢ R

theorem assumption_r [BI PROP] {P Q R : PROP} [Affine P] (h : Q ⊢ R) : P ∗ Q ⊢ R

theorem exfalso [BI PROP] {P Q : PROP} (h : P ⊢ False) : P ⊢ Q

theorem uPred_ne {P : UPred M} {n} {m₁ m₂} (H : m₁ ≡{n}≡ m₂) : P n m₁ ↔ P n m₂

theorem uPred_proper {P : UPred M} {n} {m₁ m₂} (H : m₁ ≡ m₂) : P n m₁ ↔ P n m₂

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

theorem down_up : ∀ {k} x, down F k (up F k x) ≡ x

theorem up_down {k} (x) : up F (k+1) (down F (k+1) x) ≡{k}≡ x

theorem downN_upN {k} (x : A F k) : ∀ {i}, downN F i (upN F i x) ≡ x

protected theorem Tower.up (X : Tower F) : up F (k+1) (X (k+1)) ≡{k}≡ X (k+2)

protected theorem Tower.upN (X : Tower F) : ∀ i, upN F i (X (k+1)) ≡{k}≡ X (k+1+i)

protected theorem Tower.downN (X : Tower F) : ∀ i, downN F i (X (k+i)) ≡ X k

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)

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)

theorem Tower.embed_up (x : A F k) :
    Tower.embed (k+1) (up F k x) ≡ Tower.embed k x

theorem Tower.embed_self (X : Tower F) :
    Tower.embed (k+1) (X (k+1)) ≡{k}≡ X

theorem Fix.fold_unfold (X : Fix F) : Fix.fold (Fix.unfold X) ≡ X

theorem Fix.unfold_fold (X : F (Fix F) (Fix F)) : Fix.unfold (Fix.fold X) ≡ X

theorem affinely_plainly_elim : <affine> ■ P ⊢ P

theorem persistently_elim_plainly : <pers> ■ P ⊣⊢ ■ P

theorem plainly_forall_2 {Ψ : α → PROP} : (∀ a, ■ (Ψ a)) ⊢ ■ (∀ a, Ψ a)

theorem plainly_persistently_elim : ■ <pers> P ⊣⊢ ■ P

theorem absorbingly_elim_plainly : <absorb> ■ P ⊣⊢ ■ P

theorem plainly_and_sep_elim : ■ P ∧ Q ⊢ (emp ∧ P) ∗ Q

theorem plainly_and_sep_assoc : ■ P ∧ (Q ∗ R) ⊣⊢ (■ P ∧ Q) ∗ R

theorem plainly_and_emp_elim : emp ∧ ■ P ⊢ P

theorem plainly_into_absorbingly : ■ P ⊢ <absorb> P

theorem plainly_elim [Absorbing P] : ■ P ⊢ P

theorem plainly_idemp : ■ ■ P ⊣⊢ ■ P

theorem plainly_intro' (H : ■ P ⊢ Q) : ■ P ⊢ ■ Q

theorem plainly_pure {φ} : ■ ⌜φ⌝ ⊣⊢ (⌜φ⌝ : PROP)

theorem plainly_forall {Ψ : α → PROP} : ■ (∀ a, Ψ a) ⊣⊢ ∀ a, ■ (Ψ a)

theorem plainly_exists_2 {α : Sort _} {Ψ : α → PROP} : (∃ a, ■ (Ψ a)) ⊢ ■ (∃ a, Ψ a)

theorem plainly_exists_1 [BIPlainlyExists PROP] {Ψ : α → PROP} :
    ■ (∃ a, Ψ a) ⊢ ∃ a, ■ (Ψ a)

theorem plainly_exists [BIPlainlyExists PROP] {Ψ : α → PROP} : ■ (∃ a, Ψ a) ⊣⊢ ∃ a, ■ (Ψ a)

theorem plainly_and : ■ (P ∧ Q) ⊣⊢ ■ P ∧ ■ Q

theorem plainly_or_2 : ■ P ∨ ■ Q ⊢ ■ (P ∨ Q)

theorem plainly_or [BIPlainlyExists PROP] : ■ (P ∨ Q) ⊣⊢ ■ P ∨ ■ Q

theorem plainly_impl : ■ (P → Q) ⊢ ■ P → ■ Q

theorem plainly_emp_2 : (emp : PROP) ⊢ ■ emp

theorem plainly_sep_dup : ■ P ⊣⊢ ■ P ∗ ■ P

theorem plainly_and_sep_l_1 : ■ P ∧ Q ⊢ ■ P ∗ Q

theorem plainly_and_sep_r_1 : P ∧ ■ Q ⊢ P ∗ ■ Q

theorem plainly_true_emp : ■ True ⊣⊢ ■ (emp : PROP)

theorem plainly_and_sep : ■ (P ∧ Q) ⊢ ■ (P ∗ Q)

theorem plainly_affinely_elim : ■ <affine> P ⊣⊢ ■ P

theorem intuitionistically_plainly_elim : □ ■ P ⊢ □ P

theorem intuitionistically_plainly : □ ■ P ⊢ ■ □ P

theorem and_sep_plainly : ■ P ∧ ■ Q ⊣⊢ ■ P ∗ ■ Q

theorem plainly_sep_2 : ■ P ∗ ■ Q ⊢ ■ (P ∗ Q)

theorem plainly_sep [BIPositive PROP] : ■ (P ∗ Q) ⊣⊢ ■ P ∗ ■ Q

theorem plainly_wand : ■ (P -∗ Q) ⊢ ■ P -∗ ■ Q

theorem plainly_entails_l (H : P ⊢ ■ Q) : P ⊢ ■ Q ∗ P

theorem plainly_entails_r (H : P ⊢ ■ Q) : P ⊢ P ∗ ■ Q

theorem plainly_impl_wand_2 : ■ (P -∗ Q) ⊢ ■ (P → Q)

theorem impl_wand_plainly_2 : (■ P -∗ Q) ⊢ (■ P → Q)

theorem impl_wand_affinely_plainly : (■ P → Q) ⊣⊢ (<affine> ■ P -∗ Q)

theorem persistently_wand_affinely_plainly [BIPersistentlyImplPlainly PROP] :
    (<affine> ■ P -∗ <pers> Q) ⊢ <pers> (<affine> ■ P -∗ Q)

theorem plainly_wand_affinely_plainly : (<affine> ■ P -∗ ■ Q) ⊢ ■ (<affine> ■ P -∗ Q)

theorem plainly_emp : ■ emp ⊣⊢ (emp : PROP)

theorem plainly_and_sep_l : ■ P ∧ Q ⊣⊢ ■ P ∗ Q

theorem plainly_and_sep_r : P ∧ ■ Q ⊣⊢ P ∗ ■ Q

theorem plainly_impl_wand : ■ (P → Q) ⊣⊢ ■ (P -∗ Q)

theorem impl_wand_plainly : (■ P → Q) ⊣⊢ (■ P -∗ Q)

theorem from_and_intro [BI PROP] {P Q A1 A2 : PROP} [inst : FromAnd Q A1 A2]
    (h1 : P ⊢ A1) (h2 : P ⊢ A2) : P ⊢ Q

theorem split_es [BI PROP] {Q Q1 Q2 : PROP} (h : Q ⊣⊢ Q1 ∗ Q2) : emp ∗ Q ⊣⊢ Q1 ∗ Q2

theorem split_ls [BI PROP] {P Q Q1 Q2 : PROP} (h : Q ⊣⊢ Q1 ∗ Q2) : P ∗ Q ⊣⊢ (P ∗ Q1) ∗ Q2

theorem split_rs [BI PROP] {P Q Q1 Q2 : PROP} (h : Q ⊣⊢ Q1 ∗ Q2) : P ∗ Q ⊣⊢ Q1 ∗ (P ∗ Q2)

theorem split_se [BI PROP] {P P1 P2 : PROP} (h : P ⊣⊢ P1 ∗ P2) : P ∗ emp ⊣⊢ P1 ∗ P2

theorem split_sl [BI PROP] {P Q P1 P2 : PROP} (h : P ⊣⊢ P1 ∗ P2) : P ∗ Q ⊣⊢ (P1 ∗ Q) ∗ P2

theorem split_sr [BI PROP] {P Q P1 P2 : PROP} (h : P ⊣⊢ P1 ∗ P2) : P ∗ Q ⊣⊢ P1 ∗ (P2 ∗ Q)

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)

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

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

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

theorem pure_elim_intuitionistic [BI PROP] {P P' A Q : PROP} {φ : Prop}
    [IntoPure A φ] (h : P ⊣⊢ P' ∗ □ A) (h' : φ → P' ⊢ Q) : P ⊢ Q

theorem pure_intro_affine [BI PROP] {Q : PROP} {φ : Prop}
    [h : FromPure true Q φ] [Affine P] (hφ : φ) : P ⊢ Q

theorem pure_intro_spatial [BI PROP] {Q : PROP} {φ : Prop}
    [h : FromPure false Q φ] (hφ : φ) : P ⊢ Q

theorem from_or_l [BI PROP] {P Q A1 A2 : PROP} [inst : FromOr Q A1 A2]
    (h1 : P ⊢ A1) : P ⊢ Q

theorem from_or_r [BI PROP] {P Q A1 A2 : PROP} [inst : FromOr Q A1 A2]
    (h1 : P ⊢ A2) : P ⊢ Q

theorem Excl.dist_eqv [OFE α] {n} : Equivalence (Excl.Dist (α := α) n)

theorem excl_included [OFE α] {x y : Excl α} : x ≼ y ↔ y = invalid

theorem excl_includedN [OFE α] {x y : Excl α} (n) : x ≼{n} y ↔ y = invalid

theorem invalid_included [OFE α] (ea : Excl α) : ea ≼ invalid

theorem excl_map_id : map id x = x

theorem excl_map_compose (f : α → β) (g : β → γ) :
    map (g ∘ f) x = map g (map f x)

theorem excl_map_ext [OFE α] [OFE β] (f g : α → β) (h : ∀ x, f x ≡ g x) : map f x ≡ map g x

theorem excl_map_ne [OFE α] [OFE β] (f : α -n> β) : NonExpansive (map f)

theorem uPred_entails_lim {cP cQ : Chain (UPred M)} (H : ∀ n, cP n ⊢ cQ n) :
    IsCOFE.compl cP ⊢ IsCOFE.compl cQ

theorem ownM_valid (m : M) : ownM m ⊢ cmraValid m

theorem ownM_op (m1 m2 : M) : ownM (m1 • m2) ⊣⊢ ownM m1 ∗ ownM m2

theorem ownM_always_invalid_elim (m : M) (H : ∀ n, ¬✓{n} m) : (cmraValid m : UPred M) ⊢ False

theorem intuitionistically_ownM_core (m : M) : ownM m ⊢ □ ownM (CMRA.core m)

theorem ownM_unit P : P ⊢ □ ownM (CMRA.unit : M)

theorem cmra_valid_intro P [CMRA A] (a : A) : ✓ a → P ⊢ (cmraValid a : UPred M)

theorem cmra_valid_elim [CMRA A] (a : A) : (cmraValid a : UPred M) ⊢ ⌜ ✓{0} a ⌝

theorem cmra_valid_weaken [CMRA A] (a b : A) : (cmraValid (a • b) : UPred M) ⊢ cmraValid a

theorem valid_entails [CMRA A] [CMRA B] {a : A} {b : B} (Himp : ∀ n, ✓{n} a → ✓{n} b) :
    (cmraValid a : UPred M) ⊢ cmraValid b

theorem pure_soundness : iprop(True ⊢ (⌜P⌝ : UPred M)) → P

theorem later_soundness : iprop(True ⊢ ▷ P) → iprop((True : UPred M) ⊢ P)

theorem persistently_ownM_core (a : M) : ownM a ⊢ <pers> ownM (CMRA.core a)

theorem bupd_ownM_updateP (x : M) (Φ : M → Prop) :
  (x ~~>: Φ) → ownM x ⊢ |==> ∃ y, ⌜Φ y⌝ ∧ ownM y

theorem cmraValid_intro [CMRA A] {P : UPred M} (a : A) (Ha : ✓ a) : P ⊢ cmraValid a

theorem cmraValid_elim [CMRA A] (a : A) : (cmraValid a : UPred M) ⊢ iprop(⌜ ✓{0} a ⌝)

theorem plainly_cmra_cmraValid_1 [CMRA A] (a : A) :
    (cmraValid a : UPred M) ⊢ ■ cmraValid a

theorem cmra_cmraValid_weaken [CMRA A] (a b : A) :
    (cmraValid (a • b) : UPred M) ⊢ cmraValid a

theorem cmraValid_entails [CMRA A] [CMRA B] {a : A} {b : B} (Hv : ∀ n, ✓{n} a → ✓{n} b) :
    (cmraValid a : UPred M) ⊢ cmraValid b

theorem false_elim_spatial [BI PROP] {P Q : PROP} : P ∗ False ⊢ Q

theorem false_elim_intuitionistic [BI PROP] {P Q : PROP} : P ∗ □ False ⊢ Q

theorem sep_emp_intro_spatial [BI PROP] {P Q : PROP} (h : P ⊢ Q) : P ∗ emp ⊢ Q

theorem sep_emp_intro_intuitionistic [BI PROP] {P Q : PROP}
    (h : P ⊢ Q) : P ∗ □ emp ⊢ Q

theorem exists_elim_spatial [BI PROP] {P A Q : PROP} {Φ : α → PROP} [inst : IntoExists A Φ]
    (h : ∀ a, P ∗ Φ a ⊢ Q) : P ∗ A ⊢ Q

theorem exists_elim_intuitionistic [BI PROP] {P A Q : PROP} {Φ : α → PROP} [IntoExists A Φ]
    (h : ∀ a, P ∗ □ Φ a ⊢ Q) : P ∗ □ A ⊢ Q

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

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

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

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

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

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

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

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

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

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

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

theorem intuitionistic_elim_intuitionistic [BI PROP] {A A' Q : PROP} [IntoPersistently true A A']
    (h : P ∗ □ A' ⊢ Q) : P ∗ □ A ⊢ Q

theorem spatial_elim_spatial [BI PROP] {A A' Q : PROP} [FromAffinely A' A false]
    (h : P ∗ A' ⊢ Q) : P ∗ A ⊢ Q

theorem spatial_elim_intuitionistic [BI PROP] {A A' Q : PROP} [FromAffinely A' A true]
    (h : P ∗ A' ⊢ Q) : P ∗ □ A ⊢ Q

theorem of_emp_sep [BI PROP] {A Q : PROP} (h : A ⊢ Q) : emp ∗ A ⊢ Q

theorem apply [BI PROP] {P Q1 Q2 R : PROP}
    (h : P ⊢ Q1) [inst : IntoWand false false R Q1 Q2] : P ∗ R ⊢ Q2

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

theorem apply_lean [BI PROP] {P Q R : PROP} (h1 : ⊢ Q) (h2 : P ∗ Q ⊢ R) : P ⊢ R

theorem apply_forall [BI PROP] (x : α) (P : α → PROP) {Q : PROP}
    [H1 : IntoForall Q P] (H2 : E ⊢ E' ∗ Q) : E ⊢ E' ∗ P x

theorem Agree.dist_equiv : Equivalence (dist (α := α) n)

theorem Agree.dist_def {x y : Agree α} : x ≡{n}≡ y ↔ Agree.dist n x y

theorem Agree.op_comm {x y : Agree α} :  x.op y ≡ y.op x

theorem Agree.op_commN {x y : Agree α} :  x.op y ≡{n}≡ y.op x

theorem Agree.op_assoc {x y z : Agree α} :  x.op (y.op z) ≡ (x.op y).op z

theorem Agree.idemp {x : Agree α} : x.op x ≡ x

theorem Agree.validN_ne {x y : Agree α} : x ≡{n}≡ y → x.validN n → y.validN n

theorem Agree.op_ne {x : Agree α} : OFE.NonExpansive x.op

theorem Agree.op_ne₂ : OFE.NonExpansive₂ (Agree.op (α := α))

theorem Agree.op_invN {x y : Agree α} : (x.op y).validN n → x ≡{n}≡ y

theorem Agree.op_inv {x y : Agree α} : (x.op y).valid → x ≡ y

theorem Agree.op_def {x y : Agree α} : x • y = x.op y

theorem Agree.validN_def {x : Agree α} : ✓{n} x ↔ x.validN n

theorem Agree.toAgree_injN {a b : α} : toAgree a ≡{n}≡ toAgree b → a ≡{n}≡ b

theorem Agree.toAgree_inj {a b : α} : toAgree a ≡ toAgree b → a ≡ b

theorem Agree.toAgree_uninjN {x : Agree α} : ✓{n} x → ∃ a, toAgree a ≡{n}≡ x

theorem pose [BI PROP] {P Q R : PROP}
    (H1 : P ∗ Q ⊢ R) (H2 : ⊢ Q) : P ⊢ R

theorem pose_forall [BI PROP] (x : α) (P : α → PROP) {Q : PROP}
    [H1 : IntoForall Q P] (H2 : ⊢ Q) : ⊢ P x

theorem UpdateP.equiv_left {P : α → Prop} {x y : α} (e : x ≡ y) (u : x ~~>: P) : y ~~>: P

theorem Update.equiv_left {x y z : α} (e : x ≡ y) (u : x ~~> z) : y ~~> z

theorem Update.equiv_right {x y z : α} (e : y ≡ z) (u : x ~~> y) : x ~~> z

theorem Update.of_updateP {x y : α} (h : x ~~>: (y = ·)) : x ~~> y

theorem UpdateP.of_update {x y : α} (h : x ~~> y) : x ~~>: (y = ·)

theorem UpdateP.id {P : α → Prop} {x} (h : P x) : x ~~>: P

theorem Update.id {x : α} : x ~~> x

theorem Update.trans {x y z : α} (uxy : x ~~> y) (uyz : y ~~> z) : x ~~> z

theorem UpdateP.trans {x : α} (ux : x ~~>: P) (upq : ∀ y, P y → y ~~>: Q) : x ~~>: Q

theorem Update.transP {x y : α} (uxy : x ~~> y) (uyq : y ~~>: Q) : x ~~>: Q

theorem UpdateP.weaken {x : α} (uxp : x ~~>: P) (pq : ∀ y, P y → Q y) : x ~~>: Q

theorem Update.exclusive {x y : α} [CMRA.Exclusive x] (vy : ✓ y) : x ~~> y

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

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

theorem Update.op {x₁ x₂ y₁ y₂ : α} (xy₁ : x₁ ~~> y₁) (xy₂ : x₂ ~~> y₂) : x₁ • x₂ ~~> y₁ • y₂

theorem Update.op_l {x y : α} : x • y ~~> x

theorem Update.op_r {x y : α} : x • y ~~> y

theorem Update.included {x y : α} : x ≼ y → y ~~> x

theorem Update.valid0 {x y : α} : (✓{0} x → x ~~> y) → x ~~> y

theorem UpdateP.total [CMRA.IsTotal α] :
    x ~~>: P ↔ ∀ (n : Nat) (z : α), ✓{n} (x • z) → ∃ y, P y ∧ ✓{n} (y • z)

theorem Update.total [CMRA.IsTotal α] :
    x ~~> y ↔ ∀ (n : Nat) (z : α), ✓{n} (x • z) → ✓{n} (y • z)

theorem UpdateP.discrete [CMRA.Discrete α] :
    x ~~>: P ↔ ∀ (mz : Option α), ✓ (x •? mz) → ∃ y, P y ∧ ✓ (y •? mz)

theorem Update.discrete [CMRA.Discrete α] {x y : α} :
    x ~~> y ↔ ∀ (mz : Option α), ✓ (x •? mz) → ✓ (y •? mz)

theorem UpdateP.discrete_total [CMRA.Discrete α] [CMRA.IsTotal α] :
    x ~~>: P ↔ ∀ (z : α), ✓ (x • z) → ∃ y, P y ∧ ✓ (y • z)

theorem Update.discrete_total [CMRA.Discrete α] [CMRA.IsTotal α] :
    x ~~> y ↔ ∀ (z : α), ✓ (x • z) → ✓ (y • z)

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

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

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

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

theorem UpdateP.prod' (P : α → Prop) (Q : β → Prop) (x : α × β)
    (uxp : x.fst ~~>: P) (uxq : x.snd ~~>: Q) : x ~~>: λ y ↦ P (y.fst) ∧ Q (y.snd)

theorem Update.prod (x : α × β) (uxy₁ : x.fst ~~> y.fst) (uxy₂ : x.snd ~~> y.snd) : x ~~> y

theorem UpdateP.option {P : α → Prop} {Q : Option α → Prop} {x : α}
    (uxp : x ~~>: P) (pq : ∀ y, P y → Q (some y)) : some x ~~>: Q

theorem UpdateP.option' (P : α → Prop) (x : α) (uxp : x ~~>: P) : some x ~~>: Option.rec False P

theorem Update.option (x y : α) (uxy : x ~~> y) : some x ~~> some y

theorem imp_intro_drop [BI PROP] {P Q A1 A2 : PROP} [inst : FromImp Q A1 A2] (h : P ⊢ A2) : P ⊢ Q

theorem from_forall_intro [BI PROP] {P Q : PROP} {Φ : α → PROP} [inst : FromForall Q Φ]
    (h : ∀ a, P ⊢ Φ a) : P ⊢ Q

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

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

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

theorem wand_intro_spatial [BI PROP] {P Q A1 A2 : PROP}
    [FromWand Q A1 A2] (h : P ∗ A1 ⊢ A2) : P ⊢ Q

theorem start_stop [BI PROP] (Q : PROP) (H : Q ⊢ Q) : Q ⊢ Q

theorem rename [BI PROP] (Q : PROP) : Q ⊢ Q

theorem rename_by_type [BI PROP] (Q : PROP) : □ P ∗ Q ⊢ Q

theorem rename_twice [BI PROP] (Q : PROP) : Q ⊢ Q

theorem rename_id [BI PROP] (Q : PROP) : Q ⊢ Q

theorem intuitionistic [BI PROP] (Q : PROP) : □ P ⊢ Q -∗ Q

theorem spatial [BI PROP] (Q : PROP) : <affine> P ⊢ Q -∗ Q

theorem spatial [BI PROP] (Q : PROP) : Q ⊢ Q

theorem intuitionistic [BI PROP] (Q : PROP) : □ Q ⊢ Q

theorem as_intuitionistic [BI PROP] (Q : PROP) : <affine> <pers> Q ⊢ Q

theorem as_intuitionistic_in_spatial [BI PROP] (Q : PROP) : ⊢ <pers> Q → Q

theorem drop [BI PROP] (Q : PROP) : ⊢ P → Q -∗ Q

theorem drop_after [BI PROP] (Q : PROP) : ⊢ Q -∗ P → Q

theorem «forall» [BI PROP] : ⊢ ∀ x, ⌜x = 0⌝ → (⌜x = 0⌝ : PROP)

theorem pure [BI PROP] [BIAffine PROP] (Q : PROP) : ⊢ ⌜φ⌝ -∗ Q -∗ Q

theorem pattern [BI PROP] (Q : PROP) : □ (P1 ∨ P2) ∗ Q ⊢ Q

theorem multiple_spatial [BI PROP] (Q : PROP) : ⊢ <affine> P -∗ Q -∗ Q

theorem multiple_intuitionistic [BI PROP] (Q : PROP) : ⊢ □ P -∗ □ Q -∗ Q

theorem multiple_patterns [BI PROP] (Q : PROP) : ⊢ □ (P1 ∧ P2) -∗ Q ∨ Q -∗ Q

theorem id [BI PROP] : ⊢ (∃ x, x : PROP)

theorem f [BI PROP] : ⊢ (∃ (_x : Nat), True ∨ False : PROP)

theorem pure [BI PROP] : ⊢ (⌜∃ x, x ∨ False⌝ : PROP)

theorem exact [BI PROP] (Q : PROP) : Q ⊢ Q

theorem def_eq [BI PROP] (Q : PROP) : <affine> <pers> Q ⊢ □ Q

theorem intuitionistic [BI PROP] (Q : PROP) : □ Q ⊢ Q

theorem exact [BI PROP] (Q : PROP) : Q ⊢ Q

theorem from_assumption [BI PROP] (Q : PROP) : <affine> <pers> Q ⊢ □ Q

theorem intuitionistic [BI PROP] (Q : PROP) : □ Q ⊢ Q

theorem lean [BI PROP] (Q : PROP) (H : ⊢ Q) : <affine> P ⊢ Q

theorem lean_pure [BI PROP] (Q : PROP) : <affine> ⌜⊢ Q⌝ ⊢ Q

theorem exact [BI PROP] (Q : PROP) : Q ⊢ Q

theorem apply [BI PROP] (P Q : PROP) : ⊢ P -∗ (P -∗ Q) -∗ Q

theorem multiple [BI PROP] (P Q R : PROP) : ⊢ P -∗ Q -∗ (P -∗ Q -∗ R) -∗ R

theorem multiple' [BI PROP] (P Q R S : PROP) : ⊢ (P -∗ Q) -∗ P -∗ R -∗ (Q -∗ R -∗ S) -∗ S

theorem exact_intuitionistic [BI PROP] (Q : PROP) : □ Q ⊢ Q

theorem apply_intuitionistic [BI PROP] (P Q : PROP) : ⊢ □ P -∗ (P -∗ Q) -∗ Q

theorem multiple_intuitionistic [BI PROP] (P Q R : PROP) : ⊢ □ P -∗ Q -∗ □ (P -∗ Q -∗ □ R) -∗ R

theorem later [BI PROP] (P Q : PROP) : ⊢ (▷ P -∗ Q) -∗ P -∗ Q

theorem affine [BI PROP] [BIAffine PROP] (P Q : PROP) : ⊢ (P → Q) -∗ <pers> P -∗ Q

theorem later_affine [BI PROP] [BIAffine PROP] (P Q : PROP) : ⊢ (▷ P → Q) -∗ P -∗ Q

theorem exact_lean [BI PROP] (Q : PROP) (H : ⊢ Q) : ⊢ Q

theorem exact_lean' [BI PROP] (Q : PROP) : Q ⊢ (emp ∗ Q) ∗ emp

theorem exact_lean'' [BI PROP] (Q : PROP) (H : 0 = 0 → ⊢ Q) : ⊢ Q

theorem apply_lean [BI PROP] (P Q : PROP) (H : P ⊢ Q) (HP : ⊢ P) : ⊢ Q

theorem apply_lean' [BI PROP] (P Q : PROP) (H : ⊢ P -∗ Q) (HP : ⊢ P) : ⊢ Q

theorem apply_lean'' [BI PROP] (P Q : PROP) (H1 : P ⊢ Q) (H2 : Q ⊢ R) : P ⊢ R

theorem multiple_lean [BI PROP] (P Q R : PROP) (H : P ⊢ Q -∗ R) (HP : ⊢ P) : ⊢ Q -∗ R

theorem multiple_lean' [BI PROP] (P Q R : PROP) (H : P ∗ Q ⊢ R) (HP : ⊢ P) : ⊢ Q -∗ R

theorem exact_forall [BI PROP] (P : α → PROP) (a : α) (H : ⊢ ∀ x, P x) : ⊢ P a

theorem exact_forall' [BI PROP] (P : α → PROP) (a : α) (H : ∀ x, ⊢ P x) : ⊢ P a

theorem apply_forall [BI PROP] (P Q : α → PROP) (a b : α) (H : ⊢ ∀ x, ∀ y, P x -∗ Q y) : P a ⊢ Q b

theorem apply_forall' [BI PROP] (P Q : α → PROP) (a b : α) : (∀ x, ∀ y, P x -∗ Q y) ⊢ P a -∗ Q b

theorem apply_forall_intuitionistic [BI PROP] (P Q : α → PROP) (a b : α) (H : ⊢ □ ∀ x, ∀ y, P x -∗ Q y) : P a ⊢ Q b

theorem apply_forall_intuitionistic' [BI PROP] (P Q : α → PROP) (a b : α) : (□ ∀ x, ∀ y, P x -∗ Q y) ⊢ P a -∗ Q b

theorem exact_lean [BI PROP] (Q : PROP) (H : ⊢ Q) : ⊢ Q

theorem apply_lean [BI PROP] (P Q : PROP) (H : P ⊢ Q) : ⊢ P -∗ Q

theorem apply_forall [BI PROP] (P Q : α → PROP) (a b : α) (H : ⊢ ∀ x, ∀ y, P x -∗ Q y) : P a ⊢ Q b

theorem apply_forall_intuitionistic [BI PROP] (P Q : α → PROP) (a b : α) (H : ⊢ □ ∀ x, ∀ y, P x -∗ Q y) : P a ⊢ Q b

theorem false_intro [BI PROP] (Q : PROP) : False ⊢ Q

theorem false [BI PROP] (P : PROP) : □ P ⊢ False -∗ Q

theorem pure [BI PROP] (P : PROP) (HF : False) : ⊢ P

theorem move [BI PROP] (Q : PROP) : <affine> ⌜φ⌝ ⊢ Q -∗ Q

theorem move_multiple [BI PROP] (Q : PROP) : <affine> ⌜φ1⌝ ⊢ <affine> ⌜φ2⌝ -∗ Q -∗ Q

theorem move_conjunction [BI PROP] (Q : PROP) : (⌜φ1⌝ ∧ <affine> ⌜φ2⌝) ⊢ Q -∗ Q

theorem move [BI PROP] (P : PROP) : □ P ⊢ Q -∗ Q

theorem move_multiple [BI PROP] (P : PROP) : □ P ⊢ □ Q -∗ Q

theorem move_twice [BI PROP] (P : PROP) : □ P ⊢ Q -∗ Q

theorem move [BI PROP] (P : PROP) : □ P ⊢ □ Q -∗ Q

theorem move_multiple [BI PROP] (P : PROP) : □ P ⊢ □ Q -∗ Q

theorem move_twice [BI PROP] (P : PROP) : □ P ⊢ □ Q -∗ Q

theorem simple [BI PROP] : ⊢ (emp : PROP)

theorem affine_env [BI PROP] (P : PROP) : <affine> P ⊢ emp

theorem simple [BI PROP] : ⊢ (⌜True⌝ : PROP)

theorem or [BI PROP] : ⊢ True ∨ (False : PROP)

theorem with_proof [BI PROP] (H : A → B) (P Q : PROP) : <affine> P ⊢ <pers> Q → ⌜A⌝ → ⌜B⌝

theorem wand_spatial [BI PROP] (Q : PROP) : P ⊢ (P -∗ Q) -∗ Q

theorem wand_intuitionistic [BI PROP] (Q : PROP) : □ P ⊢ □ (P -∗ Q) -∗ □ Q

theorem wand_intuitionistic_overwrite [BI PROP] (Q : PROP) : □ P ⊢ □ (□ P -∗ Q) -∗ □ Q

theorem wand_intuitionistic_required [BI PROP] (Q : PROP) : □ P ⊢ □ (□ P -∗ Q) -∗ □ Q

theorem wand_intuitionistic_spatial [BI PROP] (Q : PROP) : □ P ⊢ (P -∗ Q) -∗ Q

theorem wand_intuitionistic_required_spatial [BI PROP] (Q : PROP) : □ P ⊢ (□ P -∗ Q) -∗ Q

theorem wand_spatial_intuitionistic [BI PROP] (Q : PROP) : P ⊢ □ (P -∗ Q) -∗ Q

theorem wand_spatial_multiple [BI PROP] (Q : PROP) : ⊢ P1 -∗ P2 -∗ (P1 -∗ P2 -∗ Q) -∗ Q

theorem wand_intuitionistic_multiple [BI PROP] (Q : PROP) :
    ⊢ □ P1 -∗ □ P2 -∗ □ (P1 -∗ □ P2 -∗ Q) -∗ □ Q

theorem wand_multiple [BI PROP] (Q : PROP) :
    ⊢ P1 -∗ □ P2 -∗ P3 -∗ □ (P1 -∗ P2 -∗ P3 -∗ Q) -∗ Q

theorem forall_spatial [BI PROP] (Q : Nat → PROP) : ⊢ (∀ x, Q x) -∗ Q (y + 1)

theorem forall_intuitionistic [BI PROP] (Q : Nat → PROP) : ⊢ □ (∀ x, Q x) -∗ □ Q y

theorem forall_intuitionistic_overwrite [BI PROP] (Q : Nat → PROP) : ⊢ □ (∀ x, Q x) -∗ □ Q y

theorem forall_spatial_intuitionistic [BI PROP] (Q : Nat → PROP) : ⊢ (∀ x, □ Q x) -∗ □ Q y

theorem forall_spatial_multiple [BI PROP] (Q : Nat → Nat → PROP) :
    ⊢ (∀ x, ∀ y, Q x y) -∗ Q x y

theorem forall_intuitionistic_multiple [BI PROP] (Q : Nat → Nat → PROP) :
    ⊢ □ (∀ x, ∀ y, Q x y) -∗ □ Q x y

theorem forall_multiple [BI PROP] (Q : Nat → Nat → PROP) : ⊢ (∀ x, □ (∀ y, Q x y)) -∗ □ Q x y

theorem multiple [BI PROP] (Q : Nat → PROP) :
    ⊢ □ P1 -∗ P2 -∗ (□ P1 -∗ (∀ x, P2 -∗ Q x)) -∗ Q y

theorem and [BI PROP] (Q : PROP) : Q ⊢ Q ∧ Q

theorem sep_left [BI PROP] [BIAffine PROP] (Q : PROP) : ⊢ P -∗ Q -∗ R -∗ P ∗ Q

theorem sep_right [BI PROP] [BIAffine PROP] (Q : PROP) : ⊢ P -∗ Q -∗ R -∗ P ∗ Q

theorem sep_left_all [BI PROP] [BIAffine PROP] (Q : PROP) : ⊢ P -∗ □ Q -∗ R -∗ P ∗ Q

theorem sep_right_all [BI PROP] [BIAffine PROP] (Q : PROP) : ⊢ □ P -∗ Q -∗ R -∗ P ∗ Q

theorem left [BI PROP] (P : PROP) : P ⊢ P ∨ Q

theorem right [BI PROP] (Q : PROP) : Q ⊢ P ∨ Q

theorem complex [BI PROP] (P Q : PROP) : ⊢ P -∗ Q -∗ P ∗ (R ∨ Q ∨ R)

theorem rename [BI PROP] (P : PROP) : P ⊢ P

theorem clear [BI PROP] (P Q : PROP) : ⊢ P -∗ <affine> Q -∗ P

theorem and [BI PROP] (Q : PROP) : □ (P1 ∧ P2 ∧ Q) ⊢ Q

theorem and_intuitionistic [BI PROP] (Q : PROP) : □ P ∧ Q ⊢ Q

theorem and_persistent_left [BI PROP] (Q : PROP) : <pers> Q ∧ <affine> P ⊢ Q

theorem and_persistent_right [BI PROP] (Q : PROP) : Q ∧ <pers> P ⊢ Q

theorem sep [BI PROP] [BIAffine PROP] (Q : PROP) : P1 ∗ P2 ∗ Q ⊢ Q

theorem disjunction [BI PROP] (Q : PROP) : Q ⊢ <affine> (P1 ∨ P2 ∨ P3) -∗ Q

theorem conjunction_and_disjunction [BI PROP] [BIAffine PROP] (Q : PROP) :
    (P11 ∨ P12 ∨ P13) ∗ P2 ∗ (P31 ∨ P32 ∨ P33) ∗ Q ⊢ Q

theorem move_to_pure [BI PROP] (Q : PROP) : ⊢ <affine> ⌜⊢ Q⌝ -∗ Q

theorem move_to_pure_ascii [BI PROP] (Q : PROP) : ⊢ <affine> ⌜⊢ Q⌝ -∗ Q

theorem move_to_intuitionistic [BI PROP] (Q : PROP) : ⊢ □ Q -∗ Q

theorem move_to_intuitionistic_ascii [BI PROP] (Q : PROP) : ⊢ □ Q -∗ Q

theorem move_to_spatial [BI PROP] (Q : PROP) : ⊢ □ Q -∗ Q

theorem move_to_spatial_ascii [BI PROP] (Q : PROP) : ⊢ □ Q -∗ Q

theorem move_to_pure_conjunction [BI PROP] (Q : PROP) : ⊢ <affine> ⌜φ⌝ ∗ Q -∗ Q

theorem move_to_pure_disjunction [BI PROP] (Q : PROP) :
    ⊢ <affine> ⌜φ1⌝ ∨ <affine> ⌜φ2⌝ -∗ Q -∗ Q

theorem move_to_intuitionistic_conjunction [BI PROP] (Q : PROP) : ⊢ □ P ∗ Q -∗ Q

theorem move_to_intuitionistic_disjunction [BI PROP] (Q : PROP) : ⊢ □ Q ∨ Q -∗ Q

theorem move_to_spatial_conjunction [BI PROP] (Q : PROP) : ⊢ □ (P ∧ Q) -∗ Q

theorem move_to_spatial_disjunction [BI PROP] (Q : PROP) : ⊢ □ (Q ∨ Q) -∗ Q

theorem move_to_intuitionistic_and_back_conjunction [BI PROP] (Q : PROP) : ⊢ □ (P ∧ Q) -∗ Q

theorem move_to_intuitionistic_and_back_disjunction [BI PROP] (Q : PROP) : ⊢ □ (Q ∨ Q) -∗ Q

theorem conjunction_clear [BI PROP] [BIAffine PROP] (Q : PROP) : Q ∗ P ⊢ Q

theorem disjunction_clear [BI PROP] [BIAffine PROP] (Q : PROP) : Q ⊢ P1 ∨ P2 -∗ Q

theorem and_destruct_spatial_right [BI PROP] (Q : PROP) : P ∧ Q ⊢ Q

theorem and_destruct_spatial_left [BI PROP] (Q : PROP) : Q ∧ P ⊢ Q

theorem and_clear_spatial_multiple [BI PROP] (Q : PROP) : P1 ∧ P2 ∧ Q ∧ P3 ⊢ Q

theorem and_destruct_intuitionistic_right [BI PROP] (Q : PROP) : □ (P ∧ Q) ⊢ Q

theorem and_destruct_intuitionistic_left [BI PROP] (Q : PROP) : □ (Q ∧ P) ⊢ Q

theorem and_clear_intuitionistic_multiple [BI PROP] (Q : PROP) : □ (P1 ∧ P2 ∧ Q ∧ P3) ⊢ Q

theorem «exists» [BI PROP] (Q : Nat → PROP) : (∃ x, Q x) ⊢ ∃ x, Q x ∨ False

theorem exists_intuitionistic [BI PROP] (Q : Nat → PROP) : □ (∃ x, Q x) ⊢ ∃ x, □ Q x ∨ False

theorem HγE  (i : GId FF1) : i = γ

theorem HγLookup : FF1[γ] = COFE.constOF (Agree (LeibnizO String))

theorem MyR_always_invalid (S₁ S₂ : String) (Hne : S₁ ≠ S₂) (n : Nat) : ¬✓{n} MyR S₁ • MyR S₂

theorem remove_l [BI PROP] {P P' Q R : PROP} (h : P ⊣⊢ P' ∗ R) :
    P ∗ Q ⊣⊢ (P' ∗ Q) ∗ R

theorem remove_r [BI PROP] {P Q Q' R : PROP} (h : Q ⊣⊢ Q' ∗ R) :
    P ∗ Q ⊣⊢ (P ∗ Q') ∗ R

theorem intuitionistically_sep_dup [BI PROP] {P : PROP} : □ P ⊣⊢ □ P ∗ □ P

theorem sep_emp_rev [BI PROP] {P : PROP} : P ⊣⊢ P ∗ emp

theorem emp_sep_rev [BI PROP] {P : PROP} : P ⊣⊢ emp ∗ P

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

theorem NonExpansive.eqv [OFE α] [OFE β] {f : α → β} [NonExpansive f]
    ⦃x₁ x₂⦄ (h : x₁ ≡ x₂) : f x₁ ≡ f x₂

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₂

@[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

@[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

theorem Contractive.eqv [OFE α] [OFE β] (f : α → β) [Contractive f] ⦃x y : α⦄ (h : x ≡ y) :
    f x ≡ f 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

@[simp] theorem Leibniz.leibniz [OFE α] [Leibniz α] {x y : α} : x ≡ y ↔ x = y

@[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)

theorem InvImage.equivalence {α : Sort u} {β : Sort v}
    {r : β → β → Prop} {f : α → β} (H : Equivalence r) : Equivalence (InvImage r f)

theorem _root_.Option.Forall₂.equivalence {R : α → α → Prop}
    (H : Equivalence R) : Equivalence (Option.Forall₂ R)

@[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

theorem Option.some_is_discrete [OFE α] {a : α} (Ha : DiscreteE a) : DiscreteE (some a)

theorem Option.none_is_discrete [OFE α] : DiscreteE (none : Option α)

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)

@[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

@[simp] theorem Iso.id_apply [OFE α] {x} : ((Iso.id : Iso α α) : α -n> α) x = x

@[simp] theorem const_apply [OFE α] {a : α} {n} : const a n = a

@[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)

theorem chain_none_const [OFE V] {c : Chain (Option V)} (H : c n = none) :
    c = Chain.const none

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

theorem Eq_Equivalence {α : Type _} : Equivalence (@Eq α)

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

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)

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

@[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

theorem and_elim_l' [BI PROP] {P Q R : PROP} (h : P ⊢ R) : P ∧ Q ⊢ R

theorem and_elim_r' [BI PROP] {P Q R : PROP} (h : Q ⊢ R) : P ∧ Q ⊢ R

theorem or_intro_l' [BI PROP] {P Q R : PROP} (h : P ⊢ Q) : P ⊢ Q ∨ R

theorem or_intro_r' [BI PROP] {P Q R : PROP} (h : P ⊢ R) : P ⊢ Q ∨ R

theorem and_symm [BI PROP] {P Q : PROP} : P ∧ Q ⊢ Q ∧ P

theorem or_symm [BI PROP] {P Q : PROP} : P ∨ Q ⊢ Q ∨ P

theorem imp_intro' [BI PROP] {P Q R : PROP} (h : Q ∧ P ⊢ R) : P ⊢ Q → R

theorem mp [BI PROP] {P Q R : PROP} (h1 : P ⊢ Q → R) (h2 : P ⊢ Q) : P ⊢ R

theorem imp_elim' [BI PROP] {P Q R : PROP} (h : Q ⊢ P → R) : P ∧ Q ⊢ R

theorem imp_elim_l [BI PROP] {P Q : PROP} : (P → Q) ∧ P ⊢ Q

theorem imp_elim_r [BI PROP] {P Q : PROP} : P ∧ (P → Q) ⊢ Q

theorem false_elim [BI PROP] {P : PROP} : False ⊢ P

theorem true_intro [BI PROP] {P : PROP} : P ⊢ True

@[rw_mono_rule]
theorem and_mono [BI PROP] {P P' Q Q' : PROP} (h1 : P ⊢ Q) (h2 : P' ⊢ Q') : P ∧ P' ⊢ Q ∧ Q'

theorem and_mono_l [BI PROP] {P P' Q : PROP} (h : P ⊢ P') : P ∧ Q ⊢ P' ∧ Q

theorem and_mono_r [BI PROP] {P Q Q' : PROP} (h : Q ⊢ Q') : P ∧ Q ⊢ P ∧ Q'

@[rw_mono_rule]
theorem and_congr [BI PROP] {P P' Q Q' : PROP} (h1 : P ⊣⊢ Q) (h2 : P' ⊣⊢ Q') : P ∧ P' ⊣⊢ Q ∧ Q'

theorem and_congr_l [BI PROP] {P P' Q : PROP} (h : P ⊣⊢ P') : P ∧ Q ⊣⊢ P' ∧ Q

theorem and_congr_r [BI PROP] {P Q Q' : PROP} (h : Q ⊣⊢ Q') : P ∧ Q ⊣⊢ P ∧ Q'

@[rw_mono_rule]
theorem or_mono [BI PROP] {P P' Q Q' : PROP} (h1 : P ⊢ Q) (h2 : P' ⊢ Q') : P ∨ P' ⊢ Q ∨ Q'

theorem or_mono_l [BI PROP] {P P' Q : PROP} (h : P ⊢ P') : P ∨ Q ⊢ P' ∨ Q

theorem or_mono_r [BI PROP] {P Q Q' : PROP} (h : Q ⊢ Q') : P ∨ Q ⊢ P ∨ Q'

@[rw_mono_rule]
theorem or_congr [BI PROP] {P P' Q Q' : PROP} (h1 : P ⊣⊢ Q) (h2 : P' ⊣⊢ Q') : P ∨ P' ⊣⊢ Q ∨ Q'

theorem or_congr_l [BI PROP] {P P' Q : PROP} (h : P ⊣⊢ P') : P ∨ Q ⊣⊢ P' ∨ Q

theorem or_congr_r [BI PROP] {P Q Q' : PROP} (h : Q ⊣⊢ Q') : P ∨ Q ⊣⊢ P ∨ Q'

@[rw_mono_rule]
theorem imp_mono [BI PROP] {P P' Q Q' : PROP} (h1 : Q ⊢ P) (h2 : P' ⊢ Q') : (P → P') ⊢ Q → Q'

theorem imp_mono_l [BI PROP] {P P' Q : PROP} (h : P' ⊢ P) : (P → Q) ⊢ (P' → Q)

theorem imp_mono_r [BI PROP] {P Q Q' : PROP} (h : Q ⊢ Q') : (P → Q) ⊢ (P → Q')

@[rw_mono_rule]
theorem imp_congr [BI PROP] {P P' Q Q' : PROP}
    (h1 : P ⊣⊢ Q) (h2 : P' ⊣⊢ Q') : (P → P') ⊣⊢ (Q → Q')

theorem imp_congr_l [BI PROP] {P P' Q : PROP} (h : P ⊣⊢ P') : (P → Q) ⊣⊢ (P' → Q)

theorem imp_congr_r [BI PROP] {P Q Q' : PROP} (h : Q ⊣⊢ Q') : (P → Q) ⊣⊢ (P → Q')

theorem forall_ne [BI PROP] {Φ Ψ : α → PROP} (h : ∀ a, Φ a ≡{n}≡ Ψ a) :
    iprop(∀ a, Φ a) ≡{n}≡ iprop(∀ a, Ψ a)

theorem forall_intro [BI PROP] {P : PROP} {Ψ : α → PROP} (h : ∀ a, P ⊢ Ψ a) : P ⊢ ∀ a, Ψ a

theorem forall_elim [BI PROP] {Ψ : α → PROP} (a : α) : (∀ a, Ψ a) ⊢ Ψ a

@[rw_mono_rule]
theorem forall_mono [BI PROP] {Φ Ψ : α → PROP} (h : ∀ a, Φ a ⊢ Ψ a) : (∀ a, Φ a) ⊢ ∀ a, Ψ a

@[rw_mono_rule]
theorem forall_congr [BI PROP] {Φ Ψ : α → PROP} (h : ∀ a, Φ a ⊣⊢ Ψ a) : (∀ a, Φ a) ⊣⊢ ∀ a, Ψ a

theorem exists_ne [BI PROP] {Φ Ψ : α → PROP} (h : ∀ a, Φ a ≡{n}≡ Ψ a) :
    iprop(∃ a, Φ a) ≡{n}≡ iprop(∃ a, Ψ a)

theorem exists_intro [BI PROP] {Ψ : α → PROP} (a : α) : Ψ a ⊢ ∃ a, Ψ a

theorem exists_elim [BI PROP] {Φ : α → PROP} {Q : PROP} (h : ∀ a, Φ a ⊢ Q) : (∃ a, Φ a) ⊢ Q

@[rw_mono_rule]
theorem exists_mono [BI PROP] {Φ Ψ : α → PROP} (h : ∀ a, Φ a ⊢ Ψ a) : (∃ a, Φ a) ⊢ ∃ a, Ψ a

@[rw_mono_rule]
theorem exists_congr [BI PROP] {Φ Ψ : α → PROP} (h : ∀ a, Φ a ⊣⊢ Ψ a) : (∃ a, Φ a) ⊣⊢ ∃ a, Ψ a

theorem and_self [BI PROP] {P : PROP} : P ∧ P ⊣⊢ P

theorem or_self [BI PROP] {P : PROP} : P ∨ P ⊣⊢ P

theorem and_comm [BI PROP] {P Q : PROP} : P ∧ Q ⊣⊢ Q ∧ P

theorem or_comm [BI PROP] {P Q : PROP} : P ∨ Q ⊣⊢ Q ∨ P

theorem true_and [BI PROP] {P : PROP} : True ∧ P ⊣⊢ P

theorem and_true [BI PROP] {P : PROP} : P ∧ True ⊣⊢ P

theorem false_and [BI PROP] {P : PROP} : False ∧ P ⊣⊢ False

theorem and_false [BI PROP] {P : PROP} : P ∧ False ⊣⊢ False

theorem true_or [BI PROP] {P : PROP} : True ∨ P ⊣⊢ True

theorem or_true [BI PROP] {P : PROP} : P ∨ True ⊣⊢ True

theorem false_or [BI PROP] {P : PROP} : False ∨ P ⊣⊢ P

theorem or_false [BI PROP] {P : PROP} : P ∨ False ⊣⊢ P

theorem and_assoc [BI PROP] {P Q R : PROP} : (P ∧ Q) ∧ R ⊣⊢ P ∧ Q ∧ R

theorem or_assoc [BI PROP] {P Q R : PROP} : (P ∨ Q) ∨ R ⊣⊢ P ∨ Q ∨ R

theorem true_imp [BI PROP] {P : PROP} : (True → P) ⊣⊢ P

theorem imp_self [BI PROP] {P Q : PROP} : Q ⊢ P → P

theorem imp_trans [BI PROP] {P Q R : PROP} : (P → Q) ∧ (Q → R) ⊢ P → R

theorem false_imp [BI PROP] {P : PROP} : (False → P) ⊣⊢ True

theorem and_left_comm [BI PROP] {P Q R : PROP} : P ∧ Q ∧ R ⊣⊢ Q ∧ P ∧ R

theorem and_or_l [BI PROP] {P Q R : PROP} : P ∧ (Q ∨ R) ⊣⊢ P ∧ Q ∨ P ∧ R

theorem and_exists_l [BI PROP] {P : PROP} {Ψ : α → PROP} : P ∧ (∃ a, Ψ a) ⊣⊢ ∃ a, P ∧ Ψ a

theorem or_eq_ite [BI PROP] {P Q : PROP} : P ∨ Q ⊣⊢ ∃ (b : Bool), if b then P else Q

theorem exists_intro' [BI PROP] {P : PROP} {Ψ : α → PROP} (a : α) (h : P ⊢ Ψ a) : P ⊢ ∃ a, Ψ a

theorem sep_mono_l [BI PROP] {P P' Q : PROP} (h : P ⊢ P') : P ∗ Q ⊢ P' ∗ Q

theorem sep_mono_r [BI PROP] {P Q Q' : PROP} (h : Q ⊢ Q') : P ∗ Q ⊢ P ∗ Q'

@[rw_mono_rule]
theorem sep_congr [BI PROP] {P P' Q Q' : PROP} (h1 : P ⊣⊢ Q) (h2 : P' ⊣⊢ Q') :
    (P ∗ P') ⊣⊢ (Q ∗ Q')

theorem sep_congr_l [BI PROP] {P P' Q : PROP} (h : P ⊣⊢ P') : P ∗ Q ⊣⊢ P' ∗ Q

theorem sep_congr_r [BI PROP] {P Q Q' : PROP} (h : Q ⊣⊢ Q') : P ∗ Q ⊣⊢ P ∗ Q'

@[rw_mono_rule]
theorem wand_mono [BI PROP] {P P' Q Q' : PROP} (h1 : Q ⊢ P) (h2 : P' ⊢ Q') :
    (P -∗ P') ⊢ Q -∗ Q'

theorem wand_mono_l [BI PROP] {P P' Q : PROP} (h : P' ⊢ P) : (P -∗ Q) ⊢ P' -∗ Q

theorem wand_mono_r [BI PROP] {P Q Q' : PROP} (h : Q ⊢ Q') : (P -∗ Q) ⊢ P -∗ Q'

@[rw_mono_rule]
theorem wand_congr [BI PROP] {P P' Q Q' : PROP} (h1 : P ⊣⊢ Q) (h2 : P' ⊣⊢ Q') :
    (P -∗ P') ⊣⊢ (Q -∗ Q')

theorem wand_congr_l [BI PROP] {P P' Q : PROP} (h : P ⊣⊢ P') : (P -∗ Q) ⊣⊢ (P' -∗ Q)

theorem wand_congr_r [BI PROP] {P Q Q' : PROP} (h : Q ⊣⊢ Q') : (P -∗ Q) ⊣⊢ (P -∗ Q')

theorem sep_comm [BI PROP] {P Q : PROP} : P ∗ Q ⊣⊢ Q ∗ P

theorem sep_assoc [BI PROP] {P Q R : PROP} : (P ∗ Q) ∗ R ⊣⊢ P ∗ Q ∗ R

theorem sep_left_comm [BI PROP] {P Q R : PROP} : P ∗ Q ∗ R ⊣⊢ Q ∗ P ∗ R

theorem sep_right_comm [BI PROP] {P Q R : PROP} : (P ∗ Q) ∗ R ⊣⊢ (P ∗ R) ∗ Q

theorem sep_sep_sep_comm [BI PROP] {P Q R S : PROP} : (P ∗ Q) ∗ (R ∗ S) ⊣⊢ (P ∗ R) ∗ (Q ∗ S)

theorem sep_emp [BI PROP] {P : PROP} : P ∗ emp ⊣⊢ P

theorem true_sep_2 [BI PROP] {P : PROP} : P ⊢ True ∗ P

theorem wand_intro' [BI PROP] {P Q R : PROP} (h : Q ∗ P ⊢ R) : P ⊢ Q -∗ R

theorem wand_elim' [BI PROP] {P Q R : PROP} (h : Q ⊢ P -∗ R) : P ∗ Q ⊢ R

theorem wand_elim_l [BI PROP] {P Q : PROP} : (P -∗ Q) ∗ P ⊢ Q

theorem wand_elim_r [BI PROP] {P Q : PROP} : P ∗ (P -∗ Q) ⊢ Q

theorem sep_or_l [BI PROP] {P Q R : PROP} : P ∗ (Q ∨ R) ⊣⊢ (P ∗ Q) ∨ (P ∗ R)

theorem sep_or_r [BI PROP] {P Q R : PROP} : (P ∨ Q) ∗ R ⊣⊢ (P ∗ R) ∨ (Q ∗ R)

theorem sep_exists_l [BI PROP] {P : PROP} {Ψ : α → PROP} : P ∗ (∃ a, Ψ a) ⊣⊢ ∃ a, P ∗ Ψ a

theorem sep_exists_r [BI PROP] {Φ : α → PROP} {Q : PROP} : (∃ a, Φ a) ∗ Q ⊣⊢ ∃ a, Φ a ∗ Q

theorem wand_rfl [BI PROP] {P : PROP} : ⊢ P -∗ P

@[rw_mono_rule]
theorem wandIff_congr [BI PROP] {P P' Q Q' : PROP} (h1 : P ⊣⊢ Q) (h2 : P' ⊣⊢ Q') :
    (P ∗-∗ P') ⊣⊢ (Q ∗-∗ Q')

theorem wandIff_congr_l [BI PROP] {P P' Q : PROP} (h : P ⊣⊢ P') : (P ∗-∗ Q) ⊣⊢ (P' ∗-∗ Q)

theorem wandIff_congr_r [BI PROP] {P Q Q' : PROP} (h : Q ⊣⊢ Q') : (P ∗-∗ Q) ⊣⊢ (P ∗-∗ Q')

theorem wandIff_refl [BI PROP] {P : PROP} : ⊢ P ∗-∗ P

theorem wand_entails [BI PROP] {P Q : PROP} (h : ⊢ P -∗ Q) : P ⊢ Q

theorem entails_wand [BI PROP] {P Q : PROP} (h : P ⊢ Q) : ⊢ P -∗ Q

theorem equiv_wandIff [BI PROP] {P Q : PROP} (h : P ⊣⊢ Q) : ⊢ P ∗-∗ Q

theorem wandIff_equiv [BI PROP] {P Q : PROP} (h : ⊢ P ∗-∗ Q) : P ⊣⊢ Q

theorem pure_elim [BI PROP] (φ : Prop) {Q R : PROP} (h1 : Q ⊢ ⌜φ⌝) (h2 : φ → Q ⊢ R) : Q ⊢ R

theorem pure_mono [BI PROP] {φ1 φ2 : Prop} (h : φ1 → φ2) : ⌜φ1⌝ ⊢ (⌜φ2⌝ : PROP)

theorem pure_congr [BI PROP] {φ1 φ2 : Prop} (h : φ1 ↔ φ2) : ⌜φ1⌝ ⊣⊢ (⌜φ2⌝ : PROP)

theorem pure_elim_l [BI PROP] {φ : Prop} {Q R : PROP} (h : φ → Q ⊢ R) : ⌜φ⌝ ∧ Q ⊢ R

theorem pure_elim_r [BI PROP] {φ : Prop} {Q R : PROP} (h : φ → Q ⊢ R) : Q ∧ ⌜φ⌝ ⊢ R

theorem pure_true [BI PROP] {φ : Prop} (h : φ) : ⌜φ⌝ ⊣⊢ (True : PROP)

theorem pure_and [BI PROP] {φ1 φ2 : Prop} : ⌜φ1⌝ ∧ (⌜φ2⌝ : PROP) ⊣⊢ ⌜φ1 ∧ φ2⌝

theorem pure_or [BI PROP] {φ1 φ2 : Prop} : ⌜φ1⌝ ∨ (⌜φ2⌝ : PROP) ⊣⊢ ⌜φ1 ∨ φ2⌝

theorem pure_imp_2 [BI PROP] {φ1 φ2 : Prop} : ⌜φ1 → φ2⌝ ⊢ (⌜φ1⌝ → ⌜φ2⌝ : PROP)

theorem pure_imp [BI PROP] {φ1 φ2 : Prop} : (⌜φ1⌝ → ⌜φ2⌝ : PROP) ⊣⊢ ⌜φ1 → φ2⌝

theorem pure_forall_2 [BI PROP] {φ : α → Prop} : ⌜∀ x, φ x⌝ ⊢ ∀ x, (⌜φ x⌝ : PROP)

theorem pure_forall [BI PROP] {φ : α → Prop} : (∀ x, (⌜φ x⌝ : PROP)) ⊣⊢ ⌜∀ x, φ x⌝

theorem pure_exists [BI PROP] {φ : α → Prop} : (∃ x, ⌜φ x⌝ : PROP) ⊣⊢ ⌜∃ x, φ x⌝

theorem affinely_ne [BI PROP] : OFE.NonExpansive (@affinely PROP _)

@[rw_mono_rule]
theorem affinely_congr [BI PROP] {P P' : PROP} (h : P ⊣⊢ P') :
    <affine> P ⊣⊢ <affine> P'

theorem affinely_elim_emp [BI PROP] {P : PROP} : <affine> P ⊢ emp

theorem affinely_elim [BI PROP] {P : PROP} : <affine> P ⊢ P

@[rw_mono_rule]
theorem affinely_mono [BI PROP] {P Q : PROP} : (P ⊢ Q) → <affine> P ⊢ <affine> Q

theorem affinely_idem [BI PROP] {P : PROP} : <affine> <affine> P ⊣⊢ <affine> P

theorem affinely_intro' [BI PROP] {P Q : PROP} (h : P ⊢ <affine> Q) :
    <affine> P ⊢ <affine> Q

theorem affinely_false [BI PROP] : <affine> False ⊣⊢ (False : PROP)

theorem affinely_emp [BI PROP] : <affine> emp ⊣⊢ (emp : PROP)

theorem affinely_or [BI PROP] {P Q : PROP} : <affine> (P ∨ Q) ⊣⊢ <affine> P ∨ <affine> Q

theorem affinely_and [BI PROP] {P Q : PROP} : <affine> (P ∧ Q) ⊣⊢ <affine> P ∧ <affine> Q

theorem affinely_sep_2 [BI PROP] {P Q : PROP} : <affine> P ∗ <affine> Q ⊢ <affine> (P ∗ Q)

theorem affinely_sep_r [BI PROP] [BIPositive PROP] {P Q : PROP} :
    <affine> (P ∗ Q) ⊢ P ∗ <affine> Q

theorem affinely_sep [BI PROP] [BIPositive PROP] {P Q : PROP} :
    <affine> (P ∗ Q) ⊣⊢ <affine> P ∗ <affine> Q

theorem affinely_forall_1 [BI PROP] {Φ : α → PROP} : <affine> (∀ a, Φ a) ⊢ ∀ a, <affine> (Φ a)

theorem affinely_exists [BI PROP] {Φ : α → PROP} : <affine> (∃ a, Φ a) ⊣⊢ ∃ a, <affine> (Φ a)

theorem affinely_true [BI PROP] : <affine> True ⊣⊢ (emp : PROP)

theorem affinely_and_l [BI PROP] {P Q : PROP} : <affine> P ∧ Q ⊣⊢ <affine> (P ∧ Q)

theorem affinely_and_r [BI PROP] {P Q : PROP} : P ∧ <affine> Q ⊣⊢ <affine> (P ∧ Q)

theorem affinely_and_lr [BI PROP] {P Q : PROP} : <affine> P ∧ Q ⊣⊢ P ∧ <affine> Q

theorem affine_mono [BI PROP] {P Q : PROP} (h : P ⊢ Q) [Affine Q] : Affine P

theorem absorbingly_ne [BI PROP] : OFE.NonExpansive (@absorbingly PROP _)

@[rw_mono_rule]
theorem absorbingly_congr [BI PROP] {P P' : PROP} (h : P ⊣⊢ P') :
    <absorb> P ⊣⊢ <absorb> P'

theorem absorbingly_intro [BI PROP] {P : PROP} : P ⊢ <absorb> P

@[rw_mono_rule]
theorem absorbingly_mono [BI PROP] {P Q : PROP} : (P ⊢ Q) → <absorb> P ⊢ <absorb> Q

theorem absorbingly_idem [BI PROP] {P : PROP} : <absorb> <absorb> P ⊣⊢ <absorb> P

theorem absorbingly_pure {φ : Prop} [BI PROP] : <absorb> ⌜φ⌝ ⊣⊢ (⌜φ⌝ : PROP)

theorem absorbingly_true [BI PROP] : <absorb> True ⊣⊢ (True : PROP)

theorem absorbingly_or [BI PROP] {P Q : PROP} : <absorb> (P ∨ Q) ⊣⊢ <absorb> P ∨ <absorb> Q

theorem absorbingly_and_1 [BI PROP] {P Q : PROP} : <absorb> (P ∧ Q) ⊢ <absorb> P ∧ <absorb> Q

theorem absorbingly_forall_1 [BI PROP] {Φ : α → PROP} : <absorb> (∀ a, Φ a) ⊢ ∀ a, <absorb> (Φ a)

theorem absorbingly_exists [BI PROP] {Φ : α → PROP} :
    <absorb> (∃ a, Φ a) ⊣⊢ ∃ a, <absorb> (Φ a)

theorem absorbingly_sep [BI PROP] {P Q : PROP} : <absorb> (P ∗ Q) ⊣⊢ <absorb> P ∗ <absorb> Q

theorem absorbingly_emp [BI PROP] : <absorb> (emp : PROP) ⊣⊢ True

theorem absorbingly_wand_1 [BI PROP] {P Q : PROP} : <absorb> (P -∗ Q) ⊢ <absorb> P -∗ <absorb> Q

theorem absorbingly_sep_l [BI PROP] {P Q : PROP} : <absorb> P ∗ Q ⊣⊢ <absorb> (P ∗ Q)

theorem absorbingly_sep_r [BI PROP] {P Q : PROP} : P ∗ <absorb> Q ⊣⊢ <absorb> (P ∗ Q)

theorem absorbingly_sep_lr [BI PROP] {P Q : PROP} : <absorb> P ∗ Q ⊣⊢ P ∗ <absorb> Q

theorem affinely_absorbingly [BI PROP] [BIPositive PROP] {P : PROP} :
    <affine> <absorb> P ⊣⊢ <affine> P

theorem affine_affinely [BI PROP] (P : PROP) [Affine P] : <affine> P ⊣⊢ P

theorem biaffine_iff_true_emp [BI PROP] : BIAffine PROP ↔ (True : PROP) ⊢ emp

theorem biaffine_of_true_affine [BI PROP] [Affine (iprop(True) : PROP)] : BIAffine PROP

theorem absorbing_absorbingly [BI PROP] {P : PROP} [Absorbing P] : <absorb> P ⊣⊢ P

theorem absorbing_of_emp_absorbing [BI PROP] [Absorbing (emp : PROP)] (P : PROP) : Absorbing P

theorem sep_elim_l [BI PROP] {P Q : PROP} : [TCOr (Affine Q) (Absorbing P)] → P ∗ Q ⊢ P

theorem sep_elim_r [BI PROP] {P Q : PROP} [TCOr (Affine P) (Absorbing Q)] : P ∗ Q ⊢ Q

theorem sep_and [BI PROP] {P Q : PROP}
    [TCOr (Affine P) (Absorbing Q)] [TCOr (Affine Q) (Absorbing P)] : P ∗ Q ⊢ P ∧ Q

theorem affinely_intro [BI PROP] {P Q : PROP} [Affine P] (h : P ⊢ Q) : P ⊢ <affine> Q

theorem emp_and [BI PROP] {P : PROP} [Affine P] : emp ∧ P ⊣⊢ P

theorem and_emp [BI PROP] {P : PROP} [Affine P] : P ∧ emp ⊣⊢ P

theorem emp_or [BI PROP] {P : PROP} [Affine P] : emp ∨ P ⊣⊢ emp

theorem or_emp [BI PROP] {P : PROP} [Affine P] : P ∨ emp ⊣⊢ emp

theorem true_emp [BI PROP] [h : BIAffine PROP] : (True : PROP) ⊣⊢ emp

theorem true_sep [BI PROP] {P : PROP} [Absorbing P] : True ∗ P ⊣⊢ P

theorem sep_true [BI PROP] {P : PROP} [Absorbing P] : P ∗ True ⊣⊢ P

theorem imp_wand_1 [BI PROP] [BIAffine PROP] {P Q : PROP} : (P → Q) ⊢ P -∗ Q

theorem pure_sep [BI PROP] {φ1 φ2 : Prop} : ⌜φ1⌝ ∗ (⌜φ2⌝ : PROP) ⊣⊢ ⌜φ1 ∧ φ2⌝

theorem pure_wand_2 [BI PROP] {φ1 φ2 : Prop} : ⌜φ1 → φ2⌝ ⊢ (⌜φ1⌝ -∗ (⌜φ2⌝ : PROP))

theorem pure_wand [BI PROP] {φ1 φ2 : Prop} : (⌜φ1⌝ -∗ (⌜φ2⌝ : PROP)) ⊣⊢ ⌜φ1 → φ2⌝

@[rw_mono_rule]
theorem persistently_congr [BI PROP] {P P' : PROP} (h : P ⊣⊢ P') :
    <pers> P ⊣⊢ <pers> P'

theorem persistently_absorb_r [BI PROP] {P Q : PROP} : P ∗ <pers> Q ⊢ <pers> Q

theorem absorbingly_persistently [BI PROP] {P : PROP} : <absorb> <pers> P ⊣⊢ <pers> P

theorem persistently_forall_1 [BI PROP] {Ψ : α → PROP} : <pers> (∀ a, Ψ a) ⊢ ∀ a, <pers> (Ψ a)

theorem persistently_forall [BI PROP] [h : BIPersistentlyForall PROP] {Ψ : α → PROP} :
    <pers> (∀ a, Ψ a) ⊣⊢ ∀ a, <pers> (Ψ a)

theorem persistently_exists [BI PROP] {Ψ : α → PROP} : <pers> (∃ a, Ψ a) ⊣⊢ ∃ a, <pers> (Ψ a)

theorem persistently_and [BI PROP] {P Q : PROP} : <pers> (P ∧ Q) ⊣⊢ <pers> P ∧ <pers> Q

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)

theorem persistently_or [BI PROP] {P Q : PROP} : <pers> (P ∨ Q) ⊣⊢ <pers> P ∨ <pers> Q

theorem persistently_imp_1 [BI PROP] {P Q : PROP} : <pers> (P → Q) ⊢ (<pers> P → <pers> Q)

theorem persistently_emp_intro [BI PROP] {P : PROP} : P ⊢ <pers> emp

theorem persistently_emp [BI PROP] : <pers> (emp : PROP) ⊣⊢ True

theorem persistently_true [BI PROP] : <pers> (True : PROP) ⊣⊢ True

theorem persistently_affinely [BI PROP] {P : PROP} : <pers> <affine> P ⊣⊢ <pers> P

theorem persistently_and_affinely_sep [BI PROP] {P Q : PROP} : <pers> P ∧ Q ⊢ <affine> P ∗ Q

theorem persistently_and_sep_assoc [BI PROP] {P Q R : PROP} :
    <pers> P ∧ (Q ∗ R) ⊣⊢ (<pers> P ∧ Q) ∗ R

theorem intuitionistically_elim [BI PROP] {P : PROP} : □ P ⊢ P

theorem absorbingly_of_persistently [BI PROP] {P : PROP} : <pers> P ⊢ <absorb> P

theorem persistently_elim [BI PROP] {P : PROP} [Absorbing P] : <pers> P ⊢ P

theorem persistently_idem [BI PROP] {P : PROP} : <pers> <pers> P ⊣⊢ <pers> P

theorem persistently_intro' [BI PROP] {P Q : PROP} (h : <pers> P ⊢ Q) : <pers> P ⊢ <pers> Q

theorem persistently_pure {φ : Prop} [BI PROP] : <pers> ⌜φ⌝ ⊣⊢ (⌜φ⌝ : PROP)

theorem persistently_and_imp_sep [BI PROP] {P Q : PROP} : <pers> P ∧ Q ⊢ <pers> P ∗ Q

theorem and_persistently_imp_sep [BI PROP] {P Q : PROP} : P ∧ <pers> Q ⊢ P ∗ <pers> Q

theorem persistently_sep_persistently [BI PROP] {P : PROP} : <pers> P ∗ <pers> P ⊣⊢ <pers> P

theorem persistently_and_sep [BI PROP] {P Q : PROP} : <pers> (P ∧ Q) ⊢ <pers> (P ∗ Q)

theorem persistently_and_persistently_sep [BI PROP] {P Q : PROP} :
    <pers> P ∧ <pers> Q ⊣⊢ <pers> P ∗ <pers> Q

theorem persistently_sep_2 [BI PROP] {P Q : PROP} : <pers> P ∗ <pers> Q ⊢ <pers> (P ∗ Q)

theorem persistently_sep [BI PROP] [BIPositive PROP] {P Q : PROP} :
    <pers> (P ∗ Q) ⊣⊢ <pers> P ∗ <pers> Q

theorem self_sep_persistently [BI PROP] {P : PROP} : P ∗ <pers> P ⊣⊢ <pers> P

theorem affinely_sep_persistently [BI PROP] {P : PROP} : <affine> P ∗ <pers> P ⊣⊢ <pers> P

theorem persistently_wand_1 [BI PROP] {P Q : PROP} : <pers> (P -∗ Q) ⊢ (<pers> P -∗ <pers> Q)

theorem persistently_entails_l [BI PROP] {P Q : PROP} (h : P ⊢ <pers> Q) : P ⊢ <pers> Q ∗ P

theorem persistently_entails_r [BI PROP] {P Q : PROP} (h : P ⊢ <pers> Q) : P ⊢ P ∗ <pers> Q

theorem persistently_imp_wand_2 [BI PROP] {P Q : PROP} : <pers> (P -∗ Q) ⊢ <pers> (P → Q)

theorem imp_wand_persistently_2 [BI PROP] {P Q : PROP} : (<pers> P -∗ Q) ⊢ (<pers> P → Q)

theorem persistently_emp' [BI PROP] [BIAffine PROP] : <pers> (emp : PROP) ⊣⊢ emp

theorem persistently_and_iff_sep [BI PROP] [BIAffine PROP] {P Q : PROP} :
    <pers> P ∧ Q ⊣⊢ <pers> P ∗ Q

theorem and_persistently_iff_sep [BI PROP] [BIAffine PROP] {P Q : PROP} :
    P ∧ <pers> Q ⊣⊢ P ∗ <pers> Q

theorem persistently_imp_wand [BI PROP] [BIAffine PROP] {P Q : PROP} :
    <pers> (P → Q) ⊣⊢ <pers> (P -∗ Q)

theorem imp_wand_persistently [BI PROP] [BIAffine PROP] {P Q : PROP} :
    (<pers> P → Q) ⊣⊢ (<pers> P -∗ Q)

theorem wand_iff_exists_persistently [BI PROP] [BIAffine PROP] {P Q : PROP} :
    (P -∗ Q) ⊣⊢ ∃ R, R ∗ <pers> (P ∗ R → Q)

theorem persistently_and_emp {P : PROP} [BI PROP] : <pers> P ⊣⊢ <pers> (emp ∧ P)

theorem persistently_and_sep_elim_emp {P Q : PROP} [BI PROP] : <pers> P ∧ Q ⊢ (emp ∧ P) ∗ Q

theorem persistently_and_emp_elim {P : PROP} [BI PROP] : emp ∧ <pers> P ⊢ P

theorem sForall_persistent [BI PROP] [h : BIPersistentlyForall PROP] (Ψ : PROP → Prop)
    (H : ∀ p, Ψ p → Persistent p) : Persistent iprop(sForall Ψ)

theorem sExists_persistent [BI PROP] (Ψ : PROP → Prop)
    (H : ∀ p, Ψ p → Persistent p) : Persistent iprop(sExists Ψ)

theorem intuitionistically_ne [BI PROP] : OFE.NonExpansive (@intuitionistically PROP _)

@[rw_mono_rule]
theorem intuitionistically_congr [BI PROP] {P Q : PROP} (h : P ⊣⊢ Q) : □ P ⊣⊢ □ Q

@[rw_mono_rule]
theorem intuitionistically_mono [BI PROP] {P Q : PROP} (h : P ⊢ Q) : □ P ⊢ □ Q

theorem intuitionistically_def [BI PROP] {P : PROP} : iprop(□ P) = iprop(<affine> <pers> P)

theorem intuitionistically_elim_emp [BI PROP] {P : PROP} : □ P ⊢ emp

theorem intuitionistically_emp [BI PROP] : □ emp ⊣⊢ (emp : PROP)

theorem intuitionistically_false [BI PROP] : □ False ⊣⊢ (False : PROP)

theorem intuitionistically_true [BI PROP] : □ True ⊣⊢ (emp : PROP)

theorem intuitionistically_and [BI PROP] {P Q : PROP} : □ (P ∧ Q) ⊣⊢ □ P ∧ □ Q

theorem intuitionistically_forall_1 [BI PROP] {Φ : α → PROP} : □ (∀ x, Φ x) ⊢ ∀ x, □ Φ x

theorem intuitionistically_or [BI PROP] {P Q : PROP} : □ (P ∨ Q) ⊣⊢ □ P ∨ □ Q

theorem intuitionistically_exists [BI PROP] {Φ : α → PROP} : □ (∃ x, Φ x) ⊣⊢ ∃ x, □ Φ x

theorem intuitionistically_sep_2 [BI PROP] {P Q : PROP} : □ P ∗ □ Q ⊢ □ (P ∗ Q)

theorem intuitionistically_sep [BI PROP] [BIPositive PROP] {P Q : PROP} : □ (P ∗ Q) ⊣⊢ □ P ∗ □ Q

theorem intuitionistically_idem [BI PROP] {P : PROP} : □ □ P ⊣⊢ □ P

theorem intuitionistically_intro' [BI PROP] {P Q : PROP} (h : □ P ⊢ Q) : □ P ⊢ □ Q

theorem persistently_of_intuitionistically [BI PROP] {P : PROP} : □ P ⊢ <pers> P

theorem intuitionistically_persistently [BI PROP] {P : PROP} : □ <pers> P ⊣⊢ □ P

theorem intuitionistically_of_intuitionistic [BI PROP] {P : PROP} [Affine P] [Persistent P] :
    □ P ⊣⊢ P

theorem affinely_of_intuitionistically [BI PROP] {P : PROP} : □ P ⊢ <affine> P

theorem intuitionistically_affinely [BI PROP] {P : PROP} : □ <affine> P ⊣⊢ □ P

theorem persistently_and_intuitionistically_sep_l [BI PROP] {P Q : PROP} :
    <pers> P ∧ Q ⊣⊢ □ P ∗ Q

theorem persistently_and_intuitionistically_sep_r [BI PROP] {P Q : PROP} :
    P ∧ <pers> Q ⊣⊢ P ∗ □ Q

theorem and_sep_intuitionistically [BI PROP] {P Q : PROP} : □ P ∧ □ Q ⊣⊢ □ P ∗ □ Q

theorem intuitionistically_and_sep [BI PROP] {P Q : PROP} : □ (P ∧ Q) ⊣⊢ □ P ∗ □ Q

theorem intuitionistically_sep_idem [BI PROP] {P : PROP} : □ P ∗ □ P ⊣⊢ □ P

theorem intuitionistically_wand [BI PROP] {P Q : PROP} : (□ P -∗ Q) ⊣⊢ (<pers> P → Q)

theorem affinely_self_sep_intuitionistically [BI PROP] {P : PROP} :
    <affine> (P ∗ □ P) ⊣⊢ □ P

theorem intuitionistically_imp_wand_2 [BI PROP] {P Q : PROP} : □ (P -∗ Q) ⊢ □ (P → Q)

theorem imp_iff_exists_persistently [BI PROP] [BIAffine PROP] {P Q : PROP} :
    (P → Q) ⊣⊢ ∃ R, R ∧ <pers> (P ∧ R -∗ Q)

theorem intuitionistically_iff_persistently [BI PROP] [BIAffine PROP]
    {P : PROP} : □ P ⊣⊢ <pers> P

@[simp] theorem affinelyIf_false [BI PROP] (P : PROP) : iprop(<affine>?false P) = P

@[simp] theorem affinelyIf_true [BI PROP] (P : PROP) :
    iprop(<affine>?true P) = iprop(<affine> P)

theorem affinelyIf_ne {p : Bool} [BI PROP] : OFE.NonExpansive (affinelyIf (PROP := PROP) p)

@[rw_mono_rule]
theorem affinelyIf_mono {p : Bool} [BI PROP] {P Q : PROP}
    (h : P ⊢ Q) : <affine>?p P ⊢ <affine>?p Q

@[rw_mono_rule]
theorem affinelyIf_congr {p : Bool} [BI PROP] {P Q : PROP} (h : P ⊣⊢ Q) :
    <affine>?p P ⊣⊢ <affine>?p Q

theorem affinelyIf_flag_mono {p q : Bool} [BI PROP] {P : PROP} (h : q → p) :
    <affine>?p P ⊢ <affine>?q P

theorem affinelyIf_elim {p : Bool} [BI PROP] {P : PROP} : <affine>?p P ⊢ P

theorem affinely_affinelyIf {p : Bool} [BI PROP] {P : PROP} : <affine> P ⊢ <affine>?p P

theorem affinelyIf_intro' {p : Bool} [BI PROP] {P Q : PROP} :
    (P ⊢ <affine>?p Q) → <affine>?p P ⊢ <affine>?p Q

theorem affinelyIf_emp {p : Bool} [BI PROP] : (<affine>?p emp : PROP) ⊣⊢ emp

theorem affinelyIf_and {p : Bool} [BI PROP] {P Q : PROP} :
    <affine>?p (P ∧ Q) ⊣⊢ <affine>?p P ∧ <affine>?p Q

theorem affinelyIf_or {p : Bool} [BI PROP] {P Q : PROP} :
    <affine>?p (P ∨ Q) ⊣⊢ <affine>?p P ∨ <affine>?p Q

theorem affinelyIf_exists {p : Bool} [BI PROP] {Ψ : α → PROP} :
    <affine>?p (∃ a, Ψ a) ⊣⊢ ∃ a, <affine>?p (Ψ a)

theorem affinelyIf_forall_1 {p : Bool} [BI PROP] {Ψ : α → PROP} :
    <affine>?p (∀ a, Ψ a) ⊢ ∀ a, <affine>?p (Ψ a)

theorem affinelyIf_sep_2 {p : Bool} [BI PROP] {P Q : PROP} :
    <affine>?p P ∗ <affine>?p Q ⊢ <affine>?p (P ∗ Q)

theorem affinelyIf_sep {p : Bool} [BI PROP] [BIPositive PROP] {P Q : PROP} :
    <affine>?p (P ∗ Q) ⊣⊢ <affine>?p P ∗ <affine>?p Q

theorem affinelyIf_idem {p : Bool} [BI PROP] [BIPositive PROP] {P : PROP} :
    <affine>?p <affine>?p P ⊣⊢ <affine>?p P

theorem affinelyIf_and_l {p : Bool} [BI PROP] {P Q : PROP} :
    <affine>?p P ∧ Q ⊣⊢ <affine>?p (P ∧ Q)

theorem affinelyIf_and_r {p : Bool} [BI PROP] {P Q : PROP} :
    P ∧ <affine>?p Q ⊣⊢ <affine>?p (P ∧ Q)

theorem affinelyIf_and_lr {p : Bool} [BI PROP] {P Q : PROP} :
    <affine>?p P ∧ Q ⊣⊢ P ∧ <affine>?p Q

@[simp] theorem absorbinglyIf_false [BI PROP] (P : PROP) : iprop(<absorb>?false P) = P

@[simp] theorem absorbinglyIf_true [BI PROP] (P : PROP) :
    iprop(<absorb>?true P) = iprop(<absorb> P)

theorem absorbinglyIf_ne {p : Bool} [BI PROP] : OFE.NonExpansive (absorbinglyIf (PROP := PROP) p)

@[rw_mono_rule]
theorem absorbinglyIf_mono {p : Bool} [BI PROP] {P Q : PROP} (h : P ⊢ Q) :
    <absorb>?p P ⊢ <absorb>?p Q

@[rw_mono_rule]
theorem absorbinglyIf_congr {p : Bool} [BI PROP] {P Q : PROP} (h : P ⊣⊢ Q) :
    <absorb>?p P ⊣⊢ <absorb>?p Q

theorem absorbingly_of_absorbinglyIf {p : Bool} [BI PROP] {P : PROP} : <absorb>?p P ⊢ <absorb> P

theorem absorbinglyIf_intro {p : Bool} [BI PROP] {P : PROP} : P ⊢ <absorb>?p P

theorem absorbinglyIf_flag_mono {p q : Bool} [BI PROP] {P : PROP} (h : p → q) :
    <absorb>?p P ⊢ <absorb>?q P

theorem absorbinglyIf_idem {p : Bool} [BI PROP] {P : PROP} :
    <absorb>?p <absorb>?p P ⊣⊢ <absorb>?p P

theorem absorbinglyIf_pure {p : Bool} [BI PROP] {φ : Prop} : (<absorb>?p ⌜φ⌝ : PROP) ⊣⊢ ⌜φ⌝

theorem absorbinglyIf_or {p : Bool} [BI PROP] {P Q : PROP} :
    <absorb>?p (P ∨ Q) ⊣⊢ <absorb>?p P ∨ <absorb>?p Q

theorem absorbinglyIf_and_1 {p : Bool} [BI PROP] {P Q : PROP} :
    <absorb>?p (P ∧ Q) ⊢ <absorb>?p P ∧ <absorb>?p Q

theorem absorbinglyIf_forall_1 {p : Bool} [BI PROP] {Φ : α → PROP} :
    <absorb>?p (∀ a, Φ a) ⊢ ∀ a, <absorb>?p (Φ a)

theorem absorbinglyIf_exists {p : Bool} [BI PROP] {Φ : α → PROP} :
    <absorb>?p (∃ a, Φ a) ⊣⊢ ∃ a, <absorb>?p (Φ a)

theorem absorbinglyIf_sep {p : Bool} [BI PROP] {P Q : PROP} :
    <absorb>?p (P ∗ Q) ⊣⊢ <absorb>?p P ∗ <absorb>?p Q

theorem absorbinglyIf_wand_1 {p : Bool} [BI PROP] {P Q : PROP} :
    <absorb>?p (P -∗ Q) ⊢ (<absorb>?p P -∗ <absorb>?p Q)

theorem absorbinglyIf_sep_l {p : Bool} [BI PROP] {P Q : PROP} :
    <absorb>?p P ∗ Q ⊣⊢ <absorb>?p (P ∗ Q)

theorem absorbinglyIf_sep_r {p : Bool} [BI PROP] {P Q : PROP} :
    P ∗ <absorb>?p Q ⊣⊢ <absorb>?p (P ∗ Q)

theorem absorbinglyIf_sep_lr {p : Bool} [BI PROP] {P Q : PROP} :
    <absorb>?p P ∗ Q ⊣⊢ P ∗ <absorb>?p Q

theorem affinelyIf_absorbinglyIf {p : Bool} [BI PROP] [BIPositive PROP] {P : PROP} :
    <affine>?p <absorb>?p P ⊣⊢ <affine>?p P

@[simp] theorem persistentlyIf_false [BI PROP] (P : PROP) : iprop(<pers>?false P) = P

@[simp] theorem persistentlyIf_true [BI PROP] (P : PROP) :
    iprop(<pers>?true P) = iprop(<pers> P)

theorem persistentlyIf_ne {p : Bool} [BI PROP] :
    OFE.NonExpansive (persistentlyIf (PROP := PROP) p)

@[rw_mono_rule]
theorem persistentlyIf_mono {p : Bool} [BI PROP] {P Q : PROP} (h : P ⊢ Q) :
    <pers>?p P ⊢ <pers>?p Q

@[rw_mono_rule]
theorem persistentlyIf_congr {p : Bool} [BI PROP] {P Q : PROP} (h : P ⊣⊢ Q) :
    <pers>?p P ⊣⊢ <pers>?p Q

theorem persistentlyIf_pure {p : Bool} [BI PROP] {φ : Prop} : (<pers>?p ⌜φ⌝ : PROP) ⊣⊢ ⌜φ⌝

theorem persistentlyIf_and {p : Bool} [BI PROP] {P Q : PROP} :
    <pers>?p (P ∧ Q) ⊣⊢ <pers>?p P ∧ <pers>?p Q

theorem persistentlyIf_or {p : Bool} [BI PROP] {P Q : PROP} :
    <pers>?p (P ∨ Q) ⊣⊢ <pers>?p P ∨ <pers>?p Q

theorem persistentlyIf_forall_1 {p : Bool} [BI PROP] {Φ : α → PROP} :
    <pers>?p (∀ a, Φ a) ⊢ ∀ a, <pers>?p (Φ a)

theorem persistentlyIf_exists {p : Bool} [BI PROP] {Φ : α → PROP} :
    <pers>?p (∃ a, Φ a) ⊣⊢ ∃ a, <pers>?p (Φ a)

theorem persistentlyIf_sep_2 {p : Bool} [BI PROP] {P Q : PROP} :
    <pers>?p P ∗ <pers>?p Q ⊢ <pers>?p (P ∗ Q)

theorem persistentlyIf_sep {p : Bool} [BI PROP] [BIPositive PROP] {P Q : PROP} :
    <pers>?p (P ∗ Q) ⊣⊢ <pers>?p P ∗ <pers>?p Q

theorem persistentlyIf_idem {p : Bool} [BI PROP] [BIPositive PROP] {P : PROP} :
    <pers>?p <pers>?p P ⊣⊢ <pers>?p P

theorem persistentlyIf_persistently {p : Bool} [BI PROP] {P : PROP} :
    <pers>?p <pers> P ⊣⊢ <pers> P

theorem persistentlyIf_intutitionistically {p : Bool} [BI PROP] {P : PROP} :
    <pers>?p □ P ⊢ <pers> P

@[simp] theorem intuitionisticallyIf_false' [BI PROP] (P : PROP) : iprop(□?false P) = P

@[simp] theorem intuitionisticallyIf_true [BI PROP] (P : PROP) : iprop(□?true P) = iprop(□ P)

theorem intuitionisticallyIf_ne {p : Bool} [BI PROP] :
    OFE.NonExpansive (intuitionisticallyIf (PROP := PROP) p)

@[rw_mono_rule]
theorem intuitionisticallyIf_mono {p : Bool} [BI PROP] {P Q : PROP} (h : P ⊢ Q) : □?p P ⊢ □?p Q

@[rw_mono_rule]
theorem intuitionisticallyIf_congr {p : Bool} [BI PROP] {P Q : PROP}
    (h : P ⊣⊢ Q) : □?p P ⊣⊢ □?p Q

theorem intuitionisticallyIf_flag_mono {p q : Bool} [BI PROP] {P : PROP} (h : q → p) :
    □?p P ⊢ □?q P

theorem intuitionisticallyIf_elim {p : Bool} [BI PROP] {P : PROP} : □?p P ⊢ P

theorem intuitionisticallyIf_of_intuitionistically (p : Bool) [BI PROP] {P : PROP} : □ P ⊢ □?p P

theorem intuitionisticallyIf_intro' {p : Bool} [BI PROP] {P Q : PROP} :
    (□?p P ⊢ Q) → □?p P ⊢ □?p Q

theorem intuitionisticallyIf_emp {p : Bool} [BI PROP] : (□?p emp : PROP) ⊣⊢ emp

theorem intuitionisticallyIf_false {p : Bool} [BI PROP] : (□?p False : PROP) ⊣⊢ False

theorem intuitionisticallyIf_and {p : Bool} [BI PROP] {P Q : PROP} : □?p (P ∧ Q) ⊣⊢ □?p P ∧ □?p Q

theorem intuitionisticallyIf_or (p : Bool) [BI PROP] {P Q : PROP} : □?p (P ∨ Q) ⊣⊢ □?p P ∨ □?p Q

theorem intuitionisticallyIf_exists {p : Bool} [BI PROP] {Ψ : α → PROP} :
    (□?p ∃ a, Ψ a) ⊣⊢ ∃ a, □?p Ψ a

theorem intuitionisticallyIf_sep_2 {p : Bool} [BI PROP] {P Q : PROP} :
    □?p P ∗ □?p Q ⊢ □?p (P ∗ Q)

theorem intuitionisticallyIf_sep {p : Bool} [BI PROP] [BIPositive PROP] {P Q : PROP} :
    □?p (P ∗ Q) ⊣⊢ □?p P ∗ □?p Q

theorem intuitionisticallyIf_idem {p : Bool} [BI PROP] {P : PROP} : □?p □?p P ⊣⊢ □?p P

theorem intuitionisticallyIf_def' {p : Bool} [BI PROP] {P : PROP} :
    iprop(□?p P) = iprop(<affine>?p <pers>?p P)

theorem intuitionisticallyIf_comm {p q : Bool} [BI PROP] {P : PROP} :
    iprop(□?p □?q P) = iprop(□?q □?p P)

theorem intuitionisticallyIf_comm' {p q : Bool} [BI PROP] {P : PROP} :
    □?p □?q P ⊣⊢ □?q □?p P

theorem intuitionisticallyIf_affinely {p : Bool} [BI PROP] {P : PROP} :
    □?p <affine> P ⊣⊢ <affine> □?p P

theorem intuitionisticallyIf_intutitionistically {p : Bool} [BI PROP] {P : PROP} : □?p □ P ⊣⊢ □ P

theorem affinelyIf_of_intuitionisticallyIf {p : Bool} [BI PROP] {P : PROP} : □?p P ⊢ <affine>?p P

theorem persistent_congr [BI PROP] {P Q : PROP} (H : P ⊣⊢ Q) : Persistent P ↔ Persistent Q

theorem persistently_intro [BI PROP] {P : PROP} [Persistent P] : P ⊢ <pers> P

theorem persistently_iff [BI PROP] {P : PROP} [Persistent P] [Absorbing P] :
    <pers> P ⊣⊢ P

theorem persistently_intro'' [BI PROP] {P : PROP} [Persistent P] (h : P ⊢ Q) : P ⊢ <pers> Q

theorem persistent_and_affinely_sep_l_1 [BI PROP] {P Q : PROP} [Persistent P] :
    P ∧ Q ⊢ <affine> P ∗ Q

theorem persistent_and_affinely_sep_r_1 [BI PROP] {P Q : PROP} [Persistent Q] :
    P ∧ Q ⊢ P ∗ <affine> Q

theorem persistent_and_affinely_sep_l [BI PROP] {P Q : PROP} [Persistent P] [Absorbing P] :
    P ∧ Q ⊣⊢ <affine> P ∗ Q

theorem persistent_and_affinely_sep_r [BI PROP] {P Q : PROP} [Persistent Q] [Absorbing Q] :
    P ∧ Q ⊣⊢ P ∗ <affine> Q

theorem persistent_and_sep_1 [BI PROP] {P Q : PROP} :
    [TCOr (Persistent P) (Persistent Q)] → P ∧ Q ⊢ P ∗ Q

theorem absorbingly_intuitionistically [BI PROP] {P : PROP} : <absorb> □ P ⊣⊢ <pers> P

theorem absorbingly_affinely_intro_of_persistent [BI PROP] {P : PROP} [Persistent P] :
    P ⊢ <absorb> <affine> P

theorem bigOp_sep_nil [BI PROP] : iprop([∗] []) ⊣⊢ (emp : PROP)

theorem bigOp_and_nil [BI PROP] : iprop([∧] []) ⊣⊢ (True : PROP)

theorem bigOp_sep_cons [BI PROP] {P : PROP} {Ps : List PROP} :
    [∗] (P :: Ps) ⊣⊢ P ∗ [∗] Ps

theorem bigOp_and_cons [BI PROP] {P : PROP} {Ps : List PROP} :
    [∧] (P :: Ps) ⊣⊢ P ∧ [∧] Ps

theorem and_forall_bool [BI PROP] {P Q : PROP} :
    P ∧ Q ⊣⊢ «forall» (fun b : Bool => if b then P else Q)

theorem or_exists_bool [BI PROP] {P Q : PROP} :
    P ∨ Q ⊣⊢ «exists» (fun b : Bool => if b then P else Q)

theorem later_congr [BI PROP] {P Q : PROP} (h : P ⊣⊢ Q) : ▷ P ⊣⊢ ▷ Q

theorem later_true [BI PROP] : (▷ True ⊣⊢ (True : PROP))

theorem later_emp [BI PROP] [BIAffine PROP] : (▷ emp ⊣⊢ (emp : PROP))

theorem later_forall_2 [BI PROP] {α} {Φ : α → PROP} : (∀ a, ▷ Φ a) ⊢ ▷ ∀ a, Φ a

theorem later_forall [BI PROP] {Φ : α → PROP} :
    ▷ (∀ a, Φ a) ⊣⊢ (∀ a, ▷ Φ a)

theorem later_exists_2 [BI PROP] {Φ : α → PROP} :
    (∃ a, ▷ Φ a) ⊢ ▷ (∃ a, Φ a)

theorem later_exists_false [BI PROP] {Φ : α → PROP} :
    (▷ ∃ a, Φ a) ⊢ ▷ False ∨ ∃ a, ▷ Φ a

theorem later_exists [BI PROP] [Inhabited α] {Φ : α → PROP} :
    (∃ a, ▷ Φ a) ⊣⊢ ▷ (∃ a, Φ a)

theorem later_and [BI PROP] {P Q : PROP} : ▷ (P ∧ Q) ⊣⊢ ▷ P ∧ ▷ Q

theorem later_or [BI PROP] {P Q : PROP} : ▷ (P ∨ Q) ⊣⊢ ▷ P ∨ ▷ Q

theorem later_impl [BI PROP] {P Q : PROP} : ▷ (P → Q) ⊢ ▷ P → ▷ Q

theorem later_wand [BI PROP] {P Q : PROP} : ▷ (P -∗ Q) ⊢ ▷ P -∗ ▷ Q

theorem later_iff [BI PROP] {P Q : PROP} : ▷ (P ↔ Q) ⊢ (▷ P ↔ ▷ Q)

theorem later_wand_iff [BI PROP] {P Q : PROP} : ▷ (P ∗-∗ Q) ⊢ ▷ P ∗-∗ ▷ Q

theorem later_affinely_2 [BI PROP] {P : PROP} : <affine> ▷ P ⊢ ▷ <affine> P

theorem later_intuitionistically_2 [BI PROP] {P : PROP} : □ ▷ P ⊢ ▷ □ P

theorem later_intuitionisticallyIf_2 [BI PROP] {P : PROP} : □?p ▷ P ⊢ ▷ □?p P

theorem later_absorbingly [BI PROP] {P : PROP} : ▷ <absorb> P ⊣⊢ <absorb> ▷ P

theorem later_affinely [BI PROP] [BIAffine PROP] {P : PROP} : <affine> ▷ P ⊣⊢ ▷ <affine> P

theorem later_intuitionistically [BI PROP] [BIAffine PROP] {P : PROP} : □ ▷ P ⊣⊢ ▷ □ P

theorem later_intuitionisticallyIf [BI PROP] [BIAffine PROP] {P : PROP} : □?p ▷ P ⊣⊢ ▷ □?p P

theorem entails_impl_true [BI PROP] {P Q : PROP} :
    (P ⊢ Q) ↔ iprop((True : PROP) ⊢ (P → Q))

theorem loeb [BI PROP] [BILoeb PROP] {P : PROP} : (▷ P → P) ⊢ P

theorem loeb_weak_of_strong [BI PROP] {P : PROP} (H : ∀ P : PROP, (▷ P → P) ⊢ P)
    (H' : ▷ P ⊢ P) : True ⊢ P

theorem loeb_wand_intuitionistically [BI PROP] [BILoeb PROP] {P : PROP} :
    □ (□ ▷ P -∗ P) ⊢ P

theorem loeb_wand [BI PROP] [BILoeb PROP] {P : PROP} : □ (▷ P -∗ P) ⊢ P

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

theorem clear_intuitionistic [BI PROP] {P P' A Q : PROP}
    (h_rem : P ⊣⊢ P' ∗ □ A) (h : P' ⊢ Q) : P ⊢ Q

theorem eqv_of_Equiv [OFE V] [Store T K V] {t1 t2 : T} (H : Store.Equiv t1 t2) : t1 ≡ t2

theorem chain_get [Store T K V] [OFE V] (k : K) (c : Chain T) :
    (chain k c) i = get (c i) k

theorem lookup_incN {n} {m1 m2 : T} :
    (∃ (z : T), m2 ≡{n}≡ op m1 z) ↔
    ∀ i, (∃ z, (get m2 i) ≡{n}≡ (get m1 i) • z)

theorem lookup_inc {m1 m2 : T} :
    (∃ (z : T), m2 ≡ op m1 z) ↔
    ∀ i, (∃ z, (get m2 i) ≡ (get m1 i) • z)

theorem validN_get_validN {m : T} (Hv : ✓{n} m) (He : get m i ≡{n}≡ some x) : ✓{n} x

theorem valid_get_valid {m : T} (Hv : ✓ m) (He : get m i ≡ some x) : ✓ x

theorem set_validN {m : T} (Hx : ✓{n} x) (Hm : ✓{n} m) : ✓{n} (set m i x)

theorem set_valid {m : T} (Hx : ✓ x) (Hm : ✓ m) : ✓ (set m i x)

theorem point_valid_iff : ✓ (point i x : T) ↔ ✓ x

theorem point_validN_iff : ✓{n} (point i x : T) ↔ ✓{n} x

theorem delete_validN {m : T} (Hv : ✓{n} m) : ✓{n} (delete m i)

theorem delete_valid {m : T} (Hv : ✓ m) : ✓ (delete m i)

theorem set_equiv_point_op_point {m : T} (Hemp : get m i = none) : Equiv (set m i x) (point i x • m)

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

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))

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)

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)

theorem point_core_total [IsTotal V] {i : K} {x : V} :
    Equiv (core <| point (T := T) i (some x)) ((point i (some (core x))))

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))

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))))

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)))

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

theorem point_inc_iff {m : T} :
    (point i (T := T) (some x)) ≼ m ↔ ∃ y, (get m i ≡ some y) ∧ some x ≼ some y

theorem exclusive_point_inc_iff {m : T} (He : Exclusive x) (Hv : ✓ m) :
    (point i (T := T) (some x)) ≼ m ↔ (get m i ≡ some x)

theorem point_inc_point_iff : (point i (T := T) (some x)) ≼ (point i (some y)) ↔ some x ≼ some y

theorem total_point_inc_point_iff [IsTotal V] : (point i (T := T) (some x)) ≼ (point i (some y)) ↔ x ≼ y

theorem point_inc_point_mono (Hinc : x ≼ y) : (point (T := T) i (some x)) ≼ (point i (some y))

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)

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)

theorem disjoint_op_equiv_union {m1 m2 : T} (Hd : Set.Disjoint (dom m1) (dom m2)) :
    Equiv (m1 • m2) (union m1 m2)

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

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)

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)

theorem dom_op_union (m1 m2 : T) : dom (m1 • m2) = Set.Union (dom m1) (dom m2)

theorem inc_dom_inc {m1 m2 : T} (Hinc : m1 ≼ m2) : Set.Included (dom m1) (dom m2)

theorem as_emp_valid_1 [BI PROP] (P : PROP) [AsEmpValid1 φ P] : φ → ⊢ P

theorem as_emp_valid_2 [BI PROP] (φ : Prop) [AsEmpValid2 φ (P : PROP)] : (⊢ P) → φ

theorem empty_union {s : State Val} : s = ∅ ∪ s

theorem union_comm {a b : State Val} : a ∪ b = b ∪ a

theorem union_assoc {a b c : State Val} : (a ∪ b) ∪ c = a ∪ (b ∪ c)

theorem empty_disjoint {s : State Val} : ∅ |

theorem disjoint_comm {a b : State Val} : a |

theorem disjoint_assoc {a b c : State Val} : a ∪ b |

theorem disjoint_union {a b c : State Val} : a |

theorem bupd_frame_l {P Q : PROP} : iprop(P ∗ |==> Q ⊢ |==> (P ∗ Q))

theorem bupd_wand_l {P Q : PROP} : iprop((P -∗ Q) ∗ (|==> P) ⊢ |==> Q)

theorem bupd_wand_r {P Q : PROP} : iprop((|==> P) ∗ (P -∗ Q) ⊢ |==> Q)

theorem bupd_sep {P Q : PROP} : iprop((|==> P) ∗ (|==> Q) ⊢ |==> (P ∗ Q))

theorem bupd_idem {P : PROP} : iprop((|==> |==> P) ⊣⊢ |==> P)

theorem bupd_or {P Q: PROP} : iprop((|==> P) ∨ (|==> Q) ⊢ |==> (P ∨ Q))

theorem bupd_and {P Q : PROP} : iprop((|==> (P ∧ Q)) ⊢ (|==> P) ∧ (|==> Q))

theorem bupd_exist {A : Type} {Φ : A → PROP} : (∃ x : A, |==> Φ x) ⊢ |==> ∃ x : A, Φ x

theorem bupd_forall {A : Type} {Φ : A → PROP} :
    iprop(|==> «forall» fun x : A => Φ x) ⊢ «forall» fun x : A => iprop(|==> Φ x)

theorem bupd_except0 {P : PROP} : iprop(◇ (|==> P) ⊢ (|==> ◇ P))

theorem bupd_elim {P : PROP} [Plain P] : |==> P ⊢ P

theorem bupd_plain_forall {A : Type} (Φ : A → PROP) [∀ x, Plain (Φ x)] :
    (|==> ∀ x, Φ x) ⊣⊢ (∀ x, |==> Φ x)

theorem Proper.fractional_or_whole {a : α} (H : Proper a) : Fractional a ∨ Whole a

theorem Fractional.not_whole {a : α} (H : Fractional a) : ¬Whole a

theorem Whole.not_fractional {a : α} (H : Whole a) : ¬Fractional a

theorem add_right_cancel {a b c : α} (H : b + a = c + a) : b = c

theorem Fractional.proper {a : α} : Fractional a → Proper a

theorem Fractional.of_add_left {a a' : α} (H : Fractional (a + a')) : Fractional a

theorem Fractional.of_add_right {a a' : α} (H : Fractional (a + a')) : Fractional a'

theorem le_rfl {a : α} : a ≤ a

theorem lt_trans {a b c : α} : a < b → b < c → a < c

theorem le_trans {a b c : α} : a ≤ b → b ≤ c → a ≤ c

theorem add_le_mono {a b c : α} : a + b ≤ c → a ≤ c

theorem lt_le {a b : α} : a < b → a ≤ b

theorem add_ne_self {a b : α} : a + b ≠ a

theorem not_add_lt_self {a b : α} : ¬a + b < a

theorem not_add_le_self {a b : α} : ¬ a + b ≤ a

theorem Frac.inc_iff_lt {p q : Frac α} : p ≼ q ↔ p < q

theorem Frac.le_of_inc {p q : Frac α} (H : p ≼ q) : p ≤ q

theorem equivalence_eq : Equivalence (@Eq α)

theorem LawfulBigOp.right_id [LawfulBigOp (PROP := PROP) f unit eq] : eq (f a unit) a

theorem LawfulBigOp.congr_r [LawfulBigOp (PROP := PROP) f unit eq]
    (h : eq b b') : eq (f a b) (f a b')

theorem bigOp_nil {f : PROP → PROP → PROP} {unit : PROP} : bigOp f unit [] = unit

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))

theorem exists_intro' [BI PROP] {Φ : α → PROP} {P Q : PROP} [inst : FromExists Q Φ]
    (a : α) (h : P ⊢ Φ a) : P ⊢ Q

theorem own_whole_exclusive {w : F} (Hw : Whole w) : CMRA.Exclusive (own w)

theorem valid_own_one : ✓ own (One.one : F)

theorem valid_op_own {dq : DFrac F} {q : F} : ✓ dq • own q → Fractional q

theorem valid_own_op {dq : DFrac F} {q : F} : ✓ own q • dq → Fractional q

theorem valid_discard : ✓ (discard : DFrac F)

theorem valid_own_op_discard {q : F} : ✓ own q • discard ↔ Fractional q

theorem DFrac.is_discrete {q : DFrac F} : OFE.DiscreteE q

theorem DFrac.update_discard {dq : DFrac F} : dq ~~> .discard

theorem DFrac.update_acquire [IsSplitFraction F] :
    (.discard : DFrac F) ~~>: fun k => ∃ q, k = .own q

theorem eq_of_not_lt_not_lt {a b : Nat} : ¬(a < b) → ¬(b < a) → a = b

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

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)

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)

theorem coreId_of_eqv {x₁ x₂ : α} (e : x₁ ≡ x₂) (h : CoreId x₁) : CoreId x₂

theorem coreId_iff {x₁ x₂ : α} (e : x₁ ≡ x₂) : CoreId x₁ ↔ CoreId x₂

theorem op_right_eqv (x : α) {y z : α} (e : y ≡ z) : x • y ≡ x • z

theorem _root_.Iris.OFE.Equiv.op_r {x y z : α} : y ≡ z → x • y ≡ x • z

theorem op_right_dist (x : α) {y z : α} (e : y ≡{n}≡ z) : x • y ≡{n}≡ x • z

theorem _root_.Iris.OFE.Dist.op_r {x y z : α} : y ≡{n}≡ z → x • y ≡{n}≡ x • z

theorem op_commN {x y : α} : x • y ≡{n}≡ y • x

theorem op_assocN {x y z : α} : x • (y • z) ≡{n}≡ (x • y) • z

theorem op_left_eqv {x y : α} (z : α) (e : x ≡ y) : x • z ≡ y • z

theorem _root_.Iris.OFE.Equiv.op_l {x y z : α} : x ≡ y → x • z ≡ y • z

theorem op_left_dist {x y : α} (z : α) (e : x ≡{n}≡ y) : x • z ≡{n}≡ y • z

theorem _root_.Iris.OFE.Dist.op_l {x y z : α} : x ≡{n}≡ y → x • z ≡{n}≡ y • z

theorem _root_.Iris.OFE.Dist.op {x x' y y' : α}
    (ex : x ≡{n}≡ x') (ey : y ≡{n}≡ y') : x • y ≡{n}≡ x' • y'

theorem op_eqv {x x' y y' : α} (ex : x ≡ x') (ey : y ≡ y') : x • y ≡ x' • y'

theorem _root_.Iris.OFE.Equiv.op : (x : α) ≡ x' → y ≡ y' → x • y ≡ x' • y'

theorem op_proper2 {x₁ x₂ y₁ y₂ : α} (H1 : x₁ ≡ x₂) (H2 : y₁ ≡ y₂) : x₁ • y₁ ≡ x₂ • y₂

theorem _root_.Iris.OFE.Dist.opM {x₁ x₂ : α} {y₁ y₂ : Option α}
    (H1 : x₁ ≡{n}≡ x₂) (H2 : y₁ ≡{n}≡ y₂) : x₁ •? y₁ ≡{n}≡ x₂ •? y₂

theorem _root_.Iris.OFE.Equiv.opM {x₁ x₂ : α} {y₁ y₂ : Option α}
    (H1 : x₁ ≡ x₂) (H2 : y₁ ≡ y₂) : x₁ •? y₁ ≡ x₂ •? y₂

theorem opM_left_eqv {x y : α} (z : Option α) (e : x ≡ y) : x •? z ≡ y •? z

theorem opM_right_eqv (x : α) {y z : Option α} (e : y ≡ z) : x •? y ≡ x •? z

theorem opM_left_dist {n} {x y : α} (z : Option α) (e : x ≡{n}≡ y) : x •? z ≡{n}≡ y •? z

theorem opM_right_dist {n} (x : α) {y z : Option α} (e : y ≡{n}≡ z) : x •? y ≡{n}≡ x •? z

theorem op_opM_assoc (x y : α) (mz : Option α) : (x • y) •? mz ≡ x • (y •? mz)

theorem op_opM_assoc_dist (x y : α) (mz : Option α) : (x • y) •? mz ≡{n}≡ x • (y •? mz)

theorem Valid.validN : ✓ (x : α) → ✓{n} x

theorem valid_mapN {x y : α} (f : ∀ n, ✓{n} x → ✓{n} y) (v : ✓ x) : ✓ y

theorem validN_of_eqv {x y : α} : x ≡ y → ✓{n} x → ✓{n} y

theorem validN_iff {x y : α} (e : x ≡{n}≡ y) : ✓{n} x ↔ ✓{n} y

theorem _root_.Iris.OFE.Dist.validN : (x : α) ≡{n}≡ y → (✓{n} x ↔ ✓{n} y)

theorem valid_of_eqv {x y : α} : x ≡ y → ✓ x → ✓ y

theorem valid_iff {x y : α} (e : x ≡ y) : ✓ x ↔ ✓ y

theorem _root_.Iris.OFE.Equiv.valid : (x : α) ≡ y → (✓ x ↔ ✓ y)

theorem validN_of_le {n n'} {x : α} : n' ≤ n → ✓{n} x → ✓{n'} x

theorem valid0_of_validN {n} {x : α} : ✓{n} x → ✓{0} x

theorem validN_op_right {n} {x y : α} : ✓{n} (x • y) → ✓{n} y

theorem valid_op_right (x y : α) : ✓ (x • y) → ✓ y

theorem valid_op_left {x y : α} : ✓ (x • y) → ✓ x

theorem validN_opM {x : α} {my : Option α} : ✓{n} (x •? my) → ✓{n} x

theorem valid_opM {x : α} {my : Option α} : ✓ (x •? my) → ✓ x

theorem validN_op_opM_left {mz : Option α} : ✓{n} (x • y : α) •? mz → ✓{n} x •? mz

theorem validN_op_opM_right {mz : Option α} (h : ✓{n} (x • y : α) •? mz) : ✓{n} y •? mz

theorem pcore_proper {x y : α} (cx : α) (e : x ≡ y) (ps : pcore x = some cx)
    : ∃ cy, pcore y = some cy ∧ cx ≡ cy

theorem pcore_proper' {x y : α} (e : x ≡ y) : pcore x ≡ pcore y

theorem pcore_op_left' {x : α} {cx} (e : pcore x ≡ some cx) : cx • x ≡ x

theorem pcore_op_right {x : α} {cx} (e : pcore x = some cx) : x • cx ≡ x

theorem pcore_op_right' {x : α} {cx} (e : pcore x ≡ some cx) : x • cx ≡ x

theorem pcore_idem' {x : α} {cx} (e : pcore x ≡ some cx) : pcore cx ≡ some cx

theorem pcore_op_self {x : α} {cx} (e : pcore x = some cx) : cx • cx ≡ cx

theorem pcore_op_self' {x : α} {cx} (e : pcore x ≡ some cx) : cx • cx ≡ cx

theorem pcore_validN {n} {x : α} {cx} (e : pcore x = some cx) (v : ✓{n} x) : ✓{n} cx

theorem pcore_valid {x : α} {cx} (e : pcore x = some cx) : ✓ x → ✓ cx

theorem not_valid_exclN_op_left {n} {x : α} [Exclusive x] {y} : ¬✓{n} (x • y)

theorem not_valid_exclN_op_right {n} {x : α} [Exclusive x] {y} : ¬✓{n} (y • x)

theorem not_valid_excl_op_left {x : α} [Exclusive x] {y} : ¬✓ (x • y)

theorem not_excl_op_right {x : α} [Exclusive x] {y} : ¬✓ (y • x)

theorem none_of_excl_valid_op {n} {x : α} [Exclusive x] {my} : ✓{n} (x •? my) → my = none

theorem not_valid_of_exclN_inc {n} {x : α} [Exclusive x] {y} : x ≼{n} y → ¬✓{n} y

theorem not_valid_of_excl_inc {x : α} [Exclusive x] {y} : x ≼ y → ¬✓ y

theorem Exclusive.of_eqv {x₁ x₂ : α} (e : x₁ ≡ x₂) (h : Exclusive x₁) : Exclusive x₂

theorem exclusive_iff {x₁ x₂ : α} (e : x₁ ≡ x₂) : Exclusive x₁ ↔ Exclusive x₂

theorem _root_.Iris.OFE.Dist.exclusive {x₁ x₂ : α} : x₁ ≡ x₂ → (Exclusive x₁ ↔ Exclusive x₂)

theorem inc_of_eqv_of_inc (e : (a : α) ≡ b) : b ≼ c → a ≼ c

theorem inc_of_inc_of_eqv : (a : α) ≼ b → b ≡ c → a ≼ c

theorem incN_of_incN_of_dist : (a : α) ≼{n} b → b ≡{n}≡ c → a ≼{n} c

theorem incN_of_dist_of_incN (e : (a : α) ≡{n}≡ b) : b ≼{n} c → a ≼{n} c

theorem incN_of_inc (n) {x y : α} : x ≼ y → x ≼{n} y

theorem Included.incN {n} {x y : α} : x ≼ y → x ≼{n} y

theorem inc_iff_left (e : (a : α) ≡ b) : a ≼ c ↔ b ≼ c

theorem _root_.Iris.OFE.Equiv.inc_l : (a : α) ≡ b → (a ≼ c ↔ b ≼ c)

theorem inc_iff_right (e : (b : α) ≡ c) : a ≼ b ↔ a ≼ c

theorem _root_.Iris.OFE.Equiv.inc_r : (b : α) ≡ c → (a ≼ b ↔ a ≼ c)

theorem inc_iff (ea : (a : α) ≡ a') (eb : (b : α) ≡ b') : a ≼ b ↔ a' ≼ b'

theorem _root_.Iris.OFE.Equiv.inc : (a : α) ≡ a' → b ≡ b' → (a ≼ b ↔ a' ≼ b')

theorem incN_iff_left (e : (a : α) ≡{n}≡ b) : a ≼{n} c ↔ b ≼{n} c

theorem _root_.Iris.OFE.Dist.incN_l : (a : α) ≡{n}≡ b → (a ≼{n} c ↔ b ≼{n} c)

theorem incN_iff_right (e : (b : α) ≡{n}≡ c) : a ≼{n} b ↔ a ≼{n} c

theorem _root_.Iris.OFE.Dist.incN_r : (b : α) ≡{n}≡ c → (a ≼{n} b ↔ a ≼{n} c)

theorem incN_iff (ea : (a : α) ≡{n}≡ a') (eb : (b : α) ≡{n}≡ b') : a ≼{n} b ↔ a' ≼{n} b'

theorem _root_.Iris.OFE.Dist.incN :
    (a : α) ≡{n}≡ a' → b ≡{n}≡ b' → (a ≼{n} b ↔ a' ≼{n} b')

theorem inc_trans {x y z : α} : x ≼ y → y ≼ z → x ≼ z

theorem Included.trans : (x : α) ≼ y → y ≼ z → x ≼ z

theorem incN_trans {x y z : α} : x ≼{n} y → y ≼{n} z → x ≼{n} z

theorem IncludedN.trans : (x : α) ≼{n} y → y ≼{n} z → x ≼{n} z

theorem valid_of_inc {x y : α} : x ≼ y → ✓ y → ✓ x

theorem validN_of_incN {n} {x y : α} : x ≼{n} y → ✓{n} y → ✓{n} x

theorem IncludedN.validN {n} {x y : α} : x ≼{n} y → ✓{n} y → ✓{n} x

theorem validN_of_inc {n} {x y : α} : x ≼ y → ✓{n} y → ✓{n} x

theorem Included.validN {n} {x y : α} : x ≼ y → ✓{n} y → ✓{n} x

theorem incN_of_incN_le {n n'} {x y : α} (l1 : n' ≤ n) : x ≼{n} y → x ≼{n'} y

theorem inc0_of_incN {n} {x y : α} : x ≼{n} y → x ≼{0} y

theorem IncludedN.le {n n'} {x y : α} : n' ≤ n → x ≼{n} y → x ≼{n'} y

theorem incN_of_incN_succ {n} {x y : α} : x ≼{n.succ} y → x ≼{n} y

theorem IncludedN.succ {n} {x y : α} : x ≼{n.succ} y → x ≼{n} y

theorem incN_op_left (n) (x y : α) : x ≼{n} x • y

theorem inc_op_left (x y : α) : x ≼ x • y

theorem inc_op_right (x y : α) : y ≼ x • y

theorem incN_op_right (n) (x y : α) : y ≼{n} x • y

theorem pcore_mono {x y : α} : x ≼ y → pcore x = some cx → ∃ cy, pcore y = some cy ∧ cx ≼ cy

theorem pcore_mono' {x y : α} {cx} (le : x ≼ y) (e : pcore x ≡ some cx) :
    ∃ cy, pcore y = some cy ∧ cx ≼ cy

theorem pcore_monoN' {n} {x y : α} {cx} :
    x ≼{n} y → pcore x ≡{n}≡ some cx → ∃ cy, pcore y = some cy ∧ cx ≼{n} cy

theorem pcore_inc_self {x : α} {cx} (e : pcore x = some cx) : cx ≼ x

theorem op_mono_right {x y} (z : α) : x ≼ y → z • x ≼ z • y

theorem op_monoN_right {n x y} (z : α) : x ≼{n} y → z • x ≼{n} z • y

theorem op_monoN_left {n x y} (z : α) (h : x ≼{n} y) : x • z ≼{n} y • z

theorem op_mono_left {x y} (z : α) (h : x ≼ y) : x • z ≼ y • z

theorem op_monoN {n} {x x' y y' : α} (hx : x ≼{n} x') (hy : y ≼{n} y') : x • y ≼{n} x' • y'

theorem op_mono {x x' y y' : α} (hx : x ≼ x') (hy : y ≼ y') : x • y ≼ x' • y'

theorem op_self (x : α) [CoreId x] : x • x ≡ x

theorem op_core_right_of_inc {x y : α} [CoreId x] : x ≼ y → x • y ≡ y

theorem included_dist_l {n} {x1 x2 x1' : α} :
    x1 ≼ x2 → x1' ≡{n}≡ x1 → ∃ x2', x1' ≼ x2' ∧ x2' ≡{n}≡ x2

theorem op_core_left_of_inc {x y : α} [CoreId x] (le : x ≼ y) : y • x ≡ y

theorem CoreId.of_pcore_eq_some {x y : α} (e : pcore x = some y) : CoreId y

theorem pcore_eq_core (x : α) : pcore x = some (core x)

theorem op_core (x : α) : x • core x ≡ x

theorem core_op (x : α) : core x • x ≡ x

theorem op_core_dist (x : α) : x • core x ≡{n}≡ x

theorem core_op_dist (x : α) : core x • x ≡{n}≡ x

theorem core_op_core {x : α} : core x • core x ≡ core x

theorem validN_core {n} {x : α} (v : ✓{n} x) : ✓{n} core x

theorem valid_core {x : α} (v : ✓ x) : ✓ core x

theorem core_ne : NonExpansive (core : α → α)

theorem _root_.Iris.OFE.Dist.core :
  ∀ {n} {x₁ x₂ : α}, x₁ ≡{n}≡ x₂ → core x₁ ≡{n}≡ core x₂

theorem _root_.Iris.OFE.Equiv.core : ∀ {x₁ x₂ : α}, x₁ ≡ x₂ → core x₁ ≡ core x₂

theorem core_eqv_self (x : α) [CoreId x] : core (x : α) ≡ x

theorem coreId_iff_core_eqv_self : CoreId (x : α) ↔ core x ≡ x

theorem core_idem (x : α) : core (core x) ≡ core x

theorem inc_refl (x : α) : x ≼ x

@[refl] theorem Included.rfl {x : α} : x ≼ x

theorem incN_refl (x : α) : x ≼{n} x

@[refl] theorem IncludedN.rfl {x : α} : x ≼{n} x

theorem core_inc_self {x : α} [CoreId x] : core x ≼ x

theorem core_incN_core {n} {x y : α} (inc : x ≼{n} y) : core x ≼{n} core y

theorem core_op_mono (x y : α) : core x ≼ core (x • y)

theorem core_mono {x y : α} (Hinc : x ≼ y) : core x ≼ core y

theorem discrete_inc_l {x y : α} [HD : DiscreteE x] (Hv : ✓{0} y) (Hle : x ≼{0} y) : x ≼ y

theorem discrete_inc_r {x y : α} [HD : DiscreteE y] : x ≼{0} y → x ≼ y

theorem valid_iff_validN' [Discrete α] (n) {x : α} : ✓ x ↔ ✓{n} x

theorem valid_0_iff_validN [Discrete α] (n) {x : α} : ✓{0} x ↔ ✓{n} x

theorem inc_iff_incN [OFE.Discrete α] (n) {x y : α} : x ≼ y ↔ x ≼{n} y

theorem inc_0_iff_incN [OFE.Discrete α] (n) {x y : α} : x ≼{0} y ↔ x ≼{n} y

theorem cancelable {x y z : α} [Cancelable x] (v : ✓(x • y)) (e : x • y ≡ x • z) : y ≡ z

theorem discrete_cancelable {x : α} [Discrete α]
    (H : ∀ {y z : α}, ✓(x • y) → x • y ≡ x • z → y ≡ z) : Cancelable x

theorem Cancelable.of_eqv {x₁ x₂ : α} (e : x₁ ≡ x₂) (h : Cancelable x₁) : Cancelable x₂

theorem cancelable_iff {x₁ x₂ : α} (e : x₁ ≡ x₂) : Cancelable x₁ ↔ Cancelable x₂

theorem _root_.Iris.OFE.Equiv.cancelable {x₁ x₂ : α} : x₁ ≡ x₂ → (Cancelable x₁ ↔ Cancelable x₂)

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

theorem IdFree.of_dist {x₁ x₂ : α} {n} (e : x₁ ≡{n}≡ x₂) (h : IdFree x₁) : IdFree x₂

theorem _root_.Iris.OFE.Dist.idFree {x₁ x₂ : α} (e : x₁ ≡{n}≡ x₂) : IdFree x₁ ↔ IdFree x₂

theorem IdFree.of_eqv {x₁ x₂ : α} (e : x₁ ≡ x₂) (h : IdFree x₁) : IdFree x₂

theorem idFree_iff {x₁ x₂ : α} (e : x₁ ≡ x₂) : IdFree x₁ ↔ IdFree x₂

theorem _root_.Iris.OFE.Equiv.idFree {x₁ x₂ : α} : x₁ ≡ x₂ → (IdFree x₁ ↔ IdFree x₂)

theorem id_freeN_r {n n'} {x : α} [IdFree x] {y} (v : ✓{n} x) : ¬(x • y ≡{n'}≡ x)

theorem id_freeN_l {n n'} {x : α} [IdFree x] {y} (v : ✓{n} x) : ¬(y • x ≡{n'}≡ x)

theorem id_free_r {x : α} [IdFree x] {y} (v : ✓x) : ¬(x • y ≡ x)

theorem id_free_l {x : α} [IdFree x] {y} (v : ✓ x) : ¬(y • x ≡ x)

theorem discrete_id_free {x : α} [Discrete α] (H : ∀ y, ✓ x → ¬(x • y ≡ x)) : IdFree x

theorem unit_validN {n} : ✓{n} (unit : α)

theorem incN_unit {n} {x : α} : unit ≼{n} x

theorem inc_unit {x : α} : unit ≼ x

theorem unit_left_id_dist {n} (x : α) : unit • x ≡{n}≡ x

theorem unit_right_id {x : α} : x • unit ≡ x

theorem unit_right_id_dist (x : α) : x • unit ≡{n}≡ x

theorem _root_.Iris.OFE.Dist.to_incN {n} {x y : α} (H : x ≡{n}≡ y) : x ≼{n} y

theorem assoc_L {x y z : α} : x • (y • z) = (x • y) • z

theorem comm_L {x y : α} : x • y = y • x

theorem pcore_op_left_L {x cx : α} (h : pcore x = some cx) : cx • x = x

theorem pcore_idem_L {x cx : α} (h : pcore x = some cx) : pcore cx = some cx

theorem op_opM_assoc_L {x y : α} {mz} : (x • y) •? mz = x • (y •? mz)

theorem pcore_op_right_L {x cx : α} (h : pcore x = some cx) : x • cx = x

theorem pcore_op_self_L {x cx : α} (h : pcore x = some cx) : cx • cx = cx

theorem core_id_dup_L {x : α} [CoreId x] : x • x = x

theorem op_core_L {x : α} [IsTotal α] : x • core x = x

theorem core_op_L {x : α} [IsTotal α] : core x • x = x

theorem core_idem_L {x : α} [IsTotal α] : core (core x) = core x

theorem core_op_core_L {x : α} [IsTotal α] : core x • core x = core x

theorem coreId_iff_core_eq_self {x : α} [IsTotal α] : CoreId x ↔ core x = x

theorem core_eq_self {x : α} [IsTotal α] [c : CoreId x] : core x = x

theorem unit_left_id_L {x : α} : unit • x = x

theorem unit_right_id_L {x : α} : x • unit = x

protected theorem Hom.eqv [CMRA β] (f : α -C> β) {x₁ x₂ : α} (X : x₁ ≡ x₂) : f x₁ ≡ f x₂

protected theorem Hom.core [CMRA β] (f : α -C> β) {x : α} : core (f x) ≡ f (core x)

protected theorem Hom.mono [CMRA β] (f : α -C> β) {x₁ x₂ : α} : x₁ ≼ x₂ → f x₁ ≼ f x₂

protected theorem Hom.monoN [CMRA β] (f : α -C> β) n {x₁ x₂ : α} : x₁ ≼{n} x₂ → f x₁ ≼{n} f x₂

protected theorem Hom.valid [CMRA β] (f : α -C> β) {x : α} (H : ✓ x) : ✓ f x

theorem equiv_of_some_equiv_some {x y : α} (H : some x ≡ some y) : x ≡ y

theorem dist_of_some_dist_some {n} {x y : α} (H : some x ≡{n}≡ some y) : x ≡{n}≡ y

theorem op_some_opM_assoc {x y : α} {mz : Option α} : (x • y) •? mz ≡ x •? (some y • mz)

theorem some_op_opM {a : α} {ma : Option α} : some a • ma = some (a •? ma)

theorem opM_opM_assoc {x : α} {y z : Option α} : (x •? y) •? z ≡ x •? (y • z)

theorem op_some_opM_assoc_dist {x y : α} {mz : Option α} : (x • y) •? mz ≡{n}≡ x •? (some y • mz)

theorem some_inc_some_of_dist_opM {mz : Option α} (H : x ≡{n}≡ y •? mz) : some y ≼{n} some x

theorem inc_of_some_inc_some [IsTotal α] {x y : α} (H : some y ≼ some x) : y ≼ x :=
  let ⟨mz, hmz⟩ := H
  match mz with

theorem some_incN_some_iff_some [IsTotal α] {x y : α} : some y ≼{n} some x → y ≼{n} x

theorem exists_op_some_eqv_some (x : Option α) (y : α) : ∃ z, x • some y ≡ some z

theorem exists_op_some_dist_some {n} (x : Option α) (y : α) : ∃ z, x • some y ≡{n}≡ some z

theorem not_valid_some_exclN_op_left {n} {x : α} [Exclusive x] {y : α} : ¬✓{n} (some x • some y)

theorem validN_op_unit {n} {x : Option α} (vx : ✓{n} x) : ✓{n} x • unit

theorem inc_iff {ma mb : Option α} :
    ma ≼ mb ↔ ma = none ∨ ∃ a b, ma = some a ∧ mb = some b ∧ (a ≡ b ∨ a ≼ b)

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)

theorem inc_iff_isTotal [IsTotal α] {ma mb : Option α} :
    ma ≼ mb ↔ ma = none ∨ ∃ a b, ma = some a ∧ mb = some b ∧ a ≼ b

theorem incN_iff_isTotal [IsTotal α] {ma mb : Option α} :
    ma ≼{n} mb ↔ ma = none ∨ ∃ a b, ma = some a ∧ mb = some b ∧ a ≼{n} b

theorem some_incN_some_iff {a b : α} : some a ≼{n} some b ↔ a ≡{n}≡ b ∨ a ≼{n} b

theorem some_inc_some_iff {a b : α} : some a ≼ some b ↔ a ≡ b ∨ a ≼ b

theorem eqv_of_inc_exclusive [Exclusive (a : α)] {b : α} (H : some a ≼ some b) (Hv : ✓ b) :
     a ≡ b

theorem dist_of_inc_exclusive [Exclusive (a : α)] {b : α} (H : some a ≼{n} some b) (Hv : ✓{n} b)  :
    a ≡{n}≡ b

theorem some_inc_some_iff_isTotal [IsTotal α] {a b : α} : some a ≼ some b ↔ a ≼ b

theorem some_incN_some_iff_isTotal [IsTotal α] {a b : α} : some a ≼{n} some b ↔ a ≼{n} b

theorem validN_of_incN_validN {a b : α} (Hv : ✓{n} a) (Hinc : some b ≼{n} some a) : ✓{n} b

theorem valid_of_inc_valid {a b : α} (Hv : ✓ a) (Hinc : some b ≼ some a) : ✓ b

theorem some_inc_some_iff_opM {a b : α} : some a ≼ some b ↔ ∃ mc, b ≡ a •? mc

theorem some_incN_some_iff_opM {a b : α} : some a ≼{n} some b ↔ ∃ mc, b ≡{n}≡ a •? mc

theorem valid_fst {x : α × β} (h : ✓ x) : ✓ x.fst

theorem valid_snd {x : α × β} (h : ✓ x) : ✓ x.snd

theorem validN_fst {n} {x : α × β} (h : ✓{n} x) : ✓{n} x.fst

theorem validN_snd {n} {x : α × β} (h : ✓{n} x) : ✓{n} x.snd

congrArg in Init.Prelude
</all_available_lemmas>

<local_ctx>
import Iris.Algebra.CMRA

import Iris.Algebra.OFE

namespace Iris

section agree

variable {α : Type u}

variable (α) in

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

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

variable [OFE α]

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)

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

def Agree.valid (x : Agree α) : Prop := ∀ n, x.validN n
</local_ctx>

<target_theorem>
theorem Agree.toAgree_uninj {x : Agree α} : ✓ x → ∃ a, toAgree a ≡ x :=
</target_theorem>

