diff --git a/wyk/01_Jezyk.ipynb b/wyk/01_Jezyk.ipynb index 0e726c1..9e0108d 100644 --- a/wyk/01_Jezyk.ipynb +++ b/wyk/01_Jezyk.ipynb @@ -15,4 +15,805 @@ "\n" ] }, -{"cell_type":"markdown","metadata":{},"source":["## Język — różne perspektywy\n\n"]},{"cell_type":"markdown","metadata":{},"source":["### Słowo wstępne\n\n"]},{"cell_type":"markdown","metadata":{},"source":["W matematyce istnieją dwa spojrzenia na rzeczywistość: ciągłe i dyskretne.\n\nOtaczająca nas rzeczywistość fizyczna jest z natury ciągła\n(przynajmniej jeśli nie operujemy w mikroskali), lecz język\njest dyskretnym wyłomem w ciągłej rzeczywistości.\n\n"]},{"cell_type":"markdown","metadata":{},"source":["### Lingwistyka matematyczna\n\n"]},{"cell_type":"markdown","metadata":{},"source":["Przypomnijmy sobie definicję języka przyjętą w lingwistyce\nmatematycznej, w kontekście, na przykład, teorii automatów.\n\n****Alfabetem**** nazywamy skończony zbiór symboli.\n\n****Łańcuchem**** (****napisem****) nad alfabetem $\\Sigma$ nazywamy dowolny, skończony,\nciąg złożony z symboli z $\\Sigma$.\n\n****Językiem**** nazywamy dowolny, skończony bądź nieskończony, zbiór łańcuchów.\n\nW tym formalnym ujęciu językami są na przykład następujące zbiory:\n\n- $\\{\\mathit{poniedziałek},\\mathit{wtorek},\\mathit{środa},\\mathit{czwartek},\\mathit{piątek},\\mathit{sobota},\\mathit{niedziela}\\}$\n- $\\{\\mathit{ab},\\mathit{abb},\\mathit{abbb},\\mathit{abbbb},\\ldots\\}$\n\nTo podejście, z jednej strony oczywiście nie do końca się pokrywa się z potocznym\nrozumieniem słowa *język*, z drugiej kojarzy nam się z takimi\nnarzędziami informatyki jak wyrażenia regularne, automaty skończenie\nstanowe czy gramatyki języków programowania.\n\n"]},{"cell_type":"code","execution_count":1,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"abbb"}],"source":["import regex as re\nrx = re.compile(r'ab+')\n\nrx.search('żabbba').group(0)"]},{"cell_type":"code","execution_count":1,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"}],"source":["import rstr\n\nrstr.xeger(r'ab+')"]},{"cell_type":"markdown","metadata":{},"source":["### Ujęcie probabilistyczne\n\n"]},{"cell_type":"markdown","metadata":{},"source":["Na tym wykładzie przyjmiemy inną perspektywą, częściowo ciągłą, opartą\nna probabilistyce. Język będziemy definiować poprzez ****rozkład\nprawdopodobieństwa****: sensownym wypowiedziom czy tekstom będziemy\nprzypisywać stosunkowe wysokie prawdopodobieństwo, „ułomnym” tekstom — niższe (być może zerowe).\n\nNa ogół nie mamy jednak do czynienia z językiem jako takim tylko z\njego przybliżeniami, ****modelami**** (model może być lepszy lub gorszy,\nale przynajmniej powinien być użyteczny…). Formalnie $M$ nazywamy\nmodelem języka (nad skończonym alfabetem $\\Sigma$), jeśli określa dyskretny rozkład prawdopodobieństwa $P_M$:\n\n$$P_M \\colon \\Sigma^{*} \\rightarrow [0,1].$$\n\nRzecz jasna, skoro mamy do czynienia z rozkładem prawdopodobieństwa, to:\n\n$$\\sum_{\\alpha \\in \\Sigma^{*}} P_M(\\alpha) = 1.$$\n\nJeśli $M$ ma być modelem języka polskiego, oczekiwalibyśmy, że dla\nnapisów:\n\n- $z_1$ — *W tym stanie rzeczy pan Ignacy coraz częściej myślał o Wokulskim.*\n- $z_2$ — *Po wypełniony zbiornik pełny i należne kwotę, usłyszała w attendant*\n- $z_3$ — *xxxxyźźźźźit backspace hoooooooooop x y z*\n\nzachodzić będzie:\n\n$$ P_M(z_1) > P_M(z_2) > P_M(z_3). $$\n\n****Pytanie**** Jakiej konkretnie wartości prawdopodobieństwa\nspodziewalibyśmy się dla zdania *Dzisiaj rano kupiłem w piekarni sześć bułek*\ndla sensownego modelu języka polskiego?\n\nMoglibyśmy sprowadzić tę definicję języka do tej „dyskretnej”, tzn.\nmoglibyśmy przyjąć, że łańcuch $\\alpha$ należy do języka wyznaczonego\nprzez model $M$, jeśli $P_M(\\alpha) > 0$.\n\n****Pytanie**** Czy moglibyśmy w ten sposób opisać język nieskończony? Czy może istnieć\ndyskretny rozkład prawdopodobieństwa dla nieskończonego zbioru?\n\n"]},{"cell_type":"markdown","metadata":{},"source":["### Co jest symbolem?\n\n"]},{"cell_type":"markdown","metadata":{},"source":["Model języka daje rozkład prawdopodobieństwa nad zbiorem łańcuchów\nopartym na skończonym alfabecie, tj. zbiorze symboli. W praktyce\nalfabet nie musi być zgodny z potocznym czy językoznawczym rozumieniem\ntego słowa. To znaczy alfabet może być zbiorem znaków (liter), ale\nmodelować język możemy też przyjmując inny typ symboli: sylaby,\nmorfemy (cząstki wyrazów) czy po prostu całe wyrazy.\n\nPowinniśmy przy tym pamiętać, że, koniec końców, w pamięci komputera\nwszelkiego rodzaju łańcuchy są zapisywane jako ciągi zer i jedynek — bitów.\nOmówmy pokrótce techniczną stronę modelowania języka.\n\n"]},{"cell_type":"markdown","metadata":{},"source":["## Kodowanie znaków\n\n"]},{"cell_type":"markdown","metadata":{},"source":["### Cóż może być prostszego od pliku tekstowego?\n\n"]},{"cell_type":"markdown","metadata":{},"source":[" Ala ma kota.\n\nKomputer nic nie wie o literach.\n\n… w rzeczywistości operuje tylko na liczbach …\n\n… czy raczej na zerach i jedynkach …\n\n… a tak naprawdę na ciągłym sygnale elektrycznym …\n\n![img](./01_Jezyk/digitalsignal.jpg)\n\n… zera i jedynki są w naszej głowie …\n\n… co jest dziwne, *naprawdę* dziwne …\n\n… ale nikt normalny się tym nie przejmuje.\n\n"]},{"cell_type":"markdown","metadata":{},"source":["### Jak zakodować literę?\n\n"]},{"cell_type":"markdown","metadata":{},"source":["Zakodowanie pikseli składających się na kształtu (****glyfu****) litery A\n*oczywiście* nie jest dobrym pomysłem.\n\n![img](./01_Jezyk/raster.png)\n\nNie, potrzebujemy *arbitralnego* kodowania dla wszystkich możliwych\nkształtów litery A (*w naszych głowach*): A, $\\mathcal{A}$,\n$\\mathbb{A}$, $\\mathfrak{A}$ powinny otrzymać ten sam kod, powiedzmy 65\n(binarnie: 1000001).\n\n"]},{"cell_type":"markdown","metadata":{},"source":["### ASCII\n\n"]},{"cell_type":"markdown","metadata":{},"source":["ASCII to 7-bitowy (****nie**** 8-bitowy!) system kodowania znaków.\n\n"]},{"cell_type":"code","execution_count":1,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":"0: \u0000\n1: \u0001\n2: \u0002\n3: \u0003\n4: \u0004\n5: \u0005\n6: \u0006\n7: \u0007\n8: \b\n9:\n10:\n\n11: \u000b\n12: \f\n13:\n14: \u000e\n15: \u000f\n16: \u0010\n17: \u0011\n18: \u0012\n19: \u0013\n20: \u0014\n21: \u0015\n22: \u0016\n23: \u0017\n24: \u0018\n25: \u0019\n26: \u001a\n27: \u001b\n28: \u001c\n29: \u001d\n30: \u001e\n31: \u001f\n32:\n33: !\n34: \"\n35: #\n36: $\n37: %\n38: &\n39: '\n40: (\n41: )\n42: *\n43: +\n44: ,\n45: -\n46: .\n47: /\n48: 0\n49: 1\n50: 2\n51: 3\n52: 4\n53: 5\n54: 6\n55: 7\n56: 8\n57: 9\n58: :\n59: ;\n60: <\n61: =\n62: >\n63: ?\n64: @\n65: A\n66: B\n67: C\n68: D\n69: E\n70: F\n71: G\n72: H\n73: I\n74: J\n75: K\n76: L\n77: M\n78: N\n79: O\n80: P\n81: Q\n82: R\n83: S\n84: T\n85: U\n86: V\n87: W\n88: X\n89: Y\n90: Z\n91: [\n92: \\\n93: ]\n94: ^\n95: _\n96: `\n97: a\n98: b\n99: c\n100: d\n101: e\n102: f\n103: g\n104: h\n105: i\n106: j\n107: k\n108: l\n109: m\n110: n\n111: o\n112: p\n113: q\n114: r\n115: s\n116: t\n117: u\n118: v\n119: w\n120: x\n121: y\n122: z\n123: {\n124: |\n125: }\n126: ~\n127: "}],"source":["for code in range(0, 128):\n print(f'{code}: {chr(code)}')"]},{"cell_type":"markdown","metadata":{},"source":["### Jak zejść na poziom bitów?\n\n"]},{"cell_type":"markdown","metadata":{},"source":["#### Linux — wiersz poleceń\n\n"]},{"cell_type":"markdown","metadata":{},"source":["Linux command line:\n\n $ echo 'Ala ma kota' > file.txt\n $ hexdump -C file.txt\n 00000000 41 6c 61 20 6d 61 20 6b 6f 74 61 0a |Ala ma kota.|\n 0000000c\n\n"]},{"cell_type":"markdown","metadata":{},"source":["#### Edytor tekstu (Emacs)\n\n"]},{"cell_type":"markdown","metadata":{},"source":["![img](./01_Jezyk/hexl-mode.png)\n\n"]},{"cell_type":"markdown","metadata":{},"source":["#### Uwaga!\n\n"]},{"cell_type":"markdown","metadata":{},"source":["- kiedy dzieje się coś dziwnego, sprawdź, co tak *naprawdę* jest w pliku\n- ASCII jest 7-bitowym kodowaniem (128 znaków)\n - choć zazwyczaj uzupełnionym (ang. *padded*) do 8 bitów\n - nie mów plik *plik ASCII*, kiedy masz na myśli *prosty/czysty plik tekstowy* (ang. *plain text file*)\n\n"]},{"cell_type":"markdown","metadata":{},"source":["### Higiena plików tekstowych\n\n"]},{"cell_type":"markdown","metadata":{},"source":["#### Piekło końca wiersza\n\n"]},{"cell_type":"markdown","metadata":{},"source":["![img](./01_Jezyk/dante.jpg)\n\nWięcej na [https://re-research.pl/pl/post/2017-01-28-00042-anatomia-pliku-tekstowego-2.html](https://re-research.pl/pl/post/2017-01-28-00042-anatomia-pliku-tekstowego-2.html)\n\n"]},{"cell_type":"markdown","metadata":{},"source":["#### Dobre rady\n\n"]},{"cell_type":"markdown","metadata":{},"source":["- żadnych niepotrzebnych spacji na końcu wiersza\n\n- żadnych niepotrzebnych pustych wierszy na końcu pliku\n\n- … ale ostatni wiersz powinien zakończyć się znakiem końca wiersza\n\n- nie używać znaków tabulacji (zamiast tego 4 spacje)\n - wyjątek: pliki TSV\n - wyjątek: pliki Makefile\n\n- uwaga na niestandardowe spacje i dziwne znaki o zerowej długości\n\n"]},{"cell_type":"markdown","metadata":{},"source":["### Unikod\n\n"]},{"cell_type":"markdown","metadata":{},"source":["ASCII obejmuje 128 znaków: litery alfabetu łacińskiego (właściwie angielskiego),\ncyfry, znaki interpunkcyjne, znaki specjalne itd.\n\nCo z pozostałymi znakami? Polskimi ogonkami, czeskimi haczykami,\nfrancuskimi akcentami, cyrylicą, koreańskim alfabetem, chińskimi\nznakami, rongorongo?\n\n워싱턴, 부산, 삼성\n\nRozwiązaniem jest Unikod (ang. *Unicode*) system, który przypisuje\nznakom używanym przez ludzkość liczby (kody, ang. *code points*).\n\n| Znak|Kod ASCII|Kod Unikodowy|\n|---|---|---|\n| 9|57|57|\n| a|97|97|\n| ą|-|261|\n| ł|-|322|\n| $\\aleph$|-|1488|\n| ặ|-|7861|\n| ☣|-|9763|\n| 😇|-|128519|\n\n"]},{"cell_type":"markdown","metadata":{},"source":["### UTF-8\n\n"]},{"cell_type":"markdown","metadata":{},"source":["Kody znaków są pojęciem abstrakcyjnym. Potrzebujemy konkretnego ****kodowania****\nby zamienić kody w sekwencję bajtów. Najpopularniejszym kodowaniem jest UTF-8.\n\nW kodowaniu UTF-8 znaki zapisywane za pomocą 1, 2, 3, 4, 5 lub 6 bajtów\n(w praktyce — raczej to 4 bajtów).\n\n| Znak|Kod Unikodowy|Szesnastkowo|UTF-8 (binarnie)|\n|---|---|---|---|\n| 9|57|U+0049|01001001|\n| a|97|U+0061|01100001|\n| ą|261|U+0105|11000100:10000101|\n| ł|322|U+0142|11000101:10000010|\n| $\\aleph$|1488|U+05D0|11010111:10010000|\n| ặ|7861|U+1EB7|11100001:10111010:10110111|\n| ☣|9763|U+2623|11100010:10011000:10100011|\n| 😇|128519|U+1f607|11110000:10011111:10011000:10000111|\n\n"]},{"cell_type":"markdown","metadata":{},"source":["#### UTF-8 — ogólny schemat zamiany kodu na bajty\n\n"]},{"cell_type":"markdown","metadata":{},"source":["- 0x00 do 0x7F – 0xxxxxxx,\n- 0x80 do 0x7FF – 110xxxxx 10xxxxxx\n- 0x800 do 0xFFFF — 1110xxxx 10xxxxxx 10xxxxxx\n- 0x10000 do 0x1FFFFF – 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx\n- 0x200000 do 0x3FFFFFF – 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx\n- 0x4000000 do 0x7FFFFFFF – 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx\n\nSymbol x oznacza znaczący bit.\n\n"]},{"cell_type":"markdown","metadata":{},"source":["#### *Źdźbło* to ile bajtów w UTF-8?\n\n"]},{"cell_type":"markdown","metadata":{},"source":["Jeśli wczytać jako wiersz w języku C, 11 bajtów!\n\n![img](./01_Jezyk/zdzblo.png)\n\n"]},{"cell_type":"markdown","metadata":{},"source":["### Dlaczego UTF-8 jest doskonałym systemem kodowania?\n\n"]},{"cell_type":"markdown","metadata":{},"source":["- wstecznie kompatybilny z ASCII\n - plik ASCII jest poprawnym plikiem UTF-8\n- nie zajmuje dużo miejsca\n - chyba że w tekście jest dużo „dziwnych” znaków\n- proste grepowanie działa\n - `grep UAM text-in-utf8.txt` zadziała\n - ale nawet nie próbuj: `grep SRPOL text-in-utf16.txt`\n\n"]},{"cell_type":"markdown","metadata":{},"source":["### Porady\n\n"]},{"cell_type":"markdown","metadata":{},"source":["- zawsze używaj UTF-8\n - bądź asertywny! jeśli w pracy każą używać czegoś innego — rezygnuj z pracy\n - **NIE** używaj innych unikodowych kodowań: UTF-16, UTF-32, UCS-2\n - **NIE** używaj nieunikodowych systemów kodowania\n - ISO-8859-2, Windows-1250, Mazovia, IEA Świerk, …\n- uwaga na pułapki UTF-8\n - ustalenie długości napisu w znakach wymaga przejścia znak po znaku\n - jeśli napis w kodowaniu UTF-8 zajmuje 9 bajtów, ile to znaków?\n 3, 4, 5, 6, 7, 8 lub 9!\n\n"]},{"cell_type":"markdown","metadata":{},"source":["### **NIE** używaj sekwencji BOM\n\n"]},{"cell_type":"markdown","metadata":{},"source":["![img](./01_Jezyk/evil-bom.png)\n\n"]},{"cell_type":"markdown","metadata":{},"source":["### Unikod/UTF-8 a języki programowania\n\n"]},{"cell_type":"markdown","metadata":{},"source":["Pamiętaj, żeby być konsekwentnym!\n\n- kodowanie kodu źródłowego (literały!)\n - czasami podawane na początku pliku\n - … albo brane z ustawień *locale*\n - … albo — domyślnie — UTF-8 (w nowszych językach programowania)\n- kodowanie standardowego wejścia/wyjścia i plików\n- jak sekwencje bajtów są interpretowane w czasie działania programu?\n - *Źdźbło* jest łańcuchem złożonym z 6 czy 9 elementów??\n - 9 bajtów\n - 6 kodów\n - `\"Źdźbło\"[1]` …\n - `d`\n - … albo śmieci\n\n"]},{"cell_type":"markdown","metadata":{},"source":["#### Python 2\n\n"]},{"cell_type":"code","execution_count":1,"metadata":{},"outputs":[],"source":["#!/usr/bin/python2\n# -*- coding: utf-8 -*-\nimport sys\nfor line in sys.stdin:\n line = line.decode('utf-8').rstrip()\n if \"źdźbło\".decode('utf-8') in line:\n print len(line), ' ', line"]},{"cell_type":"markdown","metadata":{},"source":["#### Python3\n\n"]},{"cell_type":"code","execution_count":1,"metadata":{},"outputs":[],"source":["#!/usr/bin/python3\nimport sys\nfor line in sys.stdin:\n line = line.strip()\n if \"źdźbło\" in line:\n print(len(line), ' ', line)"]},{"cell_type":"markdown","metadata":{},"source":["Uwaga: zakładając, że zmienna środowiskowa `LANG` jest ustawiona na UTF-8.\n\n"]}],"metadata":{"org":null,"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.5.2"}},"nbformat":4,"nbformat_minor":0} \ No newline at end of file + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Język — różne perspektywy\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Słowo wstępne\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "W matematyce istnieją dwa spojrzenia na rzeczywistość: ciągłe i dyskretne.\n", + "\n", + "Otaczająca nas rzeczywistość fizyczna jest z natury ciągła\n", + "(przynajmniej jeśli nie operujemy w mikroskali), lecz język\n", + "jest dyskretnym wyłomem w ciągłej rzeczywistości.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Lingwistyka matematyczna\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Przypomnijmy sobie definicję języka przyjętą w lingwistyce\n", + "matematycznej, w kontekście, na przykład, teorii automatów.\n", + "\n", + "****Alfabetem**** nazywamy skończony zbiór symboli.\n", + "\n", + "****Łańcuchem**** (****napisem****) nad alfabetem $\\Sigma$ nazywamy dowolny, skończony,\n", + "ciąg złożony z symboli z $\\Sigma$.\n", + "\n", + "****Językiem**** nazywamy dowolny, skończony bądź nieskończony, zbiór łańcuchów.\n", + "\n", + "W tym formalnym ujęciu językami są na przykład następujące zbiory:\n", + "\n", + "- $\\{\\mathit{poniedziałek},\\mathit{wtorek},\\mathit{środa},\\mathit{czwartek},\\mathit{piątek},\\mathit{sobota},\\mathit{niedziela}\\}$\n", + "- $\\{\\mathit{ab},\\mathit{abb},\\mathit{abbb},\\mathit{abbbb},\\ldots\\}$\n", + "\n", + "To podejście, z jednej strony oczywiście nie do końca się pokrywa się z potocznym\n", + "rozumieniem słowa *język*, z drugiej kojarzy nam się z takimi\n", + "narzędziami informatyki jak wyrażenia regularne, automaty skończenie\n", + "stanowe czy gramatyki języków programowania.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "abbb" + ] + } + ], + "source": [ + "import regex as re\n", + "rx = re.compile(r'ab+')\n", + "\n", + "rx.search('żabbba').group(0)" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + ] + } + ], + "source": [ + "import rstr\n", + "\n", + "rstr.xeger(r'ab+')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Ujęcie probabilistyczne\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Na tym wykładzie przyjmiemy inną perspektywą, częściowo ciągłą, opartą\n", + "na probabilistyce. Język będziemy definiować poprzez ****rozkład\n", + "prawdopodobieństwa****: sensownym wypowiedziom czy tekstom będziemy\n", + "przypisywać stosunkowe wysokie prawdopodobieństwo, „ułomnym” tekstom — niższe (być może zerowe).\n", + "\n", + "Na ogół nie mamy jednak do czynienia z językiem jako takim tylko z\n", + "jego przybliżeniami, ****modelami**** (model może być lepszy lub gorszy,\n", + "ale przynajmniej powinien być użyteczny…). Formalnie $M$ nazywamy\n", + "modelem języka (nad skończonym alfabetem $\\Sigma$), jeśli określa dyskretny rozkład prawdopodobieństwa $P_M$:\n", + "\n", + "$$P_M \\colon \\Sigma^{*} \\rightarrow [0,1].$$\n", + "\n", + "Rzecz jasna, skoro mamy do czynienia z rozkładem prawdopodobieństwa, to:\n", + "\n", + "$$\\sum_{\\alpha \\in \\Sigma^{*}} P_M(\\alpha) = 1.$$\n", + "\n", + "Jeśli $M$ ma być modelem języka polskiego, oczekiwalibyśmy, że dla\n", + "napisów:\n", + "\n", + "- $z_1$ — *W tym stanie rzeczy pan Ignacy coraz częściej myślał o Wokulskim.*\n", + "- $z_2$ — *Po wypełniony zbiornik pełny i należne kwotę, usłyszała w attendant*\n", + "- $z_3$ — *xxxxyźźźźźit backspace hoooooooooop x y z*\n", + "\n", + "zachodzić będzie:\n", + "\n", + "$$ P_M(z_1) > P_M(z_2) > P_M(z_3). $$\n", + "\n", + "****Pytanie**** Jakiej konkretnie wartości prawdopodobieństwa\n", + "spodziewalibyśmy się dla zdania *Dzisiaj rano kupiłem w piekarni sześć bułek*\n", + "dla sensownego modelu języka polskiego?\n", + "\n", + "Moglibyśmy sprowadzić tę definicję języka do tej „dyskretnej”, tzn.\n", + "moglibyśmy przyjąć, że łańcuch $\\alpha$ należy do języka wyznaczonego\n", + "przez model $M$, jeśli $P_M(\\alpha) > 0$.\n", + "\n", + "****Pytanie**** Czy moglibyśmy w ten sposób opisać język nieskończony? Czy może istnieć\n", + "dyskretny rozkład prawdopodobieństwa dla nieskończonego zbioru?\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Co jest symbolem?\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Model języka daje rozkład prawdopodobieństwa nad zbiorem łańcuchów\n", + "opartym na skończonym alfabecie, tj. zbiorze symboli. W praktyce\n", + "alfabet nie musi być zgodny z potocznym czy językoznawczym rozumieniem\n", + "tego słowa. To znaczy alfabet może być zbiorem znaków (liter), ale\n", + "modelować język możemy też przyjmując inny typ symboli: sylaby,\n", + "morfemy (cząstki wyrazów) czy po prostu całe wyrazy.\n", + "\n", + "Powinniśmy przy tym pamiętać, że, koniec końców, w pamięci komputera\n", + "wszelkiego rodzaju łańcuchy są zapisywane jako ciągi zer i jedynek — bitów.\n", + "Omówmy pokrótce techniczną stronę modelowania języka.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Kodowanie znaków\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Cóż może być prostszego od pliku tekstowego?\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " Ala ma kota.\n", + "\n", + "Komputer nic nie wie o literach.\n", + "\n", + "… w rzeczywistości operuje tylko na liczbach …\n", + "\n", + "… czy raczej na zerach i jedynkach …\n", + "\n", + "… a tak naprawdę na ciągłym sygnale elektrycznym …\n", + "\n", + "![img](./01_Jezyk/digitalsignal.jpg)\n", + "\n", + "… zera i jedynki są w naszej głowie …\n", + "\n", + "… co jest dziwne, *naprawdę* dziwne …\n", + "\n", + "… ale nikt normalny się tym nie przejmuje.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Jak zakodować literę?\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Zakodowanie pikseli składających się na kształtu (****glyfu****) litery A\n", + "*oczywiście* nie jest dobrym pomysłem.\n", + "\n", + "![img](./01_Jezyk/raster.png)\n", + "\n", + "Nie, potrzebujemy *arbitralnego* kodowania dla wszystkich możliwych\n", + "kształtów litery A (*w naszych głowach*): A, $\\mathcal{A}$,\n", + "$\\mathbb{A}$, $\\mathfrak{A}$ powinny otrzymać ten sam kod, powiedzmy 65\n", + "(binarnie: 1000001).\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ASCII\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "ASCII to 7-bitowy (****nie**** 8-bitowy!) system kodowania znaków.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0: \u0000\n", + "1: \u0001\n", + "2: \u0002\n", + "3: \u0003\n", + "4: \u0004\n", + "5: \u0005\n", + "6: \u0006\n", + "7: \u0007\n", + "8: \b\n", + "9:\n", + "10:\n", + "\n", + "11: \u000b", + "\n", + "12: \f", + "\n", + "13:\n", + "14: \u000e\n", + "15: \u000f\n", + "16: \u0010\n", + "17: \u0011\n", + "18: \u0012\n", + "19: \u0013\n", + "20: \u0014\n", + "21: \u0015\n", + "22: \u0016\n", + "23: \u0017\n", + "24: \u0018\n", + "25: \u0019\n", + "26: \u001a\n", + "27: \u001b\n", + "28: \u001c", + "\n", + "29: \u001d", + "\n", + "30: \u001e", + "\n", + "31: \u001f\n", + "32:\n", + "33: !\n", + "34: \"\n", + "35: #\n", + "36: $\n", + "37: %\n", + "38: &\n", + "39: '\n", + "40: (\n", + "41: )\n", + "42: *\n", + "43: +\n", + "44: ,\n", + "45: -\n", + "46: .\n", + "47: /\n", + "48: 0\n", + "49: 1\n", + "50: 2\n", + "51: 3\n", + "52: 4\n", + "53: 5\n", + "54: 6\n", + "55: 7\n", + "56: 8\n", + "57: 9\n", + "58: :\n", + "59: ;\n", + "60: <\n", + "61: =\n", + "62: >\n", + "63: ?\n", + "64: @\n", + "65: A\n", + "66: B\n", + "67: C\n", + "68: D\n", + "69: E\n", + "70: F\n", + "71: G\n", + "72: H\n", + "73: I\n", + "74: J\n", + "75: K\n", + "76: L\n", + "77: M\n", + "78: N\n", + "79: O\n", + "80: P\n", + "81: Q\n", + "82: R\n", + "83: S\n", + "84: T\n", + "85: U\n", + "86: V\n", + "87: W\n", + "88: X\n", + "89: Y\n", + "90: Z\n", + "91: [\n", + "92: \\\n", + "93: ]\n", + "94: ^\n", + "95: _\n", + "96: `\n", + "97: a\n", + "98: b\n", + "99: c\n", + "100: d\n", + "101: e\n", + "102: f\n", + "103: g\n", + "104: h\n", + "105: i\n", + "106: j\n", + "107: k\n", + "108: l\n", + "109: m\n", + "110: n\n", + "111: o\n", + "112: p\n", + "113: q\n", + "114: r\n", + "115: s\n", + "116: t\n", + "117: u\n", + "118: v\n", + "119: w\n", + "120: x\n", + "121: y\n", + "122: z\n", + "123: {\n", + "124: |\n", + "125: }\n", + "126: ~\n", + "127: " + ] + } + ], + "source": [ + "for code in range(0, 128):\n", + " print(f'{code}: {chr(code)}')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Jak zejść na poziom bitów?\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Linux — wiersz poleceń\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Linux command line:\n", + "\n", + " $ echo 'Ala ma kota' > file.txt\n", + " $ hexdump -C file.txt\n", + " 00000000 41 6c 61 20 6d 61 20 6b 6f 74 61 0a |Ala ma kota.|\n", + " 0000000c\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Edytor tekstu (Emacs)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![img](./01_Jezyk/hexl-mode.png)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Uwaga!\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- kiedy dzieje się coś dziwnego, sprawdź, co tak *naprawdę* jest w pliku\n", + "- ASCII jest 7-bitowym kodowaniem (128 znaków)\n", + " - choć zazwyczaj uzupełnionym (ang. *padded*) do 8 bitów\n", + " - nie mów plik *plik ASCII*, kiedy masz na myśli *prosty/czysty plik tekstowy* (ang. *plain text file*)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Higiena plików tekstowych\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Piekło końca wiersza\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![img](./01_Jezyk/dante.jpg)\n", + "\n", + "Więcej na [https://re-research.pl/pl/post/2017-01-28-00042-anatomia-pliku-tekstowego-2.html](https://re-research.pl/pl/post/2017-01-28-00042-anatomia-pliku-tekstowego-2.html)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Dobre rady\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- żadnych niepotrzebnych spacji na końcu wiersza\n", + "\n", + "- żadnych niepotrzebnych pustych wierszy na końcu pliku\n", + "\n", + "- … ale ostatni wiersz powinien zakończyć się znakiem końca wiersza\n", + "\n", + "- nie używać znaków tabulacji (zamiast tego 4 spacje)\n", + " - wyjątek: pliki TSV\n", + " - wyjątek: pliki Makefile\n", + "\n", + "- uwaga na niestandardowe spacje i dziwne znaki o zerowej długości\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Unikod\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "ASCII obejmuje 128 znaków: litery alfabetu łacińskiego (właściwie angielskiego),\n", + "cyfry, znaki interpunkcyjne, znaki specjalne itd.\n", + "\n", + "Co z pozostałymi znakami? Polskimi ogonkami, czeskimi haczykami,\n", + "francuskimi akcentami, cyrylicą, koreańskim alfabetem, chińskimi\n", + "znakami, rongorongo?\n", + "\n", + "워싱턴, 부산, 삼성\n", + "\n", + "Rozwiązaniem jest Unikod (ang. *Unicode*) system, który przypisuje\n", + "znakom używanym przez ludzkość liczby (kody, ang. *code points*).\n", + "\n", + "| Znak|Kod ASCII|Kod Unikodowy|\n", + "|---|---|---|\n", + "| 9|57|57|\n", + "| a|97|97|\n", + "| ą|-|261|\n", + "| ł|-|322|\n", + "| $\\aleph$|-|1488|\n", + "| ặ|-|7861|\n", + "| ☣|-|9763|\n", + "| 😇|-|128519|\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### UTF-8\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Kody znaków są pojęciem abstrakcyjnym. Potrzebujemy konkretnego ****kodowania****\n", + "by zamienić kody w sekwencję bajtów. Najpopularniejszym kodowaniem jest UTF-8.\n", + "\n", + "W kodowaniu UTF-8 znaki zapisywane za pomocą 1, 2, 3, 4, 5 lub 6 bajtów\n", + "(w praktyce — raczej to 4 bajtów).\n", + "\n", + "| Znak|Kod Unikodowy|Szesnastkowo|UTF-8 (binarnie)|\n", + "|---|---|---|---|\n", + "| 9|57|U+0049|01001001|\n", + "| a|97|U+0061|01100001|\n", + "| ą|261|U+0105|11000100:10000101|\n", + "| ł|322|U+0142|11000101:10000010|\n", + "| $\\aleph$|1488|U+05D0|11010111:10010000|\n", + "| ặ|7861|U+1EB7|11100001:10111010:10110111|\n", + "| ☣|9763|U+2623|11100010:10011000:10100011|\n", + "| 😇|128519|U+1f607|11110000:10011111:10011000:10000111|\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### UTF-8 — ogólny schemat zamiany kodu na bajty\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- 0x00 do 0x7F – 0xxxxxxx,\n", + "- 0x80 do 0x7FF – 110xxxxx 10xxxxxx\n", + "- 0x800 do 0xFFFF — 1110xxxx 10xxxxxx 10xxxxxx\n", + "- 0x10000 do 0x1FFFFF – 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx\n", + "- 0x200000 do 0x3FFFFFF – 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx\n", + "- 0x4000000 do 0x7FFFFFFF – 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx\n", + "\n", + "Symbol x oznacza znaczący bit.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### *Źdźbło* to ile bajtów w UTF-8?\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Jeśli wczytać jako wiersz w języku C, 11 bajtów!\n", + "\n", + "![img](./01_Jezyk/zdzblo.png)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Dlaczego UTF-8 jest doskonałym systemem kodowania?\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- wstecznie kompatybilny z ASCII\n", + " - plik ASCII jest poprawnym plikiem UTF-8\n", + "- nie zajmuje dużo miejsca\n", + " - chyba że w tekście jest dużo „dziwnych” znaków\n", + "- proste grepowanie działa\n", + " - `grep UAM text-in-utf8.txt` zadziała\n", + " - ale nawet nie próbuj: `grep SRPOL text-in-utf16.txt`\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Porady\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- zawsze używaj UTF-8\n", + " - bądź asertywny! jeśli w pracy każą używać czegoś innego — rezygnuj z pracy\n", + " - **NIE** używaj innych unikodowych kodowań: UTF-16, UTF-32, UCS-2\n", + " - **NIE** używaj nieunikodowych systemów kodowania\n", + " - ISO-8859-2, Windows-1250, Mazovia, IEA Świerk, …\n", + "- uwaga na pułapki UTF-8\n", + " - ustalenie długości napisu w znakach wymaga przejścia znak po znaku\n", + " - jeśli napis w kodowaniu UTF-8 zajmuje 9 bajtów, ile to znaków?\n", + " 3, 4, 5, 6, 7, 8 lub 9!\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### **NIE** używaj sekwencji BOM\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![img](./01_Jezyk/evil-bom.png)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Unikod/UTF-8 a języki programowania\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Pamiętaj, żeby być konsekwentnym!\n", + "\n", + "- kodowanie kodu źródłowego (literały!)\n", + " - czasami podawane na początku pliku\n", + " - … albo brane z ustawień *locale*\n", + " - … albo — domyślnie — UTF-8 (w nowszych językach programowania)\n", + "- kodowanie standardowego wejścia/wyjścia i plików\n", + "- jak sekwencje bajtów są interpretowane w czasie działania programu?\n", + " - *Źdźbło* jest łańcuchem złożonym z 6 czy 9 elementów??\n", + " - 9 bajtów\n", + " - 6 kodów\n", + " - `\"Źdźbło\"[1]` …\n", + " - `d`\n", + " - … albo śmieci\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Python 2\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "#!/usr/bin/python2\n", + "# -*- coding: utf-8 -*-\n", + "import sys\n", + "for line in sys.stdin:\n", + " line = line.decode('utf-8').rstrip()\n", + " if \"źdźbło\".decode('utf-8') in line:\n", + " print len(line), ' ', line" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Python3\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "#!/usr/bin/python3\n", + "import sys\n", + "for line in sys.stdin:\n", + " line = line.strip()\n", + " if \"źdźbło\" in line:\n", + " print(len(line), ' ', line)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Uwaga: zakładając, że zmienna środowiskowa `LANG` jest ustawiona na UTF-8.\n", + "\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.2" + }, + "org": null + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/wyk/01_Jezyk.org b/wyk/01_Jezyk.org index 9a43ea4..efcd79e 100644 Binary files a/wyk/01_Jezyk.org and b/wyk/01_Jezyk.org differ diff --git a/wyk/02_Jezyki.org b/wyk/02_Jezyki.org index 84b302e..5a5cf76 100644 --- a/wyk/02_Jezyki.org +++ b/wyk/02_Jezyki.org @@ -364,7 +364,6 @@ dramatycznie na analizę statystyczną. #+RESULTS: :results: -9 OR 9FAM ZO8 QOAR9 Q*R 8ARAM 29 [O82*]OM OPCC9 OP :end: #+BEGIN_SRC python :session mysession :results file @@ -491,3 +490,303 @@ trypletu STOP (_ powyżej). Taka sekwencja to /gen/. #+RESULTS: [[file:dna_length.png]] + +** Entropia + +*Entropia* ($E$) to miara nieuporządkowania, niepewności, niewiedzy. Im +większa entropia, tym mniej wiemy. Pojęcie to pierwotnie wywodzi się z +termodynamiki, później znaleziono wiele zaskakujących zastosowań w +innych dyscyplinach nauki. + +*** Entropia w fizyce + +W termodynamice entropia jest miarą nieuporządkowania układów +fizycznych, na przykład pojemników z gazem. Przykładowo, wyobraźmy +sobie dwa pojemniki z gazem, w którym panuje różne temperatury. + +[[./02_Jezyki/gas-low-entropy.drawio.png]] + +Jeśli usuniemy przegrodę między pojemnikami, temperatura się wyrówna, +a uporządkowanie się zmniejszy. + +[[./02_Jezyki/gas-high-entropy.drawio.png]] + +Innymi słowy, zwiększy się stopień uporządkowania układu, czyli właśnie entropia. + +*** II prawo termodynamiki + +Jedno z najbardziej fundamentalnych praw fizyki, II prawo +termodynamiki głosi, że w układzie zamkniętym entropia nie spada. + +**Pytanie**: Czy to, że napisałem te materiały do wykładu i +/uporządkowałem/ wiedzę odnośnie do statystycznych własności języka, nie +jest sprzeczne z II prawem termodynamiki? + +Konsekwencją II prawa termodynamiki jest śmierć cieplna Wszechświata +(zob. [wizualizacja przyszłości Wszechświata](https://www.youtube.com/watch?v=uD4izuDMUQA)). + +*** Entropia w teorii informacji + +Pojęcie entropii zostało „odkryte” na nowo przez Claude'a Shannona, +gdy wypracował ogólną teorię informacji. + +Teoria informacji zajmuje się między innymi zagadnieniem optymalnego kodowania komunikatów. + +Wyobraźmy sobie pewne źródło (generator) losowych komunikatów z +zamkniętego zbioru symboli ($\Sigma$; nieprzypadkowo używamy oznaczeń +z poprzedniego wykładu). Nadawca $N$ chce przesłać komunikat o wyniku +losowania do odbiorcy $O$ używając zer i jedynek (bitów). +Teorioinformacyjną entropię można zdefiniować jako średnią liczbę +bitów wymaganych do przesłania komunikatu. + +*** Obliczanie entropii — proste przykłady + +Załóżmy, że nadawca chce przekazać odbiorcy informację o wyniku rzutu monetą. +Entropia wynosi wówczas rzecz jasna 1 — na jedno losowanie wystarczy jeden bit +(informację o tym, że wypadł orzeł, możemy zakodować na przykład za pomocą zera, +zaś to, że wypadła reszka — za pomocą jedynki). + +Rozpatrzmy przypadek, gdy nadawca ośmiościenną kością. Aby przekazać +wynik, potrzebuje wówczas 3 bity (a więc entropia ośmiościennej kości +wynosi 3 bity). Przykładowe kodowanie może mieć następującą postać. + ++-------+-----------+ +| Wynik | Kodowanie | ++-------+-----------+ +| 1 | 001 | +| 2 | 010 | +| 3 | 011 | +| 4 | 100 | +| 5 | 101 | +| 6 | 110 | +| 7 | 111 | +| 8 | 000 | ++-------+-----------+ + +*** Obliczenie entropii — trudniejszy przykład + +Załóżmy, że $\Sigma = \{A, B, C, D\}$, natomiast poszczególne komunikaty +są losowane zgodnie z następujących rozkładem prawdopodobieństwa: +$P(A)=1/2$, $P(B)=1/4$, $P(C)=1/8$, $P(D)=1/8$. Ile wynosi entropia w +takim przypadku? Można by sądzić, że 2, skoro wystarczą 2 bity do +przekazania wyniku losowania przy zastosowaniu następującego kodowania: + ++-------+-----------+ +| Wynik | Kodowanie | ++-------+-----------+ +| A | 00 | +| B | 01 | +| C | 10 | +| D | 11 | ++-------+-----------+ + +Problem w tym, że w rzeczywistości nie jest to /optymalne/ kodowanie. +Możemy sprytnie zmniejszyć średnią liczbę bitów wymaganych do +przekazania losowego wyniku przypisując częstszym wynikom krótsze +kody, rzadszym zaś — dłuższe. Oto takie optymalne kodowanie: + ++-------+-----------+ +| Wynik | Kodowanie | ++-------+-----------+ +| A | 0 | +| B | 10 | +| C | 110 | +| D | 111 | ++-------+-----------+ + +Używając takiego kodowanie średnio potrzebujemy: + +$$\frac{1}{2}1 + \frac{1}{4}2 + \frac{1}{8}3 + \frac{1}{8}3 = 1,75$$ + +bita. Innymi słowy, entropia takiego źródła wynosi 1,75 bita. + +*** Kodowanie musi być jednoznaczne! + +Można by sądzić, że da się stworzyć jeszcze krótsze kodowanie dla omawianego rozkładu nierównomiernego: + ++-------+-----------+ +| Wynik | Kodowanie | ++-------+-----------+ +| A | 0 | +| B | 1 | +| C | 01 | +| D | 11 | ++-------+-----------+ + +Niestety, nie jest to właściwe rozwiązanie — kodowanie musi być +jednoznaczne nie tylko dla pojedynczego komunikatu, lecz dla całej sekwencji. +Na przykład ciąg 0111 nie jest jednoznaczny przy tym kodowaniu (ABBB czy CD?). +Podane wcześniej kodowanie spełnia warunek jednoznaczności, ciąg 0111 można odkodować tylko +jako AD. + + +*** Ogólny wzór na entropię. + +Na podstawie poprzedniego przykładu można dojść do intuicyjnego wniosku, że +optymalny kod dla wyniku o prawdopodobieństwie $p$ ma długość $-\log_2(p)$, a zatem ogólnie +entropia źródła o rozkładzie prawdopodobieństwa $\{p_1,\ldots,p_|\Sigma|\}$ wynosi: + +$$E = -\Sum_{i=1}^{|\Sigma|} p_i\log_2(p_i)$$. + +Zauważmy, że jest to jeden z nielicznych przypadków, gdy w nauce naturalną +podstawą logarytmu jest 2 zamiast… podstawy logarytmu naturalnego ($e$). + +Teoretycznie można mierzyć entropię używając logarytmu naturalnego +($\ln$), jednostką entropii będzie wówczas *nat* zamiast bita, +niewiele to jednak zmienia i jest mniej poręczne i trudniejsze do interpretacji +(przynajmniej w kontekście informatyki) niż operowanie na bitach. + +**Pytanie** Ile wynosi entropia sześciennej kostki? Jak wygląda +optymalne kodowanie wyników rzutu taką kostką? + +*** Entropia dla próby Bernoulliego + +Wiemy już, że entropia dla rzutu monetą wynosi 1 bit. A jaki będzie wynik dla źle wyważonej monety? + +#+BEGIN_SRC python :session mysession :results file + import matplotlib.pyplot as plt + from math import log + import numpy as np + + def binomial_entropy(p): + return -(p * log(p, 2) + (1-p) * log(1-p, 2)) + + x = list(np.arange(0.001,1,0.001)) + y = [binomial_entropy(x) for x in x] + plt.figure().clear() + plt.plot(x, y) + + fname = f'binomial-entropy.png' + + plt.savefig(fname) + + fname +#+END_SRC + +#+RESULTS: +[[file:binomial-entropy.png]] + +*Pytanie* Dla oszukańczej monety (np. dla której wypada zawsze orzeł) entropia +wynosi 0, czy to wynik zgodny z intuicją? + +** Entropia a język + +Tekst w danym języku możemy traktować jako ciąg symboli (komunikatów) losowanych według jakiegoś +rozkładu prawdopodobieństwa. W tym sensie możemy mówić o entropii języka. + +Oczywiście, jak zawsze, musimy jasno stwierdzić, czym są symbole +języka: literami, wyrazami czy jeszcze jakimiś innymi jednostkami. + +*** Pomiar entropii języka — pierwsze przybliżenie + +Załóżmy, że chcemy zmierzyć entropię języka polskiego na przykładzie +„Pana Tadeusza” — na poziomie znaków. W pierwszym przybliżeniu można +by policzyć liczbę wszystkich znaków… + +#+BEGIN_SRC python :session mysession :exports both :results raw drawer + chars_in_pan_tadeusz = len(set(get_characters(pan_tadeusz))) + chars_in_pan_tadeusz +#+END_SRC + +#+RESULTS: +:results: +95 +:end: + +… założyć jednostajny rozkład prawdopodobieństwa i w ten sposób policzyć entropię: + +#+BEGIN_SRC python :session mysession :exports both :results raw drawer + from math import log + + 95 * (1/95) * log(95, 2) +#+END_SRC + +#+RESULTS: +:results: +6.569855608330948 +:end: + +*** Mniej rozrzutne kodowanie + +Przypomnijmy sobie jednak, że rozkład jednostek języka jest zawsze +skrajnie nierównomierny! Jeśli uwzględnić ten nierównomierny rozkład +znaków, można opracować o wiele efektywniejszy sposób zakodowania znaków składających się na „Pana Tadeusza” +(częste litery, np. „a” i „e” powinny mieć krótkie kody, a rzadkie, np. „ź” — dłuższe kody). + +Policzmy entropię przy takim założeniu: + +#+BEGIN_SRC python :session mysession :exports both :results raw drawer + from collections import Counter + from math import log + + def unigram_entropy(t): + counter = Counter(t) + + total = counter.total() + return -sum((p := count / total) * log(p, 2) for count in counter.values()) + + unigram_entropy(get_characters(pan_tadeusz)) +#+END_SRC + +#+RESULTS: +:results: +4.938605272823633 +:end: + +*** Ile wynosi entropia rękopisu Wojnicza? + +#+BEGIN_SRC python :session mysession :exports both :results raw drawer + unigram_entropy(get_characters(voynich)) +#+END_SRC + +#+RESULTS: +:results: +4.973808176335181 +:end: + +Wartość zaskakująco zbliżona do „Pana Tadeusza”! + +*** Rzeczywista entropia? + +W rzeczywistości entropia jest jeszcze mniejsza, tekst nie jest +generowany przecież według rozkładu wielomianowego. Istnieją rzecz +jasna pewne zależności między znakami, np. niemożliwe, żeby po „ń” +wystąpiły litera „a” czy „e”. Na poziomie wyrazów zależności mogę mieć +jeszcze bardziej skrajny charakter, np. po wyrazie „przede” prawie na +pewno wystąpi „wszystkim”, co oznacza w takiej sytuacji słowo +„wszystkim” może zostać zakodowane za pomocą 0 (!) bitów. + +Można uwzględnić takie zależności i uzyskać jeszcze lepsze kodowanie, +a co za tym idzie lepsze oszacowanie entropii. + +*** Rozmiar skompresowanego pliku jako przybliżenie entropii + +Cele algorytmów kompresji jest właściwie wyznaczanie efektywnych +sposobów kodowania danych. Możemy więc użyć rozmiaru skompresowanego pliku w bitach +(po podzieleniu przez oryginalną długość) jako dobrego przybliżenia entropii. + +#+BEGIN_SRC python :session mysession :exports both :results raw drawer + import zlib + + def entropy_by_compression(t): + compressed = zlib.compress(t.encode('utf-8')) + return 8 * len(compressed) / len(t) + + entropy_by_compression(pan_tadeusz) +#+END_SRC + +#+RESULTS: +:results: +3.673019884633768 +:end: + +Dla porównania wynik dla rękopisu Wojnicza: + +#+BEGIN_SRC python :session mysession :exports both :results raw drawer + entropy_by_compression(voynich) +#+END_SRC + +#+RESULTS: +:results: +2.90721912311904 +:end: diff --git a/wyk/02_Jezyki/gas-high-entropy.drawio b/wyk/02_Jezyki/gas-high-entropy.drawio new file mode 100644 index 0000000..667bb82 --- /dev/null +++ b/wyk/02_Jezyki/gas-high-entropy.drawio @@ -0,0 +1 @@ +jZPfb4MgEMf/Gh+bKFS3vs513bLsqUv2TIQKLXiO0mr31w/l/JVmydAofO444HtHRHPT7iyr5QdwoSMS8zaizxEhm3Xivx24BZCSNIDSKh5QMoG9+hEIY6QXxcV54egAtFP1EhZQVaJwC8ashWbpdgC9XLVmpbgD+4Lpe/qluJOBPpKHib8KVcph5STbBIthgzOGOEvGoQmoPxzdRjS3AC70TJsL3Wk36BIUePnDOm7Misr9Z8LpuNrG5ppe31ylDf1+P+6yFR7jyvQFDxyRtX8/ww937m6DHBYuFRddxDiiT41UTuxrVnTWxuffM+mM9qPEd8/OwmmUjXpyUFrnoMH20egh7Z6OQ+VmPLQxwsyS9c1bcN/COtH+KUgyyuzLU4ARzt68C04gFGsMS5OmOG6mRJM1MjlLcoaMYW2VY+hJft/BDAzDKdO9bXZd6PYX \ No newline at end of file diff --git a/wyk/02_Jezyki/gas-high-entropy.drawio.png b/wyk/02_Jezyki/gas-high-entropy.drawio.png new file mode 100644 index 0000000..69022e4 Binary files /dev/null and b/wyk/02_Jezyki/gas-high-entropy.drawio.png differ diff --git a/wyk/02_Jezyki/gas-low-entropy.drawio b/wyk/02_Jezyki/gas-low-entropy.drawio new file mode 100644 index 0000000..5ab76e1 --- /dev/null +++ b/wyk/02_Jezyki/gas-low-entropy.drawio @@ -0,0 +1 @@ +5ZVRT8IwEMc/zR5NtpUVeBRENMYnTHw0db1t1W7FUhj46b3RbmMwEk3UmJgQcv3f7a79/QvzyDTfzjVbZveKg/RCn289cuWF4XgQ4Hcl7KwQhZEVUi24lYJWWIh3cKLv1LXgsOoUGqWkEcuuGKuigNh0NKa1KrtliZLdqUuWwomwiJk8VR8FN5lVR+Gw1W9ApFk9OaBjm8lZXexarDLGVWml/eHIzCNTrZSxUb6dgqzY1Vwsgesz2WZjGgrzmQdeXy5mfr6JNremkDl5u3uZ04vQdtkwuXYHdps1u5qAVuuCQ9XE98ikzISBxZLFVbZEy1HLTC5xFWC4Mlq9NqQIKomQcqqk0vtuJEmAxnFTeZDhw/GzX41wWwJtYHv2rEFDEG8eqByM3mGJeyAk7vrsjtZl62HgePnZgX/Uacxdm7Rp3ZLFwMH9Amjy26A5g1HSC5rGI3hOvgc0if4a6KgHNJU4dcLFBsPU7E8+wM/DU2CDugIHdoqODEJMps+Fmm2hCjgywklMirTAZYxYAfVJBV3gv8ylS+SC82pMr+3di/EdPw965NogOnGN9phGfso0+hXTwv9pGhn9mmm4bN9L+9zBy53MPgA= \ No newline at end of file diff --git a/wyk/02_Jezyki/gas-low-entropy.drawio.png b/wyk/02_Jezyki/gas-low-entropy.drawio.png new file mode 100644 index 0000000..0217e1c Binary files /dev/null and b/wyk/02_Jezyki/gas-low-entropy.drawio.png differ