如何在coq中合并两棵树?

时间:2012-12-01 14:35:24

标签: coq

这里提到的树具有在所有子树(包括整个树)上的属性,根的内容具有最高优先级;但是没有在兄弟节点上指定顺序
树的定义如下:

Inductive tree : Set :=
| nil : tree
| cons : tree->nat->tree->tree.

我想使用coq合并两棵树。假设两个树是(cons l1 n1 r1)和(cons l2 n2 r2),如果n1&lt; = n2然后我合并l1和r1作为子树并创建新树((merge l1 r1)n1(cons l2 n2 r2) ))。当n2 <= n1时,可以使用类似的处理 以下是合并的定义:

Fixpoint merge (t1 t2 : tree) : tree.
  destruct t1 as [ | l1 n1 r1].
  apply t2.
  destruct t2 as [ | l2 n2 r2].
    apply (cons l1 n1 r1).
    destruct (le_le_dec n1 n2).
      apply (cons (merge l1 r1) n1 (cons l2 n2 r2)).
      apply (cons (cons l1 n1 r1) n2 (merge l2 r2)).
Defined.

问题是coq认为上面的定义是不正确的。但实际上合并功能最终会终止。

我知道coq需要减少修复点的参数。但是如何用两个递减的参数来处理函数呢?

引理le_le_dec仅用于案例分析:

Lemma le_le_dec : forall x y, {x <= y}+{y <= x}.
Proof.
  intros x y.
  destruct (nat_delta x y) as [xy | yx].
    destruct xy as [n e]. left. apply le_delta. exists n. assumption.
    destruct yx as [n e]. right. apply le_delta. exists n. assumption.
Qed.

引理le_delta和nat_delta如下:

Lemma le_delta: forall n m, n <= m <-> exists x, (x + n = m).
Proof.
  intros n m.
  split.
  intros e. induction e as [ |m les IHe].
    exists 0. simpl. reflexivity.
    destruct IHe as [x  e]. exists (S x). simpl. rewrite e. reflexivity.
  intros e. destruct e as [x e]. revert e. revert m.
  induction x as [ | x IHx].
    intros m e. simpl in e. rewrite e. apply le_n.
    intros m e. destruct m as [ | m].
      discriminate e.
      apply (le_S n m).
      apply (IHx m).
      inversion e. reflexivity.
Qed.

Lemma nat_delta : forall x y, {n | n+x=y} + {n | n+y=x}.
Proof.
  intros x y. induction x as [ | x IHx].
    left. exists y. simpl. rewrite <- (plus_n_O y). reflexivity.
    destruct IHx as [xy | yx].
    destruct xy as [n e]. destruct n as [ | n].
      right. exists (S 0). rewrite <- e. simpl. reflexivity.
      left. exists n. rewrite <- plus_n_Sm. rewrite <- e. simpl. reflexivity.
    destruct yx as [n e].    
    right. exists (S n). simpl. rewrite e. reflexivity.
Qed.

修复点的错误消息是:

Error:
Recursive definition of merge is ill-formed.
In environment
merge : tree -> tree -> tree
t1 : tree
t2 : tree
l1 : tree
n1 : nat
r1 : tree
l2 : tree
n2 : nat
r2 : tree
l : n2 <= n1
Recursive call to merge has principal argument equal to "l2" instead of
one of the following variables: "l1" "r1".
Recursive definition is:
"fun t1 t2 : tree =>
 match t1 with
| nil => t2
| cons l1 n1 r1 =>
     match t2 with
     | nil => cons l1 n1 r1
     | cons l2 n2 r2 =>
         let s := le_le_dec n1 n2 in
         if s
         then cons (merge l1 r1) n1 (cons l2 n2 r2)
         else cons (cons l1 n1 r1) n2 (merge l2 r2)
     end
 end".

2 个答案:

答案 0 :(得分:2)

您必须在任何递归调用中使用相同的单独递减参数。试试这个:

Fixpoint merge (t1 t2 : tree) : tree.
  destruct t1 as [ | l1 n1 r1].
  apply t2.
  destruct t2 as [ | l2 n2 r2].
    apply (cons l1 n1 r1).
    destruct (le_le_dec n1 n2).
      apply (cons (cons l2 n2 r2) n1 (merge l1 r1)).
      apply (cons (merge l1 r1) n2 (cons l2 n1 r2)).
Defined.

我不确定这种程序的属性是否会被保留,但如果您不确定是否可以尝试证明它们的存在。

如果您只是编写它而不是证明您的函数存在,那么您可以使用Function代替Fixpoint来证明您的函数在不改变其结构的情况下终止。

此外,我在尝试提取le_le_dec时出错。我认为这是因为le_le_dec在逻辑方面更多。为什么不将n1n2与返回bool的函数进行比较,并对结果进行案例分析?

你也可以试试这个:

Fixpoint meas (t1: tree): nat :=
  match t1 with
  | nil => O
  | cons t2 _ t3 => S ((meas t2) + (meas t3))
  end.

Fixpoint less_eq (n1 n2: nat): bool :=
  match n1, n2 with
  | O, O => true
  | O, S _ => true
  | S _, O => false
  | S n3, S n4 => less_eq n3 n4
  end.

Program Fixpoint merge (t1 t2: tree) {measure ((meas t1) + (meas t2))}: tree :=
  match t1 with
  | nil => t2
  | cons l1 n1 r1 =>
    match t2 with
    | nil => cons l1 n1 r1
    | cons l2 n2 r2 =>
      match less_eq n1 n2 with
      | false => cons (cons l1 n1 r1) n2 (merge l2 r2)
      | true => cons (merge l1 r1) n1 (cons l2 n2 r2)
      end
    end
  end.

然后你需要输入Next Obligation.,并证明一些东西。

答案 1 :(得分:0)

您可能需要考虑将第一个树中的元素逐个插入到第二个树中。因此,您可以使用两个递归函数合并两个树。