책과의 관계: Reynolds는 최약 사전조건(weakest precondition) wp를 이 장이 아니라
7장에서 형식화한다. 3장 §3.8(복잡한 점과 한계)의 참고문헌은 완전성 논의를
Loeckx 등(1987)과 7장의 wp로 미룰 뿐, 본문에서 다루지 않는다. 이 페이지는 그 논의를
미리 당겨, 건전성의 역인 완전성이 while 없는 조각에서 실제로 성립함을 wp를 구문으로
계산해 보인다.
건전성의 역이 완전성이다. 타당한 명세는 모두 유도되는가? 답은 아니오, 그리고 조건부로
예다.
아니오
결과 규칙의 전제는 단언의 타당성이다. 정수 산술을 담은 단언의 타당성에는 괴델 불완전성
정리 때문에 완전한 공리계가 없다. 단언 논리의 증명까지 세면 Hoare 논리는 완전할 수 없다.
조건부로 예
단언의 타당성을 오라클로 두면 완전성이 성립한다. 우리 conseq가 바로 그렇게 한다.
Cook의 상대 완전성(relative completeness)이다. 단, 모든 명령과 사후조건에 대해 최약
사전조건을 단언으로 적을 수 있어야 한다.
/-- 의미적 최약 자유 사전조건(weakest liberal precondition). `c` 가 끝나면 `Q` 가 참인 상태들. -/defwlp(c:CommV)(Q:StateV→Prop):StateV→Prop:=funσ=>∀τ,⟦c⟧ᶜσ=Flat.someτ→Qτ/-- 부분 정확성은 wlp 로 다시 쓰인다. 정의 그대로다. 그러니 `wlp c Q` 는 `{P} c {Q}` 를 만족하는
가장 약한 `P` 다. -/theorempartialCorrectS_iff_wlp{PQ:StateV→Prop}{c:CommV}:PartialCorrectSPcQ↔∀σ,Pσ→wlpcQσ:=Iff.rfl
/--
**그리고 가장 큰 해다.** 방정식의 오른쪽을 함의하는 술어 `X` (후고정점) 는 모두 wlp 보다
강하다.
`X` 가 바로 불변식이다 — 한 바퀴를 견디고, 끝난 자리에서 `Q` 를 준다. 그러니 이것은 `while`
규칙의 의미 판 `PartialCorrectS.wh`의 따름정리다. 그 규칙의 Scott 귀납법이 최대 고정점에
대한 성질을 최소 고정점(`⟦while⟧ = fix …`)에서 얻는 근거다.
-/theoremwlp_wh_greatest{b:BoolExpV}{c:CommV}{QX:StateV→Prop}(hX:∀σ,Xσ→(⟦b⟧ᵇσ=false∧Qσ)∨(⟦b⟧ᵇσ=true∧wlpcXσ)):∀σ,Xσ→wlp(.whbc)Qσ:=byV:Type uinst✝:DecidableEqVb:BoolExpVc:CommVQ:StateV→PropX:StateV→ProphX:∀(σ:StateV),Xσ→⟦b⟧ᵇσ=false∧Qσ∨⟦b⟧ᵇσ=true∧wlpcXσ⊢ ∀(σ:StateV),Xσ→wlp(Comm.whbc)Qσhavehbody:PartialCorrectS(funσ=>Xσ∧⟦b⟧ᵇσ=true)cX:=byintroσhxτhτV:Type uinst✝:DecidableEqVb:BoolExpVc:CommVQ:StateV→PropX:StateV→ProphX:∀(σ:StateV),Xσ→⟦b⟧ᵇσ=false∧Qσ∨⟦b⟧ᵇσ=true∧wlpcXσσ:StateVhx:Xσ∧⟦b⟧ᵇσ=trueτ:StateVhτ:⟦c⟧ᶜσ=Flat.someτ⊢ XτrcaseshXσhx.1with⟨hb,_⟩|⟨_,hc⟩inlV:Type uinst✝:DecidableEqVb:BoolExpVc:CommVQ:StateV→PropX:StateV→ProphX:∀(σ:StateV),Xσ→⟦b⟧ᵇσ=false∧Qσ∨⟦b⟧ᵇσ=true∧wlpcXσσ:StateVhx:Xσ∧⟦b⟧ᵇσ=trueτ:StateVhτ:⟦c⟧ᶜσ=Flat.someτhb:⟦b⟧ᵇσ=falseright✝:Qσ⊢ XτinrV:Type uinst✝:DecidableEqVb:BoolExpVc:CommVQ:StateV→PropX:StateV→ProphX:∀(σ:StateV),Xσ→⟦b⟧ᵇσ=false∧Qσ∨⟦b⟧ᵇσ=true∧wlpcXσσ:StateVhx:Xσ∧⟦b⟧ᵇσ=trueτ:StateVhτ:⟦c⟧ᶜσ=Flat.someτleft✝:⟦b⟧ᵇσ=truehc:wlpcXσ⊢ Xτ·inlV:Type uinst✝:DecidableEqVb:BoolExpVc:CommVQ:StateV→PropX:StateV→ProphX:∀(σ:StateV),Xσ→⟦b⟧ᵇσ=false∧Qσ∨⟦b⟧ᵇσ=true∧wlpcXσσ:StateVhx:Xσ∧⟦b⟧ᵇσ=trueτ:StateVhτ:⟦c⟧ᶜσ=Flat.someτhb:⟦b⟧ᵇσ=falseright✝:Qσ⊢ Xτsimp[hx.2]athbAll goals completed! 🐙·inrV:Type uinst✝:DecidableEqVb:BoolExpVc:CommVQ:StateV→PropX:StateV→ProphX:∀(σ:StateV),Xσ→⟦b⟧ᵇσ=false∧Qσ∨⟦b⟧ᵇσ=true∧wlpcXσσ:StateVhx:Xσ∧⟦b⟧ᵇσ=trueτ:StateVhτ:⟦c⟧ᶜσ=Flat.someτleft✝:⟦b⟧ᵇσ=truehc:wlpcXσ⊢ XτexacthcτhτV:Type uinst✝:DecidableEqVb:BoolExpVc:CommVQ:StateV→PropX:StateV→ProphX:∀(σ:StateV),Xσ→⟦b⟧ᵇσ=false∧Qσ∨⟦b⟧ᵇσ=true∧wlpcXσhbody:PartialCorrectS(funσ=>Xσ∧⟦b⟧ᵇσ=true)cX⊢ ∀(σ:StateV),Xσ→wlp(Comm.whbc)QσintroσhxτhτV:Type uinst✝:DecidableEqVb:BoolExpVc:CommVQ:StateV→PropX:StateV→ProphX:∀(σ:StateV),Xσ→⟦b⟧ᵇσ=false∧Qσ∨⟦b⟧ᵇσ=true∧wlpcXσhbody:PartialCorrectS(funσ=>Xσ∧⟦b⟧ᵇσ=true)cXσ:StateVhx:Xστ:StateVhτ:⟦Comm.whbc⟧ᶜσ=Flat.someτ⊢ Qτobtain⟨hxτ,hb⟩:=PartialCorrectS.whhbodyσhxτhτV:Type uinst✝:DecidableEqVb:BoolExpVc:CommVQ:StateV→PropX:StateV→ProphX:∀(σ:StateV),Xσ→⟦b⟧ᵇσ=false∧Qσ∨⟦b⟧ᵇσ=true∧wlpcXσhbody:PartialCorrectS(funσ=>Xσ∧⟦b⟧ᵇσ=true)cXσ:StateVhx:Xστ:StateVhτ:⟦Comm.whbc⟧ᶜσ=Flat.someτhxτ:Xτhb:⟦b⟧ᵇτ=false⊢ QτrcaseshXτhxτwith⟨_,hq⟩|⟨hb',_⟩inlV:Type uinst✝:DecidableEqVb:BoolExpVc:CommVQ:StateV→PropX:StateV→ProphX:∀(σ:StateV),Xσ→⟦b⟧ᵇσ=false∧Qσ∨⟦b⟧ᵇσ=true∧wlpcXσhbody:PartialCorrectS(funσ=>Xσ∧⟦b⟧ᵇσ=true)cXσ:StateVhx:Xστ:StateVhτ:⟦Comm.whbc⟧ᶜσ=Flat.someτhxτ:Xτhb:⟦b⟧ᵇτ=falseleft✝:⟦b⟧ᵇτ=falsehq:Qτ⊢ QτinrV:Type uinst✝:DecidableEqVb:BoolExpVc:CommVQ:StateV→PropX:StateV→ProphX:∀(σ:StateV),Xσ→⟦b⟧ᵇσ=false∧Qσ∨⟦b⟧ᵇσ=true∧wlpcXσhbody:PartialCorrectS(funσ=>Xσ∧⟦b⟧ᵇσ=true)cXσ:StateVhx:Xστ:StateVhτ:⟦Comm.whbc⟧ᶜσ=Flat.someτhxτ:Xτhb:⟦b⟧ᵇτ=falsehb':⟦b⟧ᵇτ=trueright✝:wlpcXτ⊢ Qτ·inlV:Type uinst✝:DecidableEqVb:BoolExpVc:CommVQ:StateV→PropX:StateV→ProphX:∀(σ:StateV),Xσ→⟦b⟧ᵇσ=false∧Qσ∨⟦b⟧ᵇσ=true∧wlpcXσhbody:PartialCorrectS(funσ=>Xσ∧⟦b⟧ᵇσ=true)cXσ:StateVhx:Xστ:StateVhτ:⟦Comm.whbc⟧ᶜσ=Flat.someτhxτ:Xτhb:⟦b⟧ᵇτ=falseleft✝:⟦b⟧ᵇτ=falsehq:Qτ⊢ QτexacthqAll goals completed! 🐙·inrV:Type uinst✝:DecidableEqVb:BoolExpVc:CommVQ:StateV→PropX:StateV→ProphX:∀(σ:StateV),Xσ→⟦b⟧ᵇσ=false∧Qσ∨⟦b⟧ᵇσ=true∧wlpcXσhbody:PartialCorrectS(funσ=>Xσ∧⟦b⟧ᵇσ=true)cXσ:StateVhx:Xστ:StateVhτ:⟦Comm.whbc⟧ᶜσ=Flat.someτhxτ:Xτhb:⟦b⟧ᵇτ=falsehb':⟦b⟧ᵇτ=trueright✝:wlpcXτ⊢ Qτsimp[hb]athb'All goals completed! 🐙
2장에서 while의 뜻은 최소 고정점이었다. while의 최약 자유 사전조건은 최대 고정점이다.
방정식의 모양은 같은데 고르는 해가 반대다. 부분 정확성은 발산을 허용하므로, 발산하는
입력에서 사전조건이 참이어도 상관없다. 그래서 가장 너그러운 해가 최약 사전조건이다.
상태 변환기의 정보 순서에서 ⊥가 아래에 있는 것과, 술어의 함의 순서에서 "모두 허용"이
위에 있는 것이 서로 뒤집힌 상이다. 그런데 최대 고정점 성질의 증명이 최소 고정점 위의
Scott 귀납법이라는 점을 보아 둘 만하다. 후고정점 X가 곧 불변식이고, 이 정리는 while
규칙의 의미 판이다.
Assert는 정수 산술과 양화사를 갖고 있어서 이론적으로는 표현력이 충분하다. 괴델의
β-함수로 유한 수열을 정수 하나로 부호화하면 반복의 최약 사전조건도 적을 수 있다. 그러나
그것을 형식화하는 일은 이 장의 범위를 넘는다. 그래서 완전성은 while 없는 조각에서만
증명한다. 거기서는 최약 사전조건이 치환만으로 계산된다(Dijkstra).
/--
`while` 없는 명령의 최약 사전조건을 **구문으로** 계산한다 (Dijkstra). 치환만으로 된다.
- `while` 에서 `none` — 여기가 표현력이 필요한 자리다.
- `newvar` 에서 결합자가 사후조건이나 초기값 식에 나오면 `none` — 이름을 바꿔 다시 부르면
된다 (§2.5 `Comm.newvar_rename`).
이름이 `Comm.wp` 이지만 3장 이름공간에 있어 `c.wp` 점 표기는 안 된다 (`Comm` 은 2장 타입).
-/defComm.wp[HasFreshV]:CommV→AssertV→Option(AssertV)|.assignve,q=>some(q/[v:=e])|.skip,q=>someq|.seqc₀c₁,q=>(Comm.wpc₁q).bind(Comm.wpc₀)|.itebc₀c₁,q=>(Comm.wpc₀q).bindfunp₀=>(Comm.wpc₁q).mapfunp₁=>.bin.and(.bin.impb.toAssertp₀)(.bin.imp(.notb.toAssert)p₁)|.wh__,_=>none|.newvarvec,q=>ifv∈q.fv∨v∈e.fvthennoneelse(Comm.wpcq).mapfunp=>.quant.allv(.bin.imp(.cmp.eq(.varv)e)p)
while 절에서 none이 나온다. 표현력이 필요한 자리가 바로 거기다.
계산한 사전조건에서 유도가 있고,
/-- **`wp` 는 유도를 준다.** 계산한 사전조건에서 `Hoare` 유도가 있다. `Annot.lean` 의 세 보조
함의(`ite_pre_then` · `ite_pre_else` · `newvar_pre`)가 그대로 쓰인다. -/@[exercise"보충 wp-sound"2]theoremwp_sound[HasFreshV](c:CommV):∀qp,Comm.wpcq=somep→Hoarepcq
힌트: induction c — 각 절에서 simp only [Comm.wp] at h로 계산을 펼친다. Option이
none인 경우는 모순이다. ite·newvar 절에서는 ite_pre_then·ite_pre_else·
newvar_pre로 결과 규칙을 적용한다.
그 사전조건은 가장 약하다.
/--
**`wp` 는 가장 약하다.** 의미적 wlp 가 참인 곳에서는 계산한 `wp` 도 참이다.
변수 선언 절이 요점이다. `∀ v. v = e ⇒ p` 에서 `v` 를 `⟦e⟧ σ` 로 고정하면 (`v ∉ FV(e)`),
안쪽 명령이 끝난 상태 `ρ` 에서 `q` 가 참이어야 하는데, 바깥에서 아는 것은 `v` 를 복원한
`ρ[v := σ v]` 에서 `q` 가 참이라는 것뿐이다. `v ∉ FV(q)` 가 둘을 잇는다 (명제 1.1).
-/@[exercise"보충 wp-weakest"3]theoremwp_weakest[HasFreshV](c:CommV):∀qp,Comm.wpcq=somep→∀σ,wlpc⟦q⟧ₐσ→⟦p⟧ₐσ
힌트: induction c. 각 절에서 wlp가 주는 "끝나면 q"를 안쪽 명령의 wlp로 옮겨
귀납 가설에 넘긴다. newvar 절에서는 v ∉ FV(e)로 n = ⟦e⟧ σ를 얻고, v ∉ FV(q)
(명제 1.1)로 복원한 상태의 q를 안쪽 상태의 q로 옮긴다.
둘을 결과 규칙의 전제 강화 하나로 이으면 상대 완전성이다.
/--
**`while` 없는 조각의 상대 완전성.** 타당한 명세는 모두 유도된다 — 단언의 타당성을 결과 규칙의
오라클로 두는 한에서.
`wp_sound` 가 유도를, `wp_weakest` 가 그 유도의 사전조건이 어떤 타당한 사전조건보다도
약하다는 것을 준다. 결과 규칙의 전제 강화 하나로 잇는다. 두 연습에 기대므로 채점 연습이
아니다 (연습 독립성 원칙).
-/theoremcomplete_loopFree[HasFreshV]{c:CommV}{pp'q:AssertV}(hwp:Comm.wpcq=somep)(h:{p'}c{q}):Hoarep'cq:=Hoare.strengthen(funσhp'=>wp_weakestcqphwpσfunτhτ=>hσhp'τhτ)(wp_soundcqphwp)