如何根据Coq中的规范构建字节列表

如何根据Coq中的规范构建字节列表,coq,proof,coq-tactic,formal-verification,Coq,Proof,Coq Tactic,Formal Verification,我正试图根据我在上下文中的规范构建一个字节列表(该规范是基于nth\u error函数的联合定义的,这些函数确定索引中的字节值(或一系列索引中的字节值)。例如,请参见下面的目标和上下文 a_len, b_len : nat a : seq.seq byte b : seq.seq byte H : Datatypes.length a = a_len /\ (* the length of list I'd like to build *) Datatypes.len

我正试图根据我在上下文中的规范构建一个字节列表(该规范是基于
nth\u error
函数的联合定义的,这些函数确定索引中的字节值(或一系列索引中的字节值)。例如,请参见下面的目标和上下文

a_len, b_len : nat
a : seq.seq byte
b : seq.seq byte
H : Datatypes.length a = a_len /\           (* the length of list I'd like to build *)
    Datatypes.length b = b_len /\           (* the length of another list concatenated at the end *)
    is_true (b_len + 4 <= a_len) /\         (* added after edit *)
    is_true (1 < b_len) /\                  (* added after edit *)
    nth_error a 0 = x00 /\                         (* the value of first byte is zero *)
    (forall i : nat,                               (* then we have a bunch of x01's *)
     is_true (0 < i) /\ is_true (i < a_len - b_len - 1) ->
     nth_error a i = Some x01) /\
    nth_error a (a_len - b_len - 1) = Some x00 /\  (* next byte is zero *)
    (forall j : nat,                               (* which ends with a list that is equal to b *)
     is_true (0 <= j) /\ is_true (j < b_len) ->
     nth_error a (a_len - b_len + j) = nth_error b j)
______________________________________(1/1)
a = [x00] ++ repeat x01 (a_len - b_len - 2) ++ [x00] ++ b
定义一些引理如下:

Lemma two_concats_equality1: 
    forall (lb1 lb1' lb2 lb2': list byte), 
           (lb1 ++ lb2) = (lb1' ++ lb2') /\ length lb1 = length lb1' -> lb1 = lb1' /\ lb2 = lb2'.
为了建立字节列表,
a
,从零开始使用
n次错误分割
,使用
two-concats\u equality1
携带信息,并多次执行此操作直到结束。但还没有成功。我甚至无法证明
two-concats\u equality1
引理(目前假设为真)。 我在字节重复的开头卡住了,
n\u错误a I=Some x01

我想知道这是否是证明这个目标的正确方法。如果不是,请告诉我你会怎么做

如有任何意见,将不胜感激

编辑:

正如@Yves指出的,我正在进行以下编辑:

  • 在上下文中修复键入错误。没有变量
    n
    ,它应该是
    a_len
  • 我在规范中又添加了两个约束,它们描述了
    a_len
    b_len
    的关系,避免了前面提到的错误陈述
  • 下面,您可以找到导入库的最小可复制示例

  • 来自mathcomp的
    要求导入所有\u ssreflect ssrnat。
    从Coq需要导入Lia。
    需要导入Init.Byte Coq.Lists.List。
    导入列表符号。
    引理根据规范构建:
    forall(a_len b_len:nat)(a b:list字节),
    Datatypes.length a=a_len/\
    Datatypes.length b=b_len/\
    a_len>=b_len+4/\
    b_len>=2/\
    n_错误a 0=某些x00/\
    (对于所有i:nat,(0
    n_错误a i=某些x01)/\
    n次误差a(a_len-b_len-1)=一些x00/\
    (对于所有j:nat,(0
    第n个错误a(a_len-b_len+j)=第n个错误bj)
    ->
    a=[x00]++重复x01(a_len-b_len-2)++[x00]++b。
    证明。
    承认。
    
    问题由原始海报编辑,更改了声明。此消息的底部是原始问题的答案

    为了解决这个问题,你需要一个在库中还不存在的定理,我在这里包括:

    Lemma eq_from_nth_error {A : Type} (l1 l2 : list A) :
      (forall i, nth_error l1 i = nth_error l2 i) -> l1 = l2.
    Proof.
    elim: l1 l2 => [ | a l1 IH] [ | a' l2] //.
        by move=> abs; have := (abs 0).
      by move=> abs; have := (abs 0).
    move=> cmp; congr (_ :: _).
      by have := (cmp 0) => /= [[]].
    apply: IH=> i; exact (cmp i.+1).
    Qed.
    
    有了这个定理,你可以通过研究所有可能的指数
    i
    来证明等式,这些指数是你作为
    n次误差
    的参数给出的。所以,你介绍你的假设,然后你应用这个定理,你介绍
    i
    ,然后你看
    i
    的5种可能的情况:

  • 如果
    i=0
  • 如果
    0
  • 如果
    i=a_len-b_len-1
  • 如果
    a_len-b_len-1
  • 如果
    a\u len
    List.nth_错误[::x00]i=Some x01)。
    按移动=>i[igt0 ilt0]。
    断言(cnd2:forall j:nat,
    0
    List.nth_错误[::x00](1-0+j)=List.nth_错误[::]j)。
    按移动=>j[jge0 glt0]。
    推广(abs10(x00::nil)nil(conj-erefl)
    (conj erefl(conj erefl(conj cnd1)(conj erefl cnd2())))。
    通过重写/=。
    Qed。
    

    此脚本混合了数学组件样式和香草coq样式,这很糟糕。

    请提供一个最小的可复制示例,特别是指出您加载的库。您的目标包含一个变量
    n
    ,如果是
    i
    ?谢谢,@Yves。我将用以下内容编辑我的问题:1)最小可重复性示例;2) 修复应为
    a_len
    n
    的打字错误;3)通过添加
    a_len
    b_len
    的缺失关系,修复您在下面的回答中指出的错误陈述问题。谢谢!我解决了这个问题。但是关于使用
    nth*
    ,我必须使用
    nth\u error
    。你认为它是否仍然可以用第n个错误来证明吗?我刚刚读了编辑过的问题。这使得答案过时了。我将尝试编辑,以便新读者不会太困惑。请注意,
    unfold在HRep中是正确的。
    是无用的,我建议删除这一行。另外,我认为作为第一个命令的
    rewrite-?(minusE,plusE)
    是笨拙的,它可能不会删除您想要删除的所有实例。因此,我们同意第二种情况是
    0
    。您几乎完成了,并且出现了
    HPrem:n\u错误a i=Some“001”%byte
    。用这个假设重写,然后使用引理
    nth\u error\u app2
    ,它的算术条件应该用
    siml来求解;lia
    。然后使用引理
    n\u error\u app1
    。对于它的算术条件,你需要一个关于重复长度的引理,这个引理被称为
    repeat\u length
    。对于
    nth\u error\u app1
    的算术条件,在用
    repeat\u length
    重写之后,您仍然需要修改假设
    i_lt_border
    ,以便它使用算术运算符
    lia
    knows,而不是ssreflect变量。这可以通过
    move/ltP:i_lt_border=>i_lt_border.
    然后
    siml;lia
    完成此算术条件。
    From mathcomp Require Import all_ssreflect ssrnat.
    From Coq Require Import Lia.
    Require Import Init.Byte Coq.Lists.List.
    Import ListNotations. 
    
    Lemma build_from_spec : 
        forall (a_len b_len : nat) (a b : list byte),
        Datatypes.length a = a_len /\
        Datatypes.length b = b_len /\
        a_len >= b_len + 4 /\
        b_len >= 2 /\
        nth_error a 0 = Some x00 /\
        (forall i : nat, (0 < i) /\ (i < a_len - b_len - 1) ->
        nth_error a i = Some x01) /\
        nth_error a (a_len - b_len - 1) = Some x00 /\
        (forall j : nat, (0 <= j) /\ (j < b_len) ->
        nth_error a (a_len - b_len + j) = nth_error b j) 
        ->
        a = [x00] ++ repeat x01 (a_len - b_len - 2) ++ [x00] ++ b.
    Proof.
    Admitted.
    
    Lemma eq_from_nth_error {A : Type} (l1 l2 : list A) :
      (forall i, nth_error l1 i = nth_error l2 i) -> l1 = l2.
    Proof.
    elim: l1 l2 => [ | a l1 IH] [ | a' l2] //.
        by move=> abs; have := (abs 0).
      by move=> abs; have := (abs 0).
    move=> cmp; congr (_ :: _).
      by have := (cmp 0) => /= [[]].
    apply: IH=> i; exact (cmp i.+1).
    Qed.
    
    have [/eqP i_is_0 | i_is_not_0] := boolP(i == 0).
    
    have [i_lt_border | is_larger] := boolP(i < a_len - b_len - 1).
    
    Lemma arithmetic_difficulty i j : i + 3 < j - 2 -> i <= j.
    Proof.
    Fail lia.
    rewrite -?(minusE, plusE).
    move/ltP => i3j2.
    apply/leP.
    lia.
    Qed.
    
    From mathcomp Require Import all_ssreflect.
    
    Set Implicit Arguments.
    Unset Strict Implicit.
    Unset Printing Implicit Defensive.
    
    Section some_context.
    
    Definition byte := nat.
    Variables x00 x01 : byte.
    
    Lemma Dan_problem : (forall (a_len b_len : nat)
    (a b : seq byte)
    (H : Datatypes.length a = a_len /\
        Datatypes.length b = b_len /\
        List.nth_error a 0 = Some x00 /\
        (forall i : nat,
        is_true (0 < i) /\ is_true (i < a_len - b_len - 1) ->
          List.nth_error a i = Some x01) /\
        List.nth_error a (a_len - b_len - 1) = Some x00 /\
        (forall j : nat,
          is_true (0 <= j) /\ is_true (j < b_len) ->
          List.nth_error a (a_len - b_len + j) = List.nth_error b j)),
    a = [:: x00] ++ List.repeat x01 (a_len - b_len - 2) ++ [:: x00] ++ b) ->
       False.
    Proof.
    intros abs.
    assert (cnd1 : forall i,  0 < i /\ i < 1 - 0 -1 ->
      List.nth_error [:: x00] i = Some x01).
      by move=> i [igt0 ilt0].
    assert (cnd2 : forall j : nat,
              0 <= j /\ j < 0 ->
             List.nth_error [:: x00] (1 - 0 + j) = List.nth_error [::] j).
      by move=> j [jge0 glt0].
    generalize (abs 1 0 (x00::nil) nil (conj erefl
        (conj erefl (conj erefl (conj cnd1 (conj erefl cnd2)))))).
    by rewrite /=.
    Qed.