From f6780feb6aae79f7a476547cb68b37b97bc5d585 Mon Sep 17 00:00:00 2001
From: "David A. Madore" <david+git@madore.org>
Date: Wed, 23 Nov 2016 15:41:06 +0100
Subject: Incomplete DFAs.  Change formating of self-loops in graphs.

---
 notes-inf105.tex | 233 ++++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 198 insertions(+), 35 deletions(-)

(limited to 'notes-inf105.tex')

diff --git a/notes-inf105.tex b/notes-inf105.tex
index a8572db..ded4af0 100644
--- a/notes-inf105.tex
+++ b/notes-inf105.tex
@@ -53,7 +53,7 @@
 %
 % NOTE: compile dot files with
 % dot2tex --figonly -f tikz --tikzedgelabels --graphstyle=automaton file.dot  > file.tex
-\tikzstyle{automaton}=[>=stealth',initial text={}]
+\tikzstyle{automaton}=[>=stealth',initial text={},every loop/.style={min distance=7mm,looseness=5}]
 \tikzstyle{state}=[]
 \tikzstyle{final}=[accepting by arrow]
 %
@@ -368,7 +368,7 @@ qu'on ne demande pas que $L$ soit fini (mais il peut l'être).
 nombre quelconque (éventuellement nul) de $c$ est un langage sur
 l'alphabet $\Sigma = \{a,b,c,d\}$.  On verra plus loin que ce langage
 est « rationnel » (et pourra être désigné par l'expression rationnelle
-$dc*$).
+$dc{*}$).
 
 Voici quelques autres exemples de langages :
 \begin{itemize}
@@ -597,7 +597,7 @@ introduit un nouvel objet, les \textbf{expressions rationnelles}
 (certains préfèrent le terme d'\textbf{expressions régulières}), qui
 sont des expressions servant à désigner un langage rationnel.  Par
 exemple, plutôt que d'écrire « $\{d\}(\{c\}^*)$ », on parlera du
-langage désigné par l'expression rationnelle $dc*$.
+langage désigné par l'expression rationnelle $dc{*}$.
 
 Plus exactement, une expression rationnelle (sur un alphabet $\Sigma$)
 est un mot sur l'alphabet $\Sigma \cup \{\bot,
@@ -626,14 +626,14 @@ l'expression $r$, de la manière suivante :
   alors $(r_1|r_2)$ est une expression rationnelle et son langage
   désigné est $L_{(r_1|r_2)} := L_1\cup L_2$,
 \item si $r$ est une expression rationnelle et $L = L_r$ les langage
-  désigné correspondant, alors $(r)*$ est une expression rationnelle
-  et son langage désigné est $L_{(r)*} := L^*$.
+  désigné correspondant, alors $(r){*}$ est une expression rationnelle
+  et son langage désigné est $L_{(r){*}} := L^*$.
 \end{itemize}
 
 À titre d'exemple, sur l'alphabet $\Sigma = \{a,b,c,d\}$, $c$ est une
-expression rationnelle qui désigne le langage $\{c\}$, donc $(c)*$ en
+expression rationnelle qui désigne le langage $\{c\}$, donc $(c){*}$ en
 est une qui désigne le langage $\{c\}^* = \{\varepsilon, c, cc,
-ccc,\ldots\}$, et enfin $d(c)*$ en est une qui désigne le langage $\{d,
+ccc,\ldots\}$, et enfin $d(c){*}$ en est une qui désigne le langage $\{d,
 dc, dcc, \ldots\}$ des mots formés d'un $d$ et d'une succession
 quelconques de $c$.  Voici quelques autres exemples, toujours sur
 $\Sigma = \{a,b,c,d\}$ :
@@ -642,11 +642,11 @@ $\Sigma = \{a,b,c,d\}$ :
   \{b\} = \{a,b\}$ formé des deux mots d'une seule lettre $a$ et $b$ ;
 \item l'expression rationnelle $(a|b)c$ désigne le langage
   $\{a,b\}\{c\} = \{ac,bc\}$, de même que $(ac|bc)$ ;
-\item l'expression rationnelle $(bc)*$ désigne le langage $\{bc\}^* =
+\item l'expression rationnelle $(bc){*}$ désigne le langage $\{bc\}^* =
   \{\varepsilon, bc, bcbc, bcbcbc, \ldots\}$ ;
-\item l'expression rationnelle $(a|(bc)*)$ désigne le langage $\{a\}
+\item l'expression rationnelle $(a|(bc){*})$ désigne le langage $\{a\}
   \cup \{bc\}^* = \{a, \varepsilon, bc, bcbc, bcbcbc, \ldots\}$ ;
-\item l'expression rationnelle $(a|(bc)*)d$ désigne le langage $\{a, d,
+\item l'expression rationnelle $(a|(bc){*})d$ désigne le langage $\{a, d,
   bcd, bcbcd, bcbcbcd, \ldots\}$.
 \end{itemize}
 
@@ -655,16 +655,16 @@ pour lequel il existe une expression rationnelle qui le désigne.
 
 On dira qu'un mot $w$ \textbf{vérifie} une expression rationnelle $r$
 lorsque ce mot appartient au langage qu'elle désigne (i.e., $w \in
-L_r$).  Par exemple, $dccc$ vérifie l'expression rationnelle $d(c)*$.
+L_r$).  Par exemple, $dccc$ vérifie l'expression rationnelle $d(c){*}$.
 
 La convention de parenthésage introduite ci-dessus est inambiguë mais
 parfois inutilement lourde : on se permettra parfois de l'alléger, par
 exemple d'écrire $(r_1|r_2|r_3)$ pour $((r_1|r_2)|r_3)$ (ou pour
 $(r_1|(r_2|r_3))$, ce qui n'a guère d'importance vu qu'elles désignent
-le même langage), ou encore $x*$ pour $(x)*$ lorsque $x$ est formé
+le même langage), ou encore $x{*}$ pour $(x){*}$ lorsque $x$ est formé
 d'un seul caractère.  La convention essentielle est que l'opération
-d'étoile $*$ est la plus prioritaire ($ab*$ se lit comme $a(b)*$ et
-non pas comme $(ab)*$), la concaténation vient après, et la barre de
+d'étoile ${*}$ est la plus prioritaire ($ab{*}$ se lit comme $a(b){*}$ et
+non pas comme $(ab){*}$), la concaténation vient après, et la barre de
 disjonction $|$ est la moins prioritaire ($ab|cd$ se lit comme
 $(ab|cd)$ et pas comme $a(b|c)d$).
 
@@ -680,7 +680,7 @@ notée $+$ par les mathématiciens.  Il y a ici un risque de confusion
 lié au fait que, en informatique, le symbole \texttt{+} est utilisé
 par de nombreux moteurs d'expressions régulières (par exemple,
 \texttt{egrep}) pour désigner l'opération évoquée en \ref{kleene-plus}
-(de sorte que $r+$ a le même sens que $rr*$).
+(de sorte que $r+$ a le même sens que $rr{*}$).
 
 
 \section{Automates finis}
@@ -748,8 +748,8 @@ dont le nombre de $b$ est pair.
   \node (q0) at (18bp,20.306bp) [draw,circle,state,initial] {$0$};
   \draw [->] (q1) ..controls (75.212bp,3.6347bp) and (64.284bp,-1.3057bp)  .. (54bp,1.3057bp) .. controls (50.042bp,2.3107bp) and (46.047bp,3.8633bp)  .. node[auto] {$b$} (q0);
   \draw [->] (q0) ..controls (46.106bp,20.306bp) and (58.578bp,20.306bp)  .. node[auto] {$b$} (q1);
-  \draw [->] (q1) ..controls (89.406bp,46.931bp) and (91.75bp,56.306bp)  .. (98bp,56.306bp) .. controls (102bp,56.306bp) and (104.4bp,52.458bp)  .. node[auto] {$a$} (q1);
-  \draw [->] (q0) ..controls (9.4062bp,46.931bp) and (11.75bp,56.306bp)  .. (18bp,56.306bp) .. controls (22.004bp,56.306bp) and (24.405bp,52.458bp)  .. node[auto] {$a$} (q0);
+  \draw [->] (q1) to[loop above] node[auto] {$a$} (q1);
+  \draw [->] (q0) to[loop above] node[auto] {$a$} (q0);
 %
 \end{tikzpicture}
 
@@ -765,8 +765,10 @@ ordre.  Le fait de consommer une lettre $x$ fait passer l'automate de
 l'état $q$ à l'état $\delta(q,x)$ (autrement dit, l'automate passe
 successivement dans les états $q_0$ puis $q_1 := \delta(q_0,x_1)$ puis
 $q_2 := \delta(q_1,x_2)$, et ainsi de suite jusqu'à $q_n :=
-\delta(q_{n-1},x_n)$).  Si $q_n$ est l'état dans lequel se trouve
-l'automate une fois qu'il a consommé le mot $w$, on dira que
+\delta(q_{n-1},x_n)$) ; on dit que l'automate effectue les transitions
+$q_0\to q_1$ (en consommant $x_1$) puis $q_1\to q_2$ (en
+consommant $x_2$q) et ainsi de suite.  Si $q_n$ est l'état dans lequel
+se trouve l'automate une fois qu'il a consommé le mot $w$, on dira que
 l'automate \emph{acepte} ou \emph{rejette} le mot selon que $q_n \in
 F$ ou que $q_n \not\in F$.
 
@@ -779,9 +781,10 @@ actuellement).  Si à la fin l'état $q_n$ est acceptant (représenté par
 une flèche pointant vers nulle part), le mot $w$ est accepté, sinon il
 est rejeté.
 
-\thingy Formellement : si $A = (Q,q_0,F,\delta)$ est un DFA sur
-l'alphabet $\Sigma$, on définit une fonction $\delta^* \colon
-Q\times\Sigma^* \to Q$ par $\delta^*(q,x_1\cdots x_n) =
+\thingy\label{definition-multiple-transition-function} Formellement :
+si $A = (Q,q_0,F,\delta)$ est un DFA sur l'alphabet $\Sigma$, on
+définit une fonction $\delta^* \colon Q\times\Sigma^* \to Q$ par
+$\delta^*(q,x_1\cdots x_n) =
 \delta(\cdots\delta(\delta(q,x_1),x_2)\cdots,x_n)$ ou, ce qui revient
 au même (par récurrence sur la longueur du second argument) :
 \begin{itemize}
@@ -799,14 +802,13 @@ Cette fonction $\delta^*$ étant définie, on dira que l'automate $A$
 $\delta^*(q_0,w) =: q_n \in F$ ; dans le cas contraire, on dira qu'il
 \textbf{rejette} le mot $w$.
 
-L'ensemble $L_A$ des mots acceptés par l'automate $A$ s'appelle
-\textbf{langage accepté}, ou \textbf{reconnu}, ou \textbf{défini}, par
-l'automate $A$.
+\thingy\label{definition-recognizable-language} L'ensemble $L_A$ des
+mots acceptés par l'automate $A$ s'appelle \textbf{langage accepté},
+ou \textbf{reconnu}, ou \textbf{défini}, par l'automate $A$.
 
-\textbf Un langage $L \subseteq \Sigma^*$ qui peut s'écrire sous la
-forme du langage $L_A$ accepté par un DFA $A$ s'appelle
-\textbf{reconnaissable} (sous-entendu : par automate déterministe
-fini).
+Un langage $L \subseteq \Sigma^*$ qui peut s'écrire sous la forme du
+langage $L_A$ accepté par un DFA $A$ s'appelle \textbf{reconnaissable}
+(sous-entendu : par automate déterministe fini).
 
 On dit que deux DFA $A,A'$ sont \textbf{équivalents} lorsqu'ils
 reconnaissent le même langage, i.e., $L_A = L_{A'}$.
@@ -828,10 +830,10 @@ constitue un état acceptant.
   \node (q0) at (18bp,18bp) [draw,circle,state,initial] {$0$};
   \node (q2) at (178bp,18bp) [draw,circle,state,final] {$2$};
   \draw [->] (q0) ..controls (46.106bp,18bp) and (58.578bp,18bp)  .. node[auto] {$a$} (q1);
-  \draw [->] (q1) ..controls (89.406bp,44.625bp) and (91.75bp,54bp)  .. (98bp,54bp) .. controls (102bp,54bp) and (104.4bp,50.152bp)  .. node[auto] {$a,c$} (q1);
+  \draw [->] (q1) to[loop above] node[auto] {$a,c$} (q1);
   \draw [->] (q1) ..controls (126.11bp,18bp) and (138.58bp,18bp)  .. node[auto] {$b$} (q2);
-  \draw [->] (q0) ..controls (9.4062bp,44.625bp) and (11.75bp,54bp)  .. (18bp,54bp) .. controls (22.004bp,54bp) and (24.405bp,50.152bp)  .. node[auto] {$b,c$} (q0);
-  \draw [->] (q2) ..controls (169.41bp,44.625bp) and (171.75bp,54bp)  .. (178bp,54bp) .. controls (182bp,54bp) and (184.4bp,50.152bp)  .. node[auto] {$a,b,c$} (q2);
+  \draw [->] (q0) to[loop above] node[auto] {$b,c$} (q0);
+  \draw [->] (q2) to[loop above] node[auto] {$a,b,c$} (q2);
 %
 \end{tikzpicture}
 
@@ -842,7 +844,8 @@ Cette description rend claire le fait que l'automate en question
 accepte exactement les mots contenant un $a$ suivi, pas forcément
 immédiatement, d'un $b$ ; autrement dit, les mots dont $ab$ est un
 sous-mot (cf. \ref{definition-subword}).  Ce langage est donc
-reconnaissable.
+reconnaissable.  (Il est aussi rationnel puisque désigné par
+l'expression rationnelle $(b|c){*}a(b|c){*}b(a|b|c){*}$.)
 
 \thingy Un état $q$ d'un DFA $A$ est dit \textbf{accessible} lorsqu'il
 existe un mot $w \in \Sigma^*$ tel que $q = \delta(q_0,w)$, autrement
@@ -868,8 +871,8 @@ cet état soit final ou non.
   \node (q2) at (172bp,20.306bp) [draw,circle,state,final] {$2$};
   \draw [->] (q1) ..controls (75.212bp,3.6347bp) and (64.284bp,-1.3057bp)  .. (54bp,1.3057bp) .. controls (50.042bp,2.3107bp) and (46.047bp,3.8633bp)  .. node[auto] {$b$} (q0);
   \draw [->] (q0) ..controls (46.106bp,20.306bp) and (58.578bp,20.306bp)  .. node[auto] {$b$} (q1);
-  \draw [->] (q1) ..controls (90.319bp,47.164bp) and (92.445bp,56.306bp)  .. (98bp,56.306bp) .. controls (101.47bp,56.306bp) and (103.6bp,52.735bp)  .. node[auto] {$a$} (q1);
-  \draw [->] (q0) ..controls (9.4062bp,46.931bp) and (11.75bp,56.306bp)  .. (18bp,56.306bp) .. controls (22.004bp,56.306bp) and (24.405bp,52.458bp)  .. node[auto] {$a$} (q0);
+  \draw [->] (q1) to[loop above] node[auto] {$a$} (q1);
+  \draw [->] (q0) to[loop above] node[auto] {$a$} (q0);
 %
 \end{tikzpicture}
 
@@ -889,6 +892,166 @@ automates déterministes finis incomplets et on va donc commencer par
 eux.
 
 
+\subsection{Automates finis déterministes à spécification incomplète (=DFAI)}
+
+\thingy Un \textbf{automate fini déterministe à spécification
+  incomplète} ou \textbf{...partielle}, ou simplement \textbf{automate
+  fini déterministe incomplet}, en abrégé \textbf{DFAI}, sur un
+alphabet $\Sigma$ est la donnée
+\begin{itemize}
+\item d'un ensemble fini $Q$ d'états,
+\item d'un état initial $q_0 \in Q$,
+\item d'un ensemble $F \subseteq Q$ d'états finaux,
+\item d'une fonction de transition \emph{partielle}\footnote{Une
+  « fonction partielle » $f\colon X\dasharrow Y$, où $X, Y$ sont deux
+  ensembles est, par définition, la même chose qu'une fonction
+  $f\colon D\to Y$ où $D\subseteq X$ est un sous-ensemble de $X$
+  appelé \textbf{ensemble de définition} de $f$.} $\delta \colon
+  Q\times\Sigma \dasharrow Q$,
+\end{itemize}
+autrement dit, la seule différence avec la définition faite
+en \ref{definition-dfa} est que la fonction $\delta$ est partielle, ce
+qui signifie qu'elle n'est pas obligatoirement définie sur tout couple
+$(q,x) \in Q\times\Sigma$.
+
+\thingy Graphiquement, on représente un DFAI comme un DFA, à la
+différence près que pour chaque $q\in Q$ et chaque $x\in \Sigma$, il y
+a maintenant \emph{au plus une} (et non plus exactement une) arête
+partant de $q$ et étiquetée par $x$.
+
+\thingy Le fonctionnement d'un DFAI est le même que celui d'un DFA, à
+la modification suivante près : si on donne à consommer à l'automate
+un symbole pour lequel la transition n'est pas définie, i.e., s'il
+rencontre un $x$ pendant qu'il se trouve dans un état $q$ pour lequel
+$\delta(q,x)$ n'est pas défini, alors l'automate cesse de
+fonctionner : l'automate n'a plus d'état, n'effectue plus de
+transition, et n'acceptera pas le mot quelles que soient les lettres
+ultérieures.
+
+\thingy Formellement : si $A = (Q,q_0,F,\delta)$ est un DFAI sur
+l'alphabet $\Sigma$, on définit une fonction $\delta^* \colon
+Q\times\Sigma^* \dasharrow Q$ par $\delta^*(q,x_1\cdots x_n) =
+\delta(\cdots\delta(\delta(q,x_1),x_2)\cdots,x_n)$ avec la convention
+que dès qu'une sous-expression n'est pas définie, toute l'expression
+n'est pas définie, ou, ce qui revient au même (par récurrence sur la
+longueur du second argument) :
+\begin{itemize}
+\item $\delta^*(q,\varepsilon) = q$ quel que soit $q\in Q$ (où
+  $\varepsilon$ désigne le mot vide),
+\item $\delta^*(q,wx) = \delta(\delta^*(q,w),x)$ à condition que $q'
+  := \delta^*(q,w)$ soit défini et que $\delta(q',x)$ le soit (et si
+  ces deux conditions ne sont pas satisfaites, $\delta^*(q,wx)$ n'est
+  pas défini).
+\end{itemize}
+
+Enfin, l'automate $A$ accepte un mot $w$ lorsque $\delta^*(q_0,w)$
+\emph{est défini} et appartient à $F$ ; dans le cas contraire (que ce
+soit parce que $\delta^*(q_0,w)$ n'est pas défini ou parce qu'étant
+défini il n'appartient pas à $F$), l'automate rejette le mot.
+
+Le langage accepté $L_A$ et l'équivalence de deux automates sont
+définis de façon analogue aux DFA
+(cf. \ref{definition-recognizable-language}).
+
+\thingy\label{discussion-example2b} Voici un exemple de DFAI sur
+l'alphabet $\Sigma = \{a,b,c\}$.  Cet automate reconnaît exactement
+les mots formés d'un nombre quelconque de $c$, suivis d'un $a$, suivis
+d'un nombre quelconque de $c$, suivis d'un $b$, suivis d'un nombre
+quelconque de $c$.
+
+\begin{center}
+%%% begin example2b %%%
+
+\begin{tikzpicture}[>=latex,line join=bevel,automaton]
+%%
+\node (q1) at (98bp,18bp) [draw,circle,state] {$1$};
+  \node (q0) at (18bp,18bp) [draw,circle,state,initial] {$0$};
+  \node (q2) at (178bp,18bp) [draw,circle,state,final] {$2$};
+  \draw [->] (q0) ..controls (46.106bp,18bp) and (58.578bp,18bp)  .. node[auto] {$a$} (q1);
+  \draw [->] (q1) to[loop above] node[auto] {$c$} (q1);
+  \draw [->] (q1) ..controls (126.11bp,18bp) and (138.58bp,18bp)  .. node[auto] {$b$} (q2);
+  \draw [->] (q0) to[loop above] node[auto] {$c$} (q0);
+  \draw [->] (q2) to[loop above] node[auto] {$c$} (q2);
+%
+\end{tikzpicture}
+
+%%% end example2b %%%
+\end{center}
+
+(Ce langage est aussi désigné par l'expression rationnelle
+$c{*}ac{*}bc{*}$.)
+
+\begin{prop}
+Soit $A = (Q,q_0,F,\delta)$ un DFAI sur un alphabet $\Sigma$.  Alors
+il existe un DFA $A' = (Q',q'_0,F',\delta')$ qui équivalent à $A$ au
+sens où il reconnaît le même langage $L_{A'} = L_A$.  De plus, $A'$ se
+déduit algorithmiquement de $A$ en ajoutant au plus un état
+\textbf{puits} à $A$ : on a $\#Q' \leq \#Q + 1$.
+\end{prop}
+\begin{proof}
+On définit $Q' = Q \cup \{q_\bot\}$ où $q_\bot$ est un nouvel état
+(n'appartenant pas à $Q$), qu'on appellera « puits ».  On garde l'état
+initial $q'_0 = q_0$.  On garde l'ensemble $F' = F$ d'états finaux,
+c'est-à-dire notamment que le puits n'est pas acceptant.  Enfin, on
+définit $\delta'(q,x)$ pour $q\in Q'$ et $x\in\Sigma$ par
+\[
+\begin{aligned}
+\delta'(q,x) &= \delta(q,x)\text{ si $\delta(q,x)$ est défini}\\
+\delta'(q,x) &= q_\bot\text{ sinon}\\
+\end{aligned}
+\]
+(notamment, $\delta'(q_\bot,x) = q_\bot$ quel que soit $x$).
+
+Il est alors facile de voir que $A'$ a le même comportement que $A$ au
+sens où $\delta^{\prime*}(q,w) = \delta^*(q,w)$ lorsque le terme de
+droite est défini et $\delta^{\prime*}(q,w) = q_\bot$ sinon (le DFA
+$A'$ « tombe dans le puits » lorsque le DFAI $A$ cesse de
+fonctionner).  En particulier, ils reconnaissent les mêmes langages.
+\end{proof}
+
+On dit que le DFA $A'$ est obtenu en \textbf{complétant} le DFAI $A$
+lorsqu'il est obtenu par la procédure décrite par la démonstration de
+cette proposition, c'est-à-dire par l'addition d'un état puits, sauf
+si $A$ est déjà complet, auquel cas on convient qu'il est son propre
+complété (i.e., on n'ajoute un puits que quand c'est réellement
+nécessaire).
+
+\thingy À titre d'exemple, le DFA suivant représente la complétion du
+DFAI représenté en \ref{discussion-example2b} :
+
+\begin{center}
+%%% begin example2c %%%
+
+\begin{tikzpicture}[>=latex,line join=bevel,automaton]
+%%
+\begin{scope}
+  \pgfsetstrokecolor{black}
+  \definecolor{strokecol}{rgb}{1.0,1.0,1.0};
+  \pgfsetstrokecolor{strokecol}
+  \definecolor{fillcol}{rgb}{1.0,1.0,1.0};
+  \pgfsetfillcolor{fillcol}
+  \filldraw (0bp,0bp) -- (0bp,182bp) -- (214bp,182bp) -- (214bp,0bp) -- cycle;
+\end{scope}
+  \node (q1) at (102bp,131bp) [draw,circle,state] {$1$};
+  \node (q0) at (18bp,85bp) [draw,circle,state,initial] {$0$};
+  \node (q2) at (196bp,85bp) [draw,circle,state,final] {$2$};
+  \node (qbot) at (102bp,22bp) [draw,circle,state] {$\bot$};
+  \draw [->] (q1) to[loop above] node[auto] {$c$} (q1);
+  \draw [->] (q2) to[loop above] node[auto] {$c$} (q2);
+  \draw [->] (qbot) to[loop below] node[auto] {$a,b,c$} (qbot);
+  \draw [->] (q0) ..controls (44.565bp,65.359bp) and (61.506bp,52.343bp)  .. node[auto] {$b$} (qbot);
+  \draw [->] (q0) to[loop above] node[auto] {$c$} (q0);
+  \draw [->] (q1) ..controls (102bp,96.993bp) and (102bp,73.356bp)  .. node[auto] {$a$} (qbot);
+  \draw [->] (q0) ..controls (46.061bp,100.18bp) and (63.141bp,109.76bp)  .. node[auto] {$a$} (q1);
+  \draw [->] (q2) ..controls (166.87bp,65.735bp) and (145.76bp,51.281bp)  .. node[auto] {$a,b$} (qbot);
+  \draw [->] (q1) ..controls (132.83bp,116.08bp) and (154.08bp,105.46bp)  .. node[auto] {$b$} (q2);
+%
+\end{tikzpicture}
+
+%%% end example2c %%%
+\end{center}
+
+
 %
 %
 %
-- 
cgit v1.2.3

