证明规则
本页列出 C* 证明内核提供的分离逻辑规则。每个条目给出规则的注册名及其在内核中的确切表述。注册名就是传给 get_theorem_by_nameget_theorem_by_name 的名字,也用于 proof_kernel.hproof_kernel.h 中相应的 get_*get_* 访问器。
下文使用的术语和记号——hprophprop、****、-*-*、&&&&、||||、-->-->、empemp、purepure、factfact、 |--|--、-|--|-,以及量词 existsexists 与 forallforall——在内存模型与断言中定义。下文的每条表述都涉及以下两点,因此在此重申:|--|-- 是蕴含(hentailhentail,类型为 boolbool),而 -|--|- 是断言之间的 HOL 等式(-|--|- 就是 hprophprop 类型上的 ==),并非另设的等价关系。内核证明了 heqheq,即 !hp1 hp2. (hp1 -||- hp2) <=> (hp1 -|- hp2)!hp1 hp2. (hp1 -||- hp2) <=> (hp1 -|- hp2),由此可以将互相蕴含与等式互换使用。由于 -|--|- 就是等式,下文的每条 -|--|- 规则都可以用于双向重写。
这些连接词都定义在内存模型之上,并非原始概念:**** 对状态的各种拆分作量化,-*-* 对状态的各种扩张作量化,empemp 表示内存为空。因此 **** 的结合律与交换律、empemp 的单位元性质以及魔术棒的伴随,都是模型的推论,并非假设。
|--|-- 是 hprophprop 上的预序,并且以 -|--|- 为等式满足反对称性。下面五条规则是各项证明的基础:hentail_transhentail_trans 串联各步,hentail_antisymhentail_antisym 把一对蕴含转换为可用于重写的等式。
hentail_reflhentail_refl——蕴含具有自反性;当目标两侧完全相同时,这条规则就能解决目标。
!hp. hp |-- hp
!hp. hp |-- hp
hentail_transhentail_trans——蕴含具有传递性,可以串联各步推理,逐步推进证明。
!hp1 hp2 hp3. (hp1 |-- hp2) ==> (hp2 |-- hp3) ==> (hp1 |-- hp3)
!hp1 hp2 hp3. (hp1 |-- hp2) ==> (hp2 |-- hp3) ==> (hp1 |-- hp3)
hentail_antisymhentail_antisym——互相蕴含即断言的等式。
!hp1 hp2. (hp1 |-- hp2) ==> (hp2 |-- hp1) ==> (hp1 -|- hp2)
!hp1 hp2. (hp1 |-- hp2) ==> (hp2 |-- hp1) ==> (hp1 -|- hp2)
hentail_sym_lefthentail_sym_left——反过来,断言的等式可以弱化为蕴含,从而将重写引理用于蕴含目标。
!hp1 hp2. (hp1 -|- hp2) ==> (hp1 |-- hp2)
!hp1 hp2. (hp1 -|- hp2) ==> (hp1 |-- hp2)
heq_symheq_sym——断言等式具有对称性。此处用 <=><=> 表述,因此可以用来调整目标的方向。
!hp1 hp2. (hp1 -|- hp2) <=> (hp2 -|- hp1)
!hp1 hp2. (hp1 -|- hp2) <=> (hp2 -|- hp1)
**** 满足结合律与交换律,并以 empemp 为单位元,也就是说,(hprop, **, emp)(hprop, **, emp) 构成交换幺半群。重排断言的空间部分时,可以使用以下规则。
hsep_assochsep_assoc——**** 满足结合律。
!hp1 hp2 hp3. (hp1 ** hp2) ** hp3 -|- hp1 ** (hp2 ** hp3)
!hp1 hp2 hp3. (hp1 ** hp2) ** hp3 -|- hp1 ** (hp2 ** hp3)
hsep_commhsep_comm——**** 满足交换律。分离合取不限定它所连接的两块堆片段的顺序。
!hp1 hp2. hp1 ** hp2 -|- hp2 ** hp1
!hp1 hp2. hp1 ** hp2 -|- hp2 ** hp1
hsep_hemp_lefthsep_hemp_left——empemp 是左单位元。
!hp. emp ** hp -|- hp
!hp. emp ** hp -|- hp
hsep_hemp_righthsep_hemp_right——empemp 是右单位元。
!hp. hp ** emp -|- hp
!hp. hp ** emp -|- hp
hsep_comm_left_parthsep_comm_left_part——把右嵌套链中间的合取项移到最前面。这条规则主要用于将某个特定资源移到长 **** 链的头部,无须手工展开整条链。
!hp hp1 hp2. hp1 ** hp ** hp2 -|- hp ** hp1 ** hp2
!hp hp1 hp2. hp1 ** hp ** hp2 -|- hp ** hp1 ** hp2
hsep_achsep_ac——将结合律与交换律合并为一条定理:上面三条重写以 HOL 重写器要求的形式组合,用于对 **** 作 AC 规范化。这里的 &&&& 是布尔合取(&&&& 是重载的,三个分量都是 boolbool),并非 handhand。
(hp1 ** hp2 -|- hp2 ** hp1) && ((hp1 ** hp2) ** hp3 -|- hp1 ** (hp2 ** hp3)) && (hp1 ** (hp2 ** hp3) -|- hp2 ** (hp1 ** hp3))
(hp1 ** hp2 -|- hp2 ** hp1) && ((hp1 ** hp2) ** hp3 -|- hp1 ** (hp2 ** hp3)) && (hp1 ** (hp2 ** hp3) -|- hp2 ** (hp1 ** hp3))
规范化使用的就是这条定理。用 hsep_achsep_ac 重写,可以调整 **** 链的顺序和括号,将其化为规范形式。因此,处理长空间合取时,很少需要单独使用 hsep_assochsep_assoc 与 hsep_commhsep_comm。
neutral_hsepneutral_hsep——在 HOL 的 neutralneutral 意义下,empemp 就是 **** 的单位元。
neutral(**) = emp
neutral(**) = emp
monoidal_hsepmonoidal_hsep——**** 是幺半群运算,这是 HOL 通用 iterateiterate 机制的前提。有了这条定理,迭代分离合取 hitersephitersep 就能直接复用整个 ITERATE_*ITERATE_* 库(插入、并集、差集、删除)。
monoidal(**)
monoidal(**)
框架消除使分离逻辑能够处理更大规模的问题:关于少数几个堆单元的证明,在一并保留其余堆且不作改动时依然成立。在 C* 中,这一原则表述为关于断言的普通定理,而非关于三元组的元定理。
hsep_cancel_lefthsep_cancel_left——在左侧保留任意框架 hp3hp3,同时加强 **** 的另一侧。
!hp1 hp2 hp3. (hp1 |-- hp2) ==> (hp3 ** hp1 |-- hp3 ** hp2)
!hp1 hp2 hp3. (hp1 |-- hp2) ==> (hp3 ** hp1 |-- hp3 ** hp2)
hsep_cancel_righthsep_cancel_right——镜像版本,在右侧做框架消除。
!hp1 hp2 hp3. (hp1 |-- hp2) ==> (hp1 ** hp3 |-- hp2 ** hp3)
!hp1 hp2 hp3. (hp1 |-- hp2) ==> (hp1 ** hp3 |-- hp2 ** hp3)
hsep_cancel_left_eqhsep_cancel_left_eq——以等式表述的版本:在 **** 的右操作数内部重写,整条断言保持不变。
!hp1 hp2 hp2'. (hp2 -|- hp2') ==> (hp1 ** hp2 -|- hp1 ** hp2')
!hp1 hp2 hp2'. (hp2 -|- hp2') ==> (hp1 ** hp2 -|- hp1 ** hp2')
hsep_monotonehsep_monotone——**** 对两个参数同时具有单调性;两条消去规则都是它的实例,只需让其中一条蕴含采用自反形式。
!hp1 hp1' hp2 hp2'. (hp1 |-- hp1') ==> (hp2 |-- hp2') ==> (hp1 ** hp2 |-- hp1' ** hp2')
!hp1 hp1' hp2 hp2'. (hp1 |-- hp1') ==> (hp2 |-- hp2') ==> (hp1 ** hp2 |-- hp1' ** hp2')
hsep_cancel_lefthsep_cancel_left 就是框架规则,只不过表述在断言层面而非三元组层面。把 hp3hp3 理解为框架 FF:任何在小足迹上证明的蕴含,在加入一块不相交的剩余部分后依然成立。
这里没有对 FF 作任何假设。前提的证明不涉及它,而 **** 的定义保证框架占据一块不相交的内存,因此结论对任意 FF 都成立。符号执行引擎由此可以将一条小足迹蕴含(只涉及某条语句所访问的单元)应用于完整的符号状态。
这些规则对应哪些策略,以及如何在证明中消去目标两侧相匹配的资源,见分离逻辑的后向证明;local_applylocal_apply 所用的前向式 frame_right_slruleframe_right_slrule,在同样意义下就是 hsep_cancel_righthsep_cancel_right。
以下两个连接词通过伴随关系刻画,而非引入与消去规则:分离蕴含 -*-* 是 **** 的右伴随,普通蕴含 -->--> 是 &&&& 的右伴随。两条规则都以 <=><=> 表述,因此可以根据目标选择使用方向。
hwand_hsep_adjointhwand_hsep_adjoint——魔术棒的伴随。
!hp1 hp2 hp3. (hp1 ** hp2 |-- hp3) <=> (hp1 |-- hp2 -* hp3)
!hp1 hp2 hp3. (hp1 ** hp2 |-- hp3) <=> (hp1 |-- hp2 -* hp3)
himpl_hand_adjointhimpl_hand_adjoint——蕴含的伴随。
!hp1 hp2 hp3. (hp1 && hp2 |-- hp3) <=> (hp1 |-- hp2 --> hp3)
!hp1 hp2 hp3. (hp1 && hp2 |-- hp3) <=> (hp1 |-- hp2 --> hp3)
实际证明中几乎不展开魔术棒的定义(对当前状态的所有扩张作量化),而是通过 hwand_hsep_adjointhwand_hsep_adjoint 使用 -*-*:将目标 hp1 |-- hp2 -* hp3hp1 |-- hp2 -* hp3 转换为 **** 形式的目标 hp1 ** hp2 |-- hp3hp1 ** hp2 |-- hp3,即可使用常规的空间推理机制处理。反过来,消耗关于魔术棒的假设时,也是先将其转换为分离合取。
非空间连接词与普通直觉主义逻辑中的行为相同,只是逐点提升到了 hprophprop。需要注意 truetrue、falsefalse 与 **** 的相互作用:fact(T)fact(T) 就是 empemp,可以从分离合取中消去; fact(F)fact(F) 则会吸收与它相邻的部分。
htrue_defhtrue_def——hprophprop 类型上的 truetrue 就是 pure(T)pure(T):任何状态都满足它,包括非空状态。
true -|- pure(T)
true -|- pure(T)
hfalse_defhfalse_def——falsefalse 就是 pure(F)pure(F),没有任何状态满足它。
false -|- pure(F)
false -|- pure(F)
htrue_introhtrue_intro——任何断言都蕴含 truetrue;这会丢弃整条断言。
!hp. hp |-- true
!hp. hp |-- true
htrue_hemphtrue_hemp——平凡的事实就是空堆。注意它与 htrue_defhtrue_def 的区别:fact(T)fact(T) 还要求堆为空,而 truetrue 没有这一要求。
fact(T) -|- emp
fact(T) -|- emp
hfalse_elimhfalse_elim——断言层面的爆炸律(ex falso)。
!hp. false |-- hp
!hp. false |-- hp
hsep_hfalse_lefthsep_hfalse_left——falsefalse 会湮灭整个分离合取。
!hp. false ** hp |-- false
!hp. false ** hp |-- false
htrue_elim_lefthtrue_elim_left——**** 左侧的平凡事实会消失。
!hp. fact(T) ** hp -|- hp
!hp. fact(T) ** hp -|- hp
htrue_elim_righthtrue_elim_right——右侧同理。
!hp. hp ** fact(T) -|- hp
!hp. hp ** fact(T) -|- hp
hfalse_absorb_lefthfalse_absorb_left——假事实会吸收与它合并的任何断言。
!hp. fact(F) ** hp -|- fact(F)
!hp. fact(F) ** hp -|- fact(F)
hfalse_absorb_righthfalse_absorb_right——右侧同理。
!hp. hp ** fact(F) -|- fact(F)
!hp. hp ** fact(F) -|- fact(F)
hand_introhand_intro——要证明一个合取,就从同一条断言出发证明两个合取项。与 **** 不同,&&&& 不会拆分堆:两侧描述的是同一个状态。
!hp1 hp2 hp3. (hp1 |-- hp2) ==> (hp1 |-- hp3) ==> (hp1 |-- hp2 && hp3)
!hp1 hp2 hp3. (hp1 |-- hp2) ==> (hp1 |-- hp3) ==> (hp1 |-- hp2 && hp3)
hand_elim1hand_elim1——投影出左合取项。
!hp1 hp2. (hp1 && hp2 |-- hp1)
!hp1 hp2. (hp1 && hp2 |-- hp1)
hand_elim2hand_elim2——投影出右合取项。
!hp1 hp2. (hp1 && hp2 |-- hp2)
!hp1 hp2. (hp1 && hp2 |-- hp2)
hand_assochand_assoc——&&&& 满足结合律。
!hp1 hp2 hp3. (hp1 && hp2) && hp3 -|- hp1 && (hp2 && hp3)
!hp1 hp2 hp3. (hp1 && hp2) && hp3 -|- hp1 && (hp2 && hp3)
hand_commhand_comm——&&&& 满足交换律。
!hp1 hp2. hp1 && hp2 -|- hp2 && hp1
!hp1 hp2. hp1 && hp2 -|- hp2 && hp1
hand_monotonehand_monotone——&&&& 对两个参数都具有单调性。
!hp1 hp1' hp2 hp2'. (hp1 |-- hp1') ==> (hp2 |-- hp2') ==> (hp1 && hp2 |-- hp1' && hp2')
!hp1 hp1' hp2 hp2'. (hp1 |-- hp1') ==> (hp2 |-- hp2') ==> (hp1 && hp2 |-- hp1' && hp2')
hor_intro1hor_intro1——选择左析取支。
!hp1 hp2. (hp1 |-- hp1 || hp2)
!hp1 hp2. (hp1 |-- hp1 || hp2)
hor_intro2hor_intro2——选择右析取支。
!hp1 hp2. (hp2 |-- hp1 || hp2)
!hp1 hp2. (hp2 |-- hp1 || hp2)
hor_elimhor_elim——分类讨论:使用一个析取时,需要处理两种情况。
!hp1 hp2 hp3. (hp1 |-- hp3) ==> (hp2 |-- hp3) ==> (hp1 || hp2 |-- hp3)
!hp1 hp2 hp3. (hp1 |-- hp3) ==> (hp2 |-- hp3) ==> (hp1 || hp2 |-- hp3)
hor_monotonehor_monotone——|||| 对两个参数都具有单调性。
!hp1 hp1' hp2 hp2'. (hp1 |-- hp1') ==> (hp2 |-- hp2') ==> (hp1 || hp2 |-- hp1' || hp2')
!hp1 hp1' hp2 hp2'. (hp1 |-- hp1') ==> (hp2 |-- hp2') ==> (hp1 || hp2 |-- hp1' || hp2')
C* 提供两种将 boolbool 嵌入 hprophprop 的方式,几乎每个常规证明步骤都涉及两者的区别。
pure(p)pure(p) 断言 pp,对堆不作任何说明:只要 pp 成立,任何状态都满足它。fact(p)fact(p) 既断言 pp,又断言堆为空,按定义 fact(p) -|- pure(p) && empfact(p) -|- pure(p) && emp。由于 fact(p)fact(p) 断言堆为空,它可以出现在 **** 链中而不消耗任何资源。这也解释了为什么规约用 factfact 书写,以及为什么 fact(T)fact(T) 可以直接消去。
下面的规则用于在 **** 与 &&&& 之间转换纯信息,并将其移入或移出断言。两条 hsep_hpure_*hsep_hpure_* 规则把 purepure 合取项从分离合取中提取出来;hsep_hfact_*hsep_hfact_* 规则对 factfact 做同样的事; hfact_hpurehfact_hpure 则用于转换这两种形式。
hpure_introhpure_intro——把一条已证命题附加到右侧。
!p hp1 hp2. p ==> (hp1 |-- hp2) ==> (hp1 |-- pure(p) && hp2)
!p hp1 hp2. p ==> (hp1 |-- hp2) ==> (hp1 |-- pure(p) && hp2)
hpure_elimhpure_elim——通过假设 pp 来消耗左侧的 purepure 合取项。
!p hp1 hp2. (p ==> (hp1 |-- hp2)) ==> (pure(p) && hp1 |-- hp2)
!p hp1 hp2. (p ==> (hp1 |-- hp2)) ==> (pure(p) && hp1 |-- hp2)
hsep_hpure_lefthsep_hpure_left——从 **** 的左操作数中提取 purepure。
!p hp1 hp2. (pure(p) && hp1) ** hp2 -|- pure(p) && (hp1 ** hp2)
!p hp1 hp2. (pure(p) && hp1) ** hp2 -|- pure(p) && (hp1 ** hp2)
hsep_hpure_righthsep_hpure_right——从 **** 的右操作数中提取 purepure。规范化时,提取纯事实的步骤就使用这两条重写规则。
!p hp1 hp2. hp1 ** (pure(p) && hp2) -|- pure(p) && (hp1 ** hp2)
!p hp1 hp2. hp1 ** (pure(p) && hp2) -|- pure(p) && (hp1 ** hp2)
hfact_defhfact_def——factfact 的定义方程。
!p hp. fact(p) -|- (pure(p) && emp)
!p hp. fact(p) -|- (pure(p) && emp)
hfact_hpurehfact_hpure——**** 链前面的 factfact 等同于用 &&&& 连接的 purepure。这条等式是两种嵌入方式之间的转换依据,两个方向都经常用到。
!p hp. fact(p) ** hp -|- pure(p) && hp
!p hp. fact(p) ** hp -|- pure(p) && hp
hfact_hpure_righthfact_hpure_right——同样的等式,调整了操作数的位置。
!p hp. hp && pure(p) -|- fact(p) ** hp
!p hp. hp && pure(p) -|- fact(p) ** hp
hfact_introhfact_intro——把一条已证事实引入蕴含的右侧。
!p hp1 hp2. p ==> (hp1 |-- hp2) ==> (hp1 |-- fact(p) ** hp2)
!p hp1 hp2. p ==> (hp1 |-- hp2) ==> (hp1 |-- fact(p) ** hp2)
hfact_elimhfact_elim——把事实从左侧移入外围的证明上下文,供普通的 HOL 推理使用。
!p hp1 hp2. (p ==> (hp1 |-- hp2)) ==> (fact(p) ** hp1 |-- hp2)
!p hp1 hp2. (p ==> (hp1 |-- hp2)) ==> (fact(p) ** hp1 |-- hp2)
hfact_elim_duphfact_elim_dup——同上,同时在右侧保留该事实;当一条事实既要使用又要保留时,通常采用这种形式。
!p hp1 hp2. (p ==> (hp1 |-- hp2)) ==> (fact(p) ** hp1 |-- fact(p) ** hp2)
!p hp1 hp2. (p ==> (hp1 |-- hp2)) ==> (fact(p) ** hp1 |-- fact(p) ** hp2)
hfact_duphfact_dup——事实是可复制的:与堆资源不同,fact(p)fact(p) 可以拆分成两份副本,因为它不拥有任何资源。
!p. fact(p) |-- fact(p) ** fact(p)
!p. fact(p) |-- fact(p) ** fact(p)
hsep_hfact_lefthsep_hfact_left——通过重新结合,把开头的事实从嵌套的 **** 中提取出来。
!p hp1 hp2. (fact(p) ** hp1) ** hp2 -|- fact(p) ** (hp1 ** hp2)
!p hp1 hp2. (fact(p) ** hp1) ** hp2 -|- fact(p) ** (hp1 ** hp2)
hsep_hfact_righthsep_hfact_right——从右操作数中提取事实。
!p hp1 hp2. hp1 ** (fact(p) ** hp2) -|- fact(p) ** (hp1 ** hp2)
!p hp1 hp2. hp1 ** (fact(p) ** hp2) -|- fact(p) ** (hp1 ** hp2)
hsep_hfact_commhsep_hfact_comm——事实可以与资源交换位置;这是 hsep_commhsep_comm 针对规范化器所处理形式的特例。
!hp p. hp ** fact(p) -|- fact(p) ** hp
!hp p. hp ** fact(p) -|- fact(p) ** hp
hpure_add_hfacthpure_add_hfact——如果一条断言已经蕴含 pp,就可以将这一信息显式表示为一个 factfact 合取项,同时保留原断言。推导出的范围条件或非空条件正是这样加入符号状态的。
!p hp. (hp |-- pure(p)) ==> (hp |-- fact(p) ** hp)
!p hp. (hp |-- pure(p)) ==> (hp |-- fact(p) ** hp)
hfact_false_elimhfact_false_elim——假事实自相矛盾,可以蕴含任何断言,因此一旦在分支中证明 fact(F)fact(F),就能立即卸除该分支的证明义务。
!hp. fact(F) |-- hp
!hp. fact(F) |-- hp
hprophprop 类型上的 existsexists 与 forallforall 是 hexistshexists 与 hforallhforall 的重载名;它们绑定一个任意类型 AA 的 HOL 变量,满足关系按逐点方式定义。引入与消去规则与通常的规则一致,这里着重说明量词如何与 **** 和 &&&& 交换。
hexists_introhexists_intro——提供一个例证。
!(x : A) hp hpA. (hp |-- hpA x) ==> (hp |-- (exists x : A. hpA x))
!(x : A) hp hpA. (hp |-- hpA x) ==> (hp |-- (exists x : A. hpA x))
hexists_elimhexists_elim——通过对任意例证证明目标,来消耗一个存在量词。
!hp hpA. (!x : A. hpA x |-- hp) ==> ((exists y : A. hpA y) |-- hp)
!hp hpA. (!x : A. hpA x |-- hp) ==> ((exists y : A. hpA y) |-- hp)
hexists_monotonehexists_monotone——将逐点蕴含提升为存在量化断言之间的蕴含。
!hpA hpA'. (!x:A. hpA x |-- hpA' x) ==> ((exists x:A. hpA x) |-- (exists x:A. hpA' x))
!hpA hpA'. (!x:A. hpA x |-- hpA' x) ==> ((exists x:A. hpA x) |-- (exists x:A. hpA' x))
hforall_introhforall_intro——通过证明每个实例来证明全称断言。
!hp hpA. (!x : A. hp |-- hpA x) ==> (hp |-- (forall x : A. hpA x))
!hp hpA. (!x : A. hp |-- hpA x) ==> (hp |-- (forall x : A. hpA x))
hforall_elimhforall_elim——把全称断言实例化到选定的 xx。
!hp hpA (x : A). (hpA x |-- hp) ==> ((forall x : A. hpA x) |-- hp)
!hp hpA (x : A). (hpA x |-- hp) ==> ((forall x : A. hpA x) |-- hp)
hforall_monotonehforall_monotone——将逐点蕴含提升为全称量化断言之间的蕴含。
!hpA hpA'. (!x:A. hpA x |-- hpA' x) ==> ((forall x:A. hpA x) |-- (forall x:A. hpA' x))
!hpA hpA'. (!x:A. hpA x |-- hpA' x) ==> ((forall x:A. hpA x) |-- (forall x:A. hpA' x))
存在量词与 **** 在两个方向上都可交换。下面的等式都是 -|--|-,因此证明既可以把存在量词向外移,使例证显式出现,也可以将其向内移,使链保持规范形式。
hsep_hexists_lefthsep_hexists_left——将存在量词移出左操作数。
!hpA hp. (exists x : A. hpA x) ** hp -|- exists x : A. (hpA x ** hp)
!hpA hp. (exists x : A. hpA x) ** hp -|- exists x : A. (hpA x ** hp)
hsep_hexists_righthsep_hexists_right——将存在量词移出右操作数。
!hp hpA. hp ** (exists x : A. hpA x) -|- exists x : A. (hp ** hpA x)
!hp hpA. hp ** (exists x : A. hpA x) -|- exists x : A. (hp ** hpA x)
全称量词则不同。对应的规则以 |--|-- 而非 -|--|- 表述,并且只有一个方向成立。
hsep_hforall_lefthsep_hforall_left——只在一个方向上成立:将 **** 分配到全称量词内部是健全的,但逆向无法推导,因为反方向会允许每个实例 xx 共享同一块堆片段 hphp,而 **** 不允许这样做。
!hpA hp. (forall x : A. hpA x) ** hp |-- forall x : A. (hpA x ** hp)
!hpA hp. (forall x : A. hpA x) ** hp |-- forall x : A. (hpA x ** hp)
hsep_hforall_righthsep_hforall_right——镜像版本,同样只有单向成立。
!hp hpA. hp ** (forall x : A. hpA x) |-- forall x : A. (hp ** hpA x)
!hp hpA. hp ** (forall x : A. hpA x) |-- forall x : A. (hp ** hpA x)
把 **** 换成 &&&& 后,这种不对称依然存在,但原因来自普通逻辑而非资源:&&&& 会复制状态,所以存在量词仍在两个方向上可交换,全称量词则不然。
hand_hexists_lefthand_hexists_left——存在量词在左侧与 &&&& 可交换。
!hpA hp. (exists x : A. hpA x) && hp -|- exists x : A. (hpA x && hp)
!hpA hp. (exists x : A. hpA x) && hp -|- exists x : A. (hpA x && hp)
hand_hexists_righthand_hexists_right——右侧亦然。
!hp hpA. hp && (exists x : A. hpA x) -|- exists x : A. (hp && hpA x)
!hp hpA. hp && (exists x : A. hpA x) -|- exists x : A. (hp && hpA x)
hand_hforall_lefthand_hforall_left——与 **** 一样,只有一个方向成立。
!hpA hp. (forall x : A. hpA x) && hp |-- forall x : A. (hpA x && hp)
!hpA hp. (forall x : A. hpA x) && hp |-- forall x : A. (hpA x && hp)
hand_hforall_righthand_hforall_right——镜像版本。
!hp hpA. hp && (forall x : A. hpA x) |-- forall x : A. (hp && hpA x)
!hp hpA. hp && (forall x : A. hpA x) |-- forall x : A. (hp && hpA x)
在证明块内部,可以通过返回 thmthm 的函数调用获取本页的规则。访问器名称由规则的注册名加上前缀 get_get_ 构成:
[[cst::proof]] { thm assoc = get_hsep_assoc(); // |- !hp1 hp2 hp3. (hp1 ** hp2) ** hp3 -|- hp1 ** (hp2 ** hp3) cst_set_symbolic_state(rewrite_rule(THM_LIST(assoc), cst_get_symbolic_state()));}
[[cst::proof]] { thm assoc = get_hsep_assoc(); // |- !hp1 hp2 hp3. (hp1 ** hp2) ** hp3 -|- hp1 ** (hp2 ** hp3) cst_set_symbolic_state(rewrite_rule(THM_LIST(assoc), cst_get_symbolic_state()));}
返回的定理经过完全量化;spec_rulespec_rule 可以将其实例化,match_mp_rulematch_mp_rule 则利用已有定理卸除 hentail_transhentail_trans 这类蕴含式规则的前提。
完整的访问器索引见内核对象与定理,其中按头文件顺序列出 proof_kernel.hproof_kernel.h 中的每条 get_*get_* 声明,并附其确切的 HOL 表述。其中标记为 @derived@derived 的访问器,对应的是内核由上述规则推导出的引理,而非核心规则集中的成员: hsep_hfalse_lefthsep_hfalse_left、hsep_hfact_commhsep_hfact_comm、hfact_hpure_righthfact_hpure_right、hsep_comm_left_parthsep_comm_left_part、 hentail_sym_lefthentail_sym_left、hsep_cancel_left_eqhsep_cancel_left_eq、hfact_elim_duphfact_elim_dup、hpure_add_hfacthpure_add_hfact、 hsep_achsep_ac 与 heq_symheq_sym。这一标记表示内核开发中的分层,与信任无关:无论是否标记为派生,访问器返回的都是已证明的定理。
没有 get_*get_* 访问器的规则,仍可按名字取得:
thm mono = get_theorem_by_name("monoidal_hsep");
thm mono = get_theorem_by_name("monoidal_hsep");
- 本页每一条规则都是已证明的定理,由连接词的定义与内存模型推导而来;其上的带类型内存层的每一条规则也是如此。
- 由于连接词都是定义,
****的结合律与交换律、empemp的单位元性质以及魔术棒的伴随都是模型的推论,并非假设。 |--|--是预序,以-|--|-为等式满足反对称性;-|--|-是hprophprop上真正的 HOL 等式,因此每条-|--|-规则同时也可以当作一条重写规则。(hprop, **, emp)(hprop, **, emp)构成交换幺半群;hsep_achsep_ac将这一事实组合为重写所需的形式,monoidal_hsepmonoidal_hsep则让hitersephitersep可以复用整套库。hsep_cancel_lefthsep_cancel_left是断言层面的框架规则;hsep_monotonehsep_monotone把它一次性推广到两个操作数。-*-*与-->-->通过各自的伴随来使用,而非通过定义来使用。pure(p)pure(p)只约束命题;fact(p)fact(p)还断言堆为空,可以复制,也是书写规约时所用的形式。- 存在量词与
****、&&&&以等式形式交换;全称量词只能单向分配。