Skip to content

feat: fixpoint base of weakest precondition#389

Closed
lihaokun wants to merge 11 commits into
leanprover-community:masterfrom
lihaokun:stage/1-wp-fixpoint
Closed

feat: fixpoint base of weakest precondition#389
lihaokun wants to merge 11 commits into
leanprover-community:masterfrom
lihaokun:stage/1-wp-fixpoint

Conversation

@lihaokun
Copy link
Copy Markdown

Description

Lean 4 port of the fixpoint base of Coq Iris's program logic weakest
precondition (iris/program_logic/weakestpre.v). Adds Stuckness, the
IrisGS typeclass, wp_pre (with num_laters_per_step parameterization),
its Contractive instance, and wp / wp_unfold via the upstream
fixpoint / fixpoint_unfold machinery.

Builds on #370 (Language interface).

Contributes to porting weakestpre.v in PORTING.md.

Iris/Iris/ProgramLogic/WeakestPre.lean

  • Stuckness inductive — 1:1 with Coq stuckness
  • IrisGS typeclass — all 5 fields of Coq irisGS_gen:
    • iris_invGS via extends InvGS_gen hlc GF
    • state_interp / fork_post
    • num_laters_per_step / state_interp_mono
  • wp_pre (body 1:1 with Coq, using ={∅}▷=∗^[num_laters_per_step ns + 1])
  • wp_pre_contractive Contractive instance
  • wp := fixpoint (wp_pre s)
  • wp_unfold via upstream fixpoint_unfold

Adds one private helper step_fupdN_ne to factor out the
BIFUpdate.ne + later_ne + BIFUpdate.ne induction over
num_laters_per_step ns needed by the Contractive proof.

Adaptations vs Coq

  • Stuckness constructors lowercase: notStuck / maybeStuck per Lean
    convention.
  • Plain function-space arrows: CoPset → Expr → (Val → IProp GF) → IProp GF
    rather than Coq's explicit discrete-OFE arrows -d>. The upstream
    function-space COFE instance derives the equivalent OFE structure
    automatically (and the source types here have no non-trivial OFE structure).
  • wp_pre_contractive proof is manual: ~25 lines plus the small private
    step_fupdN_ne helper, since iris-lean doesn't yet have the equivalent of
    Coq's f_contractive tactic. Structure follows
    Iris/Examples/IProp.lean:wp_F_contractive. Once tactic automation lands
    (cf. feat: iloeb #387 for iLöb), this can likely be shortened.
  • wp_unfold proof: wraps wp_pre s into a ContractiveHom, then
    combines fixpoint_unfold with pointwise evaluation on the function-space
    OFE and BI.equiv_iff to convert to ⊣⊢. Same pattern as
    Iris/Examples/IProp.lean:wp_unfold.
  • Auxiliary instance: Inhabited (WPFun) (required by fixpoint); set to
    the constant True proposition.

Checklist

  • My code follows the mathlib naming and code style conventions
  • I have updated PORTING.md as appropriate
  • I have added my name to the authors section of any appropriate files

lihaokun added 10 commits May 12, 2026 17:13
Stuckness inductive + IrisGS typeclass + wp_pre (实定义,命题 1:1 自 Coq Iris
weakestpre.v) + wp/wp_unfold/wp_pre_contractive 接口签名。

Phase 1-A 出口:lake build OK + 4 个预期 sorry:
  • COFE (WPFun) — Phase 1-B 用 OFE.discrete_funO
  • wp_pre_contractive — Phase 1-B nl-proof
  • wp body — Phase 1-B 用 fixpoint (wp_pre s)
  • wp_unfold body — Phase 1-B 用 fixpoint_unfold

简化(vs Coq 原版,文件头有注释):
  • num_laters_per_step = 0 (硬编码;Coq 原是 S (num_laters_per_step ns))
  • IrisGS 暂不含 state_interp_mono 字段(Phase 1-B 按需补)

References (三参考交叉):
  • Coq iris/program_logic/weakestpre.v (commit d663f775) — 命题来源(canonical)
  • hxrts/iris-lean@fork/iris/vendor:src/Iris/ProgramLogic/WeakestPre.lean — 思路
  • upstream Iris/Algebra/OFE.lean (Contractive/fixpoint) +
    Iris/Instances/Lib/{WSat,FUpd}.lean (InvGS/uPred_fupd) +
    Iris/BI/Updates.lean (|={E1,E2}=>, |={E}▷=∗^[n]) +
    Iris/BI/BigOp/BigSepList.lean ([∗list]) — 算子来源
…rive

nl-proof:
  - IProp GF = UPred (IResUR GF) → IsCOFE 实例 (Iris/Algebra/UPred.lean:93)
  - 函数空间封闭:instance [∀ x, COFE (β x)] : COFE ((x : α) → β x)
    (Iris/Algebra/OFE.lean:854) 套用 3 层 (CoPset → Expr → (Val → IProp GF))

修法:删除显式 sorry 实例,typeclass resolution 自动 derive。

Stage 1 sorry 数:4 → 3(剩 wp_pre_contractive / wp / wp_unfold)。
Phase 1-B 第 1 个 sorry 消除(按 D33 D34 nl-proof 纪律)。
…orry)

nl-proof v3:~25 行 tactic(模板 Iris/Examples/IProp.lean:131 wp_F_contractive
11 行同模式)。

结构:
  - value case:unfold + simp + .rfl(W 不出现)
  - non-value case:透过 5+3 层 forall_ne / 2 层 wand_ne / 4 次 BIFUpdate.ne /
    sep_ne / Contractive.distLater_dist (▷ 关键步) / bigSepL_dist

upstream API 全部已验证存在:
  • BI.forall_ne (DerivedLaws.lean:122)
  • BI.{sep,wand}_ne (BI.lean:35-36)
  • BIFUpdate.ne (Updates.lean:108)
  • Contractive.distLater_dist (OFE.lean:132) — 用于 ▷ via sbi_later_contractive
    (InternalEq.lean:408)
  • Iris.BI.BigSepL.bigSepL_dist (BigSepList.lean:77)

工程问题:Nat.repeat _ 1 X = f X 由 rfl 自动 reduce,
{E,∅}=∗ X = wand _ (fupd E ∅ _) macro 展开后透过依次 wand_ne + BIFUpdate.ne。

Stage 1 sorry 数:3 → 2(剩 wp def + wp_unfold,可立即用 fixpoint + fixpoint_unfold)。
首次编译即通过,0 修复迭代——nl-proof v3 工程问题预解决方案有效。
…eanprover-community#3 leanprover-community#4)

wp def:
  - wp s := fixpoint (fun W : WPFun => wp_pre s W)
  - 依赖 COFE (auto-derive) + Inhabited + wp_pre_contractive 全就位

wp_unfold:
  - 包装 ContractiveHom { f := fun W => wp_pre s W, contractive := inferInstance }
  - fixpoint_unfold 给 ≡ at WPFun level
  - 函数空间 OFE.Equiv pointwise → 应用 (E e Φ) 拿 IProp 层 Equiv
  - BI.equiv_iff.mp 转 ⊣⊢

Stage 1 全部 4 sorry 消除!0 sorry / 0 axiom 干净 build。

第一个完成真证明的 stage,PR-ready 候选(仍需 stage/2-4 真证明 + maintainer 沟通)。
为 upstream PR 做准备:IrisGS 补 state_interp_mono 字段(Coq weakestpre.v
irisGS_gen 第 5 字段)。

  state_interp_mono (σ : State) (ns : Nat) (κs : List Obs) (nt : Nat) :
    state_interp σ ns κs nt ⊢ iprop(|={∅}=> state_interp σ (ns + 1) κs nt)

调研结论(不补):
  - num_laters_per_step:hxrts 同样省(precedent);Phase 1-2 swap/数组不需要
  - hlc 参数化:upstream Examples/IProp.lean 不参数化
  - Wp typeclass / WP notation:upstream Examples/IProp.lean 不注册

stage/1 现在 5/5 IrisGS 字段(vs Coq 6 字段,仅省 num_laters_per_step
sub-precedent)。0 sorry / 0 axiom build。
IrisGS 加 num_laters_per_step : Nat → Nat 字段(Coq 第 4 字段)。
wp_pre body 用 `={∅}▷=∗^[iG.num_laters_per_step ns + 1]` 替代硬编码 `^[1]`。

新增 helper `step_fupdN_ne`(10 行 induction):透过 step_fupdN k 层
NonExpansive(每层 BIFUpdate.ne + later_ne + BIFUpdate.ne)。

wp_pre_contractive proof 增加 step_fupdN_ne 调用(透过 num_laters_per_step ns
层后到达内层 inner);Nat.repeat (S k) X = f (Nat.repeat f k X) by rfl reduce。

stage/1 现在与 Coq Iris weakestpre.v irisGS_gen **6/6 字段全 1:1**:
  • iris_invGS    → extends InvGS GF
  • state_interp  ✓
  • fork_post     ✓
  • num_laters_per_step ✓ (新补)
  • state_interp_mono   ✓ (上次补)

0 sorry / 0 axiom build。Phase 1-B 完整严格 1:1 PR-ready 状态。
…nces for PR

Remove all references to hxrts/iris-lean (private fork; PR leanprover-community#149/leanprover-community#150 closed)
and to project-internal terminology (Phase 1-A/B, stage/N, CLAUDE.md).
Translate Chinese comments to English. All documentation now references only
Coq Iris weakestpre.v and upstream iris-lean modules.

Module remains 1:1 with Coq Iris weakestpre.v (commit d663f775):
  - 6/6 IrisGS fields
  - wp_pre with num_laters_per_step parameterization
  - wp_pre_contractive proof following Iris/Examples/IProp.lean wp_F_contractive
  - wp / wp_unfold via upstream fixpoint / fixpoint_unfold
Adds `(hlc : outParam Bool)` parameter to IrisGS, mirroring Coq's
`irisGS_gen (hlc : has_lc)`. `extends InvGS GF` becomes
`extends InvGS_gen hlc GF`.

Also fixes Coq 1:1 match on bigSepL: `[∗list] ef ∈ efs, ...`
(was `[∗list] _i ↦ ef ∈ efs, ...` to silence the linter, but upstream
syntax supports the index-less form).

stage/1 now strictly 1:1 with Coq weakestpre.v's irisGS_gen + wp_pre +
wp_pre_contractive + wp + wp_unfold.
Tracks the fixpoint base scope ported in this PR:
  - Stuckness + IrisGS (all 5 fields)
  - wp_pre + Contractive instance
  - wp via fixpoint + wp_unfold via fixpoint_unfold

Remaining items in weakestpre.v (wp_value_fupd, wp_strong_mono, wp_mono,
fupd_wp, wp_fupd, wp_wand, wp_atomic, wp_frame_l/r, wp_bind/bind_inv)
will follow in subsequent PRs.
…is FIXME)

Coq Iris weakestpre.v has a FIXME noting that wp_pre_contractive's proof
would simplify with a 'proper instance for step_fupdN'. This lifts the
NonExpansive lemma for `|={Eo}[Ei]▷=∗^[k]` to Iris/BI/Updates.lean (the
home of step_fupdN), generalized over any [BI PROP] [BIFUpdate PROP].

WeakestPre.lean now imports it from upstream rather than defining a
file-local helper. Also cleans up two small redundancies in opens
(removed redundant 'Iris.BI'; added 'Iris.BI.BigSepL' so the bigSepL_dist
call drops its fully-qualified path).
@lihaokun lihaokun marked this pull request as ready for review May 12, 2026 12:10
@lzy0505 lzy0505 linked an issue May 12, 2026 that may be closed by this pull request
@lzy0505
Copy link
Copy Markdown
Collaborator

lzy0505 commented May 12, 2026

Thanks for the PR. Before reviewing it, can you clean up all the AI generated comments, and add @[rocq_alias] annotations?

- Removed verbose doc comments and section-level "Coq weakestpre.v: ..."
  blocks; kept only the file-level summary and per-field doc strings on
  IrisGS members. Inline tactic comments in wp_pre_contractive removed.
- Added @[rocq_alias] to:
  - Stuckness          (Coq: stuckness)
  - Stuckness.le       (Coq: stuckness_le)
  - IrisGS             (Coq: irisGS_gen)
  - wp_pre             (Coq: wp_pre)
  - wp_pre_contractive (Coq: wp_pre_contractive)
  - wp                 (Coq: wp_def)
  - wp_unfold          (Coq: wp_unfold)
  - step_fupdN_ne      (Coq: step_fupdN_ne)
@lihaokun
Copy link
Copy Markdown
Author

lihaokun commented May 13, 2026

Thanks @lzy0505, addressed both points in 8238b50:

  • Trimmed comments: removed the section-level blocks and inline tactic
    comments; kept only the file header summary and a single-line per-field doc
    on IrisGS. Happy to add specific docs back if anything is unclear.
  • @[rocq_alias] annotations on: Stuckness, Stuckness.le, IrisGS,
    wp_pre, wp_pre_contractive, wp (Coq wp_def), wp_unfold, and
    step_fupdN_ne (in Iris/BI/Updates.lean).

@lzy0505
Copy link
Copy Markdown
Collaborator

lzy0505 commented May 13, 2026

@lihaokun BTW, @ayhon is also working on this. So please coordinate to make sure you two don't work on the same thing if you plan to port the rest of the file.

@ayhon
Copy link
Copy Markdown
Contributor

ayhon commented May 13, 2026

I think there's a lot of overlap between this PR and mine, see https://github.com/ayhon/iris-lean/tree/fele/feat/add-weakestpre.

@ayhon
Copy link
Copy Markdown
Contributor

ayhon commented May 13, 2026

In particular, these seem to be all definitions I had already ported in my PR, although some of the proofs are a bit shorter, in particular I needed many more lines and auxiliary lemmas to prove wp_pre_contractive. Other than that, in my PR I seem to be a bit further ahead, I have also proved wp_contractive, wp_ne, and some lemmas on fupd using the proof mode.

@ayhon
Copy link
Copy Markdown
Contributor

ayhon commented May 13, 2026

@lihaokun I had paused development of this PR to develop the iloeb tactic, but if it's something you require right now I wouldn't mind reprioritizing it so you are unblocked. What are you working towards right now?

@lihaokun
Copy link
Copy Markdown
Author

Hi @lzy0505 and @ayhon,

First — thanks @lzy0505 for the careful review on this PR; the feedback will carry over to the next round either way.

And second, I'm sorry — I missed @ayhon's fele/feat/add-weakestpre branch before opening this. There's clear overlap, and his version is more complete than what I have here (real proofs for wp_strong_mono / fupd_wp / wp_fupd / wp_atomic, a three-class decomposition StateInterp / NumLatersPerStep / IrisGS_gen, and consistent style with the merged #370). Before deciding what to do with this PR, I'd like to discuss how we might divide the work.

Some context on why I'm interested in this corner of iris-lean: I'm exploring whether VST (the Verified Software Toolchain for CompCert C) can be ported to Lean 4. For that I'll eventually need the full Iris program logic stack on Lean:

Coq file issue who
program_logic/weakestpre.v #346 @ayhon (in progress on fele/feat/add-weakestpre)
program_logic/lifting.v #348 unclaimed
program_logic/ectx_lifting.v #349 unclaimed
program_logic/adequacy.v #352 unclaimed
base_logic/lib/ghost_map.v unclaimed
base_logic/lib/gen_heap.v unclaimed

@ayhon — if you're taking on weakestpre.v, that's wonderful. In the meantime I can keep moving on my side by stubbing those downstream interfaces (lifting.v / ectx_lifting.v / adequacy.v plus the two base_logic/lib/ files) locally; once yours lands I'd be happy to revisit and turn the work into upstream PRs if that's useful.

Happy to hear thoughts on how to coordinate. Sorry again for the duplicate effort.

@Kaptch
Copy link
Copy Markdown
Collaborator

Kaptch commented May 13, 2026

Hi @lihaokun. Thank you for your PR! I agree that we should discuss the splitting of program logic into chunks for unblocking purposes.
The definition of wp probably should lend first, and then later we could take a look how to merge everything else.

@ayhon would you mind create a separate early PR for just a bare-bone definition of wp + wp-unfold from your branch (and probably some lemmas that you feel could be merged early on)?
It might be better if there is an open PR, so that people can start building on top of it.
In this case, notations/proof mode typeclasses/lifts/adequacy/etc. can be later merged on top, and meanwhile @lihaokun and other people interested in working with HeapLang/VST can already start doing so by using downstream substitutes on top of your PR, and later we can see how to integrate it all together.

@lihaokun would you be okay with that? It might be easier to merge other things that @ayhon was working on, if the definition of wp comes from fele/feat/add-weakestpre.
If both you and @ayhon are okay with this solution, then we could also discuss here if/how you want to split some other parts about program logic, so that there are no overlaps.
It's just a proposal, and other people working on the port are also extremely welcome to voice their opinions.

Just in case of concerns about merging, I can help with backporting and merging, when the need arises.

@ayhon
Copy link
Copy Markdown
Contributor

ayhon commented May 13, 2026

@Kaptch I don't mind publishing my current PR as a draft. I need to rebase it so it sits on top of #387 though, since I intend to use the iloeb tactic in my proofs. I will get to it once I finish redacting this message.

EDIT: I published my current draft in #393. I'll try to remember not to force push onto it to ease the work of people basing off of it.

@lihaokun, I just got back form talking with my supervisors and we have no plans to work on program_logic/adequacy.v in the future, so feel free to work on that right now. program_logic/weakestpre.v is what I'm currently working on, and my plans for next steps would be to work on program_logic/lifting.v and program_logic/ectx_lifting.v, since I expect to use them in the future. In particular, because I expect to use them a lot in the future, I would like to have the opportunity of porting them, since I believe this would help me develop a better understanding of their contents. However, I currently have no estimates as to how long it will take me to finish them. What are your time constraints on having these files ready? Would waiting for a week be acceptable to you?

@lihaokun
Copy link
Copy Markdown
Author

lihaokun commented May 13, 2026

Hi @ayhon — sounds good to me, and a week is completely fine. I'm still on the CompCert/VST translation side (currently Common / Clight), so the WP layer isn't on my critical path yet.

So the division would be:

  • you: weakestpre.v + lifting.v + ectx_lifting.v (you mentioned wanting to port the latter two yourself for understanding — happy to leave them to you)
  • me: program_logic/adequacy.v (thanks for the explicit hand-off)

In the meantime I'll keep sorry'd stubs of the WP interface in lean-vst and rebase onto your draft PR once it's open.

@Kaptch — the proposal works for me, thanks for offering to help with backports.

@lihaokun lihaokun closed this May 13, 2026
lihaokun added a commit to lihaokun/iris-lean that referenced this pull request May 14, 2026
按 PR leanprover-community#389 review 反馈套用同样规范:
- 17 个顶级 decl 全部加 @[rocq_alias] 注解(wptp / steps_sum / wp_step /
  wptp_step / wp_not_stuck / wptp_preservation / wptp_postconditions /
  wptp_progress / wp_progress_gen / wp_strong_adequacy_gen /
  wp_strong_adequacy / adequate / adequate_alt / adequate_tp_safe /
  wp_adequacy_gen / wp_adequacy / wp_invariance_gen / wp_invariance)
- 删除文件头大段 Contents / Depends-on 注释(重复 namespace 与 import 即可看出)
- 删除内联 docstring 中 "Coq adequacy.v line N" 重复信息(保留必要的注解,
  例如 `wp_progress_gen` 的 `_hwp : True` 占位说明)
- 删除 section header `/-! ## §X ... -/` 装饰(按 PR leanprover-community#389 风格)
- adequate record 字段 docstring 精简

度量:246 → 188 lines(-58)。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Port program_logic/weakestpre.v

4 participants