Semantyka i weryfikacja programów/Ćwiczenia 2: Różnice pomiędzy wersjami

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Sl (dyskusja | edycje)
Nie podano opisu zmian
m Zastępowanie tekstu – „.↵</math>” na „</math>”
 
(Nie pokazano 6 wersji utworzonych przez 2 użytkowników)
Linia 1: Linia 1:


== Zawartość ==
== Zawartość ==
Linia 23: Linia 22:




{{rozwiazanie||roz1|
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
 
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie</span>
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">


Przypomnijmy składnię wyrażeń boolowskich i arytmetycznych:
Przypomnijmy składnię wyrażeń boolowskich i arytmetycznych:
Linia 62: Linia 61:


<math>
<math>
e, s \,\Longrightarrow\, e', s
e, s \,\Longrightarrow, e', s
</math>
</math>


Linia 68: Linia 67:


<math>
<math>
b, s \,\Longrightarrow\, b', s
b, s \,\Longrightarrow, b', s
</math>
</math>


Linia 75: Linia 74:


<math>
<math>
e, s \,\Longrightarrow\, n
e, s \,\Longrightarrow, n
\quad \quad
\quad \quad
\mbox{ oraz }
\mbox{ oraz }
\quad \quad
\quad \quad
b, s \,\Longrightarrow\, l
b, s \,\Longrightarrow, l
</math>
</math>
gdzie <math>n \in</math> jest liczbą całkowitą, <math>n \in \mathbf{Num}</math>, a <math>l \in \mathbf{Bool} = \{ \mathbf{true}, \mathbf{false} \}</math>.
gdzie <math>n \in</math> jest liczbą całkowitą, <math>n \in \mathbf{Num}</math>, a <math>l \in \mathbf{Bool} = \{ \mathbf{true}, \mathbf{false} \}</math>.
Linia 89: Linia 88:
</math>
</math>


a konfiguracje końcowe to <math>\mathbf{State}</math>; aczkolwiek konfiguracje ze zbioru <math>\mathbf{Num} \, \cup \, \mathbf{Bool}</math> pełnią podobną rolę dla wyrażeń arytmetycznych i boolowskich jako konfiguracje końcowe dla instrukcji.
a konfiguracje końcowe to <math>\mathbf{State}</math>, aczkolwiek konfiguracje ze zbioru <math>\mathbf{Num} \, \cup \, \mathbf{Bool}</math> pełnią podobną rolę dla wyrażeń arytmetycznych i boolowskich jako konfiguracje końcowe dla instrukcji.
Przypomnijmy, że <math>\mathbf{Stmt}</math>  oznacza zbiór instrukcji, <math>I \in \mathbf{Stmt}</math>.
Przypomnijmy, że <math>\mathbf{Stmt}</math>  oznacza zbiór instrukcji, <math>I \in \mathbf{Stmt}</math>.


Linia 95: Linia 94:


<math>
<math>
l, s \,\Longrightarrow\, l
l, s \,\Longrightarrow, l
\quad \quad
\quad \quad
n, s \,\Longrightarrow\, n.
n, s \,\Longrightarrow, n</math>
</math>


Podobnie jak poprzednio, zakładamy tutaj dla wygody, że <math>\mathbf{Num} \subseteq \mathbf{Exp}</math> oraz <math>\mathbf{Bool} \subseteq \mathbf{BExp}</math>.
Podobnie jak poprzednio, zakładamy tutaj dla wygody, że <math>\mathbf{Num} \subseteq \mathbf{Exp}</math> oraz <math>\mathbf{Bool} \subseteq \mathbf{BExp}</math>.
Pozwala nam to nie odróżniać stałych występujących w wyrażeniach a zatem pojawiających się po lewej stonie tranzycji od wartości im odpowiadających pojawiających się po prawej stronie.
Pozwala nam to nie odróżniać stałych występujących w wyrażeniach, a zatem pojawiających się po lewej stonie tranzycji od wartości im odpowiadających, pojawiających się po prawej stronie.


Przejdźmy do spójników logicznych, powiedzmy <math>b_1 \land b_2</math>.
Przejdźmy do spójników logicznych, powiedzmy <math>b_1 \land b_2</math>.
Linia 107: Linia 105:


<math>
<math>
\frac{b_1, s \,\Longrightarrow\, b'_1, s}
\frac{b_1, s \,\Longrightarrow, b'_1, s}
{b_1 \land b_2, s \,\Longrightarrow\, b'_1 \land b_2, s}
{b_1 \land b_2, s \,\Longrightarrow, b'_1 \land b_2, s}
\quad \quad
\quad \quad
\frac{b_2, s \,\Longrightarrow\, b'_2, s}
\frac{b_2, s \,\Longrightarrow, b'_2, s}
{l_1 \land b_2, s \,\Longrightarrow\, l_1 \land b_2, s}
{l_1 \land b_2, s \,\Longrightarrow, l_1 \land b_2, s}
\quad \quad
\quad \quad
l_1 \land l_2, s \,\Longrightarrow\, l, s   
l_1 \land l_2, s \,\Longrightarrow, l, s   
\mbox{ o ile } l = l_1 \land l_2  
\mbox{ o ile } l = l_1 \land l_2  
</math>
</math>
Linia 121: Linia 119:


<math>
<math>
\frac{b_1, s \,\Longrightarrow\, b'_1, s}
\frac{b_1, s \,\Longrightarrow, b'_1, s}
{b_1 \land b_2, s \,\Longrightarrow\, b'_1 \land b_2, s}
{b_1 \land b_2, s \,\Longrightarrow, b'_1 \land b_2, s}
\quad \quad
\quad \quad
\mathbf{false} \land b_2, s \,\Longrightarrow\, \mathbf{false}, s
\mathbf{false} \land b_2, s \,\Longrightarrow, \mathbf{false}, s
\quad \quad
\quad \quad
\mathbf{true}  \land b_2, s \,\Longrightarrow\, b_2, s.
\mathbf{true}  \land b_2, s \,\Longrightarrow, b_2, s</math>
</math>


Analogicznie reguły prawostronne to:
Analogicznie reguły prawostronne to:


<math>
<math>
\frac{b_2, s \,\Longrightarrow\, b'_2, s}
\frac{b_2, s \,\Longrightarrow, b'_2, s}
{b_1 \land b_2, s \,\Longrightarrow\, b_1 \land b'_2, s}
{b_1 \land b_2, s \,\Longrightarrow, b_1 \land b'_2, s}
\quad \quad
\quad \quad
b_1 \land \mathbf{false}, s \,\Longrightarrow\, \mathbf{false}, s
b_1 \land \mathbf{false}, s \,\Longrightarrow, \mathbf{false}, s
\quad \quad
\quad \quad
b_1 \land \mathbf{true}, s \,\Longrightarrow\, b_1, s.
b_1 \land \mathbf{true}, s \,\Longrightarrow, b_1, s</math>
</math>


Reguły ''równoległe'' otrzymujemy jako sumę reguł lewo- i prawostronnych (w sumie 6 reguł). Zauważmy, że obliczanie wyrażeń <math>b_1</math> i <math>b_2</math> odbywa się teraz w tzw. ,,przeplocie": Pojedynczy krok polega na wykonaniu jednego kroku obliczenia <math>b_1</math> albo jednego kroku obliczenia <math>b_2</math>.
Reguły ''równoległe'' otrzymujemy jako sumę reguł lewo- i prawostronnych (w sumie 6 reguł). Zauważmy, że obliczanie wyrażeń <math>b_1</math> i <math>b_2</math> odbywa się teraz w tzw. "przeplocie": Pojedynczy krok polega na wykonaniu jednego kroku obliczenia <math>b_1</math> albo jednego kroku obliczenia <math>b_2</math>.
Zwróćmy też uwagę, że nasze tranzycje nie posiadają teraz własności ''determinizmu'': wyrażenie <math>b_1 \land b_2</math> może wyewoluować w pojedyńczym kroku albo do <math>b'_1 \land b_2</math> albo do <math>b_1 \land b'_2</math>.
Zwróćmy też uwagę, że nasze tranzycje nie posiadają teraz własności ''determinizmu'': wyrażenie <math>b_1 \land b_2</math> może wyewoluować w pojedyńczym kroku albo do <math>b'_1 \land b_2</math> albo do <math>b_1 \land b'_2</math>.
Na szczęście końcowy wynik, do jakiego oblicza się wyrażenie jest zawsze taki sam, niezależnie od przeplotu.
Na szczęście końcowy wynik, do jakiego oblicza się wyrażenie, jest zawsze taki sam, niezależnie od przeplotu.


Oto reguły dla negacji:
Oto reguły dla negacji:


<math>
<math>
\neg \mathbf{true}, s \,\Longrightarrow\, \mathbf{false}, s
\neg \mathbf{true}, s \,\Longrightarrow, \mathbf{false}, s
\quad \quad \quad
\quad \quad \quad
\neg \mathbf{false}, s \,\Longrightarrow\, \mathbf{true}, s  
\neg \mathbf{false}, s \,\Longrightarrow, \mathbf{true}, s  
\quad \quad \quad
\quad \quad \quad
\frac{b, s \,\Longrightarrow\, b', s}
\frac{b, s \,\Longrightarrow, b', s}
     {\neg b, s \,\Longrightarrow\, \neg b', s}
     {\neg b, s \,\Longrightarrow, \neg b', s}
</math>
</math>


Linia 158: Linia 154:


<math>
<math>
\frac{e_1, s \,\Longrightarrow\, e'_1, s}
\frac{e_1, s \,\Longrightarrow, e'_1, s}
{e_1 \leq e_2, s \,\Longrightarrow\, e'_1 \leq e_2, s}
{e_1 \leq e_2, s \,\Longrightarrow, e'_1 \leq e_2, s}
\quad \quad
\quad \quad
\frac{e_2, s \,\Longrightarrow\, e'_2, s}
\frac{e_2, s \,\Longrightarrow, e'_2, s}
{e_1 \leq e_2, s \,\Longrightarrow\, e_1 \leq e'_2, s}
{e_1 \leq e_2, s \,\Longrightarrow, e_1 \leq e'_2, s}
</math>
</math>


<math>
<math>
n_1 \leq n_2, s \,\Longrightarrow\, \mathbf{true}, s  \quad \mbox{ o ile } n_1 \leq n_2
n_1 \leq n_2, s \,\Longrightarrow, \mathbf{true}, s  \quad \mbox{ o ile } n_1 \leq n_2
\quad \quad
\quad \quad
n_1 \leq n_2, s \,\Longrightarrow\, \mathbf{false}, s  \quad  \mbox{ o ile } n_1 > n_2.
n_1 \leq n_2, s \,\Longrightarrow, \mathbf{false}, s  \quad  \mbox{ o ile } n_1 > n_2</math>
</math>


Reguły powyższe zależą od semantyki wyrażen arytmetycznych.
Reguły powyższe zależą od semantyki wyrażen arytmetycznych.
Zauważmy, że ponownie pozostawiliśmy dowolność jeśli chodzi o kolejność obliczania wyrażeń arytmetycznych <math>e_1</math> i <math>e_2</math>.
Zauważmy, że ponownie pozostawiliśmy dowolność, jeśli chodzi o kolejność obliczania wyrażeń arytmetycznych <math>e_1</math> i <math>e_2</math>.


Jako pierwszą z instrukcji rozważmy przypisanie.
Jako pierwszą z instrukcji rozważmy przypisanie.
Linia 178: Linia 173:


<math>
<math>
\frac{e, s \,\Longrightarrow\, e', s}
\frac{e, s \,\Longrightarrow, e', s}
     {x := e, s \,\Longrightarrow\, x := e', s}
     {x := e, s \,\Longrightarrow, x := e', s}
\quad \quad
\quad \quad
{x := n, s \,\Longrightarrow\, s[x \mapsto n]}
{x := n, s \,\Longrightarrow, s[x \mapsto n]}
</math>
</math>


Linia 188: Linia 183:


<math>
<math>
\frac{b, s \,\Longrightarrow\, b', s}
\frac{b, s \,\Longrightarrow, b', s}
{\mathbf{if}\, b \,\mathbf{then}\, I_1 \,\mathbf{else}\, I_2, s \,\Longrightarrow\,  
{\mathbf{if}\, b \,\mathbf{then}\, I_1 \,\mathbf{else}\, I_2, s \,\Longrightarrow,  
\mathbf{if}\, b' \,\mathbf{then}\, I_1 \,\mathbf{else}\, I_2, s}
\mathbf{if}\, b' \,\mathbf{then}\, I_1 \,\mathbf{else}\, I_2, s}
\quad \quad
\quad \quad
\frac{b, s \,\Longrightarrow\, b', s}
\frac{b, s \,\Longrightarrow, b', s}
{\mathbf{while}\, b \,\mathbf{do}\, I, s \,\Longrightarrow\, \mathbf{while}\, b' \,\mathbf{do}\, I, s}
{\mathbf{while}\, b \,\mathbf{do}\, I, s \,\Longrightarrow, \mathbf{while}\, b' \,\mathbf{do}\, I, s}
</math>
</math>


Linia 200: Linia 195:


<math>
<math>
\mathbf{if}\, \mathbf{true} \,\mathbf{then}\, I_1 \,\mathbf{else}\, I_2, s \,\Longrightarrow\, I_1, s
\mathbf{if}\, \mathbf{true} \,\mathbf{then}\, I_1 \,\mathbf{else}\, I_2, s \,\Longrightarrow, I_1, s
\quad \quad
\quad \quad
\mathbf{if}\, \mathbf{false} \,\mathbf{then}\, I_1 \,\mathbf{else}\, I_2, s \,\Longrightarrow\, I_2, s
\mathbf{if}\, \mathbf{false} \,\mathbf{then}\, I_1 \,\mathbf{else}\, I_2, s \,\Longrightarrow, I_2, s
</math>
</math>


Linia 208: Linia 203:


<math>
<math>
\mathbf{while}\, \mathbf{true} \,\mathbf{do}\, I, s \,\Longrightarrow\,  
\mathbf{while}\, \mathbf{true} \,\mathbf{do}\, I, s \,\Longrightarrow,  
I;\, \mathbf{while}\, ? \,\mathbf{do}\, I, s
I;\, \mathbf{while}\, ? \,\mathbf{do}\, I, s
</math>
</math>


ale nie wiemy już, jaki był dozór pętli (widzimy tylko wynik obliczenia tego dozoru w stanie s, czyli <math>\mathbf{true}</math>).
ale nie wiemy już, jaki był dozór pętli (widzimy tylko wynik obliczenia tego dozoru w stanie s, czyli <math>\mathbf{true}</math>).
Możemy odwołać się do tranzytywnego domknięcia relacji <math>\,\Longrightarrow\,</math> (czyli w zasadzie do semantyki dużych kroków):
Możemy odwołać się do tranzytywnego domknięcia relacji <math>\,\Longrightarrow</math>, (czyli w zasadzie do semantyki dużych kroków):


<math>
<math>
\frac{b, s \,\Longrightarrow\,^{*} \mathbf{true}}
\frac{b, s \,\Longrightarrow,^{*} \mathbf{true}}
{\mathbf{while}\, b \,\mathbf{do}\, I, s \,\Longrightarrow\,  
{\mathbf{while}\, b \,\mathbf{do}\, I, s \,\Longrightarrow,  
  I;\, \mathbf{while}\, b \,\mathbf{do}\, I, s}
  I;\, \mathbf{while}\, b \,\mathbf{do}\, I, s}
\quad \quad
\quad \quad
\frac{b, s \,\Longrightarrow\,^{*} \mathbf{false}}
\frac{b, s \,\Longrightarrow,^{*} \mathbf{false}}
{\mathbf{while}\, b \,\mathbf{do}\, I, s \,\Longrightarrow\, s}
{\mathbf{while}\, b \,\mathbf{do}\, I, s \,\Longrightarrow, s}
</math>
</math>


Istnieją inne możliwe rozwiązania w stylu małych kroków.
Istnieją inne możliwe rozwiązania w stylu małych kroków.
Jedno z nich oparte jest na pomyśle, aby ''rozwinąc'' pętlę <math>\mathbf{while}\,</math>, zanim obliczymy wartość dozoru <math>b</math>.
Jedno z nich oparte jest na pomyśle, aby "rozwinąć" pętlę <math>\mathbf{while}\ </math>, zanim obliczymy wartość dozoru <math>b</math>.
Jedyną reguła dla pętli <math>\mathbf{while}\,</math> byłaby wtedy reguła:
Jedyną reguła dla pętli <math>\mathbf{while}\ </math>, byłaby wtedy reguła:


<math>
<math>
\mathbf{while}\, b \,\mathbf{do}\, I, s \,\Longrightarrow\, \mathbf{if}\, b \,\mathbf{then}\, (I; \mathbf{while}\, b \,\mathbf{do}\, I) \,\mathbf{else}\, \mathbf{skip}, s.
\mathbf{while}\, b \,\mathbf{do}\, I, s \,\Longrightarrow, \mathbf{if}\, b \,\mathbf{then}\, (I; \mathbf{while}\, b \,\mathbf{do}\, I) \,\mathbf{else}\, \mathbf{skip}, s</math>
</math>


Dzięki temu obliczany warunek logiczny <math>b</math> jest zawsze ''jednorazowy''.
Dzięki temu obliczany warunek logiczny <math>b</math> jest zawsze ''jednorazowy''.
Linia 238: Linia 232:


</div></div>
</div></div>
}}
 




Linia 257: Linia 251:




{{rozwiazanie||roz2|


<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie</span>
<div class="mw-collapsible-content" style="display:none">


'''Instrukcja <math>\mathbf{repeat}\,</math>'''
'''Instrukcja <math>\mathbf{repeat}\ </math>,'''
<br>
<br>


Zacznijmy od pętli <math>\mathbf{repeat}\, I \,\mathbf{until}\, b</math>.
Zacznijmy od pętli <math>\mathbf{repeat}\, I \,\mathbf{until}\, b</math>.
Przyjrzyjmy się dwóm podejściom, które zastosowaliśmy dla pętli <math>\mathbf{while}\,</math> w poprzednim zadaniu.
Przyjrzyjmy się dwóm podejściom, które zastosowaliśmy dla pętli <math>\mathbf{while}\ </math>, w poprzednim zadaniu.
Po pierwsze rozwinięcie:
Po pierwsze, rozwinięcie:


<math>
<math>
\mathbf{repeat}\, I \,\mathbf{until}\, b, s \,\Longrightarrow\, I; \mathbf{if}\, b \,\mathbf{then}\, (\mathbf{repeat}\, I \,\mathbf{until}\, b) \,\mathbf{else}\, \mathbf{skip}, s.
\mathbf{repeat}\, I \,\mathbf{until}\, b, s \,\Longrightarrow, I; \mathbf{if}\, b \,\mathbf{then}\, (\mathbf{repeat}\, I \,\mathbf{until}\, b) \,\mathbf{else}\, \mathbf{skip}, s</math>
</math>


Po drugie, spróbujmy odwołać się do <math>\,\Longrightarrow\,^{*}</math> dla dozoru pętli <math>b</math>:
Po drugie, spróbujmy odwołać się do <math>\,\Longrightarrow,^{*}</math> dla dozoru pętli <math>b</math>:


<math>
<math>
\frac{I, s \,\Longrightarrow\, I', s'}
\frac{I, s \,\Longrightarrow, I', s'}
     {\mathbf{repeat}\, I \,\mathbf{until}\, b, s \,\Longrightarrow\, \mathbf{repeat}\, I' \,\mathbf{until}\, b, s'}
     {\mathbf{repeat}\, I \,\mathbf{until}\, b, s \,\Longrightarrow, \mathbf{repeat}\, I' \,\mathbf{until}\, b, s'}
</math>
</math>


<math>
<math>
\frac{I, s \,\Longrightarrow\, s' \quad b, s \,\Longrightarrow\,^{*} \mathbf{false}}
\frac{I, s \,\Longrightarrow, s' \quad b, s \,\Longrightarrow,^{*} \mathbf{false}}
     {\mathbf{repeat}\, I \,\mathbf{until}\, b, s \,\Longrightarrow\, s'}
     {\mathbf{repeat}\, I \,\mathbf{until}\, b, s \,\Longrightarrow, s'}
\quad \quad
\quad \quad
\frac{I, s \,\Longrightarrow\, s' \quad b, s \,\Longrightarrow\,^{*} \mathbf{true}}
\frac{I, s \,\Longrightarrow, s' \quad b, s \,\Longrightarrow,^{*} \mathbf{true}}
     {\mathbf{repeat}\, I \,\mathbf{until}\, b, s \,\Longrightarrow\, \mathbf{repeat}\, ? \,\mathbf{until}\, b, s'}
     {\mathbf{repeat}\, I \,\mathbf{until}\, b, s \,\Longrightarrow, \mathbf{repeat}\, ? \,\mathbf{until}\, b, s'}
</math>
</math>


Okazuje się, że jest jeszcze gorzej niż w przypadku pętli <math>\mathbf{while}\,</math>: nie pamiętamy już, jaka była instrukcja wewnętrzna naszej pętli!
Okazuje się, że jest jeszcze gorzej niż w przypadku pętli <math>\mathbf{while}\ </math>,: nie pamiętamy już, jaka była instrukcja wewnętrzna naszej pętli!
Czyli takie podejście jest teraz nieskuteczne.
Czyli takie podejście jest teraz nieskuteczne.


Linia 298: Linia 292:


<math>
<math>
\frac{e, s \,\Longrightarrow\, e', s}
\frac{e, s \,\Longrightarrow, e', s}
     {\,\mathbf{do}\, e \,\mathbf{times}\, I, s \,\Longrightarrow\, D e' \,\mathbf{times}\, I, s}
     {\,\mathbf{do}\, e \,\mathbf{times}\, I, s \,\Longrightarrow, D e' \,\mathbf{times}\, I, s}
</math>
</math>


Linia 305: Linia 299:


<math>
<math>
\,\mathbf{do}\, n \,\mathbf{times}\, I, s.
\,\mathbf{do}\, n \,\mathbf{times}\, I, s</math>
</math>


Teraz jest juz łatwo:
Teraz jest już łatwo:


<math>
<math>
\,\mathbf{do}\, n \,\mathbf{times}\, I, s \,\Longrightarrow\, I; \,\mathbf{do}\, n{-}1 \,\mathbf{times}\, I, s  
\,\mathbf{do}\, n \,\mathbf{times}\, I, s \,\Longrightarrow, I; \,\mathbf{do}\, n{-}1 \,\mathbf{times}\, I, s  
\quad \mbox{ o ile } n > 0
\quad \mbox{ o ile } n > 0
</math>
</math>


<math>
<math>
\,\mathbf{do}\, n \,\mathbf{times}\, I, s \,\Longrightarrow\, s  
\,\mathbf{do}\, n \,\mathbf{times}\, I, s \,\Longrightarrow, s  
\quad \mbox{ o ile } n = 0.
\quad \mbox{ o ile } n = 0</math>
</math>


<br>
<br>
'''Instrukcja <math>\mathbf{for}\,</math>'''
'''Instrukcja <math>\mathbf{for}\ </math>,'''
<br>
<br>


W przypadku pętli <math>\mathbf{for}\,</math> przyjmijmy, że wartości wyrażeń <math>e_1</math> i <math>e_2</math> obliczane są przed pierwszą iteracją pętli.  
W przypadku pętli <math>\mathbf{for}\ </math>, przyjmijmy, że wartości wyrażeń <math>e_1</math> i <math>e_2</math> obliczane są przed pierwszą iteracją pętli.  
Dodatkowo ustalmy, że np. <math>e_1</math> będzie obliczone jako pierwsze.
Dodatkowo ustalmy, że np. <math>e_1</math> będzie obliczone jako pierwsze.
Następnie podstawiamy wartość <math>e_1</math> na zmienną <math>x</math>.
Następnie podstawiamy wartość <math>e_1</math> na zmienną <math>x</math>.
Linia 330: Linia 322:


<math>
<math>
\frac{e_1, s \,\Longrightarrow\, e'_1, s}
\frac{e_1, s \,\Longrightarrow, e'_1, s}
     {\mathbf{for}\, x = e_1 \,\mathbf{to}\, e_2 \,\mathbf{do}\, I,s \,\Longrightarrow\, \mathbf{for}\, x = e'_1 \,\mathbf{to}\, e_2 \,\mathbf{do}\, I, s}
     {\mathbf{for}\, x = e_1 \,\mathbf{to}\, e_2 \,\mathbf{do}\, I,s \,\Longrightarrow, \mathbf{for}\, x = e'_1 \,\mathbf{to}\, e_2 \,\mathbf{do}\, I, s}
</math>
</math>


<math>
<math>
\frac{e_2, s \,\Longrightarrow\, e'_2, s}
\frac{e_2, s \,\Longrightarrow, e'_2, s}
     {\mathbf{for}\, x = n \,\mathbf{to}\, e_2 \,\mathbf{do}\, I,s \,\Longrightarrow\, \mathbf{for}\, x = n \,\mathbf{to}\, e'_2 \,\mathbf{do}\, I, s}
     {\mathbf{for}\, x = n \,\mathbf{to}\, e_2 \,\mathbf{do}\, I,s \,\Longrightarrow, \mathbf{for}\, x = n \,\mathbf{to}\, e'_2 \,\mathbf{do}\, I, s}
</math>
</math>


Linia 342: Linia 334:


<math>
<math>
\mathbf{for}\, x = n_1 \,\mathbf{to}\, n_2 \,\mathbf{do}\, I, s.
\mathbf{for}\, x = n_1 \,\mathbf{to}\, n_2 \,\mathbf{do}\, I, s</math>
</math>


Dalsze reguły mogą być podobne do reguł dla pętli <math>\,\mathbf{do}\, n \,\mathbf{times}\, I</math>:
Dalsze reguły mogą być podobne do reguł dla pętli <math>\,\mathbf{do}\, n \,\mathbf{times}\, I</math>:


<math>
<math>
\mathbf{for}\, x = n_1 \,\mathbf{to}\, n_2 \,\mathbf{do}\, I, s \,\Longrightarrow\, I; \mathbf{for}\, x = n_1+1 \,\mathbf{to}\, n_2 \,\mathbf{do}\, I, s[x \mapsto n_1]
\mathbf{for}\, x = n_1 \,\mathbf{to}\, n_2 \,\mathbf{do}\, I, s \,\Longrightarrow, I; \mathbf{for}\, x = n_1+1 \,\mathbf{to}\, n_2 \,\mathbf{do}\, I, s[x \mapsto n_1]
\quad \mbox{ o ile } n_1 \leq n_2
\quad \mbox{ o ile } n_1 \leq n_2
</math>
</math>


<math>
<math>
\mathbf{for}\, x = n_1 \,\mathbf{to}\, n_2 \,\mathbf{do}\, I, s \,\Longrightarrow\, s
\mathbf{for}\, x = n_1 \,\mathbf{to}\, n_2 \,\mathbf{do}\, I, s \,\Longrightarrow, s
\quad \mbox{ o ile } n_1 > n_2
\quad \mbox{ o ile } n_1 > n_2
</math>
</math>


Zauważmy, wartość zmiennej <math>x</math> po zakończeniu pętli wynosi albo <math>n_2</math> albo pozostaje niezmieniona, o ile nie była ona zmieniana wewnątrz instrukcji <math>I</math>.  
Zauważmy, wartość zmiennej <math>x</math> po zakończeniu pętli wynosi albo <math>n_2</math>, albo pozostaje niezmieniona, o ile nie była ona zmieniana wewnątrz instrukcji <math>I</math>.  
Ponieważ nie zostało wyspecyfikowane jaka powinna być wartość tej zmiennej, możemy taką semantykę uznać za poprawną.
Ponieważ nie zostało wyspecyfikowane, jaka powinna być wartość tej zmiennej, możemy taką semantykę uznać za poprawną.


'''Pytanie:''' oto inna wersja jednej z powyższych reguł:  
'''Pytanie:''' oto inna wersja jednej z powyższych reguł:  
<math>
<math>
\mathbf{for}\, x = n_1 \,\mathbf{to}\, n_2 \,\mathbf{do}\, I, s \,\Longrightarrow\, I; \mathbf{for}\, x = n_1+1 \,\mathbf{to}\, n_2 \,\mathbf{do}\, I, s[x \mapsto s(x)+1]
\mathbf{for}\, x = n_1 \,\mathbf{to}\, n_2 \,\mathbf{do}\, I, s \,\Longrightarrow, I; \mathbf{for}\, x = n_1+1 \,\mathbf{to}\, n_2 \,\mathbf{do}\, I, s[x \mapsto s(x)+1]
\quad \mbox{ o ile } s(x) \leq n_2.
\quad \mbox{ o ile } s(x) \leq n_2</math>
</math>
Czy semantyka jest taka sama?
Czy semantyka jest taka sama?
(Rozważ sytuację, gdy zmienna <math>x</math> jest zmieniana przez instrukcję <math>I</math>.)
(Rozważ sytuację, gdy zmienna <math>x</math> jest zmieniana przez instrukcję <math>I</math>.)
Linia 376: Linia 366:


<math>
<math>
\,\mathbf{do}\, I \,\mathbf{while}\, b, s \,\Longrightarrow\, \mathbf{repeat}\, I \,\mathbf{until}\, \neg b, s.
\,\mathbf{do}\, I \,\mathbf{while}\, b, s \,\Longrightarrow, \mathbf{repeat}\, I \,\mathbf{until}\, \neg b, s</math>
</math>


</div></div>
</div></div>
}}


== Kalkulator binarny ==
== Kalkulator binarny ==
Linia 403: Linia 390:




{{rozwiazanie||roz3|


<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie</span>
<div class="mw-collapsible-content" style="display:none">


Składnia wyrażeń pozwala na wygodny dostęp do najmniej znacząceg bitu liczby. Spróbujmy zatem zastosować metodę dodawania pisemnego:
Składnia wyrażeń pozwala na wygodny dostęp do najmniej znaczącego bitu liczby. Spróbujmy zatem zastosować metodę dodawania pisemnego:


<math>
<math>
e_1 0 + e_2 0 \,\Longrightarrow\, (e_1 + e_2) 0
e_1 0 + e_2 0 \,\Longrightarrow, (e_1 + e_2) 0
</math>
</math>


<math>
<math>
e_1 0 + e_2 1 \,\Longrightarrow\, (e_1 + e_2) 1
e_1 0 + e_2 1 \,\Longrightarrow, (e_1 + e_2) 1
</math>
</math>


<math>
<math>
e_1 1 + e_2 0 \,\Longrightarrow\, (e_1 + e_2) 1
e_1 1 + e_2 0 \,\Longrightarrow, (e_1 + e_2) 1
</math>
</math>


Linia 424: Linia 412:


<math>
<math>
e_1 1 + e_2 1 \,\Longrightarrow\, ?
e_1 1 + e_2 1 \,\Longrightarrow, ?
</math>
</math>


Linia 430: Linia 418:


<math>
<math>
e_1 1 + e_2 1 \,\Longrightarrow\, ((e_1 + e_2) + \epsilon 1) 0
e_1 1 + e_2 1 \,\Longrightarrow, ((e_1 + e_2) + \epsilon 1) 0
</math>
</math>


Linia 452: Linia 440:


Zanim dopiszemy pozostałe reguły, określmy zbiór konfiguracji jako zbiór wyrażeń. Konfiguracje końcowe to wyrażenia bez operatora dodawania (liczby binarne).  
Zanim dopiszemy pozostałe reguły, określmy zbiór konfiguracji jako zbiór wyrażeń. Konfiguracje końcowe to wyrażenia bez operatora dodawania (liczby binarne).  
Nasz pomysł jest taki, że tranzycje stopniowo przesuwają operator dodawania w lewo, aż się go ostatecznie ''pozbędą''.
Nasz pomysł jest taki, że tranzycje stopniowo przesuwają operator dodawania w lewo, aż się go ostatecznie pozbędą.


Gdy obydwa składniki mają tyle samo cyfr, do zakończenia dodawania potrzebujemy reguły:
Gdy obydwa składniki mają tyle samo cyfr, do zakończenia dodawania potrzebujemy reguły:


<math>
<math>
\epsilon + \epsilon \,\Longrightarrow\, \epsilon.
\epsilon + \epsilon \,\Longrightarrow, \epsilon</math>
</math>


Gdy jeden ze składników ma mniej cyfr niż drugi, potrzebujemy reguł:
Gdy jeden ze składników ma mniej cyfr niż drugi, potrzebujemy reguł:


<math>
<math>
\epsilon + e 0 \,\Longrightarrow\, e 0
\epsilon + e 0 \,\Longrightarrow, e 0
\quad \quad
\quad \quad
\epsilon + e 1 \,\Longrightarrow\, e 1
\epsilon + e 1 \,\Longrightarrow, e 1
</math>
</math>


Linia 471: Linia 458:


<math>
<math>
e 0 + \epsilon \,\Longrightarrow\, e 0
e 0 + \epsilon \,\Longrightarrow, e 0
\quad \quad
\quad \quad
e 1 + \epsilon \,\Longrightarrow\, e 1.
e 1 + \epsilon \,\Longrightarrow, e 1</math>
</math>


Niestety, nie możemy użyć reguły przemienności:
Niestety, nie możemy użyć reguły przemienności:


<math>
<math>
e_1 + e_2 \,\Longrightarrow\, e_2 + e_1
e_1 + e_2 \,\Longrightarrow, e_2 + e_1
</math>
</math>


gdyż spowodowałaby ona możliwość ''pętlenia się'', a zatem braku wyniku obliczenia.
gdyż spowodowałaby ona możliwość "pętlenia się", a zatem braku wyniku obliczenia.


Na koniec dodajemy typowe reguły opisujące jak krok podwyrażenia indukuje krok całego wyrażenia:
Na koniec dodajemy typowe reguły opisujące jak krok podwyrażenia indukuje krok całego wyrażenia:


<math>
<math>
\frac{e_1 \,\Longrightarrow\, e'_1}
\frac{e_1 \,\Longrightarrow, e'_1}
     {e_1 + e_2 \,\Longrightarrow\, e'_1 + e_2}
     {e_1 + e_2 \,\Longrightarrow, e'_1 + e_2}
\quad \quad
\quad \quad
\frac{e_2 \,\Longrightarrow\, e'_2}
\frac{e_2 \,\Longrightarrow, e'_2}
     {e_1 + e_2 \,\Longrightarrow\, e_1 + e'_2}
     {e_1 + e_2 \,\Longrightarrow, e_1 + e'_2}
\quad \quad
\quad \quad
\frac{e \,\Longrightarrow\, e'}
\frac{e \,\Longrightarrow, e'}
     {e 0 \,\Longrightarrow\, e' 0}
     {e 0 \,\Longrightarrow, e' 0}
\quad \quad
\quad \quad
\frac{e \,\Longrightarrow\, e'}
\frac{e \,\Longrightarrow, e'}
     {e 1 \,\Longrightarrow\, e' 1}
     {e 1 \,\Longrightarrow, e' 1}
\quad \quad
\quad \quad
</math>
</math>


</div></div>
</div></div>
}}
 




{{cwiczenie|4|cw4|
{{cwiczenie|4|cw4|


Rozszerzmy składnię o jeden symbol <math>p</math> oznaczający ''przepełnienie'':
Rozszerzmy składnię o jeden symbol <math>p</math> oznaczający "przepełnienie":


<math>
<math>
Linia 515: Linia 501:
       e 0  \,\,|\,\,
       e 0  \,\,|\,\,
       e 1  \,\,|\,\,
       e 1  \,\,|\,\,
       e_1 + e_2 .
       e_1 + e_2 </math>
</math>


Na przykład <math>p 1 0 1</math> oznacza tę samą liczbę co <math>\epsilon 1 0 1</math>, ale z dodatkową informacją, że podczas jej obliczania nastąpiło ''przepełnienie''.
Na przykład <math>p 1 0 1</math> oznacza tę samą liczbę, co <math>\epsilon 1 0 1</math>, ale z dodatkową informacją, że podczas jej obliczania nastąpiło "przepełnienie".
Rozumiemy przez to sytuację, gdy wynik ma więcej cyfr niż każdy z argumentów.  
Rozumiemy przez to sytuację, gdy wynik ma więcej cyfr niż każdy z argumentów.  
Cyfry zero z lewej strony (najbardziej znaczące) również uważamy za pełnoprawne cyfry, nie należy ich usuwać ani dodawać nowych.
Cyfry zero z lewej strony (najbardziej znaczące) również uważamy za pełnoprawne cyfry, nie należy ich usuwać ani dodawać nowych.
Linia 535: Linia 520:
       \epsilon  \,\,|\,\,
       \epsilon  \,\,|\,\,
       b 0  \,\,|\,\,
       b 0  \,\,|\,\,
       b 1.
       b 1</math>
</math>


reprezentujących sumę liczb binarnych.
reprezentujących sumę liczb binarnych.
Linia 542: Linia 526:




{{rozwiazanie||roz4|
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
 
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie</span>
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible-content" style="display:none">


Zadanie dotyczy w zasadzie składni ograniczonej, ale jako konfiguracji pośrednich będziemy zapewne potrzebować wyrażeń wykraczających poza tę składnię, np. <math>(e_1 + e_2) 0</math>, podobnie jak w poprzednim zadaniu.  
Zadanie dotyczy w zasadzie składni ograniczonej, ale jako konfiguracji pośrednich będziemy zapewne potrzebować wyrażeń wykraczających poza tę składnię, np. <math>(e_1 + e_2) 0</math>, podobnie jak w poprzednim zadaniu.  
Zatem mamy tu do czynienia z typowym zabiegiem rozszerzania składni na użytek semantyki operacyjnej (z tym, że rozszerzenie jest dane z góry i nie musimy go wymyślać :)
Zatem mamy tu do czynienia z typowym zabiegiem rozszerzania składni na użytek semantyki operacyjnej (z tym że rozszerzenie jest dane z góry i nie musimy go wymyślać :)


Przyjmijmy, że konfiguracjami są dowolne wyrażenia, a konfiguracjami końcowymi wyrażenia bez operatora dodawania (ale teraz mogą to być np. wyrażenia postaci <math>p 1 0 0</math>).
Przyjmijmy, że konfiguracjami są dowolne wyrażenia, a konfiguracjami końcowymi wyrażenia bez operatora dodawania (ale teraz mogą to być np. wyrażenia postaci <math>p 1 0 0</math>).
Linia 556: Linia 540:


<math>
<math>
p + e 0 \,\Longrightarrow\, e 0
p + e 0 \,\Longrightarrow, e 0
\quad \quad
\quad \quad
p + e 1 \,\Longrightarrow\, e 1
p + e 1 \,\Longrightarrow, e 1
\quad \quad
\quad \quad
e 0 + p \,\Longrightarrow\, e 0
e 0 + p \,\Longrightarrow, e 0
\quad \quad
\quad \quad
e 1 + p \,\Longrightarrow\, e 1.
e 1 + p \,\Longrightarrow, e 1</math>
</math>


W takiej sytuacji oczywiście informacja o przepełnieniu zostaje wymazana.
W takiej sytuacji oczywiście informacja o przepełnieniu zostaje wymazana.
Linia 569: Linia 552:


<math>
<math>
\epsilon + e 0 \,\Longrightarrow\, e 0
\epsilon + e 0 \,\Longrightarrow, e 0
\quad \quad
\quad \quad
\epsilon + e 1 \,\Longrightarrow\, e 1
\epsilon + e 1 \,\Longrightarrow, e 1
\quad \quad
\quad \quad
e 0 + \epsilon \,\Longrightarrow\, e 0
e 0 + \epsilon \,\Longrightarrow, e 0
\quad \quad
\quad \quad
e 1 + \epsilon \,\Longrightarrow\, e 1.
e 1 + \epsilon \,\Longrightarrow, e 1</math>
</math>


z poprzedniego zadania są wystarczające.
z poprzedniego zadania są wystarczające.
Linia 584: Linia 566:


<math>
<math>
p + p \,\Longrightarrow\, p.
p + p \,\Longrightarrow, p</math>
</math>


Ale co należy zrobić, gdy tylko jeden ze składników odnotował przepełnienie? <math>p + \epsilon \,\Longrightarrow\, ?</math>
Ale co należy zrobić, gdy tylko jeden ze składników odnotował przepełnienie? <math>p + \epsilon \,\Longrightarrow, ?</math>
Oczywiście, w tej sytuacji żadnego przepełnienia nie ma, ponieważ drugi składnik ma wystarczająco dużo cyfr by je przesłonić.
Oczywiście, w tej sytuacji żadnego przepełnienia nie ma, ponieważ drugi składnik ma wystarczająco dużo cyfr, by je przesłonić.
Oto odpowiednie reguły:
Oto odpowiednie reguły:


<math>
<math>
p + \epsilon \,\Longrightarrow\, \epsilon
p + \epsilon \,\Longrightarrow, \epsilon
\quad \quad
\quad \quad
\epsilon + p \,\Longrightarrow\, \epsilon.
\epsilon + p \,\Longrightarrow, \epsilon</math>
</math>


Na koniec zostało najważniejsze: kiedy powinniśmy generować sygnał o przepełnieniu?
Na koniec zostało najważniejsze: kiedy powinniśmy generować sygnał o przepełnieniu?
Przypomnijmy sobie reguły dla dadawania pisemnego w poprzednim zadaniu.
Przypomnijmy sobie reguły dla dodawania pisemnego w poprzednim zadaniu.
Jeśli nie ma przeniesienia, to przepełnienie nie może powstać.
Jeśli nie ma przeniesienia, to przepełnienie nie może powstać.
Natomiast jeśli jest przeniesienie, to stanowi ono ''potencjalne przepełnienie''.  
Natomiast jeśli jest przeniesienie, to stanowi ono ''potencjalne przepełnienie''.  
Linia 604: Linia 584:


<math>
<math>
e_1 1 + e_2 1 \,\Longrightarrow\, ((e_1 + e_2) + p 1) 0.
e_1 1 + e_2 1 \,\Longrightarrow, ((e_1 + e_2) + p 1) 0</math>
</math>


Nowy sztuczny składnik <math>p 1</math> zawiera jakby na wszelki wypadek informacje o potencjalnym przepełnieniu.
Nowy sztuczny składnik <math>p 1</math> zawiera jakby na wszelki wypadek informacje o potencjalnym przepełnieniu.
Jeśli którykolwiek z pozostałych składników  <math>e_1</math> i <math>e_2</math>  ma przynajmniej jedną cyfrę,
Jeśli którykolwiek z pozostałych składników  <math>e_1</math> i <math>e_2</math>  ma przynajmniej jedną cyfrę,
to <math>p</math> zostanie usunięte. W przeciwnym wypadku symbol <math>p</math> i przetrwa i będzie poprawnie informował o sytuacji przepełnienia.
to <math>p</math> zostanie usunięte. W przeciwnym wypadku symbol <math>p</math> i przetrwa,i będzie poprawnie informował o sytuacji przepełnienia.


</div></div>
</div></div>
}}


== Zadania domowe ==
== Zadania domowe ==
Linia 620: Linia 597:
{{cwiczenie|1|cw1.dom|
{{cwiczenie|1|cw1.dom|


Podaj przykład wyrażenia boolowskiego, które nie policzy się ani przy użyciu strategii lewo- ani prawostronnej, a policzy się przy strategii równoległej.
Podaj przykład wyrażenia boolowskiego, które nie policzy się ani przy użyciu strategii lewo-, ani prawostronnej, a policzy się przy strategii równoległej.
}}
}}


Linia 626: Linia 603:
{{cwiczenie|2|cw2.dom|
{{cwiczenie|2|cw2.dom|


Zmodyfikuj semantykę wyrażeń następująco: dla każdego podwyrażenia niedeterministycznie wybierana jest albo strategia lewo- albo prawostronna, ale niedozwolony jest ,,przeplot".
Zmodyfikuj semantykę wyrażeń następująco: dla każdego podwyrażenia niedeterministycznie wybierana jest strategia lewo- albo prawostronna, ale niedozwolony jest "przeplot".
}}
}}


Linia 644: Linia 621:
{{cwiczenie|5|cw15.dom|
{{cwiczenie|5|cw15.dom|


Zaproponuj semantykę przypisania równoległego w języku Tiny:
Zaproponuj semantykę przypisania równoległego w języku TINY:


<math>
<math>
Linia 650: Linia 627:
</math>
</math>


polegającego na obliczeniu najpierw wartości wyrażeń <math>e_1, \ldots, e_n</math> a następnie na podstawieniu tych wartości na zmienne <math>x_1, \ldots, x_n</math>.
polegającego na obliczeniu najpierw wartości wyrażeń <math>e_1, \ldots, e_n</math>, a następnie na podstawieniu tych wartości na zmienne <math>x_1, \ldots, x_n</math>.
}}
}}

Aktualna wersja na dzień 21:29, 11 wrz 2023

Zawartość

Ćwiczymy dalej semantykę małych kroków. Uzupełnimy semantykę języka Tiny o semantykę operacyjną wyrażeń boolowskich i arytmetycznych. Następnie rozszerzymy nasz język o róznorodne konstrukcje iteracji. Na koniec zdefiniujemy operacje arytmetyczne liczb binarnych.


Rozszerzenia semantyki języka Tiny

Ćwiczenie 1

Semantyka języka Tiny z wykładu używała funkcji semantycznych B,E:StateState dla określenia znaczenia wyrażeń boolowskich i arytmetycznych. Zdefiniuj znaczenie wyrażeń za pomocą semantyki operacyjnej, w stylu małych kroków.


Rozwiązanie


Ćwiczenie 2

Rozszerzmy język Tiny o następujące dobrze znane konstrukcje iteracji:

I::=𝐫𝐞𝐩𝐞𝐚𝐭I𝐮𝐧𝐭𝐢𝐥b|𝐟𝐨𝐫x:=e1𝐭𝐨e2𝐝𝐨I|𝐝𝐨e𝐭𝐢𝐦𝐞𝐬I|𝐝𝐨I𝐰𝐡𝐢𝐥𝐞b

Napisz semantykę małych kroków dla powyższych konstrukcji.


Rozwiązanie

Kalkulator binarny

Ćwiczenie 3

Rozważmy następujący język wyrażeń (liczby binarne z dodawaniem):

e::=ϵ|e0|e1|e1+e2

ϵ oznacza słowo puste, czyli np. ϵ1011 oznacza binarną liczbę 1011. Napisz semantykę operacyjną obliczającą wartość wyrażeń.


Rozwiązanie


Ćwiczenie 4

Rozszerzmy składnię o jeden symbol p oznaczający "przepełnienie":

e::=ϵ|p|e0|e1|e1+e2

Na przykład p101 oznacza tę samą liczbę, co ϵ101, ale z dodatkową informacją, że podczas jej obliczania nastąpiło "przepełnienie". Rozumiemy przez to sytuację, gdy wynik ma więcej cyfr niż każdy z argumentów. Cyfry zero z lewej strony (najbardziej znaczące) również uważamy za pełnoprawne cyfry, nie należy ich usuwać ani dodawać nowych.

Napisz semantykę operacyjną obliczającą wartość wyrażenia wraz z informacja o ewentualnym przepełnieniu. Wynik powinien byc poprawny przynajmniej dla wyrażeń e w składni ograniczonej:

e::=b|e1+e2

b::=ϵ|b0|b1

reprezentujących sumę liczb binarnych.


Rozwiązanie

Zadania domowe

Ćwiczenie 1

Podaj przykład wyrażenia boolowskiego, które nie policzy się ani przy użyciu strategii lewo-, ani prawostronnej, a policzy się przy strategii równoległej.


Ćwiczenie 2

Zmodyfikuj semantykę wyrażeń następująco: dla każdego podwyrażenia niedeterministycznie wybierana jest strategia lewo- albo prawostronna, ale niedozwolony jest "przeplot".


Ćwiczenie 3

Rozważ inną semantykę pętli 𝐟𝐨𝐫x=e1𝐭𝐨e2𝐝𝐨I, w której wyrażenie e2 jest obliczane na nowo przed każdą iteracją pętli.


Ćwiczenie 4

Dodaj do wyrażeń binarnych operację odejmowania.


Ćwiczenie 5

Zaproponuj semantykę przypisania równoległego w języku TINY:

x1:=e1||||xn:=en

polegającego na obliczeniu najpierw wartości wyrażeń e1,,en, a następnie na podstawieniu tych wartości na zmienne x1,,xn.