坚持关于正则表达式的简单证明

问题描述 投票:4回答:3

我正在尝试使用Coq在正则表达式(RE)上形式化一些属性。但是,我有一些麻烦要证明一个相当简单的财产:

对于所有字符串s,如果s的语言为(epsilon)* RE,则s =“”,其中epsilon和*表示空字符串RE和Kleene星操作。

这似乎是归纳/反演策略的明显应用,但我无法使其发挥作用。

带有问题的引理的最小工作代码在以下gist中。关于我应该如何进行的任何提示将不胜感激。

编辑:

我的一次尝试是这样的:

Lemma star_lemma : forall s, s <<- (#1 ^*) -> s = "".
Proof.  
  intros s H.
  inverts* H.
  inverts* H2.
  inverts* H1.
  inverts* H1.
  inverts* H2.
  simpl in *.
  -- stuck here

这让我有以下目标:

s' : string
H4 : s' <<- (#1 ^*)
============================
s' = ""

至少在我看来,使用感应会完成证明,因为我可以在感应假设中使用H4来完成证明,但是当我开始使用证据时

induction H

代替

inverts* H

我得到了一些(至少对我而言)毫无意义的目标。在Idris / Agda中,这样的证明只是通过模式匹配和s << - (#1 ^ *)结构的递归。我的观点是如何在Coq中进行这样的递归。

coq
3个回答
3
投票

这是原始问题的一种可能的解决方案:

Lemma star_lemma : forall s,
    s <<- (#1 ^*) -> s = "".
Proof.
  refine (fix star_lemma s prf {struct prf} : s = "" := _).
  inversion_clear prf; subst.
  inversion_clear H; subst.
  - now inversion H0.
  - inversion_clear H0; subst. inversion_clear H; subst.
    rewrite (star_lemma s' H1).
    reflexivity.
Qed.

主要思想是在上下文中引入一个类似于典型Idris证明中的递归调用的术语。使用rememberdependent induction的方法不能很好地工作(没有修改in_regex),因为它们引入了不可能满足方程式作为归纳假设的前提。

注意:检查此引理可能需要一段时间(在Coq 8.5pl3下我的机器上大约40秒)。我认为这是因为inversion战术倾向于产生大的证明条款。


3
投票

这个问题困扰了我一个星期,我终于找到了一个我觉得优雅的解决方案。

我已经读过,当感应原理不符合您的需求时,您可以编写并证明另一个,更适合您的问题。这就是我在这种情况下所做的。我们想要的是使用this answer中给出的更自然的定义时获得的那个。通过这样做,我们可以保持相同的定义(例如,如果更改它意味着太多的更改),并且更容易理解它。

这是归纳原理的证明(我使用一个部分来精确指定隐式参数,因为否则我会观察到它们的奇怪行为,但这里根本没有必要使用section机制)。

Section induction_principle.

Context (P : string -> regex -> Prop)
  (H_InEps : P "" #1)
  (H_InChr : forall c, P (String c "") ($ c))
  (H_InCat : forall {e e' s s' s1}, s <<- e -> P s e -> s' <<- e' ->
    P s' e' -> s1 = s ++ s' -> P s1 (e @ e'))
  (H_InLeft : forall {s e e'}, s <<- e -> P s e -> P s (e :+: e'))
  (H_InRight : forall {s' e e'}, s' <<- e' -> P s' e' -> P s' (e :+: e'))
  (H_InStar_Eps : forall e, P "" (e ^*))
  (H_InStar_Cat : forall {s1 s2 e}, s1 <<- e -> s2 <<- (e ^*) ->
    P s1 e -> P s2 (e ^*) -> P (s1++s2) (e ^*)).

Arguments H_InCat {_ _ _ _ _} _ _ _ _ _.
Arguments H_InLeft {_ _ _} _ _.
Arguments H_InRight {_ _ _} _ _.
Arguments H_InStar_Cat {_ _ _} _ _ _ _.

Definition in_regex_ind2 : forall (s : string) (r : regex), s <<- r -> P s r.
Proof.
  refine (fix in_regex_ind2 {s r} prf {struct prf} : P s r :=
    match prf with
    | InEps => H_InEps
    | InChr c => H_InChr c
    | InCat prf1 prf2 eq1 =>
        H_InCat prf1 (in_regex_ind2 prf1) prf2 (in_regex_ind2 prf2) eq1
    | InLeft _ prf => H_InLeft prf (in_regex_ind2 prf)
    | InRight _ prf => H_InRight prf (in_regex_ind2 prf)
    | InStar prf => _
    end).
  inversion prf; subst.
  - inversion H1. apply H_InStar_Eps.
  - inversion H1; subst.
    apply H_InStar_Cat; try assumption; apply in_regex_ind2; assumption.
Qed.

End induction_principle.

事实证明,这个证明的Qed不是瞬间的(可能是因为inversionthis answer中产生了大的术语),但是花了不到1秒(可能因为引理更抽象)。

star_lemma几乎是微不足道的证明(一旦我们知道remember技巧),就像自然的定义一样。

Lemma star_lemma : forall s, s <<- (#1 ^*) -> s = "".
Proof.
  intros s H. remember (#1 ^*) as r.
  induction H using in_regex_ind2; try discriminate.
  - reflexivity.
  - inversion Heqr; subst.
    inversion H. rewrite IHin_regex2 by reflexivity. reflexivity.
Qed.

3
投票

我修改了你的in_regex谓词的定义:

Inductive in_regex : string -> regex -> Prop :=
| InEps
  : "" <<- #1
| InChr
  : forall c
  , (String c EmptyString) <<- ($ c)
| InCat
  :  forall e e' s s' s1
  ,  s <<- e
  -> s' <<- e'
  -> s1 = s ++ s'
  -> s1 <<- (e @ e')
| InLeft
  :  forall s e e'
  ,  s <<- e
  -> s <<- (e :+: e')
| InRight
  :  forall s' e e'
  ,  s' <<- e'
  -> s' <<- (e :+: e')
| InStarLeft
  : forall e
  , "" <<- (e ^*)
| InStarRight
  :  forall s s' e
  ,  s <<- e
  -> s' <<- (e ^*)
  -> (s ++ s') <<- (e ^*)
where "s '<<-' e" := (in_regex s e).

并且可以证明你的引理:

Lemma star_lemma : forall s, s <<- (#1 ^*) -> s = "".
Proof.
  intros s H.
  remember (#1 ^*) as r.
  induction H; inversion Heqr; clear Heqr; trivial.
  subst e.
  rewrite IHin_regex2; trivial.
  inversion H; trivial.
Qed.

一些解释是必要的。

  1. 我对H进行了归纳。理由是:如果我有s <<- (#1 ^*)证明,那么此证明必须具有以下形式......
  2. 战术remember创造了一个新的假设Heqr,与inversion结合将有助于摆脱不可能提供这种证据的案件(实际上所有案件减去^*在结论中的那些案例)。
  3. 不幸的是,这种推理路径不适用于你对in_regex谓词的定义,因为它会为归纳假设创造一个不可满足的条件。这就是我修改你的归纳谓词的原因。
  4. 修改后的归纳法试图给出在(e ^*)中更为基本的定义。在语义上,我认为这是等价的。

我有兴趣阅读原始问题的证据。

© www.soinside.com 2019 - 2024. All rights reserved.