50 \end{tikzpicture} |
50 \end{tikzpicture} |
51 & |
51 & |
52 \begin{tikzpicture} |
52 \begin{tikzpicture} |
53 \begin{axis}[ |
53 \begin{axis}[ |
54 xlabel={$n$}, |
54 xlabel={$n$}, |
55 x label style={at={(1.05,0.0)}}, |
55 x label style={at={(1.1,0.0)}}, |
|
56 %%xtick={0,1000000,...,5000000}, |
56 ylabel={time in secs}, |
57 ylabel={time in secs}, |
57 enlargelimits=false, |
58 enlargelimits=false, |
58 ymax=35, |
59 ymax=35, |
59 ytick={0,5,...,30}, |
60 ytick={0,5,...,30}, |
60 axis lines=left, |
61 axis lines=left, |
61 scaled ticks=false, |
62 %scaled ticks=false, |
62 width=6.5cm, |
63 width=6.5cm, |
63 height=5cm, |
64 height=5cm, |
64 legend entries={Scala V3}, |
65 legend entries={Our matcher}, |
65 legend pos=north east, |
66 legend pos=north east, |
66 legend cell align=left] |
67 legend cell align=left] |
67 %\addplot[green,mark=square*,mark options={fill=white}] table {re2a.data}; |
68 %\addplot[green,mark=square*,mark options={fill=white}] table {re2a.data}; |
68 \addplot[black,mark=square*,mark options={fill=white}] table {re3a.data}; |
69 \addplot[black,mark=square*,mark options={fill=white}] table {re3a.data}; |
69 \end{axis} |
70 \end{axis} |
70 \end{tikzpicture} |
71 \end{tikzpicture} |
71 \end{tabular} |
72 \end{tabular} |
72 \end{center} |
73 \end{center}\bigskip |
73 |
74 |
74 \begin{center} |
75 \begin{center} |
75 Graphs: $a^{?\{n\}} \cdot a^{\{n\}}$ and strings $\underbrace{a\ldots a}_{n}$\\ |
76 Graphs: $a^{?\{n\}} \cdot a^{\{n\}}$ and strings $\underbrace{a\ldots a}_{n}$\\ |
76 \begin{tabular}{@{}cc@{}} |
77 \begin{tabular}{@{}cc@{}} |
77 \begin{tikzpicture} |
78 \begin{tikzpicture} |
108 ytick={0,5,...,30}, |
109 ytick={0,5,...,30}, |
109 scaled ticks=false, |
110 scaled ticks=false, |
110 axis lines=left, |
111 axis lines=left, |
111 width=6.5cm, |
112 width=6.5cm, |
112 height=5cm, |
113 height=5cm, |
113 legend entries={Scala V3}, |
114 legend entries={Our matcher}, |
114 legend pos=north east, |
115 legend pos=north east, |
115 legend cell align=left] |
116 legend cell align=left] |
116 %\addplot[green,mark=square*,mark options={fill=white}] table {re2.data}; |
117 %\addplot[green,mark=square*,mark options={fill=white}] table {re2.data}; |
117 \addplot[black,mark=square*,mark options={fill=white}] table {re3.data}; |
118 \addplot[black,mark=square*,mark options={fill=white}] table {re3.data}; |
118 \end{axis} |
119 \end{axis} |
119 \end{tikzpicture} |
120 \end{tikzpicture} |
120 \end{tabular} |
121 \end{tabular} |
121 \end{center} |
122 \end{center} |
122 \medskip |
123 \bigskip |
123 |
124 |
124 \noindent |
125 \noindent |
125 We will use these regular expressions and strings as running |
126 In what follows we will use these regular expressions and strings as |
126 examples. There will be several versions (V1, V2, V3,\ldots) of the |
127 running examples. There will be several versions (V1, V2, V3,\ldots) |
127 algorithm.\footnote{The corresponding files are \texttt{re1.scala}, |
128 of our matcher.\footnote{The corresponding files are |
128 \texttt{re2.scala} and so on. As usual, you can find the code on |
129 \texttt{re1.scala}, \texttt{re2.scala} and so on. As usual, you can |
129 KEATS.}\bigskip |
130 find the code on KEATS.}\bigskip |
130 |
131 |
131 \noindent |
132 \noindent |
132 Having specified in the previous lecture what |
133 Having specified in the previous lecture what |
133 problem our regular expression matcher is supposed to solve, |
134 problem our regular expression matcher is supposed to solve, |
134 namely for any given regular expression $r$ and string $s$ |
135 namely for any given regular expression $r$ and string $s$ |
136 |
137 |
137 \[ |
138 \[ |
138 s \in L(r) |
139 s \in L(r) |
139 \] |
140 \] |
140 |
141 |
141 \noindent we can look at an algorithm to solve this problem. Clearly |
142 \noindent we can look for an algorithm to solve this problem. Clearly |
142 we cannot use the function $L$ directly for this, because in general |
143 we cannot use the function $L$ directly for this, because in general |
143 the set of strings $L$ returns is infinite (recall what $L(a^*)$ is). |
144 the set of strings $L$ returns is infinite (recall what $L(a^*)$ is). |
144 In such cases there is no way we can implement an exhaustive test for |
145 In such cases there is no way we can implement an exhaustive test for |
145 whether a string is member of this set or not. In contrast our |
146 whether a string is member of this set or not. In contrast our |
146 matching algorithm will operate on the regular expression $r$ and |
147 matching algorithm will operate on the regular expression $r$ and |
235 (r_1 + \ZERO) \cdot \ONE + ((\ONE + r_2) + r_3) \cdot (r_4 \cdot \ZERO) |
236 (r_1 + \ZERO) \cdot \ONE + ((\ONE + r_2) + r_3) \cdot (r_4 \cdot \ZERO) |
236 \label{big} |
237 \label{big} |
237 \end{equation} |
238 \end{equation} |
238 |
239 |
239 \noindent If we can find an equivalent regular expression that is |
240 \noindent If we can find an equivalent regular expression that is |
240 simpler (smaller for example), then this might potentially make our |
241 simpler (that usually means smaller), then this might potentially make |
241 matching algorithm run faster. We can look for such a simpler regular |
242 our matching algorithm run faster. We can look for such a simpler |
242 expression $r'$ because whether a string $s$ is in $L(r)$ or in |
243 regular expression $r'$ because whether a string $s$ is in $L(r)$ or |
243 $L(r')$ with $r\equiv r'$ will always give the same answer. In the |
244 in $L(r')$ with $r\equiv r'$ will always give the same answer. Yes? |
244 example above you will see that the regular expression is equivalent |
245 |
245 to just $r_1$. You can verify this by iteratively applying the |
246 In the example above you will see that the regular expression is |
246 simplification rules from above: |
247 equivalent to just $r_1$. You can verify this by iteratively applying |
|
248 the simplification rules from above: |
247 |
249 |
248 \begin{center} |
250 \begin{center} |
249 \begin{tabular}{ll} |
251 \begin{tabular}{ll} |
250 & $(r_1 + \ZERO) \cdot \ONE + ((\ONE + r_2) + r_3) \cdot |
252 & $(r_1 + \ZERO) \cdot \ONE + ((\ONE + r_2) + r_3) \cdot |
251 (\underline{r_4 \cdot \ZERO})$\smallskip\\ |
253 (\underline{r_4 \cdot \ZERO})$\smallskip\\ |
262 rule is applied. Our matching algorithm in the next section |
264 rule is applied. Our matching algorithm in the next section |
263 will often generate such ``useless'' $\ONE$s and |
265 will often generate such ``useless'' $\ONE$s and |
264 $\ZERO$s, therefore simplifying them away will make the |
266 $\ZERO$s, therefore simplifying them away will make the |
265 algorithm quite a bit faster. |
267 algorithm quite a bit faster. |
266 |
268 |
267 Finally here are three equivalences between regulare expressions which are |
269 Finally here are three equivalences between regular expressions which are |
268 not so obvious: |
270 not so obvious: |
269 |
271 |
270 \begin{center} |
272 \begin{center} |
271 \begin{tabular}{rcl} |
273 \begin{tabular}{rcl} |
272 $r^*$ & $\equiv$ & $1 + r\cdot r^*$\\ |
274 $r^*$ & $\equiv$ & $1 + r\cdot r^*$\\ |
274 $(r_1 \cdot r_2)^*$ & $\equiv$ & $1 + r_1\cdot (r_2 \cdot r_1)^* \cdot r_2$\\ |
276 $(r_1 \cdot r_2)^*$ & $\equiv$ & $1 + r_1\cdot (r_2 \cdot r_1)^* \cdot r_2$\\ |
275 \end{tabular} |
277 \end{tabular} |
276 \end{center} |
278 \end{center} |
277 |
279 |
278 \noindent |
280 \noindent |
279 You can try to establish them. As an aside, there has been a lot of research |
281 We will not use them in our algorithm, but feel free to make sure they |
280 in questions like: Can one always decide when two regular expressions are |
282 hold. As an aside, there has been a lot of research about questions |
281 equivalent or not? What does an algorithm look like to decide this? |
283 like: Can one always decide when two regular expressions are |
|
284 equivalent or not? What does an algorithm look like to decide this |
|
285 efficiently? |
282 |
286 |
283 \subsection*{The Matching Algorithm} |
287 \subsection*{The Matching Algorithm} |
284 |
288 |
285 The algorithm we will define below consists of two parts. One |
289 The algorithm we will define below consists of two parts. One |
286 is the function $\textit{nullable}$ which takes a regular expression as |
290 is the function $\textit{nullable}$ which takes a regular expression as |
313 |
317 |
314 The other function of our matching algorithm calculates a |
318 The other function of our matching algorithm calculates a |
315 \emph{derivative} of a regular expression. This is a function |
319 \emph{derivative} of a regular expression. This is a function |
316 which will take a regular expression, say $r$, and a |
320 which will take a regular expression, say $r$, and a |
317 character, say $c$, as arguments and returns a new regular |
321 character, say $c$, as arguments and returns a new regular |
318 expression. Be careful that the intuition behind this function |
322 expression. Be mindful that the intuition behind this function |
319 is not so easy to grasp on first reading. Essentially this |
323 is not so easy to grasp on first reading. Essentially this |
320 function solves the following problem: if $r$ can match a |
324 function solves the following problem: if $r$ can match a |
321 string of the form $c\!::\!s$, what does the regular |
325 string of the form $c\!::\!s$, what does a regular |
322 expression look like that can match just $s$? The definition |
326 expression look like that can match just $s$? The definition |
323 of this function is as follows: |
327 of this function is as follows: |
324 |
328 |
325 \begin{center} |
329 \begin{center} |
326 \begin{tabular}{l@ {\hspace{2mm}}c@ {\hspace{2mm}}l} |
330 \begin{tabular}{l@ {\hspace{2mm}}c@ {\hspace{2mm}}l} |
370 $c\!::\!s$, then the first part must be ``matched'' by a |
374 $c\!::\!s$, then the first part must be ``matched'' by a |
371 single copy of $r$. Therefore we call recursively $\textit{der}\,c\,r$ |
375 single copy of $r$. Therefore we call recursively $\textit{der}\,c\,r$ |
372 and ``append'' $r^*$ in order to match the rest of $s$. Still |
376 and ``append'' $r^*$ in order to match the rest of $s$. Still |
373 makes sense? |
377 makes sense? |
374 |
378 |
375 If all this did not make sense yet, here is another way to rationalise |
379 If all this did not make sense yet, here is another way to explain the |
376 the definition of $\textit{der}$ by considering the following operation |
380 definition of $\textit{der}$ by considering the following operation on |
377 on sets: |
381 sets: |
378 |
382 |
379 \begin{equation}\label{Der} |
383 \begin{equation}\label{Der} |
380 \textit{Der}\,c\,A\;\dn\;\{s\,|\,c\!::\!s \in A\} |
384 \textit{Der}\,c\,A\;\dn\;\{s\,|\,c\!::\!s \in A\} |
381 \end{equation} |
385 \end{equation} |
382 |
386 |
452 $\textit{ders}\, (c\!::\!s)\, r$ & $\dn$ & $\textit{ders}\,s\,(\textit{der}\,c\,r)$ & \\ |
456 $\textit{ders}\, (c\!::\!s)\, r$ & $\dn$ & $\textit{ders}\,s\,(\textit{der}\,c\,r)$ & \\ |
453 \end{tabular} |
457 \end{tabular} |
454 \end{center} |
458 \end{center} |
455 |
459 |
456 \noindent This function iterates $\textit{der}$ taking one character at |
460 \noindent This function iterates $\textit{der}$ taking one character at |
457 the time from the original string until it is exhausted. |
461 the time from the original string until the string is exhausted. |
458 Having $\textit{der}s$ in place, we can finally define our matching |
462 Having $\textit{der}s$ in place, we can finally define our matching |
459 algorithm: |
463 algorithm: |
460 |
464 |
461 \[ |
465 \[ |
462 \textit{matches}\,s\,r \dn \textit{nullable}(\textit{ders}\,s\,r) |
466 \textit{matches}\,s\,r \dn \textit{nullable}(\textit{ders}\,s\,r) |
491 |
495 |
492 \begin{figure}[p] |
496 \begin{figure}[p] |
493 \lstinputlisting[numbers=left,linebackgroundcolor= |
497 \lstinputlisting[numbers=left,linebackgroundcolor= |
494 {\ifodd\value{lstnumber}\color{capri!3}\fi}] |
498 {\ifodd\value{lstnumber}\color{capri!3}\fi}] |
495 {../progs/app5.scala} |
499 {../progs/app5.scala} |
496 \caption{Scala implementation of the \textit{nullable} and |
500 \caption{A Scala implementation of the \textit{nullable} and |
497 derivative functions. These functions are easy to |
501 derivative functions. These functions are easy to |
498 implement in functional languages, because their built-in pattern |
502 implement in functional languages. This is because pattern |
499 matching and recursion allow us to mimic the mathematical |
503 matching and recursion allow us to mimic the mathematical |
500 definitions very closely.\label{scala1}} |
504 definitions very closely. Nearly all functional |
|
505 programming languages support pattern matching and |
|
506 recursion out of the box.\label{scala1}} |
501 \end{figure} |
507 \end{figure} |
502 |
508 |
503 |
509 |
504 %Remember our second example involving the regular expression |
510 %Remember our second example involving the regular expression |
505 %$(a^*)^* \cdot b$ which could not match strings of $n$ \texttt{a}s. |
511 %$(a^*)^* \cdot b$ which could not match strings of $n$ \texttt{a}s. |
536 %strings up to the length of 6500. After that we receive a |
542 %strings up to the length of 6500. After that we receive a |
537 %StackOverflow exception, but still\ldots |
543 %StackOverflow exception, but still\ldots |
538 |
544 |
539 For running the algorithm with our first example, the evil |
545 For running the algorithm with our first example, the evil |
540 regular expression $a^?{}^{\{n\}}a^{\{n\}}$, we need to implement |
546 regular expression $a^?{}^{\{n\}}a^{\{n\}}$, we need to implement |
541 the optional regular expression and the exactly $n$-times |
547 the optional regular expression and the `exactly $n$-times |
542 regular expression. This can be done with the translations |
548 regular expression'. This can be done with the translations |
543 |
549 |
544 \lstinputlisting[numbers=none]{../progs/app51.scala} |
550 \lstinputlisting[numbers=none]{../progs/app51.scala} |
545 |
551 |
546 \noindent Running the matcher with this example, we find it is |
552 \noindent Running the matcher with this example, we find it is |
547 slightly worse then the matcher in Ruby and Python. |
553 slightly worse then the matcher in Ruby and Python. |
589 \noindent Our algorithm traverses such regular expressions at |
595 \noindent Our algorithm traverses such regular expressions at |
590 least once every time a derivative is calculated. So having |
596 least once every time a derivative is calculated. So having |
591 large regular expressions will cause problems. This problem |
597 large regular expressions will cause problems. This problem |
592 is aggravated by $a^?$ being represented as $a + \ONE$. |
598 is aggravated by $a^?$ being represented as $a + \ONE$. |
593 |
599 |
594 We can however fix this by having an explicit constructor for |
600 We can however fix this easily by having an explicit constructor for |
595 $r^{\{n\}}$. In Scala we would introduce a constructor like |
601 $r^{\{n\}}$. In Scala we would introduce a constructor like |
596 |
602 |
597 \begin{center} |
603 \begin{center} |
598 \code{case class NTIMES(r: Rexp, n: Int) extends Rexp} |
604 \code{case class NTIMES(r: Rexp, n: Int) extends Rexp} |
599 \end{center} |
605 \end{center} |
632 |
638 |
633 \noindent Now we are talking business! The modified matcher can within |
639 \noindent Now we are talking business! The modified matcher can within |
634 25 seconds handle regular expressions up to $n = 1,100$ before a |
640 25 seconds handle regular expressions up to $n = 1,100$ before a |
635 StackOverflow is raised. Recall that Python and Ruby (and our first |
641 StackOverflow is raised. Recall that Python and Ruby (and our first |
636 version, Scala V1) could only handle $n = 27$ or so in 30 |
642 version, Scala V1) could only handle $n = 27$ or so in 30 |
637 seconds. There is no change for our second example $(a^*)^* \cdot |
643 seconds. We have not tried our algorithm on the second example $(a^*)^* \cdot |
638 b$---so this is still good. |
644 b$---but it is doing OK with it. |
639 |
645 |
640 |
646 |
641 The moral is that our algorithm is rather sensitive to the |
647 The moral is that our algorithm is rather sensitive to the |
642 size of regular expressions it needs to handle. This is of |
648 size of regular expressions it needs to handle. This is of |
643 course obvious because both $\textit{nullable}$ and $\textit{der}$ frequently |
649 course obvious because both $\textit{nullable}$ and $\textit{der}$ frequently |
654 $\textit{der}\,c\,r = ((\ZERO \cdot b) + \ZERO)\cdot r$ |
660 $\textit{der}\,c\,r = ((\ZERO \cdot b) + \ZERO)\cdot r$ |
655 \end{tabular} |
661 \end{tabular} |
656 \end{center} |
662 \end{center} |
657 |
663 |
658 \noindent |
664 \noindent |
659 If we simplify them according to the simple rules from the |
665 If we simplify them according to the simplification rules from the |
660 beginning, we can replace the right-hand sides by the |
666 beginning, we can replace the right-hand sides by the smaller |
661 smaller equivalent regular expressions |
667 equivalent regular expressions |
662 |
668 |
663 \begin{center} |
669 \begin{center} |
664 \begin{tabular}{l} |
670 \begin{tabular}{l} |
665 $\textit{der}\,a\,r \equiv b \cdot r$\\ |
671 $\textit{der}\,a\,r \equiv b \cdot r$\\ |
666 $\textit{der}\,b\,r \equiv r$\\ |
672 $\textit{der}\,b\,r \equiv r$\\ |
724 string of 28 \texttt{a}s and the regular expression $a^{?\{n\}} \cdot |
730 string of 28 \texttt{a}s and the regular expression $a^{?\{n\}} \cdot |
725 a^{\{n\}}$. We need a third of this time to do the same with strings |
731 a^{\{n\}}$. We need a third of this time to do the same with strings |
726 up to 11,000 \texttt{a}s. Similarly, Java and Python needed 30 |
732 up to 11,000 \texttt{a}s. Similarly, Java and Python needed 30 |
727 seconds to find out the regular expression $(a^*)^* \cdot b$ does not |
733 seconds to find out the regular expression $(a^*)^* \cdot b$ does not |
728 match the string of 28 \texttt{a}s. We can do the same in |
734 match the string of 28 \texttt{a}s. We can do the same in |
729 for strings of 6,000,000 \texttt{a}s: |
735 for strings composed of nearly 6,000,000 \texttt{a}s: |
730 |
736 |
731 |
737 |
732 \begin{center} |
738 \begin{center} |
733 \begin{tikzpicture} |
739 \begin{tikzpicture} |
734 \begin{axis}[ |
740 \begin{axis}[ |
753 \end{tikzpicture} |
759 \end{tikzpicture} |
754 \end{center} |
760 \end{center} |
755 |
761 |
756 \subsection*{Epilogue} |
762 \subsection*{Epilogue} |
757 |
763 |
758 (23/Aug/2016) I recently found another place where this algorithm can be |
764 (23/Aug/2016) I recently found another place where this algorithm can |
759 sped up (this idea is not integrated with what is coming next, |
765 be sped up (this idea is not integrated with what is coming next, but |
760 but I present it nonetheless). The idea is to define \texttt{ders} |
766 I present it nonetheless). The idea is to not define \texttt{ders} |
761 not such that it iterates the derivative character-by-character, but |
767 that it iterates the derivative character-by-character, but in bigger |
762 in bigger chunks. The resulting code for \texttt{ders2} looks as |
768 chunks. The resulting code for \texttt{ders2} looks as follows: |
763 follows: |
|
764 |
769 |
765 \lstinputlisting[numbers=none]{../progs/app52.scala} |
770 \lstinputlisting[numbers=none]{../progs/app52.scala} |
766 |
771 |
767 \noindent |
772 \noindent |
768 I have not fully understood why this version is much faster, |
773 I have not fully understood why this version is much faster, |
788 xmax=7100000, |
793 xmax=7100000, |
789 ytick={0,5,...,30}, |
794 ytick={0,5,...,30}, |
790 ymax=33, |
795 ymax=33, |
791 %scaled ticks=false, |
796 %scaled ticks=false, |
792 axis lines=left, |
797 axis lines=left, |
793 width=5.5cm, |
798 width=5.3cm, |
794 height=5cm, |
799 height=5cm, |
795 legend entries={Scala V3, Scala V4}, |
800 legend entries={Scala V3, Scala V4}, |
796 legend style={at={(0.1,-0.2)},anchor=north}] |
801 legend style={at={(0.1,-0.2)},anchor=north}] |
797 \addplot[black,mark=square*,mark options={fill=white}] table {re3.data}; |
802 \addplot[black,mark=square*,mark options={fill=white}] table {re3.data}; |
798 \addplot[purple,mark=square*,mark options={fill=white}] table {re4.data}; |
803 \addplot[purple,mark=square*,mark options={fill=white}] table {re4.data}; |
804 title={Graph: $(a^*)^* \cdot b$ and strings $\underbrace{a\ldots a}_{n}$}, |
809 title={Graph: $(a^*)^* \cdot b$ and strings $\underbrace{a\ldots a}_{n}$}, |
805 xlabel={$n$}, |
810 xlabel={$n$}, |
806 x label style={at={(1.09,0.0)}}, |
811 x label style={at={(1.09,0.0)}}, |
807 ylabel={time in secs}, |
812 ylabel={time in secs}, |
808 enlargelimits=false, |
813 enlargelimits=false, |
809 xmax=8100000, |
814 xmax=8200000, |
810 ytick={0,5,...,30}, |
815 ytick={0,5,...,30}, |
811 ymax=33, |
816 ymax=33, |
812 %scaled ticks=false, |
817 %scaled ticks=false, |
813 axis lines=left, |
818 axis lines=left, |
814 width=5.5cm, |
819 width=5.3cm, |
815 height=5cm, |
820 height=5cm, |
816 legend entries={Scala V3, Scala V4}, |
821 legend entries={Scala V3, Scala V4}, |
817 legend style={at={(0.1,-0.2)},anchor=north}] |
822 legend style={at={(0.1,-0.2)},anchor=north}] |
818 \addplot[black,mark=square*,mark options={fill=white}] table {re3a.data}; |
823 \addplot[black,mark=square*,mark options={fill=white}] table {re3a.data}; |
819 \addplot[purple,mark=square*,mark options={fill=white}] table {re4a.data}; |
824 \addplot[purple,mark=square*,mark options={fill=white}] table {re4a.data}; |
825 |
830 |
826 \section*{Proofs} |
831 \section*{Proofs} |
827 |
832 |
828 You might not like doing proofs. But they serve a very |
833 You might not like doing proofs. But they serve a very |
829 important purpose in Computer Science: How can we be sure that |
834 important purpose in Computer Science: How can we be sure that |
830 our algorithm matches its specification. We can try to test |
835 our algorithm matches its specification? We can try to test |
831 the algorithm, but that often overlooks corner cases and an |
836 the algorithm, but that often overlooks corner cases and an |
832 exhaustive testing is impossible (since there are infinitely |
837 exhaustive testing is impossible (since there are infinitely |
833 many inputs). Proofs allow us to ensure that an algorithm |
838 many inputs). Proofs allow us to ensure that an algorithm |
834 really meets its specification. |
839 really meets its specification. |
835 |
840 |
846 & $\mid$ & $r_1 \cdot r_2$ & sequence\\ |
851 & $\mid$ & $r_1 \cdot r_2$ & sequence\\ |
847 & $\mid$ & $r^*$ & star (zero or more)\\ |
852 & $\mid$ & $r^*$ & star (zero or more)\\ |
848 \end{tabular} |
853 \end{tabular} |
849 \end{center} |
854 \end{center} |
850 |
855 |
851 \noindent If you want to show a property $P(r)$ for all |
856 \noindent If you want to show a property $P(r)$ for \emph{all} |
852 regular expressions $r$, then you have to follow essentially |
857 regular expressions $r$, then you have to follow essentially |
853 the recipe: |
858 the recipe: |
854 |
859 |
855 \begin{itemize} |
860 \begin{itemize} |
856 \item $P$ has to hold for $\ZERO$, $\ONE$ and $c$ |
861 \item $P$ has to hold for $\ZERO$, $\ONE$ and $c$ |
898 \textit{nullable}(r_1 + r_2) \;\;\text{if and only if}\;\; |
903 \textit{nullable}(r_1 + r_2) \;\;\text{if and only if}\;\; |
899 []\in L(r_1 + r_2) |
904 []\in L(r_1 + r_2) |
900 \label{propalt} |
905 \label{propalt} |
901 \end{equation} |
906 \end{equation} |
902 |
907 |
903 \noindent The difference to the base cases is that in this |
908 \noindent The difference to the base cases is that in the inductive |
904 case we can already assume we proved |
909 cases we can already assume we proved $P$ for the components, that is |
|
910 we can assume. |
905 |
911 |
906 \begin{center} |
912 \begin{center} |
907 \begin{tabular}{l} |
913 \begin{tabular}{l} |
908 $\textit{nullable}(r_1) \;\;\text{if and only if}\;\; []\in L(r_1)$ and\\ |
914 $\textit{nullable}(r_1) \;\;\text{if and only if}\;\; []\in L(r_1)$ and\\ |
909 $\textit{nullable}(r_2) \;\;\text{if and only if}\;\; []\in L(r_2)$\\ |
915 $\textit{nullable}(r_2) \;\;\text{if and only if}\;\; []\in L(r_2)$\\ |
910 \end{tabular} |
916 \end{tabular} |
911 \end{center} |
917 \end{center} |
912 |
918 |
913 \noindent These are the induction hypotheses. To check this |
919 \noindent These are called the induction hypotheses. To check this |
914 case, we can start from $\textit{nullable}(r_1 + r_2)$, which by |
920 case, we can start from $\textit{nullable}(r_1 + r_2)$, which by |
915 definition is |
921 definition of $\textit{nullable}$ is |
916 |
922 |
917 \[ |
923 \[ |
918 \textit{nullable}(r_1) \vee \textit{nullable}(r_2) |
924 \textit{nullable}(r_1) \vee \textit{nullable}(r_2) |
919 \] |
925 \] |
920 |
926 |
933 |
939 |
934 \[ |
940 \[ |
935 [] \in L(r_1)\cup L(r_2) |
941 [] \in L(r_1)\cup L(r_2) |
936 \] |
942 \] |
937 |
943 |
938 \noindent but this is by definition of $L$ exactly $[] \in |
944 \noindent but this is by definition of $L$ exactly $[] \in L(r_1 + |
939 L(r_1 + r_2)$, which we needed to establish according to |
945 r_2)$, which we needed to establish according to statement in |
940 \eqref{propalt}. What we have shown is that starting from |
946 \eqref{propalt}. What we have shown is that starting from |
941 $\textit{nullable}(r_1 + r_2)$ we have done equivalent transformations |
947 $\textit{nullable}(r_1 + r_2)$ we have done equivalent transformations |
942 to end up with $[] \in L(r_1 + r_2)$. Consequently we have |
948 to end up with $[] \in L(r_1 + r_2)$. Consequently we have established |
943 established that $P(r_1 + r_2)$ holds. |
949 that $P(r_1 + r_2)$ holds. |
944 |
950 |
945 In order to complete the proof we would now need to look |
951 In order to complete the proof we would now need to look |
946 at the cases \mbox{$P(r_1\cdot r_2)$} and $P(r^*)$. Again I let you |
952 at the cases \mbox{$P(r_1\cdot r_2)$} and $P(r^*)$. Again I let you |
947 check the details. |
953 check the details. |
948 |
954 |
949 You might have to do induction proofs over strings. |
955 You might also have to do induction proofs over strings. |
950 That means you want to establish a property $P(s)$ for all |
956 That means you want to establish a property $P(s)$ for all |
951 strings $s$. For this remember strings are lists of |
957 strings $s$. For this remember strings are lists of |
952 characters. These lists can be either the empty list or a |
958 characters. These lists can be either the empty list or a |
953 list of the form $c::s$. If you want to perform an induction |
959 list of the form $c::s$. If you want to perform an induction |
954 proof for strings you need to consider the cases |
960 proof for strings you need to consider the cases |
980 |
986 |
981 \[ |
987 \[ |
982 L(\textit{der}\,c\,r) = \textit{Der}\,c\,(L(r)) |
988 L(\textit{der}\,c\,r) = \textit{Der}\,c\,(L(r)) |
983 \] |
989 \] |
984 |
990 |
985 \noindent holds (this would be of course a property that |
991 \noindent holds (this would be of course another property that needs |
986 needs to be proved in a side-lemma by induction on $r$). |
992 to be proved in a side-lemma by induction on $r$). This is a bit |
|
993 more challenging, but not impossible. |
987 |
994 |
988 To sum up, using reasoning like the one shown above allows us |
995 To sum up, using reasoning like the one shown above allows us |
989 to show the correctness of our algorithm. To see this, |
996 to show the correctness of our algorithm. To see this, |
990 start from the specification |
997 start from the specification |
991 |
998 |
1000 \begin{equation} |
1007 \begin{equation} |
1001 [] \in \textit{Ders}\,s\,(L(r)) |
1008 [] \in \textit{Ders}\,s\,(L(r)) |
1002 \label{dersstep} |
1009 \label{dersstep} |
1003 \end{equation} |
1010 \end{equation} |
1004 |
1011 |
1005 \noindent But we have shown above in \eqref{dersprop}, that |
1012 \noindent You agree? But we have shown above in \eqref{dersprop}, |
1006 the $\textit{Ders}$ can be replaced by $L(\textit{ders}\ldots)$. That means |
1013 that the $\textit{Ders}$ can be replaced by |
1007 \eqref{dersstep} is equivalent to |
1014 $L(\textit{ders}\ldots)$. That means \eqref{dersstep} is equivalent to |
1008 |
1015 |
1009 \begin{equation} |
1016 \begin{equation} |
1010 [] \in L(\textit{ders}\,s\,r) |
1017 [] \in L(\textit{ders}\,s\,r) |
1011 \label{prefinalstep} |
1018 \label{prefinalstep} |
1012 \end{equation} |
1019 \end{equation} |
1031 \[ |
1038 \[ |
1032 matches\,s\,r\;\;\text{if and only if}\;\; |
1039 matches\,s\,r\;\;\text{if and only if}\;\; |
1033 s\in L(r) |
1040 s\in L(r) |
1034 \] |
1041 \] |
1035 |
1042 |
1036 \noindent which is the property we set out to prove: |
1043 \noindent which is the property we set out to prove: our algorithm |
1037 our algorithm meets its specification. To have done |
1044 meets its specification. To have done so, requires a few induction |
1038 so, requires a few induction proofs about strings and |
1045 proofs about strings and regular expressions. Following the \emph{induction |
1039 regular expressions. Following the recipes is already a big |
1046 recipes} is already a big step in actually performing these proofs. |
1040 step in performing these proofs. |
1047 If you do not believe it, proofs have helped me to make sure my code |
|
1048 is correct and in several instances prevented me of letting slip |
|
1049 embarassing mistakes into the `wild'. |
1041 |
1050 |
1042 \end{document} |
1051 \end{document} |
1043 |
1052 |
1044 |
1053 |
1045 |
1054 |