数据类型转换功能需要很长时间才能证明

时间:2019-05-24 11:26:18

标签: isabelle formal-verification

Isabelle需要很多时间来证明(在我眼中)相当简单的数据类型转换函数的正确性。例如,我创建了表示数学表达式和布尔表达式的数据类型,以及一个简化了此类表达式的函数。

datatype 'a math_expr =
  Num int |
  Add "'a math_expr" "'a math_expr" |
  Mul "'a math_expr" "'a math_expr" |
  Sub "'a math_expr" "'a math_expr" |
  Div "'a math_expr" "'a math_expr"

datatype 'a expr =
  True |
  False |
  And "'a expr" "'a expr" |
  Or "'a expr" "'a expr" |
  Eq "'a math_expr" "'a math_expr" |
  Ne "'a math_expr" "'a math_expr" |
  Lt "'a math_expr" "'a math_expr" |
  Le "'a math_expr" "'a math_expr" |
  Gt "'a math_expr" "'a math_expr" |
  Ge "'a math_expr" "'a math_expr" |
  If "'a expr" "'a expr" "'a expr"

function (sequential) simplify :: "'a expr ⇒ 'a expr" where
"simplify (And a True) = a" |
"simplify (And True b) = b" |
"simplify (Or a True) = True" |
"simplify (Or True b) = True" |
"simplify e = e"
by pat_completeness auto
termination by lexicographic_order

在笔记本上,Isabelle需要花费很多时间来证明功能(签名和正文突出显示),甚至花费更多时间来证明其完整性(突出显示by pat_completeness auto)。所需的计算时间高度取决于expr数据类型的复杂性和simplify中的模式匹配规则的数量。数据类型中的构造函数越多,模式匹配规则越多,所需的时间就越长。

此行为的原因是什么?有没有办法使这种功能更容易证明?

1 个答案:

答案 0 :(得分:1)

sequential选项使function命令专门用于重叠方程,以使它们不再重叠。但是,这只是实际内部构造的预处理器,实际上支持重叠模式(前提是可以证明右侧对于重叠实例表示相同的HOL值,即它们是一致的)。此一致性证明表示为单个目标(如果使用auto选项,sequential本质上总是解决的,因为它足以证明它们不能重叠)。然而,消除歧义方程的数量在方方面有许多目标。因此,如果添加更多构造函数,则重叠的方程式将被拆分为更多的情况,这些情况将转化为二次数量的目标。

函数不递归时有两种解决方法:

对于非递归函数,建议将definition与右边的case表达式一起使用。然后,您可以使用simps_of_case中的HOL-Library.Simps_Case_Conv来获得简化规则。但是,您没有很好的区分大小写规则。

definition simplify :: "'a expr ⇒ 'a expr" where
  "simplify e = (case e of And a True => a | And True b => b | ... | _ => e)"

simps_of_case simplify_simps [simp]: simplify_def

如果要有很好的区分大小写定理,可以将函数定义拆分为几个帮助函数:

fun simplify_add :: "'a expr => 'a expr => 'a expr" where
  "simplify_add a True = a"
| "simplify_add True b = b"
| "simplify_add a b = Add a b"

fun simplify_or (* similarly *)

fun simplify :: "'a expr => 'a expr" where
  "simplify (And a b) = simplify_and a b"
| "simplify (Or a b) = simplify_or a b"
| "simplify e = e"

对于递归函数,可以通过将一些大小写区别移到右侧来避免爆炸。例如:

fun simplify :: "'a expr ⇒ 'a expr" where
  "simplify (And a b) = (case b of True => a | _ => case a of True => b | _ => And a b)"
| ...

再次,这使等式不重叠后大大减少了等式的数量,但是不再有相同的区分大小写规则(和归纳规则)。