(* This program is free software; you can redistribute it and/or *)
(* modify it under the terms of the GNU Lesser General Public License *)
(* as published by the Free Software Foundation; either version 2.1 *)
(* of the License, or (at your option) any later version. *)
(* This program is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)
(* GNU General Public License for more details. *)
(* You should have received a copy of the GNU Lesser General Public *)
(* License along with this program; if not, write to the Free *)
(* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *)
(* Contribution to the Coq Library V6.3 (July 1999) *)
(****************************************************************************)
(* The Calculus of Inductive Constructions *)
(****************************************************************************)
(****************************************************************************)
(* Formal Language Theory *)
(* Judicael Courant - Jean-Christophe Filliatre *)
(* Developped in V5.8 June-July 1993 *)
(* Ported to V5.10 October 1994 *)
(****************************************************************************)
(* On definit le predicat (automate q qd qa d), ou q represente *)
(* l'ensemble des etats, qd ceux de depart, qa ceux d'arrivee, *)
(* et d la relation de transition, comme la conjonction de : *)
(* qd et qa sont inclus dans q , et d est inclus dans qxalphxq *)
Definition automate (q qd qa d : Ensf) : Prop :=
inclus qa q /\ inclus qd q /\ inclus d (prodcart q (prodcart alph q)).
automate q qd qa d -> inclus d (prodcart q (prodcart alph q)).
intros H1 H0; elim H0; clear H0.
forall q qd qa d : Ensf, automate q qd qa d -> inclus qd q.
intros H1 H0; elim H0; clear H0.
forall q qd qa d : Ensf, automate q qd qa d -> inclus qa q.
intros H1 H0; elim H0; clear H0.
(* On definit le predicat (chemin e1 e2 q d w), qui signifie : *)
(* On passe de e1 a e2 par le mot w dans un automate d'ensemble *)
(* d'etats q et de transition d. *)
Inductive chemin : Elt -> Elt -> Ensf -> Ensf -> Word -> Prop :=
forall (e1 e2 : Elt) (q d : Ensf),
dans e1 q -> e1 = e2 :>Elt -> chemin e1 e2 q d nil
forall (e1 e2 : Elt) (q d : Ensf) (w : Word) (e a : Elt),
dans (couple e (couple a e1)) d -> chemin e e2 q d (cons a w).
(* On definit le meme predicat d'une autre facon, qui sera plus utile *)
Definition Chemin (e1 e2 : Elt) (q d : Ensf) (w : Word) : Prop :=
(* nil *) dans e1 q /\ e1 = e2 :>Elt
dans e1 q /\ dans a alph /\ dans (couple e1 (couple a e)) d
(* On montre l'equivalence entre les 2 definitions : *)
forall (e1 e2 : Elt) (q d : Ensf) (w : Word),
Chemin e1 e2 q d w -> chemin e1 e2 q d w.
cut (dans e1 q /\ e1 = e2 :>Elt); auto.
intro H0; elim H0; clear H0.
intros; apply chemin_nil; auto.
dans e1 q /\ dans x alph /\ dans (couple e1 (couple x e)) d);
intros e H2; elim H2; clear H1 H2.
intros H1 H2; elim H2; clear H2.
intros H2 H3; elim H3; clear H3.
apply chemin_cons with e; auto.
Hint Resolve Chemin_chemin.
forall (e1 e2 : Elt) (q d : Ensf) (w : Word),
chemin e1 e2 q d w -> Chemin e1 e2 q d w.
intros e1 e2 q d w H; elim H; clear H.
red in |- *; simpl in |- *; auto.
red in |- *; simpl in |- *.
Hint Resolve chemin_Chemin.
(* Si (q,qd,qa,d) est un automate alors (reconnait q qd qa d) est le *)
(* langage reconnu par cet automate. *)
(* On le definit est disant que w est dans ce langage s'il est tout *)
(* d'abord dans le monoid libre engendre par alph, et s'il existe *)
(* 2 etats e1 et e2, repsectivement dans qd et qa, tels que *)
(* (chemin e1 e2 q d w) soit vrai. *)
Definition reconnait (q qd qa d : Ensf) (w : Word) : Prop :=
(exists e2 : Elt, dans e1 qd /\ dans e2 qa /\ chemin e1 e2 q d w)).
(* Si on a un chemin de e1 a e2 alors e1 et e2 sont dans q. *)
forall (q d : Ensf) (w : Word) (e1 e2 : Elt),
chemin e1 e2 q d w -> dans e1 q.
cut (Chemin e1 e2 q d nil); auto.
cut (dans e1 q /\ e1 = e2 :>Elt); auto.
cut (Chemin e1 e2 q d (cons x w0)); auto.
dans e1 q /\ dans x alph /\ dans (couple e1 (couple x e)) d);
intro Ht; elim Ht; clear Ht.
intros e Ht; elim Ht; clear Ht.
intros H2 Ht; elim Ht; auto.
forall (q d : Ensf) (w : Word) (e1 e2 : Elt),
chemin e1 e2 q d w -> dans e2 q.
cut (Chemin e1 e2 q d nil); auto.
cut (dans e1 q /\ e1 = e2 :>Elt); auto.
cut (Chemin e1 e2 q d (cons x w0)); auto.
dans e1 q /\ dans x alph /\ dans (couple e1 (couple x e)) d);
intro Ht; elim Ht; clear Ht.
intros e Ht; elim Ht; clear Ht.
(* Un chemin est un mot sur X *)
forall (w : Word) (q qd qa d : Ensf),
forall e1 e2 : Elt, chemin e1 e2 q d w -> inmonoid alph w.
intros x w0 H q qd qa d H0 e1 e2 H1.
cut (Chemin e1 e2 q d (cons x w0)); auto.
dans e1 q /\ dans x alph /\ dans (couple e1 (couple x e)) d);
intro H3; elim H3; clear H3.
intros e H3; elim H3; clear H3.
intros H3 H4; elim H4; clear H4.
intros H4 H5; elim H5; clear H5; intros.
apply inmonoid_cons; auto.
apply (H q qd qa d H0 e e2); auto.
(* Si le triplet (e1,x,e2) est dans d alors on a *)
(* (chemin e1 e2 q d (cons x nil)) *)
forall (e1 e2 x : Elt) (q d : Ensf),
dans (couple e1 (couple x e2)) d -> chemin e1 e2 q d (cons x nil).
apply chemin_cons with e2; auto.
(* AUTOMATES ASYNCHRONES *)
Definition automate_A (q qd qa d : Ensf) : Prop :=
inclus qd q /\ inclus d (prodcart q (prodcart (add epsilon alph) q)).
forall q qd qa d : Ensf, automate_A q qd qa d -> inclus qd q.
intros H0 Ht; elim Ht; auto.
(* On va definir de meme la notion de chemin sur un automate *)
(* asynchrone en rajoutant les transitions par epsilon. *)
Inductive chemin_A (q d : Ensf) : Elt -> Elt -> Word -> Prop :=
dans e1 q -> e1 = e2 :>Elt -> chemin_A q d e1 e2 nil
forall (e1 e e2 x : Elt) (w : Word),
dans (couple e1 (couple x e)) d -> chemin_A q d e1 e2 (cons x w)
forall (e1 e e2 : Elt) (w : Word),
dans (couple e1 (couple epsilon e)) d -> chemin_A q d e1 e2 w.
Hint Resolve chemin_A_nil.
(* Inversion de la definition... *)
Definition Chemin_A (q d : Ensf) (e1 e2 : Elt) (w : Word) : Prop :=
dans e1 q /\ e1 = e2 :>Elt \/
dans e1 q /\ dans (couple e1 (couple epsilon e)) d)
dans e1 q /\ dans a alph /\ dans (couple e1 (couple a e)) d) \/
dans e1 q /\ dans (couple e1 (couple epsilon e)) d)
(* Si on a un chemin pour une relation de transition d1 alors on a *)
(* le meme chemin pour toute relation de transition contenant d1. *)
forall (q d1 d2 : Ensf) (w : Word) (e1 e2 : Elt),
chemin_A q d1 e1 e2 w -> inclus d1 d2 -> chemin_A q d2 e1 e2 w.
apply chemin_A_cons with e; auto.
apply chemin_A_epsilon with e; auto.
(* De meme pour deux ensembles d'etats q1 et q2 tesl que q1 est inclus *)
forall (q1 q2 d : Ensf) (e1 e2 : Elt) (w : Word),
chemin_A q1 d e1 e2 w -> inclus q1 q2 -> chemin_A q2 d e1 e2 w.
intros q1 q2 d w e1 e2 H.
apply chemin_A_cons with e; auto.
apply chemin_A_epsilon with e; auto.
(* Si on a un chemin au sens des AF alors on a un chemin au sens des *)
forall (q d : Ensf) (w : Word) (e1 e2 : Elt),
chemin e1 e2 q d w -> chemin_A q d e1 e2 w.
apply chemin_A_cons with e0; auto.
(* Si on va de e1 a e par w1 et de e a e2 par w2 alors on va de *)
(* e1 a e2 par (Append w1 w2). *)
forall (e1 e e2 : Elt) (q d : Ensf) (w1 w2 : Word),
chemin_A q d e e2 w2 -> chemin_A q d e1 e2 (Append w1 w2).
intros e1 e e2 q d w1 w2 H.
simpl in |- *; rewrite H1; auto.
cut (chemin_A q d e3 e2 (Append w w2)); auto.
apply chemin_A_cons with e3; auto.
cut (chemin_A q d e3 e2 (Append w w2)); auto.
apply chemin_A_epsilon with e3; auto.
(* Si on a un cheminA de e1 a e2 alors e1 et e2 sont dans q. *)
forall (q d : Ensf) (w : Word) (e1 e2 : Elt),
chemin_A q d e1 e2 w -> dans e1 q.
forall (q d : Ensf) (w : Word) (e1 e2 : Elt),
chemin_A q d e1 e2 w -> dans e2 q.
(* Un mot reconnu par un automate_A est dans le monoide engendre par *)
forall (w : Word) (q qd qaA dA : Ensf),
automate_A q qd qaA dA ->
forall e1 e2 : Elt, chemin_A q dA e1 e2 w -> inmonoid alph w.
(* Pour un chemin de la forme (cons x w) il existe un etat *)
Lemma chemin_A2_cons_inv : (q,dA:Ensf)(w:Word)(e1,e2,x:Elt)
(chemin_A2 q dA (cons x w) e2 e1) -> (<Elt>Ex ([e:Elt](
(chemin_A2 q dA (cons x nil) e e1) /\ (chemin_A2 q dA w e2 e)
Cut (Chemin e0 e2 q dA (cons x w)); Auto.
(chemin e e2 q dA w) /\ (dans e0 q) /\ (dans x alph)
/\ (dans (couple e0 (couple x e)) dA)) ); Auto.
Intro Ht; Elim Ht; Clear Ht.
Intros e Ht; Elim Ht; Clear Ht.
Intros H3 Ht; Elim Ht; Clear Ht.
Intros H4 Ht; Elim Ht; Clear Ht.
2:Apply chemin_A2_un; Auto.
2:Apply (inmonoid_cons_inv alph w x); Auto.
Cut (chemin e0 e q dA (cons x nil)); Auto.
Apply (chemin_cons e e q dA nil e0 x); Auto.
Apply (dans_e1_q q dA w e e2); Auto.
Intros e0' Ht; Elim Ht; Clear Ht.
Apply chemin_A2_deux with e; Auto.
Lemma chemin_A_cons_inv : (q,dA:Ensf)(w:Word)(e1,e2,x:Elt)
(chemin_A e1 e2 q dA (cons x w)) -> (<Elt>Ex ([e:Elt](
(chemin_A e1 e q dA (cons x nil)) /\ (chemin_A e e2 q dA w)
(chemin_A2 q dA (cons x nil) e e1) /\ (chemin_A2 q dA w e2 e)
2:Apply chemin_A2_cons_inv; Auto.
Intro Ht; Elim Ht; Clear Ht.
Intros e Ht; Elim Ht; Clear Ht.
(* De meme on definit reconnait_A... *)
Definition reconnait_A (q qd qa d : Ensf) (w : Word) : Prop :=
(exists e2 : Elt, dans e1 qd /\ dans e2 qa /\ chemin_A q d e1 e2 w)).
(* A partir d'une relation de transition asynchrone dA construisons *)
(* la relation synchrone d correspondante. On elimine les transitions *)
(* avec epsilon en disant : *)
(* dans (e,a,e') d <-> (chemin_A e e' q dA (cons a nil)) *)
Definition est_dans_d2 (q dA : Ensf) (e y : Elt) : Prop :=
| couple a e' => chemin_A q dA e e' (cons a nil)
Definition est_dans_d (q dA : Ensf) (x : Elt) : Prop :=
| couple e y => est_dans_d2 q dA e y
Definition sync_d (q dA : Ensf) : Ensf :=
tq (est_dans_d q dA) (prodcart q (prodcart alph q)).
Definition sync_qa (q qaA dA : Ensf) : Ensf :=
(fun e : Elt => exists e' : Elt, dans e' qaA /\ chemin_A q dA e e' nil)
(* Les etats de d'arrivee de l'automate fini comprennent ceux de *)
(* l'automate asynchrone. *)
Lemma inclus_qaA_qa : forall q qaA dA : Ensf, inclus qaA (sync_qa q qaA dA).
(* Par definition on a... *)
forall (q qaA dA : Ensf) (e : Elt),
(exists e' : Elt, dans e' qaA /\ chemin_A q dA e e' nil) ->
dans e (sync_qa q qaA dA).
intros e' Ht; elim Ht; clear Ht.
forall (e1 e2 x : Elt) (q dA : Ensf),
chemin_A q dA e1 e2 (cons x nil) ->
dans (couple e1 (couple x e2)) (sync_d q dA).
apply (dansA_e1_q q dA (cons x nil) e1 e2); auto.
apply (dansA_e2_q q dA (cons x nil) e1 e2); auto.
forall (e1 e2 x : Elt) (q dA : Ensf),
dans (couple e1 (couple x e2)) (sync_d q dA) ->
chemin_A q dA e1 e2 (cons x nil).
(dans (couple e1 (couple x e2)) (prodcart q (prodcart alph q)) /\
est_dans_d q dA (couple e1 (couple x e2))).
2: apply dans_tq_imp; auto.
intro Ht; elim Ht; clear Ht.
unfold est_dans_d in |- *.
unfold est_dans_d2 in |- *.
forall (q dA : Ensf) (e0 e x : Elt),
dans (couple e0 (couple x e)) dA ->
dans (couple e0 (couple x e)) (sync_d q dA).
cut (chemin_A q dA e0 e (cons x nil)).
cut (chemin_A q dA e e nil); auto.
apply chemin_A_cons with e; auto.
(* Commencons par montrer que si (q,qd,qaA,dA) est un automate alors *)
(* (q,qd,qa,d) en est un aussi, ou qa=(sunc_qa q qaA dA) et *)
Lemma automateA_automate :
forall q qd qaA dA : Ensf,
automate_A q qd qaA dA -> automate q qd (sync_qa q qaA dA) (sync_d q dA).
intros H1 H2; elim H2; clear H2; intros H2 H3.
apply union_inclus; auto.
(* Si on a un chemin de e a e2 dans l'automate fini, avec e2 etat *)
(* d'arrivee, et s'il y a une transition de e1 a e2 par epsilon, *)
(* alors il y a un chemin de e1 a e2' par le meme mot, avec e2' *)
forall (q qaA dA : Ensf) (w : Word) (e1 e e2 : Elt),
chemin e e2 q (sync_d q dA) w ->
dans (couple e1 (couple epsilon e)) dA ->
dans e2 (sync_qa q qaA dA) ->
chemin e1 e2' q (sync_d q dA) w /\ dans e2' (sync_qa q qaA dA).
cut (Chemin e e2 q (sync_d q dA) nil); auto.
cut (dans e q /\ e = e2 :>Elt); auto.
intro Ht; elim Ht; clear Ht.
cut (chemin_A q dA e e2 nil); auto.
cut (chemin_A q dA e1 e2 nil).
2: apply chemin_A_epsilon with e; auto.
(fun e : Elt => exists e' : Elt, dans e' qaA /\ chemin_A q dA e e' nil)
2: apply dans_union; auto.
intro Ht; elim Ht; clear Ht.
intro; apply nouvx_dans_qa; auto.
(fun e : Elt => exists e' : Elt, dans e' qaA /\ chemin_A q dA e e' nil) e2).
ex (fun e' : Elt => dans e' qaA /\ chemin_A q dA e e' nil));
intro Ht; elim Ht; clear Ht.
intros H9 Ht; elim Ht; clear Ht.
intros e3 Ht; elim Ht; clear Ht.
cut (chemin_A q dA e e3 nil); auto.
cut (chemin_A q dA e1 e3 nil).
2: apply chemin_A_epsilon with e; auto.
intro; apply nouvx_dans_qa; auto.
intros x w0 H e1 e e2 H0 H1 H2 H3.
cut (Chemin e e2 q (sync_d q dA) (cons x w0)); auto.
chemin e22 e2 q (sync_d q dA) w0 /\
dans e q /\ dans x alph /\ dans (couple e (couple x e22)) (sync_d q dA));
intro Ht; elim Ht; clear Ht.
intros e22 Ht; elim Ht; clear Ht.
intros H5 Ht; elim Ht; clear Ht.
intros H6 Ht; elim Ht; clear Ht; intros H7 H8.
cut (chemin_A q dA e e22 (cons x nil)).
2: apply sync_d_def2; auto.
cut (chemin_A q dA e1 e22 (cons x nil)).
2: apply chemin_A_epsilon with e; auto.
cut (dans (couple e1 (couple x e22)) (sync_d q dA)).
2: apply sync_d_def; auto.
apply chemin_cons with e22; auto.
(* Si on a un chemin de e1 a e2 par w dans un automate asynchrone *)
(* avec e2 etat d'arrivee, alors il existe un etat d'arrivee e2' *)
(* de l'automate fini correspondant et un chemin de e1 a e2 par w *)
forall q qd qaA dA : Ensf,
automate_A q qd qaA dA ->
forall (w : Word) (e1 e2 : Elt),
chemin e1 e2' q (sync_d q dA) w /\ dans e2' (sync_qa q qaA dA).
intros q qd qaA dA H_aut w.
cut (inclus qaA (sync_qa q qaA dA)).
apply dans_trans with qaA; auto.
chemin e e2' q (sync_d q dA) w0 /\ dans e2' (sync_qa q qaA dA));
intro Ht; elim Ht; clear Ht.
intros e2' Ht; elim Ht; clear Ht.
apply chemin_cons with e; auto.
2: apply (dans_e1_q q (sync_d q dA) w0 e e2'); auto.
chemin e e2' q (sync_d q dA) w0 /\ dans e2' (sync_qa q qaA dA));
intro Ht; elim Ht; clear Ht.
intros e9 Ht; elim Ht; clear Ht.
apply (epsilon_chemin q qaA dA w0 e0 e e9); auto.
(* Montrons maintenant que si (q,qd,qaA,dA) est un automate async. *)
(* alors (reconnait_A q qd qaA dA w) -> (reconnait q qd qa d w) *)
(* ou qa=(sunc_qa q qaA dA) et d=(sync_d q dA). *)
Lemma reconnaitA_reconnait :
forall (q qd qaA dA : Ensf) (w : Word),
automate_A q qd qaA dA ->
reconnait_A q qd qaA dA w ->
reconnait q qd (sync_qa q qaA dA) (sync_d q dA) w.
intros q qd qaA dA w H_aut.
unfold reconnait_A in |- *.
intro H; elim H; clear H.
intros H1 H; elim H; clear H.
intros e1 H; elim H; clear H.
intros e2 H; elim H; clear H.
intros H2 H; elim H; clear H; intros H3 H4.
unfold reconnait in |- *.
chemin e1 e2' q (sync_d q dA) w /\ dans e2' (sync_qa q qaA dA)).
2: apply (cheminA_chemin q qd qaA dA H_aut w e1 e2); auto.
intro Ht; elim Ht; clear Ht.
intros e2' Ht; elim Ht; clear Ht.
(* Reciproquement, si on a un chemin de e1 a e2 dans l'automate fini *)
(* correspondant a un automate asynchrone, alors on a un chemin de e1 *)
(* a e2 dans l'automate asynchrone. *)
forall q qd qaA dA : Ensf,
automate_A q qd qaA dA ->
forall (w : Word) (e1 e2 : Elt),
chemin e1 e2 q (sync_d q dA) w -> chemin_A q dA e1 e2 w.
intros q qd qaA dA H_aut.
cut (Chemin e1 e2 q (sync_d q dA) nil); auto.
cut (dans e1 q /\ e1 = e2 :>Elt); auto.
intro Ht; elim Ht; clear Ht.
intros; apply chemin_A_nil; auto.
cut (Chemin e1 e2 q (sync_d q dA) (cons x w0)); auto.
chemin e e2 q (sync_d q dA) w0 /\
dans e1 q /\ dans x alph /\ dans (couple e1 (couple x e)) (sync_d q dA));
intro Ht; elim Ht; clear Ht.
intros e Ht; elim Ht; clear Ht.
intros H2 Ht; elim Ht; clear Ht.
cut (chemin_A q dA e e2 w0); auto.
elim H4; clear H4; intros H4 H6.
cut (chemin_A q dA e1 e (cons x nil)).
2: apply sync_d_def2; auto.
replace (cons x w0) with (Append (cons x nil) w0); auto.
apply chemin_Append with e; auto.
(* On en deduit qu'un mot reconnu par l'automate fini associe a un *)
(* automate asynchrone etait reconnu par l'automate asynchrone. *)
Lemma reconnait_reconnaitA :
forall (q qd qaA dA : Ensf) (w : Word),
automate_A q qd qaA dA ->
reconnait q qd (sync_qa q qaA dA) (sync_d q dA) w ->
reconnait_A q qd qaA dA w.
intros q qd qaA dA w H_aut.
unfold reconnait in |- *.
intro Ht; elim Ht; clear Ht.
intros H Ht; elim Ht; clear Ht.
intros e1 Ht; elim Ht; clear Ht.
intros e2 Ht; elim Ht; clear Ht.
intros H0 Ht; elim Ht; clear Ht.
exists e' : Elt, dans e' qaA /\ chemin_A q dA e e' nil) q)));
(fun e : Elt => exists e' : Elt, dans e' qaA /\ chemin_A q dA e e' nil)
2: apply dans_union; auto.
unfold reconnait_A in |- *.
apply (chemin_cheminA q qd qaA dA H_aut); auto.
(fun e : Elt => exists e' : Elt, dans e' qaA /\ chemin_A q dA e e' nil) e2).
exists e' : Elt, dans e' qaA /\ chemin_A q dA e e' nil);
intro Ht; elim Ht; clear Ht.
intros H5 Ht; elim Ht; clear Ht.
intros e2' Ht; elim Ht; clear Ht.
cut (chemin_A q dA e1 e2 w).
2: apply (chemin_cheminA q qd qaA dA H_aut); auto.
replace w with (Append w nil).
apply chemin_Append with e2; auto.
(* Et le resultat final : *)
(* Pour tout automate asynchrone (utilisant des transitions avec *)
(* epsilon) il existe un automate fini reconnaissant le meme *)
forall q qd qaA dA : Ensf,
automate_A q qd qaA dA ->
eqwordset (reconnait_A q qd qaA dA) (reconnait q qd qa d)).
exists (sync_qa q qaA dA).
apply automateA_automate; auto.
unfold eqwordset in |- *.
apply reconnaitA_reconnait; auto.
apply reconnait_reconnaitA; auto.
(* Les mots reconnus par un automate forment un langage : *)
(* par definition meme puisqu'un mot reconnu est dans le monoide *)
(* engendre par alph... *)
automate q qd qa d -> islanguage alph (reconnait q qd qa d).
unfold islanguage at 1 in |- *.
unfold reconnait at 1 in |- *.
(* Le predicat isregular definit les langages reguliers. *)
Definition isregular (l : wordset) : Prop :=
automate q qd qa d /\ eqwordset (reconnait q qd qa d) l))).
Definition isregular_A (l : wordset) : Prop :=
automate_A q qd qa d /\ eqwordset (reconnait_A q qd qa d) l))).
Lemma isregular_A_isregular :
forall l : wordset, isregular_A l -> isregular l.
unfold isregular_A in |- *.
intros l Ht; elim Ht; clear Ht.
intros q Ht; elim Ht; clear Ht.
intros qd Ht; elim Ht; clear Ht.
intros qaA Ht; elim Ht; clear Ht.
intros dA Ht; elim Ht; clear Ht.
eqwordset (reconnait_A q qd qaA dA) (reconnait q qd qa d))).
2: apply async_is_sync; auto.
intro Ht; elim Ht; clear Ht.
intros d Ht; elim Ht; clear Ht.
intros qa Ht; elim Ht; clear Ht.
unfold isregular in |- *.
apply eqwordset_trans with (reconnait_A q qd qaA dA); auto.
apply eqwordset_sym; auto.
Definition isregular_D (l : wordset) : Prop :=
automate q (singleton g0) qa d /\
(forall w : Word, chemin g0 g0 q d w -> w = nil :>Word) /\
eqwordset (reconnait q (singleton g0) qa d) l))).
Definition transition_D (g0 x : Elt) : Elt := couple g0 (couple epsilon x).
Definition delta_D (g0 : Elt) (qd : Ensf) : Ensf := map (transition_D g0) qd.
forall (q qd qa d : Ensf) (g0 : Elt),
automate_A (add g0 q) (singleton g0) qa (union d (delta_D g0 qd)).
unfold automate_A in |- *.
apply automate_def3 with qd d; auto.
apply inclus_trans with (prodcart q (prodcart alph q)).
apply automate_def1 with qd qa; assumption.
cut (exists y : Elt, dans y qd /\ x = transition_D g0 y :>Elt).
intro Ht; elim Ht; clear Ht; intros t Ht; elim Ht; clear Ht; intros.
unfold transition_D in |- *.
apply dans_trans with qd; auto.
apply automate_def2 with qa d; auto.
(* Si on a un chemin_A de e a e2 dans l'automate D et que e est dans *)
(* q alors on a un chemin dans l'automate fini. *)
forall (q qd qa d : Ensf) (g0 e e2 : Elt) (w : Word),
chemin_A (add g0 q) (union d (delta_D g0 qd)) e e2 w ->
dans e q -> chemin e e2 q d w.
intros q qd qa d g0 e e2 w H_aut H_g0 H.
intros e1 e0 e3 x w0 H H0 H1 H2 H3 H4.
(dans (couple e1 (couple x e0)) d \/
dans (couple e1 (couple x e0)) (delta_D g0 qd));
intro Ht; elim Ht; clear Ht.
cut (dans (couple e1 (couple x e0)) (prodcart q (prodcart alph q))).
2: apply dans_trans with d; auto.
2: apply automate_def1 with qd qa; auto.
cut (dans e1 q /\ dans (couple x e0) (prodcart alph q)).
intro Ht; elim Ht; clear Ht; intros.
cut (dans x alph /\ dans e0 q).
intro Ht; elim Ht; clear Ht; intros.
apply chemin_cons with e0; auto.
dans y qd /\ couple e1 (couple x e0) = transition_D g0 y :>Elt).
intro Ht; elim Ht; clear Ht; intros y' Ht; elim Ht; clear Ht; intros.
unfold transition_D in H7.
cut (e1 = g0 :>Elt /\ couple x e0 = couple epsilon y' :>Elt).
2: apply equal_couple; auto.
intro Ht; elim Ht; clear Ht; intros.
cut (x = epsilon :>Elt /\ e0 = y' :>Elt).
2: apply equal_couple; auto.
intro Ht; elim Ht; clear Ht; intros.
absurd (dans x alph); auto.
red in |- *; intro; apply not_dans_epsilon_alph; assumption.
intros e1 e0 e3 w0 H H1 H2 H3 H4.
(dans (couple e1 (couple epsilon e0)) d \/
dans (couple e1 (couple epsilon e0)) (delta_D g0 qd));
intro Ht; elim Ht; clear Ht.
cut (dans (couple e1 (couple epsilon e0)) (prodcart q (prodcart alph q))).
2: apply dans_trans with d; auto.
2: apply automate_def1 with qd qa; auto.
cut (dans e1 q /\ dans (couple epsilon e0) (prodcart alph q)).
intro Ht; elim Ht; clear Ht; intros.
cut (dans epsilon alph /\ dans e0 q).
intro Ht; elim Ht; clear Ht; intros.
absurd (dans epsilon alph); auto.
red in |- *; intro; apply not_dans_epsilon_alph; assumption.
dans y qd /\ couple e1 (couple epsilon e0) = transition_D g0 y :>Elt).
intro Ht; elim Ht; clear Ht; intros y' Ht; elim Ht; clear Ht; intros.
unfold transition_D in H6.
cut (e1 = g0 :>Elt /\ couple epsilon e0 = couple epsilon y' :>Elt).
2: apply equal_couple; auto.
intro Ht; elim Ht; clear Ht; intros.
absurd (dans g0 q); auto.
(* Si on a un chemin de g0 a e2 avec e2 dans qa alors il existe un *)
(* etat e dans qd tel que l'on ait un chemin_A de e a e2 par le meme *)
forall (q qd qa d : Ensf) (g0 e1 e2 : Elt) (w : Word),
chemin_A (add g0 q) (union d (delta_D g0 qd)) e1 e2 w ->
dans e qd /\ chemin_A (add g0 q) (union d (delta_D g0 qd)) e e2 w.
intros q qd qa d g0 e1 e2 w H_aut H_g0 H.
absurd (dans g0 q); auto.
apply dans_trans with qa; auto.
apply automate_def3 with qd d; auto.
intros e0 e e3 x w0 H H0 H1 H2 H3 H4 H5.
(dans (couple e0 (couple x e)) d \/
dans (couple e0 (couple x e)) (delta_D g0 qd)); auto.
intro Ht; elim Ht; clear Ht.
cut (dans (couple e0 (couple x e)) (prodcart q (prodcart alph q))).
2: apply dans_trans with d; auto.
2: apply automate_def1 with qd qa; auto.
cut (dans e0 q /\ dans (couple x e) (prodcart alph q)).
intro Ht; elim Ht; clear Ht; intros.
absurd (dans g0 q); auto.
dans y qd /\ couple e0 (couple x e) = transition_D g0 y :>Elt).
intro Ht; elim Ht; clear Ht; intros y' Ht; elim Ht; clear Ht; intros.
unfold transition_D in H7.
cut (e0 = g0 :>Elt /\ couple x e = couple epsilon y' :>Elt).
2: apply equal_couple; auto.
intro Ht; elim Ht; clear Ht; intros.
cut (x = epsilon :>Elt /\ e = y' :>Elt).
2: apply equal_couple; auto.
intro Ht; elim Ht; clear Ht; intros.
absurd (dans x alph); auto.
red in |- *; intro; apply not_dans_epsilon_alph; assumption.
intros e0 e e3 w0 H H0 H1 H2 H3 H4.
(dans (couple e0 (couple epsilon e)) d \/
dans (couple e0 (couple epsilon e)) (delta_D g0 qd));
intro Ht; elim Ht; clear Ht.
cut (dans (couple e0 (couple epsilon e)) (prodcart q (prodcart alph q))).
2: apply dans_trans with d; auto.
2: apply automate_def1 with qd qa; auto.
cut (dans e0 q /\ dans (couple epsilon e) (prodcart alph q)).
intro Ht; elim Ht; clear Ht; intros.
cut (dans epsilon alph /\ dans e q).
intro Ht; elim Ht; clear Ht; intros.
absurd (dans epsilon alph); auto.
red in |- *; intro; apply not_dans_epsilon_alph; assumption.
dans y qd /\ couple e0 (couple epsilon e) = transition_D g0 y :>Elt).
intro Ht; elim Ht; clear Ht; intros y' Ht; elim Ht; clear Ht; intros.
unfold transition_D in H6.
cut (e0 = g0 :>Elt /\ couple epsilon e = couple epsilon y' :>Elt).
2: apply equal_couple; auto.
intro Ht; elim Ht; clear Ht; intros.
cut (epsilon = epsilon :>Elt /\ e = y' :>Elt).
2: apply equal_couple; auto.
intro Ht; elim Ht; clear Ht; intros.
(* On ne peut avoir de chemin de e a g0 si e est dans q. *)
Lemma chemin_A_e1_g0_abs :
forall (q qd qa d : Ensf) (g0 e e2 : Elt) (w : Word),
e2 = g0 :>Elt -> ~ chemin_A (add g0 q) (union d (delta_D g0 qd)) e e2 w.
intros q qd qa d g0 e e2 w H_aut H H0 H1.
cut (e2 = g0 :>Elt); auto.
intros e1 e0 H3 H4 H5 H6.
absurd (dans g0 q); auto.
rewrite <- H4; assumption.
intros e1 e0 e3 x w0 H3 H4 H5 H6 H7 H8 H9.
(dans (couple e1 (couple x e0)) d \/
dans (couple e1 (couple x e0)) (delta_D g0 qd));
intro Ht; elim Ht; clear Ht.
cut (dans (couple e1 (couple x e0)) (prodcart q (prodcart alph q))).
2: apply dans_trans with d; auto.
2: apply automate_def1 with qd qa; auto.
cut (dans e1 q /\ dans (couple x e0) (prodcart alph q)).
intro Ht; elim Ht; clear Ht; intros.
cut (dans x alph /\ dans e0 q).
intro Ht; elim Ht; clear Ht; intros.
dans y qd /\ couple e1 (couple x e0) = transition_D g0 y :>Elt).
intro Ht; elim Ht; clear Ht; intros y' Ht; elim Ht; clear Ht; intros.
unfold transition_D in H12.
cut (e1 = g0 :>Elt /\ couple x e0 = couple epsilon y' :>Elt).
2: apply equal_couple; auto.
intro Ht; elim Ht; clear Ht; intros.
absurd (dans e1 q); auto.
intros e1 e0 e3 w0 H3 H4 H5 H6 H7 H8.
(dans (couple e1 (couple epsilon e0)) d \/
dans (couple e1 (couple epsilon e0)) (delta_D g0 qd));
intro Ht; elim Ht; clear Ht.
cut (dans (couple e1 (couple epsilon e0)) (prodcart q (prodcart alph q))).
2: apply dans_trans with d; auto.
2: apply automate_def1 with qd qa; auto.
cut (dans e1 q /\ dans (couple epsilon e0) (prodcart alph q)).
intro Ht; elim Ht; clear Ht; intros.
cut (dans epsilon alph /\ dans e0 q).
intro Ht; elim Ht; clear Ht; intros.
absurd (dans epsilon alph); auto.
dans y qd /\ couple e1 (couple epsilon e0) = transition_D g0 y :>Elt).
intro Ht; elim Ht; clear Ht; intros y' Ht; elim Ht; clear Ht; intros.
unfold transition_D in H11.
cut (e1 = g0 :>Elt /\ couple epsilon e0 = couple epsilon y' :>Elt).
2: apply equal_couple; auto.
intro Ht; elim Ht; clear Ht; intros.
absurd (dans e1 q); auto.
(* Si on a un chemin_A de e1 a g0 alors c'est forcement par le mot *)
forall (q qd qa d : Ensf) (g0 e1 e2 : Elt) (w : Word),
chemin_A (add g0 q) (union d (delta_D g0 qd)) e1 e2 w ->
e2 = g0 :>Elt -> w = nil :>Word.
intros q qd qa d g0 e1 e2 w H_aut H_g0 H.
intros e0 e e3 x w0 H0 H1 H2 H3 H4 H5.
absurd (chemin_A (add g0 q) (union d (delta_D g0 qd)) e g0 w0).
2: cut (chemin_A (add g0 q) (union d (delta_D g0 qd)) e e3 w0); auto.
apply chemin_A_e1_g0_abs with qa; auto.
(dans (couple e0 (couple x e)) d \/
dans (couple e0 (couple x e)) (delta_D g0 qd)); auto.
intro Ht; elim Ht; clear Ht.
cut (dans (couple e0 (couple x e)) (prodcart q (prodcart alph q))).
2: apply dans_trans with d; auto.
2: apply automate_def1 with qd qa; auto.
cut (dans e0 q /\ dans (couple x e) (prodcart alph q)).
intro Ht; elim Ht; clear Ht; intros.
cut (dans x alph /\ dans e q).
intro Ht; elim Ht; clear Ht; intros.
dans y qd /\ couple e0 (couple x e) = transition_D g0 y :>Elt).
intro Ht; elim Ht; clear Ht; intros y' Ht; elim Ht; clear Ht; intros.
unfold transition_D in H8.
cut (e0 = g0 :>Elt /\ couple x e = couple epsilon y' :>Elt).
2: apply equal_couple; auto.
intro Ht; elim Ht; clear Ht; intros.
cut (x = epsilon :>Elt /\ e = y' :>Elt).
2: apply equal_couple; auto.
intro Ht; elim Ht; clear Ht; intros.
absurd (dans x alph); auto.
red in |- *; intro; apply not_dans_epsilon_alph; assumption.
(* Pour tout automate A=(q,qd,qa,d) l'automate ((add g0 q), *)
(* (singleton g0),qa,(union d (delta_D g0 qd))) reconnait le meme *)
(* langage que A et possede la propriete que seul le mot nil *)
(* permet de passer de g0 a g0 par un chemin. *)
Lemma isregular_isregular_D_1 :
forall (q qd qa d : Ensf) (g0 : Elt),
eqwordset (reconnait q qd qa d)
(reconnait_A (add g0 q) (singleton g0) qa (union d (delta_D g0 qd))) /\
chemin_A (add g0 q) (union d (delta_D g0 qd)) g0 g0 w -> w = nil :>Word).
unfold eqwordset in |- *.
unfold reconnait in |- *.
intro Ht; elim Ht; clear Ht; intros H1 Ht; elim Ht; clear Ht; intros e1 Ht;
elim Ht; clear Ht; intros e2 Ht; elim Ht; clear Ht;
intros H2 Ht; elim Ht; clear Ht; intros.
unfold reconnait_A in |- *.
apply chemin_A_epsilon with e1; auto.
apply chemin_A_d1_d2 with d; auto.
apply chemin_A_q1_q2 with q; auto.
apply chemin_chemin_A; auto.
replace (couple g0 (couple epsilon e1)) with (transition_D g0 e1);
unfold reconnait_A in |- *.
intro Ht; elim Ht; clear Ht; intros H1 Ht; elim Ht; clear Ht; intros e1 Ht;
elim Ht; clear Ht; intros e2 Ht; elim Ht; clear Ht;
intros H2 Ht; elim Ht; clear Ht; intros.
unfold reconnait in |- *.
cut (e1 = g0 :>Elt); auto.
dans e qd /\ chemin_A (add g0 q) (union d (delta_D g0 qd)) e e2 w).
2: apply chemin_A_g0_e2 with qa e1; auto.
intro Ht; elim Ht; clear Ht; intros e Ht; elim Ht; clear Ht; intros.
split; [ assumption | split ].
apply chemin_D_chemin with qd qa g0; auto.
apply dans_trans with qd; auto.
apply automate_def2 with qa d; auto.
apply chemin_A_e1_g0 with q qd qa d g0 g0 g0; auto.
(* Si l est regulier, alors l est regulier au sens de isregular_D, *)
(* ie il existe un automate a un seul etat de depart g0 et possedant *)
(* la propriete que seul le mot nil permet d'aller de g0 a g0 par *)
(* un chemin qui reconnait l. *)
Lemma isregular_isregular_D :
forall l : wordset, isregular l -> isregular_D l.
unfold isregular at 1 in |- *.
intro Ht; elim Ht; clear Ht; intros q Ht; elim Ht; clear Ht; intros qd Ht;
elim Ht; clear Ht; intros qa Ht; elim Ht; clear Ht;
intros d Ht; elim Ht; clear Ht; intros.
cut (exists g0 : Elt, ~ dans g0 q).
intro Ht; elim Ht; clear Ht; intros g0 H1.
cut (automate_A (add g0 q) (singleton g0) qa (union d (delta_D g0 qd))).
2: apply automate_A_D; auto.
unfold isregular_D in |- *.
exists (sync_qa (add g0 q) qa (union d (delta_D g0 qd))).
exists (sync_d (add g0 q) (union d (delta_D g0 qd))).
apply automateA_automate; auto.
(eqwordset (reconnait q qd qa d)
(reconnait_A (add g0 q) (singleton g0) qa (union d (delta_D g0 qd))) /\
chemin_A (add g0 q) (union d (delta_D g0 qd)) g0 g0 w -> w = nil :>Word)).
2: apply isregular_isregular_D_1; auto.
intro Ht; elim Ht; clear Ht; intros.
cut (chemin_A (add g0 q) (union d (delta_D g0 qd)) g0 g0 w).
2: apply chemin_cheminA with (singleton g0) qa; auto.
with (reconnait_A (add g0 q) (singleton g0) qa (union d (delta_D g0 qd))).
unfold eqwordset in |- *.
apply reconnait_reconnaitA; auto.
apply reconnaitA_reconnait; auto.
apply eqwordset_trans with (reconnait q qd qa d); auto.
apply eqwordset_sym; assumption.