Compare commits
No commits in common. "0e3b4678b3cb84ad714f612cd2094a5e31d723ea" and "a21165d65d06a1920ba85afc17e342a3e13d13e5" have entirely different histories.
0e3b4678b3
...
a21165d65d
@ -157,7 +157,7 @@ Vytvoříme povrch, kde hodnota je konstantní. Na vytvoření isosurface může
|
||||
### Direct volume rendering
|
||||
|
||||
Vykreslíme objemová data přímo. Můžeme použít různé techniky, jako např. ray casting, nebo splatting.
|
||||
Detailní fungování je popsané v otázce [PGV06](../pgv06_vykreslovani_objemovych_dat).
|
||||
Detailní fungování je popsané v otázce [PGV06](../PGV06_vykreslovani_objemovych_dat).
|
||||
|
||||
## Geovizualizace
|
||||
|
||||
|
@ -388,6 +388,249 @@ k + (\|S\| - k) - \|S\| = 0 & \text{pokud } \|S\| > k \\
|
||||
\end{cases}
|
||||
```
|
||||
|
||||
## Vyhledávání řetězců (string matching)
|
||||
|
||||
_String matching_ označuje rodinu problémů obsahující třeba:
|
||||
|
||||
- Nalezení prvního přesného výskytu podřetězce (_patternu_) v řetězci (_stringu_ / _textu_).
|
||||
- Nalezení všech výskytů podřetězce v řetězci.
|
||||
- Výpočet vzdálenosti dvou řetězců.
|
||||
- Hledání opakujících se podřetězců.
|
||||
|
||||
Většinou je řetězec polem znaků z konečné abecedy $\Sigma$. String matching algoritmy se ale dají použít na ledacos.
|
||||
|
||||
Vzorek $P$ se vyskytuje v textu $T$ s posunem $s$, pokud $0 \le s \le n - m$ a zároveň $T\lbrack (s+1) .. (s + m) \rbrack = P$. Pro nalezení platných posunů lze použít řadu algoritmů, které se liší složitostí předzpracování i samotného vyhledávání: [^iv003-strings]
|
||||
|
||||
| Algoritmus | Preprocessing | Searching |
|
||||
| ----------------------------------- | ------------------------------------ | ----------------------------------- |
|
||||
| Brute force / naivní | $0$ | $\mathcal{O}((n - m + 1) \cdot m)$ |
|
||||
| Karp-Rabin | $\Theta(m)$ | $\mathcal{O}((n - m + 1) \cdot m)$ |
|
||||
| finite automata | $\Theta(m \cdot \vert \Sigma \vert)$ | $\Theta(n)$ |
|
||||
| Knuth-Morris-Pratt | $\Theta(m)$ | $\Theta(m)$ |
|
||||
| Boyer-Moore | $\Theta(m + \vert \Sigma \vert)$ | $\mathcal{O}((n - m + 1) \cdot m)$ |
|
||||
|
||||
- $T$ nebo $T\lbrack 1..n \rbrack$ -- text.
|
||||
- $P$ nebo $P\lbrack 1..m \rbrack$ -- pattern.
|
||||
- $n$ -- délka textu $T$.
|
||||
- $m$ -- délka vzorku / podřetězce / patternu $P$.
|
||||
- $\Sigma$ -- konečná abeceda, ze které je složen text i pattern.
|
||||
|
||||
### Brute force / naivní
|
||||
|
||||
Prochází všechny pozice v textu a porovnává je s patternem. Pokud se neshodují, posune se o jedno pole dopředu.
|
||||
|
||||
Pokud se text neshoduje už v prvním znaku, je složitost lineární. Avšak v nejhorším případě, kdy se pattern shoduje s textem až na poslední znak, je složitost až kvadratická.
|
||||
|
||||
```csharp
|
||||
int Naive(string text, string pattern)
|
||||
{
|
||||
int n = text.Length;
|
||||
int m = pattern.Length;
|
||||
for (int i = 0; i < n - m + 1; i++)
|
||||
{
|
||||
// NB: Substring creates a new string but let's not worry about that.
|
||||
if (text.Substring(i, m) == pattern)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
```
|
||||
|
||||
- **Složitost**\
|
||||
Cyklus je proveden $n-m+1$-krát. V každé iteraci se provede přinejhorším až $m$ porovnání. (Zanedbáváme složitost `Substring`, která v C# dělá kopii.)
|
||||
|
||||
### Karp-Rabin
|
||||
|
||||
Používá hashování. Vytvoří hash z patternu a hashuje i všechny podřetězce délky $m$ v textu. Nejprve eliminuje všechny pozice, kde se hashe neshodují. Pokud se shodují, porovná je znak po znaku.
|
||||
|
||||
```csharp
|
||||
int KarpRabin(string text, string pattern)
|
||||
{
|
||||
int n = text.Length;
|
||||
int m = pattern.Length;
|
||||
int patternHash = pattern.GetHash();
|
||||
for (int i = 0; i < n - m + 1; i++)
|
||||
{
|
||||
// NB: Assume that `GetHash` is a rolling hash, even though in .NET it's not.
|
||||
if (text.Substring(i, m).GetHash() == patternHash)
|
||||
{
|
||||
if (text.Substring(i, m) == pattern)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
```
|
||||
|
||||
- **Hashování**\
|
||||
Trik spočívá v použití _rolling_ hashovacího algoritmu. Ten je schopný při výpočtu hashe pro $T\lbrack s .. (s + m) \rbrack$ použít hash $T\lbrack s .. (s + m - 1) \rbrack$ s využitím pouze jednoho dalšího znaku $T\lbrack s + m \rbrack$. Přepočet hashe je tedy $\mathcal{O}(1)$.
|
||||
|
||||
Jeden takový algoritmus lze získat použitím Hornerova schématu pro evaluaci polynomu. [^horner] Předpokládejme, že $\Sigma = \{0, 1, ..., 9\}$ (velikost může být libovolná), pak pro hash $h$ platí
|
||||
|
||||
```math
|
||||
\begin{align*}
|
||||
h &= P[1] + 10 \cdot P[2] + 10^2 \cdot P[3] + ... + 10^{m-1} \cdot P[m] \\
|
||||
&= P[1] + 10 \cdot (P[2] + 10 \cdot (P[3] + ... + 10 \cdot P[m] ... ))
|
||||
\end{align*}
|
||||
```
|
||||
|
||||
Pokud jsou hashe příliš velké, lze navíc použít modulo $q$, kde $10 \cdot q \approx \text{machine word}$.
|
||||
|
||||
- **Složitost**\
|
||||
Předzpracování zahrnuje výpočet $T \lbrack 1..m \rbrack$ v $\Theta(m)$.
|
||||
|
||||
Složitost výpočtu je v nejhorším případě $\mathcal{O}((n - m + 1) \cdot m)$, jelikož je potřeba porovnat všechny podřetězce délky $m$ s patternem.
|
||||
|
||||
Tento algoritmus se hodí použít, pokud hledáme v textu celé věty, protože neočekáváme velké množství "falešných" shod, které mají stejný hash jako $P$. V tomto případě je průměrná složitost $\mathcal{O}(n)$.
|
||||
|
||||
### Konečné automaty
|
||||
|
||||
Složitost naivního algortmu lze vylepšit použitím konečného automatu.
|
||||
|
||||
Mějmě DFA $A = (\{0, ..., m\}, \Sigma, \delta, \{0\}, \{m\})$, kde přechodobou funkci definujeme jako:
|
||||
|
||||
```math
|
||||
\delta(q, x) = \text{největší } k \text{ takové, že } P[1..k] \text{ je \textbf{prefix} a zároveň \textbf{suffix} } P[1..q] . x
|
||||
```
|
||||
|
||||
Jinými slovy, $\delta$ vrací delků nejdelšího možného začátku $P$, který se nachází na daném místě (stavu $q$) v řetězci $T$.
|
||||
|
||||
Prakticky by příprava přechodové funkce mohla vypadat takto:
|
||||
|
||||
```csharp
|
||||
int[,] CreateAutomaton(string pattern)
|
||||
{
|
||||
int m = pattern.Length;
|
||||
// NB: Assumes that the alphabet is ASCII.
|
||||
int[,] automaton = new int[m + 1, 256];
|
||||
for (int q = 0; q <= m; q++)
|
||||
{
|
||||
for (int c = 0; c < 256; c++)
|
||||
{
|
||||
int k = Math.Min(m + 1, q + 2);
|
||||
do
|
||||
{
|
||||
k--;
|
||||
}
|
||||
while (!pattern.Substring(0, q).Equals(pattern.Substring(0, k) + (char)c));
|
||||
automaton[q, c] = k;
|
||||
}
|
||||
}
|
||||
return automaton;
|
||||
}
|
||||
```
|
||||
|
||||
Vyhledávání v textu pak bude vypadat takto:
|
||||
|
||||
```csharp
|
||||
int FiniteAutomaton(string text, string pattern)
|
||||
{
|
||||
int n = text.Length;
|
||||
int m = pattern.Length;
|
||||
int[,] automaton = CreateAutomaton(pattern);
|
||||
int q = 0;
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
q = automaton[q, text[i]];
|
||||
if (q == m)
|
||||
{
|
||||
return i - m + 1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
```
|
||||
|
||||
Tato metoda šetří čas, pokud se pattern v některých místech opakuje. Mějmě například pattern `abcDabcE` a text `abcDabcDabcE`. Tato metoda nemusí začínat porovnávat pattern od začátku po přečtení druhého `D`, ale začne od $P \lbrack 5 \rbrack$ (včetně), protože _ví_, že předchozí část patternu se již vyskytla v textu.
|
||||
|
||||
Jinými slovy na indexu druhého `D` je `abcD` nejdelší prefix $P$, který je zároveň suffixem už načteného řetězce.
|
||||
|
||||
- **Složitost**\
|
||||
Vytvoření automatu vyžaduje $\Theta(m^3 \cdot |\Sigma|)$ času, dá se však provést efektivněji než v `CreateAutomaton` a to v čase $\Theta(m \cdot |\Sigma|)$.
|
||||
|
||||
Složitost hledání je pak v $\Theta(n)$. [^iv003-strings]
|
||||
|
||||
### Knuth-Morris-Pratt (KMP)
|
||||
|
||||
KMP představuje efektivnější využití idei z metody konečného automatu:
|
||||
|
||||
- Každý stav $q$ je označen písmenem z patternu. Výjimkou je počáteční stav $S$ a koncový stav $F$.
|
||||
- Každý stav má hranu `success`, která popisuje sekvenci znaků z patternu, a `failure` hranu, která míří do některého z předchozích stavů -- takového, že už načtené znaky jsou největší možný prefix patternu.
|
||||
|
||||
V reálné implementaci nejsou `success` hrany potřeba; potřebujeme jen vědět, kam skočit v případě neúspěchu.
|
||||
|
||||
```csharp
|
||||
/// <summary>
|
||||
/// Computes the longest proper prefix of P[0..i]
|
||||
/// that is also a suffix of P[0..i].
|
||||
/// </summary>
|
||||
int[] ComputeFailure(string pattern)
|
||||
{
|
||||
int m = pattern.Length;
|
||||
int[] fail = new int[m];
|
||||
int j = 0;
|
||||
for (int i = 1; i < m; i++)
|
||||
{
|
||||
while (j >= 0 && pattern[j] != pattern[i])
|
||||
{
|
||||
j = fail[j];
|
||||
}
|
||||
|
||||
// If comparison at i fails,
|
||||
// return to j as the new starting point.
|
||||
fail[i] = j;
|
||||
|
||||
j++;
|
||||
}
|
||||
return fail;
|
||||
}
|
||||
|
||||
int KnuthMorrisPratt(string text, string pattern)
|
||||
{
|
||||
int[] fail = ComputeFailure(pattern);
|
||||
int n = text.Length;
|
||||
int m = pattern.Length;
|
||||
// NB: I index from 0 here. Although I use 1..n in the text.
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
while (j >= 0 && text[i] != pattern[j])
|
||||
{
|
||||
/*
|
||||
There can be at most n-1 failed comparisons
|
||||
since the number of times we decrease j cannot
|
||||
exceed the number of times we increment i.
|
||||
*/
|
||||
j = fail[j];
|
||||
}
|
||||
|
||||
j++;
|
||||
if (j == m)
|
||||
{
|
||||
return i - m;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> Nejsem si jistý, že ty indexy v kódu výše mám dobře.
|
||||
|
||||
> [!NOTE]
|
||||
> "In other words we can amortize character mismatches against earlier character matches." [^iv003-strings]
|
||||
|
||||
- **Složitost**\
|
||||
Amortizací neúspěšných porovnání vůči úspěšným získáme $\mathcal{O}(m)$ pro `ComputeFailure` a $\mathcal{O}(n)$ pro `KnuthMorrisPratt`.
|
||||
|
||||
|
||||
[^iv003]: [IV003 Algoritmy a datové struktury II (jaro 2021)](https://is.muni.cz/auth/el/fi/jaro2021/IV003/)
|
||||
[^iv003-strings]: https://is.muni.cz/auth/el/fi/jaro2021/IV003/um/slides/stringmatching.pdf
|
||||
[^rabin-karp-wiki]: https://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm
|
||||
[^horner]: https://en.wikipedia.org/wiki/Horner%27s_method
|
||||
[^backtracking]: https://betterprogramming.pub/the-technical-interview-guide-to-backtracking-e1a03ca4abad
|
||||
|
@ -322,7 +322,7 @@ description: "TODO"
|
||||
### Změna struktury sítě
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Modifikace meshů mají značný přesah do otázky [Křivky a povrchy](../szp05_krivky_a_povrchy/) a taky [Pokročilá počítačová grafika](../vph01_pokrocila_grafika/)
|
||||
> Modifikace meshů mají značný přesah do otázky [Křivky a povrchy](../krivky-a-povrchy/) a taky [Pokročilá počítačová grafika](../vph01_pokrocila_grafika/)
|
||||
|
||||
- **Překlápění hrany / edge flip**\
|
||||
Lokální změna, která nahradí hranu $(b,c)$ hranou $(a,d)$. Trojúhelníky $(a,b,c)$ a $(b,d,c)$ se stanou $(a,d,c)$ a $(a,b,d)$. [^pa010-2021]
|
||||
|
@ -135,9 +135,6 @@ Hledá nejkratší cesty z jednoho vrcholu do všech ostatních.
|
||||
- Využívá relaxaci hran.
|
||||
- Funguje i na grafech se zápornými hranami.
|
||||
- Má časovou složitost $\mathcal{O}(\lvert V \rvert \cdot \lvert E \rvert)$.
|
||||
- Udělá max $V-1$ iterací, protože nejdelší cesta může mít max $V-1$ hran (přes žádný vertex nepůjdeš dvakrát).
|
||||
- _Modifikace_: Po $V-1$ by už nejkratší cesty měly být nalezeny. Udělejme ještě jednu iteraci - pokud se hodnoty změní, pak nejkratší cesta obsahuje negativní cyklus. Viz python kód dole.
|
||||
- _Modifikace_: Early stop - pokud se 2 interace po sobě hodnoty vrcholů nezmění, pak jsme našli nejkratší cesty.
|
||||
|
||||
```python
|
||||
def bellmanford(graph: List[List[Tuple[int, int]]], s: int) \
|
||||
@ -229,9 +226,9 @@ Dijkstrův algoritmus lze optimalizovat, pokud nás zajímá jen nejkratší ces
|
||||
- **Fundamental cutset / řez**\
|
||||
Fundamental cutset je množina hran $D$ v grafu $G$ taková, že přidáním libovolné hrany $e \in D$ získáme kostru.
|
||||
- **Red rule**\
|
||||
Najdi cyklus bez červených hran, vyber v něm **neobarvenou** hranu s **nejvyšší** cenou a obarvi ji červeně. Červená hrana znamená odebrání z finální kostry.
|
||||
Najdi cyklus bez červených hran, vyber v něm **neobarvenou** hranu s **nejvyšší** cenou a obarvi ji červeně.
|
||||
- **Blue rule**\
|
||||
Najdi řez bez modrých hran, vyber v něm **neobarvenou** hranu s **nejmenší** cenou a obarvi ji modře. Modrá hrana znamená přidání do finální kostry.
|
||||
Najdi řez bez modrých hran, vyber v něm **neobarvenou** hranu s **nejmenší** cenou a obarvi ji modře.
|
||||
- **Greedy algoritmus**\
|
||||
Nedeterministicky aplikuj red rule a blue rule, dokud to jde (stačí $n-1$ iterací). Modré hrany tvoří MST.
|
||||
- **Jarníkův / Primův algoritmus**\
|
||||
@ -308,7 +305,7 @@ Dijkstrův algoritmus lze optimalizovat, pokud nás zajímá jen nejkratší ces
|
||||
Je funkce $f: E \rightarrow \mathbb{R}^+$, která splňuje:
|
||||
|
||||
- podmínku kapacity: $(\forall e \in E)(f(e) \ge 0 \land f(e) \leq c(e))$
|
||||
- _tok hranou je nezáporný a nepřevyšuje povolenou kapacitu_
|
||||
- _tok hranou je nezáporný a nepřevyšuje povolennou kapacitu_
|
||||
- podmínku kontinuity: $(\forall v \in V \setminus \{s, t\})(\sum_{e \in \delta^+(v)} f(e) = \sum_{e \in \delta^-(v)} f(e))$
|
||||
- _tok do vrcholu je stejný jako tok z vrcholu_
|
||||
|
||||
@ -335,7 +332,7 @@ Dijkstrův algoritmus lze optimalizovat, pokud nás zajímá jen nejkratší ces
|
||||
$$
|
||||
|
||||
- **Augmenting path $P$**\
|
||||
Jednoduchá $s \rightsquigarrow t$ cesta v residuální síti $G_f$. Cesty hledáš buď BFS nebo DFS - každou iteraci si prostě nějakou vybereš.
|
||||
Jednoduchá $s \rightsquigarrow t$ cesta v residuální síti $G_f$.
|
||||
|
||||
> [!NOTE]
|
||||
> T.j. cesta která může jít i proti směru toku $f$.
|
||||
@ -521,11 +518,11 @@ Dijkstrův algoritmus lze optimalizovat, pokud nás zajímá jen nejkratší ces
|
||||
|
||||
**Srovnání algoritmů Ford-Fulkerson a Push-Relabel**
|
||||
|
||||
| Ford-Fulkerson | Push-Relabel (Goldberg) |
|
||||
| ------------------------------------ | ----------------------- |
|
||||
| global character | local character |
|
||||
| update flow along an augmenting path | update flow on edges |
|
||||
| flow conservation | preflow |
|
||||
| Ford-Fulkerson |
|
||||
| ----------------------- | ------------------------------------ |
|
||||
| Push-Relabel (Goldberg) | global character |
|
||||
| local character | update flow along an augmenting path |
|
||||
| update flow on edges | flow conservation |
|
||||
|
||||
## Maximální párování v bipartitních grafech
|
||||
|
||||
@ -559,6 +556,9 @@ Dijkstrův algoritmus lze optimalizovat, pokud nás zajímá jen nejkratší ces
|
||||
|
||||

|
||||
|
||||
[^ib000]: [IB000 Matematické základy informatiky (podzim 2022)](https://is.muni.cz/auth/el/fi/podzim2022/IB000/um/)
|
||||
[^ib002]: [IB002 Algoritmy a datové struktury (jaro 2020)](https://is.muni.cz/auth/el/fi/jaro2020/IB002/um/)
|
||||
[^ib003]: [IV003 Algoritmy a datové struktury II (jaro 2021)](https://is.muni.cz/auth/el/fi/jaro2021/IV003/um/)
|
||||
[^matching]: [Wikipedia: Párování grafu](https://cs.wikipedia.org/wiki/P%C3%A1rov%C3%A1n%C3%AD_grafu)
|
||||
[^mcm]: [Wikipedia: Maximum cardinality matching](https://en.wikipedia.org/wiki/Maximum_cardinality_matching)
|
||||
|
||||
|
@ -4,7 +4,7 @@ description: "TODO"
|
||||
---
|
||||
|
||||
> [!WARNING]
|
||||
> Tato je stará verze otázky. Nová verze: [Grafické principy ve vývoji her](../vph01_graficke_principy_ve_vyvoji_her).
|
||||
> Tato je stará verze otázky. Nová verze: [Grafické principy ve vývoji her](../VPH01_graficke_principy_ve_vyvoji_her).
|
||||
|
||||
> [!NOTE]
|
||||
> Techniky aproximace objektů. Renderování objemových dat (bodový mrak, techniky rekonstrukce povrchů, přímé renderování objemu). Lokální a globální modely nasvícení. Renderování založené na fyzikálních modelech (PBR). Techniky renderování stínů.
|
||||
|
@ -4,7 +4,7 @@ description: "TODO"
|
||||
---
|
||||
|
||||
> [!WARNING]
|
||||
> Tato je stará verze otázky. Nová verze: [Fyzikální principy ve vývoji her](../vph02_fyzikalni_principy_ve_vyvoji_her).
|
||||
> Tato je stará verze otázky. Nová verze: [Fyzikální principy ve vývoji her](../VPH02_fyzikalni_principy_ve_vyvoji_her).
|
||||
|
||||
> [!NOTE]
|
||||
> Příprava a vývoj scény, grayboxing, zástupné modely (placeholders). Optimalizace výkonu vykreslování (úrovně detailů, odstřelování objektů, MIP mapy). Využití shaderů pro efekty ve hrách. Sledování paprsků, objekty pro detekci kolizí, fyzika hadrové panenky.
|
||||
|
@ -50,11 +50,6 @@ for f in files:
|
||||
search = f"../{url}"
|
||||
if search in l:
|
||||
lines[i] = l.replace(search, f"../{links[url].lower()}")
|
||||
l = lines[i]
|
||||
|
||||
for filename in links.values():
|
||||
if filename in l:
|
||||
lines[i] = l.replace(filename, filename.lower())
|
||||
|
||||
with open(os.path.join(TARGET_DIR, f), "w") as file:
|
||||
file.writelines(lines)
|
Loading…
Reference in New Issue
Block a user