unfold isregular in |- *.
intros l1 l2 H1 H2.
elim H1; clear H1.
intros q1 H1; elim H1; clear H1; intros qd1 H1; elim H1; clear H1;
intros qa1 H1; elim H1; clear H1; intros d1 H1; elim H1;
clear H1.
intros H1_aut H1_eq.
elim H2; clear H2.
intros q2 H2; elim H2; clear H2; intros qd2 H2; elim H2; clear H2;
intros qa2 H2; elim H2; clear H2; intros d2 H2; elim H2;
clear H2.
intros H2_aut H2_eq.
exists (union_disj q1 q2).
exists (union_disj qd1 qd2).
exists (union_disj qa1 qa2).
exists (union (injg_d1 q1 d1) (injd_d2 q2 d2)).
split.
red in |- *.
split.
apply inclus_union_disj.
apply automate_def3 with qd1 d1; auto.
apply automate_def3 with qd2 d2; auto.
split.
apply inclus_union_disj.
apply automate_def2 with qa1 d1; auto.
apply automate_def2 with qa2 d2; auto.
apply d_is_good.
apply lunion_is_reg1; auto.
Qed.
(************************************************************************)
(*									*)
(*  La concatenation de 2 langages reguliers est un langage regulier.	*)
(*									*)
(************************************************************************)
(*  On definit (pont qa1 qd2) comme l'ensemble des transitions		*)
(*  (e,epsilon,e') avec e dans qa1 et e' dans qd2.			*)
Definition transition_pont (x : Elt) : Elt :=
match x return Elt with
| natural n =>
(* natural *)  zero (* couple  *)
| couple e e' =>
couple (couple e zero) (couple epsilon (couple e' un))
(* up      *)
| up e => zero
(* word    *)
| word w => zero
end.
Definition pont (qa1 qd2 : Ensf) : Ensf :=
map transition_pont (prodcart qa1 qd2).
(*  L'automate construit pour reconnaitre l1.l2 est bien un automate	*)
(*  asynchrone.								*)

Lemma automate_lconc_isgood :
forall q1 qd1 qa1 d1 q2 qd2 qa2 d2 : Ensf,
automate q1 qd1 qa1 d1 ->
automate q2 qd2 qa2 d2 ->
automate_A (union_disj q1 q2) (map injgauche qd1)
(map injdroite qa2)
(union (pont qa1 qd2) (union (injg_d1 q1 d1) (injd_d2 q2 d2))).