Ltac 用于操作数的确定性重写/排序

问题描述 投票:0回答:1

我想创建 Coq 策略来解决各种等式子目标,这些子目标可以通过混合使用重写规则(例如运算符的结合性和交换性)来解决。

虽然这不是我的最终目标,但一个简单的例子是解决和等式,例如例如,表明

a + b + c + d = a + (d + c) + b

我知道我可以使用以下规则来做到这一点:

Require Import FMapList OrderedTypeEx List Rdefinitions Raxioms RIneq.
Open Scope R.

Ltac sort_sums_step :=
  let rec solve_sub_equality sub_equality :=
    lazymatch sub_equality with
    | ?a + ?c = ?b + ?c => solve_sub_equality (a = b)
    | ?a + ?c = ?b + ?d => rewrite (Rplus_comm (b) (d)); repeat rewrite <- (Rplus_assoc _ _ _)
    | _ => fail
    end
  in
  lazymatch goal with
  | |- ?a => solve_sub_equality a
  end.

Ltac solve_sum_equality :=
  repeat rewrite <- (Rplus_assoc _ _ _); repeat sort_sums_step; reflexivity.

Theorem TestEasyTheorem (a b c d:R) : a + b + c + d = a + (d + c) + b.
Proof.
  solve_sum_equality.
Qed.

这些策略的“问题”在于,它们只是试图盲目地交换术语,虽然这对于简单的求和来说效果很好,但如果我们混合其他运算符,如乘法、除法等,随机尝试所有的交换的复杂性将会激增,并且该策略将需要永远计算。

因此,我正在尝试编写一个“智能”策略,该策略决定操作数的特定顺序(理想情况下只是基于目标本身构建,而不是明确提供给策略),然后基于等式两边进行排序以此排序为独特的规范形式(这样仅仅

reflexity
就可以解决平等目标)。

这在 Coq 中可能吗?我应该如何实现?



注意我的尝试:

我设法制定了一种策略,在给定操作数的排序的情况下,构建总和中操作数的索引列表(稍后可能用于对它们重新排序):


Ltac reverse_indices_of_left_sum_in_list l :=
  let rec id_index id lst :=
    lazymatch lst with
    | id::?q => O
    | ?a::?q => let idx1 := (id_index id q) in (constr:(S idx1))
    | _ => fail "1"
    end
  in
  let rec build_list sum_expr :=
    lazymatch sum_expr with
    | ?a + ?b => let q := (build_list a) in let idxb := (id_index b l) in (constr:(cons idxb q))
    | ?a => let idx := (id_index a l) in (constr:(cons idx nil))
    end
  in
  lazymatch goal with
  | |- ?a = ?b => let test := build_list a in pose (foo := test)
  | |- _ => fail "2"
  end.


Theorem TestEasyTheorem2 (a b c d:R) : (a + d + c + b)%R = (a + b + c + d)%R.
Proof.
  reverse_indices_of_left_sum_in_list (a::b::c::d::nil).
  (* Defines: foo := 1%nat :: 2%nat :: 3%nat :: 0%nat :: nil : list nat *)
Admitted.

但是,当我尝试使用索引对总和进行排序时,我的尝试都没有成功。例如:

Ltac sort_sums_step l :=
  let rec id_index id lst :=
    lazymatch lst with
    | id::?q => O
    | ?a::?q => let idx1 := (id_index id q) in (constr:(S idx1))
    | _ => fail "Identifier not found: " id
    end
  in
  let rec sort_sums sum_expr :=
    lazymatch sum_expr with
    | ?a + ?b + ?c => sort_sums (a + b) || (
      let idx_cmp := (compare (id_index b l) (id_index c l)) in
      match (eval compute in idx_cmp) with
      | Lt => fail "All good"
      | Eq => fail "All good"
      | Gt => rewrite (Rplus_assoc a b c); rewrite (Rplus_comm b c); rewrite <- (Rplus_assoc a c b)
      end)
    | ?b + ?c => let idx_cmp := compare (id_index b l) (id_index c l) in
      match (eval compute in idx_cmp) with
      | Lt => fail "All good"
      | Eq => fail "All good"
      | Gt => rewrite (Rplus_comm b c)
      end
    | ?a => fail "All good"
    end
  in
  lazymatch goal with
  | |- ?a = ?b => sort_sums a || sort_sums b
  | |- _ => fail "2"
  end.

Theorem TestEasyTheorem2 (a b c d:R) : (a + d + c + b)%R = (a + b + c + d)%R.
Proof.
  sort_sums_step (a::b::c::d::nil).

失败:

Variable id_index should be bound to a term but is bound to a tacvalue.

当我尝试从目标本身构建列表时,我也遇到类似的错误:

Ltac build_list :=
  let rec add_to_list id lst :=
    lazymatch lst with
    | id::?q => constr:(cons id q)
    | ?a::?q => constr:(cons a (add_to_list id q))
    | @nil => constr:(cons id nil)
    end
  in
  let rec build_id_list sum_expr lst :=
    lazymatch sum_expr with
    | ?a + ?b =>
      let lst_with_a := eval compute in (build_id_list a lst) in
      let lst_with_b := eval compute in (build_id_list b lst_with_a) in
      lst_with_b
    | ?c =>
      eval compute in (add_to_list c lst)
    end
  in
  lazymatch goal with
  | |- ?a = ?b => let bar := build_id_list a nil in let baz := (eval compute in bar) in pose (foo := baz)
  | |- _ => fail "2"
  end.

Theorem TestEasyTheorem3 (a b c:R) : a + b + c = a + c + b.
Proof.
  build_list.

给出:

Variable build_id_list should be bound to a term but is bound to a tacvalue.
coq coq-tactic
1个回答
0
投票

感谢 Feryll 的指点,我设法修复了问题中的两个错误策略。

我遗漏的主要内容是,不可能混合战术和术语,并且需要使用诸如

constr:(...)
之类的东西来在战术中使用(构造)术语。同样,
eval compute in ...
仅对构造术语有用,对策略调用(直接评估)无效。

固定代码:(看起来不太好,可能会受益于问题评论的建议,但至少它有效)

Require Import Init.Datatypes FMapList Init.Nat OrderedTypeEx List Rdefinitions Raxioms RIneq.
Open Scope R.

Ltac sort_sums_step l :=
  let rec id_index id lst :=
    lazymatch lst with
    | id::?q => O
    | ?a::?q => let idx1 := id_index id q in (constr:(S idx1))
    | _ => fail "Identifier not found: " id
    end
  in
  let rec sort_sums sum_expr :=
    lazymatch sum_expr with
    | ?a + ?b + ?c => sort_sums (a + b) || (
      let idx_b := id_index b l in
      let idx_c := id_index c l in
      let idx_cmp := constr:(compare idx_b idx_c) in
      match (eval compute in idx_cmp) with
      | Lt => fail "All good"
      | Eq => fail "All good"
      | Gt => rewrite (Rplus_assoc a b c); rewrite (Rplus_comm b c); rewrite <- (Rplus_assoc a c b)
      end)
    | ?b + ?c =>
      let idx_b := id_index b l in
      let idx_c := id_index c l in
      let idx_cmp := constr:(compare idx_b idx_c) in
      (match (eval compute in idx_cmp) with
      | Lt => fail "All good"
      | Eq => fail "All good"
      | Gt => rewrite (Rplus_comm b c)
      end)
    | ?a => fail "All good"
    end
  in
  lazymatch goal with
  | |- ?a = ?b => sort_sums a || sort_sums b
  | |- _ => fail "2"
  end.

Ltac build_list :=
  let rec add_to_list id lst :=
    lazymatch lst with
    | id::?q => constr:(cons id q)
    | ?a::?q => let id_q := add_to_list id q in constr:(cons a id_q)
    | nil => constr:(cons id nil)
    end
  in
  let rec build_id_list sum_expr lst :=
    lazymatch sum_expr with
    | ?a + ?b =>
      let lst_with_a := (build_id_list a lst) in
      let lst_with_b := (build_id_list b lst_with_a) in
      lst_with_b
    | ?c =>
      (add_to_list c lst)
    end
  in
  lazymatch goal with
  | |- ?a = ?b => build_id_list a (nil: list R)
  | |- _ => fail "2"
  end.


Ltac solve_sum_equality :=
  repeat rewrite <- (Rplus_assoc _ _ _);
  let operands_list := build_list in
  repeat sort_sums_step operands_list;
  reflexivity.

Theorem TestEasyTheorem (a b c d:R) : a + b + c + d = a + (d + c) + b.
Proof.
  solve_sum_equality.
Qed.
© www.soinside.com 2019 - 2024. All rights reserved.