定义" arg max"像有限集上的函数,证明它的一些属性,并避免通过列表绕道而行

时间:2013-05-22 22:51:06

标签: list function set fold isabelle

我正在使用向量的自定义实现作为函数,其域是自然数的有限“索引集”,并且其图像是某种类型,可以在其上定义最大值,通常为real。例如。我可以使用vv 1 = 2.7生成二维向量v 3 = 4.2

在这些向量上,我想定义一个类似于运算符的“arg max”,它告诉我上面3示例中的最大分量v的索引。我说的是“索引”,因为“arg max”like运算符还会接受一个打破平局功能,以应用于具有值的组件。 (背景为bids in auctions。)

我知道有限集上的Max是使用fold1定义的(我还不知道它是如何工作的)。我尝试了这个,这本身就被接受了,但后来对我想做的其他事情没有用处:

fun arg_max_tb :: "index_set ⇒ tie_breaker ⇒ (real vector) ⇒ nat"
where "arg_max_tb N t v = fold1
  (λ x y . if (v x > v y) then x      (* component values differ *)
   else if (v x = v y ∧ t x y) then x (* tie-breaking needed *)
   else y) N"

请注意,此外我想证明我的“arg max”运算符的某些属性,这可能需要归纳。我知道有限集的归纳有finite_ne_induct规则。好的,但我也希望能够以这样的方式定义我的运算符,以便可以对其进行评估(例如,在尝试使用具体的有限集时),但是评估

value "arg_max_tb {1::nat} (op >) (nth [27::real, 42])"
带有预期回报值1

给出了以下错误:

Wellsortedness error
(in code equation arg_max_tb ?n ?t ?v \equiv
                  fold1 (\lambda x y. if ord_real_inst.less_real (?v y) (?v x) then ...) ?n):
Type nat not of sort enum
 No type arity nat :: enum

因此我采用将有限集转换为列表。在列表中,我已经能够定义运算符,并通过使用list_nonempty_induct的归纳来证明它的一些属性(如果感兴趣的话可以共享代码)。

基于工作清单的定义如下:

fun arg_max_l_tb :: "(nat list) ⇒ tie_breaker ⇒ (real vector) ⇒ nat"
where "arg_max_l_tb [] t v = 0"
      (* in practice we will only call the function
         with lists of at least one element *)
    | "arg_max_l_tb [x] t v = x"
    | "arg_max_l_tb (x # xs) t v =
      (let y = arg_max_l_tb xs t v in
        if (v x > v y) then x              (* component values differ *)
        else if (v x = v y ∧ t x y) then x (* tie-breaking needed *)
        else y)"

fun arg_max_tb :: "index_set ⇒ tie_breaker ⇒ (real vector) ⇒ nat"
where "arg_max_tb N t v = arg_max_l_tb (sorted_list_of_set N) t v"

我没有成功直接在有限集的构造函数上定义函数。以下不起作用:

fun arg_max_tb :: "index_set ⇒ tie_breaker ⇒ (real vector) ⇒ participant"
where "arg_max_tb {} t b = 0"
    | "arg_max_tb {x} t b = x"
    | "arg_max_tb (insert x S) t b =
      (let y = arg_max_tb S t b in
        if (b x > b y) then x
        else if (b x = b y ∧ t x y) then x
        else y)"

它给我错误信息

Malformed definition:
Non-constructor pattern not allowed in sequential mode.
⋀t b. arg_max_tb {} t b = 0

这可能是因为列表构造函数定义为datatype,而有限集仅定义为inductive方案吗?

无论如何 - 你知道在有限集上定义这个函数的方法吗?要么通过直接写下来,要么通过一些类似折叠的效用函数?

2 个答案:

答案 0 :(得分:4)

对有限集进行折叠要求结果与访问集合元素的顺序无关,因为集合是无序的。因此,大多数关于fold1 f的引理假设折叠操作f是左对齐的,即f a (f b x) = f b (f a x)对所有abx

您在第一个定义中提供给fold1的函数不满足此要求,因为打破平局函数是一个任意谓词。例如,采取打破平局功能%v v'. True。因此,如果你想坚持这个定义,你必须首先找到打破平局的充分条件,并通过你所有的引理来解决这个假设。

基于元素排序列表的工作解决方案避免了这种交换性问题。您对{}{x}insert x S上的模式匹配的最后建议不起作用有两个原因。首先,fun只能在数据类型构造函数上进行模式匹配,因此您必须使用function;这解释了错误消息。但是,你必须证明方程式不重叠,因此你会再次遇到相同的交换问题。此外,您将无法证明终止,因为S可能是无限的。

代码生成的良好排序错误来自fold1的设置。 fold1 f A定义为THE x. fold1Set f A x fold1Set f A x,其中xfA在某些元素顺序上折叠x的结果。为了检查所有结果是否相同,生成的代码天真地测试fold1Set f A x的所有可能值是否x成立。如果它确实只找到一个这样的值,那么它返回该值。否则,它会引发异常。在您的情况下,nat是一个索引,即类型为nat的索引,其中包含无限多的值。因此,无法进行详尽的测试。从技术上讲,这转换为enum不是类型类fold1的实例。

通常,您可以根据{{1}}为您定义的所有内容推导出专门的代码方程式。请参阅有关程序优化的代码生成器教程。

答案 1 :(得分:3)

这个问题确实包含多个问题。

在有限集上定义函数

fold / foldl1

通常的递归组合是Finite_Set.fold(或fold1)。但是,为了能够证明fold f z S的任何内容,结果必须独立于f的元素S的顺序。

如果f具有关联性和可交换性,您可以使用Finite_Set.ab_semigroup_mult.fold1_insertFinite_Set.fold1_singleton获取fold1 f S的简单规则,并且您应该可以使用finite_ne_induct作为你的归纳规则。

请注意,如果f是线性顺序,则您给fold1的函数(我称之为t)只是可交换的:

fun arg_max_tb :: "index_set ⇒ tie_breaker ⇒ (real vector) ⇒ nat"
where "arg_max_tb N t v = fold1
  (λ x y . if (v x > v y) then x      (* component values differ *)
   else if (v x = v y ∧ t x y) then x (* tie-breaking needed *)
   else y) N"

这不包含在fold1上​​的现有引理中,因此您需要证明Finite_Set.ab_semigroup_mult.fold1_insert的通用变体或插入额外的平局,例如

   else if (v x = v y ∧ ~t x y ∧ ~t y x ∧ x < y) then x

如果t是线性订单,您将能够从simp规则中删除这个额外的决胜局。请注意,这个额外的决胜局基本上是您使用sorted_list_of_set获得的。

THE / SOME

您的arg_max_tb选择具有特定属性的列表中的一个元素。这也可以使用构造THE x. P xSOME x. P x(选择运算符)直接定义。前者选择满足属性P的唯一元素(如果不存在唯一元素,结果未定义),后者选择满足属性P的某个元素(如果不存在这样的元素,则结果是未定义的)。两者都适用于无限列表。

如果您不需要可执行代码,通常会更好。

获取可执行功能

由递归定义的函数(即primrecfunfunction)在默认情况下是可执行的(如果其定义中使用的所有函数也是可执行的)。 THESOME通常只能针对可枚举域执行(这是您从value获得的错误消息 - nat不可枚举,因为它不是有限的)。

但是,您始终可以为代码生成器提供函数的替代定义。请参阅函数定义教程,特别是有关细化的部分。

如果您更喜欢带有选择运算符的公式进行证明,而且还希望您的函数可执行,最简单的方法可能是证明arg_max_tb通过选择和sorted_list_of_set的定义是等效的。然后,您可以使用[code_unfold]谓词将选项替换为sorted_list_of_set

的(可执行)定义