diff --git a/data_lib.py b/data_lib.py index 147957c9562f10e01477519a609e4c84d327d6aa..37812aed72624343cb2f042a11fd0a670d5a8881 100644 --- a/data_lib.py +++ b/data_lib.py @@ -46,9 +46,6 @@ class Run: self._from = None self.seed = json["seed"] - if self.error: - print(self, self.print_pipeline(), self.algo_version, self.is_up_to_date()) - def print_pipeline(self, versions=False): x = "" if self._from: @@ -64,6 +61,8 @@ class Run: return x def is_up_to_date(self): + if not self.data_cls.validate_versions: + return True if self._from and not self._from.is_up_to_date(): return False return self.algo_version == self.algo.current_version diff --git a/prace/bakalarka/formatitko_commands.py b/prace/bakalarka/formatitko_commands.py index 127589752ab6a050c1162e26b6abdaf7b789d8f3..95213f5541c724a9424802d6c9e1e49859ca22ee 100644 --- a/prace/bakalarka/formatitko_commands.py +++ b/prace/bakalarka/formatitko_commands.py @@ -42,7 +42,8 @@ def box(element, context, processor): 'task': "Úloha", 'algo': "Algoritmus", 'theorem': "Věta", - 'lemma': "Lemma" + 'lemma': "Lemma", + 'def': "Definice", }[element.attributes["t"]] out = [] intro = [] @@ -86,3 +87,48 @@ def figure(element, content, processor): x = processor.transform([pf.Figure(*data, caption=pf.Caption(pf.Plain(*caption)), identifier=element.identifier, attributes=element.attributes)]) x[0].content = remove_div_para_to_plain(*x[0].content) return x + +def copy(e, *content): + kwargs = dict() + if hasattr(e, 'attributes'): + kwargs['attributes'] = e.attributes + if hasattr(e, 'classes'): + kwargs['classes'] = e.classes + if hasattr(e, 'identifier'): + kwargs['identifier'] = e.identifier + return type(e)( + *content, + **kwargs + ) + +def texb(s): + return pf.RawBlock(s, format="tex") +def texi(s): + return pf.RawInline(s, format="tex") + +@formatitko_command +def refs(element, content, processor): + x = [] + (div1,) = element.content + assert type(div1) == pf.Div + for div2 in div1.content: + assert type(div2) == pf.Div, type(div2) + for para in div2.content: + assert type(para) == pf.Para, para + x.append(copy(div2, copy(para, + texi("\\hskip -1.3cm\\hbox to 1.3cm{"), + para.content[0], + texi("\\hfil}"), + *para.content[1:], + ))) + + return [ + texb( + """{ + \\leftskip=1.3cm + \\rightskip=0pt plus 3em + \\relax""" + ), + copy(div1, *x), + texb("}"), + ] diff --git a/prace/bakalarka/g.py b/prace/bakalarka/g.py index 41db803c2322ddea2a02262724c72c522464e178..e7909a105ae0a55e5b374013bc60563d0b7b4767 100644 --- a/prace/bakalarka/g.py +++ b/prace/bakalarka/g.py @@ -4,12 +4,16 @@ import plotly.graph_objects as go import numpy as np from . import data_lib import pathlib +import sys, os d = pathlib.Path("/".join(__file__.split("/")[:-1])) def load(name): return data_lib.Data(d/name, validate_versions=False) +def load_main_test(): + return load(d/"main_test/log") + algo_to_name = { "greedy": "Hladové ř.", "rg": "Rekurzivní ř.", @@ -38,11 +42,12 @@ def draw_algo_graph(fig, data, algo, n, val_getter=lambda x:x.score, name=None, def intro_graph(algo): fig = plotly.subplots.make_subplots(rows=2, cols=1, row_heights=[0.8, 0.2], shared_xaxes=True, vertical_spacing = 0.05) - draw_algo_graph(fig, data_lib.Data(d/"log-intr", validate_versions=False), algo, 200) + draw_algo_graph(fig, load_main_test(), algo, 200) return fig def nonzero_coords(n, seeds, max_dim=20): - nonzero_coords = [[float(i) for i in open(d/f"semidef_prog_nonzero_coord/n{n}_seed{i:04}").read().split()] for i in seeds] + data_dir = d/"main_test/sdp/nonzero_coord" + nonzero_coords = [[float(i) for i in open(data_dir/f).read().split()] for f in os.listdir(data_dir) if f.startswith(f"{n}-")] fig = go.Figure(data=[go.Box( y=[x[i] for x in nonzero_coords], @@ -61,7 +66,8 @@ def nonzero_coords(n, seeds, max_dim=20): return fig def max_coords(n, seeds, max_dim=20): - max_coords = [[float(i) for i in open(d/f"semidef_prog_max_coord/n{n}_seed{i:04}").read().split()] for i in seeds] + data_dir = d/"main_test/sdp/max_coord" + max_coords = [[float(i) for i in open(data_dir/f).read().split()] for f in os.listdir(data_dir) if f.startswith(f"{n}-")] fig = go.Figure(data=[go.Box( y=[x[i] for x in max_coords], diff --git a/prace/bakalarka/index.md b/prace/bakalarka/index.md index 454b5087032944165839e690b333c48f236980f7..9b64deaf0f30106250a2df273ea9e3e2351bbedf 100755 --- a/prace/bakalarka/index.md +++ b/prace/bakalarka/index.md @@ -8,7 +8,18 @@ ft: department: Informatický ústav Univerzity Karlovy department_type: Ústav supervisor: doc. Mgr. Robert Šámal, Ph.D. - abstract: TODO + abstract: | + Binární paint shop je následující optimalizační úloha: + Na barvicí linku vjíždí řada aut. + Od každého typu auta jsou tu právě dvě auta a + jedno z nich bychom rádi nabarvili červeně a druhé modře. + Měnit barvu, kterou aktuálně barvíme, je složitá operace, + proto bychom rádi pro danou posloupnost aut provedli co nejméně změn. + Je známé, že úloha je NP-těžká a za určitých předpokladů dokonce neaproximovatelná, + proto je na místě zkoumat řešení, co se chovají dobře na náhodném vstupu. + V této práci je představen nový algoritmus založený na semidefinitním programování, který dle provedených měření pro náhodné vstupy s až 400 typy aut dosahuje výsledků okolo 0.33-násobku počtu typů aut. + O algoritmu jsme dokázali, že pro každý vstup vrátí řešení nejhůře o 0.212 násobek počtu typů aut horší než optimum. + Bohužel se mi nepodařilo dokázat žádný netriviální horní odhad na střední hodnotu počtu změn na náhodném vstupu. keywords: [binární paint shop problém, aproximační algoritmus] year: 2024 study_programme: Informatika @@ -20,22 +31,42 @@ ft: abstract: TODO (en) --- ``` {c=cmt} -velka tecka -float mezery -Algoritmus na Maximáľní řez: rozčlenit na věty a podobné +Algoritmus na Maximální řez: rozčlenit na věty a podobné +Pozicování stránek: nadpisy na konci, float do dalších sekcí +Opravit tvrzení o skoropotimáľníĺ řešení SDP +Klikaci věci + generování obsahu formátítkem +Více řezů +složitost je n^c pro jaké c? +intervaly *[]* <> + ``` ::: {only=html} $\def\progline#1#2#3{\hbox{#1}\hskip 1cm\relax #2 \hskip 1cm\relax #3} \def\P{{\rm P}} \def\NP{{\rm NP}} -\def\APX{{\rm APX}}$ +\def\APX{{\rm APX}} +\def\opt{{\rm opt}} +\def\algo#1{{\bf #1}} +\def\alg{\algo{alg}}$ ::: ``` {=tex} \def\progline#1#2#3{\hbox to 3cm{#1\hfil}\hbox to 5cm{\hfil$\displaystyle #2$\hfil}\hbox to 4cm{$\displaystyle #3$\hfil}} \def\P{{\rm P}} \def\NP{{\rm NP}} \def\APX{{\rm APX}} +\def\vec#1{\overrightarrow{#1\,}} +\let\rightarrowfillreal\rightarrowfill +\catcode`@=11 +\def\overrightarrow#1{\vbox{\m@th\ialign{##\crcr + \rightarrowfill\crcr\noalign{\kern-\p@\kern 0.09em\nointerlineskip} + $\hfil\displaystyle{#1}\hfil$\crcr}}} +\def\rightarrowfill{$\settextsize{5}\m@th\smash-\mkern-7mu% + \cleaders\hbox{$\mkern-2mu\smash-\mkern-2mu$}\hfill + \settextsize{5}\mkern-7mu\mathord\rightarrow$} +\def\opt{{\rm opt}} +\def\algo#1{{\bf #1}} +\def\alg{\algo{alg}} ``` ::: {c=head} @@ -50,18 +81,16 @@ Obsah {-} Úvod ===== -TODO - -V této práci si představíme binární paint shop problem. -Jedná se o úlohu, kterou neumíme efektivně řešit a ani aproximovat, +V této práci představíme binární paint shop problem. +Jedná se o úlohu, kterou neumíme efektivně řešit (protože je $\NP$ úplná) +a ani aproximovat (za předpokladu Unique games conjecture je $c$-aproximace také $\NP$ těžká), takže mimo jiné probíhá aktivní výzkum snažící se najít algoritmus, který je dobrý v průměrném případě (pro náhodný vstup). - Zadání ------ -Nejprve si pojďme představit zadání binárního paint shop problému (dále těž BPS): +Zadání binárního paint shop problému (dále těž BPS) je následující: ::: {c=box t=task name="Binární paint shop"} V řadě je $2n$ aut $n$ různých typů -- od každého typu dvě. @@ -72,51 +101,28 @@ Tedy měnit barvu, kterou se barví, je složitá a drahá záležitost. Chceme tedy nají obarvení aut tak, aby od každého typu bylo jedno červené a jedno modré, přitom počet změn barev v řadě byl co nejmenší. ::: -Počet změn barev značíme jako skóre algoritmu. +Počet změn barev řešení považujeme za skóre algoritmu. Problém můžeme chápat buď jako optimalizační problém, kde účelová funkce je počet změn v řešení a snažíme se ji minimalizovat, nebo jako rozhodovací problém, kde se ptáme, jestli existuje řešení s nejvýše nějakým zadaným počtem změn. -Zobecněné verze a související problémy --------------------------------------- +Cíle práce +---------- -Zobecněním binárního paint shopu je obecný paint shop problém, zavedený Epingem a spol. [@ps], -Z něj pochází motivace k binární verzi. +Naším cílem bude najít co nejlepší algoritmus řešící BPS +a odhadnout u něj střední hodnotu skóre pro náhodný vstup. -::: {c=box t=task name="Obecný paint shop problém"} -V řadě je $m$ aut $n$ různých typů -- nyní však již od každého typu libovolný počet. -Dále máme definováno pro každou kombinaci typu a barvy (kterých také může být více než dvě), kolik aut daného typu má být nabarveno -na danou barvu. -Chceme tedy nají obarvení aut tak, aby počet změn barev v řadě byl co nejmenší. -::: -Binární verze problému je tedy speciální případ obecného paint shop problému, -kde od každého typu máme dvě auta, máme jen dvě požadované barvy a -navíc platí, že pro každou kombinaci typu a barvy chceme právě jedno auto. +Struktura práce +--------------- -Souvisejícím problémem je dělení náhrdelníku zavedený v Alonově článku [@necklace]: - -::: {c=box t=task name="Dělení náhrdelníku"} -Skupina $k$ loupežníků uloupí náhrdelník skládající se z $kn$ drahokamů $t$ různých typů. -Pro každý typ $i$ platí, že náhrdelník obsahuje právě $ka_i$ drahokamů daného typu (pro nějaké celé $a_i$). -Loupežníci si jej chtějí férově rozdělit. -Náhrdelník tedy rozdělí na několik navzájem nepřekrývajících se intervalů, -jejichž sjednocení je celý náhrdelník. -Každý z intervalů pak přiřadí nějakému loupežníkovi tak, -aby každý loupežník získat od každého typu $i$ právě $a_i$ drahokamů (což znamená, že všichni budou mít od každého typu stejný počet drahokamů). -Chceme minimalizovat počet intervalů, na které je nutné náhrdelník rozdělit. -::: - -Nejprve si všimněme, že dělení náhrdelníku je speciálním případem obecného paint shop problému. -Auta pro nás budou drahokamy. Barva auta bude označovat, který loupežník získá daný drahokam. -Minimalizovat počet intervalů je to stejné jako minimalizovat počet hranic mezi nimi (kterých je o jedna méně něž intervalů). -Ve vstupu problému dělení náhrdelníku navíc musí platit, pro každý typ má být stejný počet aut obarvený jednotlivými barvami -(a tedy počet aut daného typu musí být násobkem $k$). - -Naopak binární paint shop problém je speciálním případem dělení náhrdelníku -pro dva lupiče, kde navíc platí, že všechna $a_i$ jsou 1 (tedy od každého drahokamu jsou na náhrdelníku právě dva drahokamy). - -V této práci se však budeme věnovat pouze binárnímu paint shop problému. +Nejprve si zavedeme notaci potřebnou pro pohodlnou práci s BPS +a definujeme si aproximační algoritmy. +Dále následuji shrnutí doposud známých algoritmů a jiných výsledků ohledně BPS. +V následující kapitole je představen princip semidefinitního programování, +které má uplatnění v algoritmu představeném o kapitolu dál. +Poslední kapitola se věnuje praktické implementaci tohoto algoritmu +a naměřeným datům o něm. Notace ------ @@ -128,30 +134,88 @@ Pomocí $a_{i,0}$ budeme značit pozici prvního auta typu $i$ a pomocí $a_{i,1 Opačně $t_i$ bude značit typ auta na pozici $i$ a $p_i$ bude značit, jestli se jedná o první nebo druhé auto daného typu (tedy bude nabývat hodnoty $0$ nebo $1$). -Protože někdy bude výhodnější zacházet se znaménky, zavedeme ještě $P_i = -1+2 p_i$, které bude nabývat hodnot $-1$ a $1$. +Protože někdy bude výhodnější zacházet se znaménky, zavedeme $P_i = -1+2 p_i$, které bude nabývat hodnot $-1$ a $1$. Také rozšíříme notaci o $a_{i, -1} = a_{i,0}$. Nakonec ještě zavedeme zkratku indexu druhého auta stejného typu jako je auto na pozici $i$: $o_i = a_{t_i,-P_i}$. -Barvy pro nás budou $0$ a $1$. Pokud budeme uvažovat nějaké konkrétní obarvení $c$, $c(i)$ bude značit barvu +Barvy pro nás budou $0$ a $1$. Pokud budeme uvažovat nějaké konkrétní obarvení $c$, tak $c(i)$ bude značit barvu auta na pozici $i$. -Pro algoritmus ${\rm alg}$ označíme skóre na vstupu $\alpha$ -pomocí $\gamma_{\rm alg}(\alpha)$. -Dále označme všechny vstupy délky $n$ jako $\aleph_n$. -Průměrné skóre algoritmu na všech vstupech délky $n$ tedy bude: -$$\gamma_{\rm alg}(n) = {\sum_{\alpha \in \aleph_n} \gamma_{\rm alg} (\alpha) \over |\aleph_n|}$$ -Toto hodnotu můžeme také chápat jako střední hodnotu skóre pro uniformě náhodný vstup délky $n$. -K tomu ještě zavedeme $\delta_{\rm alg}(\alpha) = \gamma_{\rm alg}(\alpha)/n_{\alpha}$ a $\delta_{\rm alg}(n) = \gamma_{\rm alg}(n)/n$, -tedy pomocí $\delta$ si označíme podíly příslušné $\gamma$ a $n$. -Nakonec označme $\delta_{\rm alg} = \lim_{n\to\infty} \delta_{\rm alg}(n) = \lim_{n\to\infty} \gamma_{\rm alg}(n)/n$. -Význam těchto definicí bude vysvětlen v následující sekci. +Pro algoritmus $\alg$ označíme skóre na vstupu $\alpha$ +pomocí $\gamma_{\alg}(\alpha)$. +Dále označme všechny vstupy délky $n$ jako $w_n$. +Průměrné skóre algoritmu na všech vstupech délky $n$ tedy bude +$$\gamma_{\alg}(n) = {\sum_{\alpha \in w_n} \gamma_{\alg} (\alpha) \over |w_n|}.$$ +Tuto hodnotu mimo jiné můžeme chápat jako střední hodnotu skóre pro uniformně náhodný vstup délky $n$. +K tomu ještě zavedeme $\delta_{\alg}(\alpha) = \gamma_{\alg}(\alpha)/n_{\alpha}$ a analogicky $\delta_{\alg}(n) = \gamma_{\alg}(n)/n$. +Nakonec označme $\delta_{\alg} = \lim_{n\to\infty} \delta_{\alg}(n) = \lim_{n\to\infty} \gamma_{\alg}(n)/n$. +Protože limita nemusí vždy existovat, zavedeme ještě limes superior a limes inferior: +$\delta^+_{\alg} = \limsup_{n\to\infty} \delta_{\alg}(n)$ a +$\delta^-_{\alg} = \liminf_{n\to\infty} \delta_{\alg}(n)$. +Význam těchto definicí bude vysvětlen v následující kapitole. Dále označme $\gamma(\alpha)$ optimální skóre na vstupu $\alpha$. -A následně analogicky definujeme $\gamma(n), \delta(\alpha), \delta(n)$ a $\delta$ +A následně analogicky definujeme $\gamma(n), \delta(\alpha), \delta(n)$, $\delta$, $\delta^+$ a $\delta^-$ stejně jako u variant s algoritmem, jen skóre daného algoritmu nahradíme za optimální skóre. -Doposud známe výsledky +Definice aproximačních algoritmů +-------------------------------- + +Protože ne na všechny problémy známe polynomiální algoritmus, co je schopný je vyřešit, +zajímavý výsledek může být, i když se k řešení zvládneme jen v nějakém smysl alespoň přiblížit. +Na to nejprve musíme říct, co pro nás znamená, že nějaké řešení je několikrát horší než jiné. To nám poskytne obecná definice optimalizačního problému. + +::: {c=box t=def name="Optimalizační problém"} +Problém je _optimalizační_, pokud pro každý vstup $I$, existuje množina +přípustných řešení $F(I)$. +Dále existuje účelová funkce $f$, která pro každý vstup a jeho přípustné řešení určuje reálné nezáporné číslo -- jeho hodnotu. + +Pokud se jedná o minimalizační problém, tak pod pojmem _optimum_ daného vstupu (značíme $\opt(I)$) myslíme infimum hodnot účelové funkce přes všechny přípustné řešení, tedy $\inf f[F(i)]$. +Pro minimalizační problém analogicky použijeme supremum. +::: + +A nyní již přejdeme k samotným definicím algoritmů blížících se optimu. + +::: {c=box t=def name="Aproximační algoritmus"} +Algoritmus $\alg$ je $g(n)$-aproximační na minimalizačním problému, +pokud pro každý vstup $I$ algoritmus vrátí přípustné řešení $\algo(I)$, pro které platí, že $f(\algo(I)) \le g(|I|) \cdot \opt(I)$. +::: + +Předešlá definice záleží na tom, co považujeme za velikost vstupu, což se pro různé problémy a jejich interpretace může lišit. +Naštěstí nás většinou budou zajímat $c$-aproximace, tedy +aproximace, kde $f(n)$ je konstantní funkce rovna $c$. + +U maximalizačních problémů je drobný problém v terminologii, +protože není shoda na tom, jestli má platit +$f(A(I)) \ge g(|I|) \cdot \opt(I)$ +nebo +$f(A(I)) \ge {1\over g(|I|)} \cdot \opt(I)$. +Na štěstí podle kontextu jde snadno rozžnout, která definice se používá, +protože je potřeba násobit optimum číslem menším rovno jedné (jinak by pro +kladné hodnoty účelové funkce nemohl existovat žádný vyhovující algoritmus). + +Bohužel někdy asi ani s aproximačními algoritmy nevystačíme a proto zavedeme +pravděpodobností relaxaci. + +::: {c=box t=def name="Pravděpodobnostní aproximační algoritmus"} +Algoritmus $\alg$ je pravděpodobnostně $g(n)$-aproximační, existuje konstanta $p \in (0,1)$, taková, že pro každý vstup $I$ algoritmus vrátí přípustně řešení, +pro které s pravděpodobností $\ge p$ platí, že $f(\alg(I)) \le g(|I|) \cdot \opt(I)$. +::: + +Všimněme si, že na konstantě $p$ příliš nezáleží. +Opakovaným spouštěním algoritmu a pak vybráním nejlepšího +z dodaných řešení zvládneme $p$ libovolně těsně přiblížit k jedné. + +Pokud řešíme složitost algoritmů a úloh, +většinou vyžadujeme, aby účelová funkce i rozhodování přípustnosti řešení byly vyčíslitelné v polynomiálním čase. +Navíc chceme, aby všechny přípustné řešení měli omezenou délku nějakým polynomem v délce vstupu. +Snadno nahlédneme, že za takovýchto podmínek je rozhodovací verze, +jestli je optimum alespoň zadané číslo v $NP$. +Pro takovou úlohu většinou hledáme polynomiální aproximační algoritmus. +Binární paint shop vyhovuje všem těchto podmínkám. + +Doposud známé výsledky ====================== Bonsmaa, Epping, a Hochstättler [@apx] dokázali, že optimalizační verze BPS je $\APX$-těžký problém, @@ -163,18 +227,18 @@ Snadno nahlédneme, že rozhodovací problém patří do $\NP$. Když nám někd V lineárním čase jsme schopni ověřit, že počet změn je dostatečně malý a od každého typu a barvy auta je právě jeden výskyt. Tedy rozhodovací problém je $\NP$-úplný. -Dále pak Gupta a spol [@neaprox] ukázali, že za předpokladu Unique games conjecture je NP-těžké i problém libovolně konstantně aproximovat. +Dále pak Gupta a spol. [@neaprox] ukázali, že za předpokladu Unique games conjecture je NP-těžké i problém libovolně konstantně aproximovat. K tomu využili převod na problém minimálního ne-řezu. To je problém podobný maximálnímu řezu, který bude představen později. Ovšem místo maximalizace počtu hran v řezu minimalizujeme počet hran mimo něj (tedy v rámci partit). Tyto dva problémy mají stejné optimum, ovšem aproximovatelnost se na nich chová drasticky jinak. -V momentě, kdy jsou skoro všechny hrany v řezu¸tak přidání další hrany do řezu skoro nezmění počet hran v něm. Ovšem odebrání hrany z ne-řezu bude mít velký vliv (procentuálně) na počet hran v ne-řezu. +V momentě, kdy jsou skoro všechny hrany v řezu, tak přidání další hrany do řezu skoro nezmění počet hran v něm. Ovšem odebrání hrany z ne-řezu bude mít velký vliv (procentuálně) na počet hran v ne-řezu. Vzhledem k předešlým výsledkům je na místě zkoumat různé heuristiky a obecně algoritmy, co jsou nás schopny k řešení alespoň částečně přiblížit. -Jedním z takových algoritmů je hladový algoritmus popsaný Andresem and Hochstättler [@gr]: +Jedním z takových algoritmů je hladový algoritmus popsaný Andresem and Hoch\-stättlerem [@gr]: ::: {c=box t=algo name="Hladový algoritmus" notation=g} Autům budeme přiřazovat barvy v pořadí, v jakém jsou na vstupu. @@ -183,13 +247,13 @@ Dále budeme vždy první auto daného typu barvit stejně jako předcházejíc auto a druhé auto daného typu obarvíme vždy zbývající barvou. ::: -V daném článku autoři o tomto algoritmu dokázali, když vezmeme uniformě +V daném článku autoři o tomto algoritmu dokázali, když vezmeme uniformně náhodný vstup délky $n$, tak střední hodnota počtu změn ve vygenerovaném řešení je $\sum_{0\le k < n} {2k^2-1 \over 4k^2-1}$. -Hladový algoritmus budeme značit ${\rm g}$, tedy předešlou hodnotu značíme $\gamma_{\rm g}(n)$. -Připomeňme, že pomocí $\delta_{\rm g}(n)$ značíme tuto hodnotu vydělenou velikostí vstupu, tedy $\gamma_{\rm g}(n) / n$. +Hladový algoritmus budeme značit $\algo g$, tedy předešlou hodnotu značíme $\gamma_{\algo g}(n)$. +Připomeňme, že pomocí $\delta_{\algo g}(n)$ značíme tuto hodnotu vydělenou velikostí vstupu, tedy $\gamma_{\algo g}(n) / n$. -Pro dostatečně velká $n$ se $\gamma_{\rm g}(n)$ pohybuje zhruba okolo $(1 / 2) n$ (formálně řečeno: platí, že $\delta_{\rm g} = \lim_{n\to\infty} {\gamma_{\rm g}(n) / n} = {1 / 2}$). +Pro dostatečně velká $n$ se $\gamma_{\algo g}(n)$ pohybuje zhruba okolo $(1 / 2) n$ (formálně řečeno: platí, že $\delta_{\algo g} = \lim_{n\to\infty} {\gamma_{\algo g}(n) / n} = {1 / 2}$) (viz obrázek [](#e-g)). ::: {#e-g c=figure} @@ -207,10 +271,10 @@ fig.update_layout( showlegend=False ) ``` -Graf střední hodnoty skóre hladového řešení $\delta_{g}(n)$ v závislosti na $n$. +Graf střední hodnoty skóre hladového řešení $\delta_{\algo g}(n)$ v závislosti na $n$. ::: -U hladového řešení je tedy střední hodnota skóre přes uniformě náhodný vstup přesně vyčíslená. +U hladového řešení je tedy střední hodnota skóre přes uniformně náhodný vstup přesně vyčíslená. Pro nás je zejména důležité, že ji jsme schopni shora odhadnout. Střední hodnotu totiž můžeme považovat za ukazatel kvality algoritmu (čím menší je, tím se jedná o lepší algoritmus) a tedy horní odhad nám dává záruku kvality algoritmu. @@ -218,69 +282,76 @@ Zajímavé je pro nás zkoumat chování algoritmů na velkých vstupech, tedy d smysl uvažovat limitu střední hodnoty do nekonečna. Ovšem s narůstajícím počtem aut narůstá i počet potřebných změn, takže samotná limita střední hodnoty moc nedává smysl, protože by byla nekonečná. -Místo ní budeme uvažovat $\lim_{n\to\infty} {\gamma_{\rm alg}(n)) / n} = \lim_{n\to\infty}\delta_{\rm alg}$. +Místo ní budeme uvažovat $\lim_{n\to\infty} {\gamma_{\alg}(n)) / n} = \lim_{n\to\infty}\delta_{\alg}(n)$. O ní víme, že pro libovolný algoritmus (pokud existuje) bude v intervalu $[0, 2]$, protože maximální počet změn musí být mezi $0$ a $2n-1$. I když nejsme schopní hledat optimum efektivně, pro každý vstup je určitě optimum dobře definovaná hodnota. Můžeme se tedy ptát na otázku, kolik vyjde limita, kde místo skóre algoritmu vložíme -optimum pro daný vstup, tedy $\lim_{n\to\infty} \delta_n = \lim_{n\to\infty} \gamma_n/n$. +optimum pro daný vstup, tedy $\lim_{n\to\infty} \delta(n) = \lim_{n\to\infty} \gamma(n)/n$. Označme hodnotu této limity $\delta$. -TODO Víme, že limita existuje? +Bohužel není zřejmé, že limita skutečně existuje, proto +místo limity budeme často uvažovat limes supervisor a inferior. +Ty budeme značit přidáním $\pm$ jako horního indexu. +Stejnou notaci budeme používat i u limit algoritmů. Jelikož optimum musí být alespoň tak dobré jako výstup hladového řešení, -dostáváme konstruktivní horní odhad $\delta \le 0.5$. +dostáváme konstruktivní horní odhad $\delta^+ \le 0.5$. Hledáním lepších algoritmů můžeme horní odhad zlepšovat. -Překvapivě však je, že Hančl a kol. [@docw] ukázali dolní odhad $\delta \ge 0.214$ pomocí počítání pravděpodobností pro náhodné obarvení. -Samotný fakt, že $\gamma > 0$ je již poměrně zajímavé tvrzení. +Překvapivě však je, že Hančl a kol. [@docw] ukázali dolní odhad $\delta^- \ge 0.214$ pomocí počítání pravděpodobností pro náhodné obarvení. +Samotný fakt, že $\delta^- > 0$ je již poměrně zajímavé tvrzení. To nám říká, že každý algoritmus na průměrném vstupu musí použít aspoň $\Omega(n)$ změn barev. Nemůže tedy například existovat algoritmus, kterému by stačilo jen $\O(n / \log n)$ změn. -To také říká, že odhadovat algoritmy pomocí $\lim_{n\to\infty} \gamma_{\rm algo}/n$, +To také říká, že odhadovat algoritmy pomocí $\lim_{n\to\infty} \gamma_{\alg}/n$, je alespoň co se týče asymptoticky dostačující, protože vystihuje konstantu nejvýznačnějšího členu polynomiální aproximace. -Dále si představíme několik algoritmů, které se snaží konstruktivně zlepšit horní odhad na $\delta$. +Dále si představíme několik algoritmů, které se snaží konstruktivně zlepšit horní odhad na $\delta^+$. ::: {c=box t=algo name="Rekurzivní hladové řešení" notation="rg"} -Z řady aut odstraní první auto a auto stejného typu. -Zbytek aut rekurzivně obarví a pak do řady přidáme odebranou dvojici tak, -aby byl počet změn co nejmenší možný. +Z řady aut odstraníme první auto a auto stejného typu. +Zbytek aut rekurzivně obarvíme a pak do řady přidáme odebranou dvojici tak, +aby byl počet změn co možná nejmenší možný. ::: -Autoři algoritmu, Andresem and Hochstättler [@gr], o něm dokázali, že -${2\over 5}\ n - {8\over 15} \le \gamma_{\rm rg}(n) \le {2\over 5}\ n + {7\over 10}$, -tedy $\delta_{\rm rg} = 2/5 = 0.4$. +Autoři algoritmu, Andres and Hochstättler [@gr], o něm dokázali, že +${2\over 5}\ n - {8\over 15} \le \gamma_{\algo{rg}}(n) \le {2\over 5}\ n + {7\over 10}$, +tedy $\delta_{\algo{rg}} = 2/5 = 0.4$. Dále se o zlepšení tohoto algoritmu pokusili Hančl a kol. Ti si všimli, že ve výstupu rekurzivního řešení se občas stane, že přebarvením dvojic typů aut se zlepší skóre. Ukázali, že -takových dvojic je vždy ve výstupu lineárně a z toho pak -ukázali horní odhad $\delta \le 0.4 - \varepsilon < 0.4$ (pro $\varepsilon$ zhrube $2\cdot 10^6$). +takových dvojic je vždy ve výstupu lineárně mnoho a z toho pak +ukázali horní odhad $\delta^+ \le 0.4 - \varepsilon < 0.4$ (pro $\varepsilon$ zhruba $2\cdot 10^6$). Hančl a kol. přišli ještě s dalším způsobem, jak vylepšit rekurzivní hladové řešení. Při běhu hladového řešení se občas stane, že některá dvojice aut stejného typu si může prohodit barvy bez změny skóre řešení. -Když přidáváme auto do okolí takovéto dvojice, v některých případech můžeme provézt toto prohození +Když přidáváme auto do okolí takovéto dvojice, v některých případech můžeme provést toto prohození a tím snížit počet nově vytvořených změn barev. -Algoritmus si tedy bude udržovat některé z takovýchto dvojic -a pokud se bude přidávat auto do okolí evidované dvojice, tak, že -prohození barev dané dvojice by pomohlo, prohodí její barvy. +Budeme si tedy bude udržovat některé z takovýchto dvojic +a pokud se budeme přidávat auto do okolí evidované dvojice, tak, že +prohození barev dané dvojice by pomohlo, prohodíme její barvy. + +Budeme pracovat nad rozšířenou abecedou barev o znak "$*$" reprezentující neurčenou barvu. +Při rekurzi budeme udržovat invariant, že pro každý typ obě auta buď budou označeny $*$ a nebo ani jedno z nich nebude označeno $*$ a pak nutně budou mít různé barvy. +Navíc bude platit, že $*$ nikdy není na okrajích a nejsou dvě vedle sebe. +Specificky tedy na $*$ se budeme přebarvovat dvojice aut v momentě, kdy získá všechny sousedy. -Algoritmus bude pracovat nad rozšířenou abecedou barev o $*$ reprezentující neurčenou barvu. -Při rekurzi bude udržovat invariant, že $*$ nikdy není na okrajích a nejsou dvě vedle sebe. -Specificky tedy na $*$ se bude přebarvovat dvojice aut v momentě, kdy získá všechny sousedy. -Navíc bude platit, že pro každý typ obě auta buď budou označeny $*$ a nebo ani jedno z nich nebude označeno $*$ a pak nutně budou mít různé barvy. +Pro popis algoritmu zavedeme notaci $N(i)$, +což bude reprezentovat multimnožinu barev aut sousedících s autem na pozici $0<i<2n-1$, +tedy $\{c(i-1), c(i+1)\}$. ::: {c=box t=algo name="Hvězdičkové rekurzivní řešení" notation="rsg"} -Algoritmus bude procovat nad rozšířenou škálou barev o $*$. -Ze vstupu odebere auta typu $t_0$ a zarekurzí se na zbytek. -Tím získá nějaké obarvení, které může použít na původní vstup s tím, -že auta typu $t_0$ zatím nebudou obarvená, ty dobarví dle následujících pravidel: +Bude pracovat nad rozšířenou škálou barev $\{0,1,*\}$. +Ze vstupu odebereme auta typu $t_0$ a zarekurzíme se na zbytek. +Tím získáme nějaké obarvení, které může použít na původní vstup s tím, +že auta typu $t_0$ zatím nebudou obarvená, ty dobarvíme dle následujících pravidel: A) Když $o_0 = 2$ a $n>1$ nastavíme $c(1)=c(2)$. B) Když $o_0=2n-1$ nastavíme $c(0) = 1$. @@ -289,195 +360,92 @@ D) Když $N(o_0) = \{0,1\}$, nastavíme $c(0) = c(1)$. E) Když $N(o_0) = \{1-c(1), *\}$, nastavíme $c(0) = c(1)$. F) Když $N(o_0) = \{c(1), *\}$, nastavíme $c(0) = c(1)$ a přenastavíme $*$ v okolí $o_0$ na $1-c(1)$ a druhé auto daného typu na opačnou barvu. -A druhé auto typu $t_0$ obarví zbývající barvou. +A druhé auto typu $t_0$ obarvíme zbývající barvou. Pokud auta typu $t_{1}$ spolu nesousedí, $* \not\in N(1) \cap N(o_1)$ a prohození barev aut typu $t_1$ by zachovalo počet změn, přenastavíme jejich barvy na $*$. -Po návratu ze všech rekurzí zbylé auta na indexu $i$ barvy $*$ přebarví na $p_i$. +Po návratu ze všech rekurzí zbylé dvojice aut $*$ přebarvíme na dvě různé barvy. ::: - -TODO notace okolí - ::: {#rsg c=figure} ```python {c=plotly} +import math +hypoth = 1/13 * math.sqrt(61) - 3/13 import bakalarka.g as g, bakalarka.data_lib as data_lib fig = g.intro_graph("rsg") -fig.add_vline(x=200*0.361, - annotation_text="0.361n", annotation_position="top left", +fig.add_vline(x=200*hypoth, + annotation_text="hypotéza", annotation_position="top left", fillcolor="green") ``` Graf skóre $100$ běhů hvězdičkového rekurzivního řešení pro $n=200$. ::: -Autoři algoritmu o něm vyslovili domněnku, že $\delta_{\rm rsg} = 0.361$ . -Na obrázku [](#rsg) je zobrazen histogram skóre tohoto algoritmu spuštěného na náhodných vstupech a hodnota $0.361n$ z předešlé hypotézy. - -:::: {c=cmt} +Autoři algoritmu o něm vyslovili domněnku, že $\delta_{\algo{rsg}} = {1\over 13} \cdot \sqrt{61} - {3\over 13} \sim 0.370$ . +Na obrázku [](#rsg) je zobrazen histogram skóre tohoto algoritmu spuštěného na náhodných vstupech a hodnota z předešlé hypotézy. -::: {#semidef_prog c=figure} -```python {c=plotly} -import bakalarka.g as g, bakalarka.data_lib as data_lib, plotly -data = g.load("log-intr") -fig = plotly.subplots.make_subplots(rows=2, cols=1, row_heights=[0.8, 0.3], shared_xaxes=True, vertical_spacing = 0.05) -g.draw_algo_graph(fig, data, "semidef_prog(10)", 200, name="Řešení") -g.draw_algo_graph(fig, data, "semidef_prog(10)", 200, val_getter=lambda x: int(x.data["lower_bound"]+0.99), name="Dolní odhad", color="green") -``` -Graf skóre řešení pomocí semidefinitního programování. -::: -# Statistická práce +Zobecněné verze a související problémy +-------------------------------------- -Na níže uvedeném grafu jsou výsledky všech výše uvedených algoritmů pohromadě (pozor na to, že v grafu je zobrazena jen zajímavá část vertikální osy mezi $0.25 n$ a $0.6n$. +Zobecněním binárního paint shopu je obecný paint shop problém, zavedený Epingem a spol. [@ps], +Z něj pochází motivace k binární verzi. -::: {#all c=figure} -```python {c=plotly} -import bakalarka.g as g, bakalarka.data_lib as data_lib -data = g.load("log-intr") -fig = plotly.subplots.make_subplots(rows=2, cols=1, row_heights=[0.8, 0.5], shared_xaxes=True, vertical_spacing = 0.05) -g.draw_algo_graph(fig, data, "greedy", 200) -g.draw_algo_graph(fig, data, "rg", 200) -g.draw_algo_graph(fig, data, "rsg", 200) -g.draw_algo_graph(fig, data, "semidef_prog(10)", 200) -fig.update_xaxes(range=[0.25*200, 0.6*200]) -``` -Skóre všech algoritmů. +::: {c=box t=task name="Obecný paint shop problém"} +V řadě je $m$ aut $n$ různých typů -- nyní však již od každého typu libovolný počet. +Dále máme definováno pro každou kombinaci typu a barvy (kterých také může být více než dvě), kolik aut daného typu má být nabarveno +na danou barvu. +Chceme tedy nají obarvení aut tak, aby počet změn barev v řadě byl co nejmenší. ::: -Z grafu můžeme odhadnout, že jako nejlepší algoritmus se jeví semidefinitní programování a po něm hvězdičkové rekurzivní řešení. -V následující části bych rád ukázal, že tomu tak skutečně je. - - -To vypadá jako jednoduchá úloha pro [Welchův t-test](https://en.wikipedia.org/wiki/Welch%27s_t-test). -Vygeneruji dalších 30 běhů každého algoritmu a na nich spustím: - - -```python {c=code_and_output highlight=True} -import bakalarka.g as g, bakalarka.data_lib as data_lib -import scipy.stats - -data = g.load("log-t-test") - -rsg = [ x.score for x in data.pipelines["rsg"] ] -semidef_prog = [ x.score for x in data.pipelines["semidef_prog(10)"] ] - -print(scipy.stats.ttest_ind(rsg, semidef_prog, equal_var=False)) -``` - -Z tohoto bychom mohli usuzovat, že řešení pomocí semidefinitního programování je na $99\%$ lepší, -protože `pvalue` je dokonce o několik řádů menší než $0.01$. - -V čem je tedy problém? -Problém t-testu je že nesamplovaná data musí pocházet z normální distribuce -a já vůbec netuším, jak bych dokazoval, že naše data se jí alespoň blíží (pokud to vůbec platí). - -Pojďme tedy využít trošku více dřevorubecké řešení, kterým to dokážeme. - -Budeme se snažit dokázat, že algoritmus pomocí semidefinitního programování je lepší než hvězdičkové rekurzivní řešení. -Tedy:\ -$H_0:$ Hvězdičkové řešení je stejně dobré nebo dokonce lepší.\ -$H_1:$ Řešení pomocí semidefinitního programování je lepší. - -Víme, že rozptyl náhodné veličiny skóre řešení je nejvýše $n^2$, protože se jedná o náhodnou veličinu z intervalu $0$ až $2n$. -Když víme, že $\sigma^2(X) \le n^2$, tak $\sigma^2(X_1 + \cdots + X_k) \le kn^2$ -(pro nezávislé $X_1,\dots,X_n$, což v našem případě jsou, protože vybíráme vstupy nezávisle). -Tedy $\sigma^2(\overline{X_k}) = \sigma^2({X_1 + \cdots + X_k \over k}) \le {k\cdot n^2 \over k^2} = {n^2 \over k}$. - -Dle Cebyševovy nerovnosti tedy (pro $t>0$): -$$P\left(\mathbb{E}(X) \ge \overline{X_k} + t {n^2 \over k}\right) \le {1 \over 2 t^2}$$ -Což můžeme využít následovně: - -Nechť $X$ a $Y$ jsou náhodné veličiny skóre dvou algoritmů (semidefinitního programování a hvězdičkového rekurzivního), kde naměříme $\overline{X_k} < \overline{Y_k}$. -$$ -P(H_0) = P\left( \mathbb{E}(X) \ge \mathbb{E}(Y) \right) -= 1 - P\left( \mathbb{E}(X) < \mathbb{E}(Y) \right) -\le 1 - P\left( \mathbb{E}(X) < { \overline{X_k}+\overline{Y_k} \over 2} < \mathbb{E}(Y) \right) -\le -$$ -$$ -\le 1 - P\left( \mathbb{E}(X) < { \overline{X_k}+\overline{Y_k} \over 2} \right) + 1 - P\left( { \overline{X_k}+\overline{Y_k} \over 2} < \mathbb{E}(Y) \right) -\le P\left( \mathbb{E}(X) \ge \overline{X_k} + { \overline{Y_k}-\overline{X_k} \over 2} \right) + P\left( \overline{Y_k} - { \overline{Y_k}-\overline{X_k} \over 2} \ge \mathbb{E}(Y) \right) -$$ - -Nyní použijeme výše uvedenou nerovnost pro $t{n^2\over k} = { \overline{Y_k}-\overline{X_k} \over 2}$, tedy $t = k {\overline{Y_k}-\overline{X_k} \over 2n^2}$. -Symetrická nerovnost funguje i pro $Y$ a otočený směr odhadu. - -$$ -P\left( H_0 \right) \le -2 {1 \over 2 \left({k(\overline{Y_k}-\overline{X_k}) \over 2n^2}\right)^2} = -{4n^4 \over k^2 \left({\overline{Y_k}-\overline{X_k} }\right)^2} -$$ - -Pokud chceme, abychom věděli, že algoritmus $X$ je lepší než algoritmus $Y$ (pro danou velikost vstupu) s jistotou $99\%$, musí platit, že: - -$$ -{4n^4 \over k^2\left({\overline{Y_k}-\overline{X_k} }\right)^2} < 0.01 -$$ - -Z výše uvedených grafů můžeme doufat, že $\overline{Y_k}-\overline{X_k}$ bude alespoň zhruba $10$. -Pro $k = 500$ by tedy mohla být výsledná hodnota mohla dost malá. - -Navrhneme tedy následující pokus: -Spustíme oba dva algoritmy na $100\,000$ náhodně vybraných vstupů a spočítáme -jejich průměry. - -Pokud výsledek výše uvedené formule bude menší než $0.01$, můžeme zamítnout $H_0$ s pravděpodobností $99\%$. - -```python {c=code_and_output highlight=True} -import bakalarka.g as g, bakalarka.data_lib as data_lib -import scipy.stats - - -n = 200 - -data = g.load("log-correct-test") - - - -rsg = [ x.score for x in data.pipelines["rsg"] ] -semidef_prog = [ x.score for x in data.pipelines["semidef_prog(10)"] ] - -k = len(rsg) -assert k == len(semidef_prog) - -rsg_avg = sum(rsg) / k -semidef_prog_avg = sum(semidef_prog) / k +Binární verze problému je tedy speciální případ obecného paint shop problému, +kde od každého typu máme dvě auta, máme jen dvě požadované barvy a +navíc platí, že pro každou kombinaci typu a barvy chceme právě jedno auto. -print(f"n: {n} k: {k}") -print("rsg: ", rsg_avg) -print("semidef_prog:", semidef_prog_avg) +Souvisejícím problémem je dělení náhrdelníku zavedený v Alonově článku [@necklace]: -assert semidef_prog_avg < rsg_avg -print(4*n**4 / k**2 / (rsg_avg - semidef_prog_avg)**2) -``` +::: {c=box t=task name="Dělení náhrdelníku"} +Skupina $k$ loupežníků uloupí náhrdelník skládající se z $kn$ drahokamů $t$ různých typů. +Pro každý typ $i$ platí, že náhrdelník obsahuje právě $ka_i$ drahokamů daného typu (pro nějaké celé $a_i$). +Loupežníci si jej chtějí férově rozdělit. +Náhrdelník tedy rozdělí na několik navzájem nepřekrývajících se intervalů, +jejichž sjednocení je celý náhrdelník. +Každý z intervalů pak přiřadí nějakému loupežníkovi tak, +aby každý loupežník získat od každého typu $i$ právě $a_i$ drahokamů (což znamená, že všichni budou mít od každého typu stejný počet drahokamů). +Chceme minimalizovat počet intervalů, na které je nutné náhrdelník rozdělit. +::: -Nulovou hypotézu se nám tedy podařilo zamítnout a tudíž řešení pomocí semidefinitního programování je lepší. +Nejprve si všimněme, že dělení náhrdelníku je speciálním případem obecného paint shop problému. +Auta pro nás budou drahokamy. Barva auta bude označovat, který loupežník získá daný drahokam. +Minimalizovat počet intervalů je to stejné jako minimalizovat počet hranic mezi nimi (kterých je o jedna méně něž intervalů). +Ve vstupu problému dělení náhrdelníku navíc musí platit, pro každý typ má být stejný počet aut obarvený jednotlivými barvami +(a tedy počet aut daného typu musí být násobkem $k$). -Všimněte si, že pokud by platilo, že se jedná o normální rozdělení, tak nám stačí mnohem méně dat a máme mnohem větší jistotu. +Naopak binární paint shop problém je speciálním případem dělení náhrdelníku +pro dva lupiče, kde navíc platí, že všechna $a_i$ jsou 1 (tedy od každého drahokamu jsou na náhrdelníku právě dva drahokamy). -:::: +V této práci se budeme věnovat pouze binárnímu paint shop problému. Semidefinitní programování ========================== -TODO vysvětlit indexování - -V této kapitole si představíme princip semidefinitního programování [@semidef] a jeho použití na problém maximálního řezu, +V této kapitole si představíme princip semidefinitního programování, jak jej popisují Gärtner a Matoušek [@semidef], a jeho použití na problém maximálního řezu, z něhož vychází algoritmus na binary paint shop. - - -Nechť $\SYM_n = \{X \in \R^{n\times n} \mid x_{i,j} = x_{j,i} \hbox{\ pro všechna\ } 0 \le i,j < n\}$ je třída všech symetrických matic a nechť $X \bullet Y = \sum_{i=0}^n \sum_{j=0}^n x_{i,j} y_{i,j}$ značí součin matic po složkách. -Nakonec ozmačme skutečnost, že je matice $X$ pozitivně semidefinitní (bude vysvětleno níže) pomocí $X \succeq 0$. +Nejprve zavedeme a připomeneme notaci důležitou v této kapitole. +Nechť $\R^{n\times m}$ značí množinu $n$ řádkových $m$ sloupcových matic +složených z reálných čísel. +Řádky i sloupce indexujeme od $0$, +tedy matice $A\in R^{n\times m}$ obsahuje prvky $A_{i,j}$ pro všechna $0\le i < n$ a $0 \le j < m$. +Nechť $\SYM_n = \{X \in \R^{n\times n} \mid x_{i,j} = x_{j,i} \hbox{\ pro všechna\ } 0 \le i,j < n\}$ je třída všech symetrických matic a nechť $X \circ Y = \sum_{0\le i<n} \sum_{0\le j<0} x_{i,j} y_{i,j}$ značí součet součinu matic po složkách. +Nakonec $X \succeq 0$ bude značit skutečnost, že matice $X$ je pozitivně semidefinitní (bude vysvětleno později). Úloha semidefinitního programování je optimalizační úloha (podobně jako lineární programování) následujícího formátu: - -$$\progline{maximalizuj}{C \bullet X}{}$$ -$$\progline{za podmínek}{A_i \bullet X = b_i}{0 \le i < m-1}$$ +$$\progline{maximalizuj}{C \circ X}{}$$ +$$\progline{za podmínek}{A_i \circ X = b_i}{0 \le i < m-1}$$ $$\progline{}{X \succeq 0.}{}$$ -Vstupem programu je tedy velikost matice $n$, počet podmínek $m \in \N$ +Vstupem programu tedy je velikost matice $n$, počet podmínek $m \in \N$ a pak pro každou podmínku matice $A_i \in \SYM_n$ a číslo $b_i \in \R$. Výstupem je pak $X\in \SYM_n$ splňující výše uvedené podmínky. @@ -487,21 +455,20 @@ Pro nás bude důležitý následující fakt z lineární algebry: Nechť $X \in \SYM_n$. Následující tvrzení jsou ekvivalentní definice pozitivně semidefinitní matice: - Všechny vlastní čísla matice $X$ jsou nezáporná. - - Pro každý vektor $\vec{x} \in \R^n$ platí $\vec{x}^{\,\rm T} X\vec{x}\ge 0$. + - Pro každý vektor $\vec{x} \in \R^n$ platí $\vec{x}^{\rm T} X\vec{x}\ge 0$. - Existuje matice $Y \in \R^{n\times n}$ taková, že $X = Y^{\rm T} Y$. ::: - Pro nás bude důležitá zejména třetí podmínka, protože navíc platí, že ze semidefinitní matice $X$ zvládneme zkonstruovat $Y$ pomocí Choleského dekompozice a to v čase $\O(n^3)$. -Ještě poznamenejme, že pro libovolnou matici $Y$ je $Y^{\rm T} Y$ symetrická. -Tedy semidefinitní programování můžeme chápat jako optimalizační úlohu na $Y\in \R^{n\times n}$. +Navíc pro libovolnou reálnou matici $Y$ je $Y^{\rm T} Y$ symetrická. +Tedy semidefinitní programování můžeme chápat jako optimalizační úlohu na $Y\in \R^{n\times n}$. Pojďme se zamyslet nad tím, co v takovémto pohledu znamenají podmínky a účelová funkce. -Matici $Y$ můžeme považovat za $n$ sloupcových vektorů $\vec{y_0}, \dots, \vec{y_{n-1}}$ vedle sebe. (TODO sazba větší šipky nad vektorem) -Matice $Y^{\rm T}$ pak odpovídá těmto vektorům zapsaných v řádcích pod sebou. -Matice $X = Y^{\rm T} Y$ tedy na pozici $i,j$ obsahuje skalární součin vektorů $y_i$ a $y_j$. +Matici $Y$ můžeme považovat za $n$ sloupcových vektorů $\vec{y_0}, \dots, \vec{y_{n-1}}$ vedle sebe. +Matice $Y^{\rm T}$ pak odpovídá těmto vektorům zapsaných v řádcích pod sebou. +Matice $X = Y^{\rm T} Y$ tedy na pozici $i,j$ obsahuje skalární součin vektorů $\vec{y_i}$ a $\vec{y_j}$. Účelová funkce tedy je lineární kombinací skalárních součinů a podmínky odpovídají vynucení rovnosti lineární kombinace skalárních součinů vektorů a konstanty. Speciálně tedy můžeme mít podmínku na délku vektoru: $|\vec{y_i}|^2 = \vec{y_i}^{\rm T}\vec{y_i} = C$. @@ -523,12 +490,9 @@ Cílem je maximalizovat hodnotu řezu. ::: Problém maximálního řezu (resp. rozhodovací verze, kde se ptáme na existenci řezu alespoň dané velikosti) -je NP-úplný TODO Citace, proto +je NP-úplný [@maxcut-np], proto se u něj zkoumají aproximační algoritmy a pravděpodobností aproximační algoritmy. - -TODO vysvětlit aproximační a pravděpodobnostní algo - Nejprve si ukážeme triviální $0.5$-aproximační pravděpodobnostní algoritmus: ::: {c=box t=algo} @@ -541,25 +505,24 @@ Triviální algoritmus je $0.5$ aproximační pravděpodobnostní algoritmus. ::: {c=proof} Algoritmus zjevně běží v polynomiálním čase. -Dále ukážeme, že ve střední hodnotě bude součet řešení alespoň $1/2$ optimálního součtu hran. +Dále ukážeme, že ve střední hodnotě bude součet řešení alespoň $1/2$ optimálního součtu vah hran. Každá hrana bude v řezu s pravděpodobností $1/2$ -- při umisťování druhého vrcholu dané hrany máme pravděpodobnost $1/2$, že ho umístíme do stejné množiny a tedy hrna nebude součásti řezu a pravděpodobnost $1/2$ že do opačné a tedy bude součástí řezu. Součet hran v řezu je součtem indikátorů jevů přítomnosti jednotlivých hran v řezu vynásobený jejich hodnotou. -Z linearity součtu středních hodnot tedy střední hodnota součtu hran v řezu je $1/2$ celkového součtu hran, což je alespoň $1/2$ optima. +Z linearity součtu středních hodnot tedy střední hodnota součtu vah hran v řezu je $1/2$ celkového součtu vah hran, což je alespoň $1/2$ optima. ::: -Předešlý algoritmus lze derandomizovat. -Výsledný algoritmus pak vždy najde řešení obsahující alespoň $1/2$ hran, tedy alespoň $1/2$ optima. -[TODO citace] - Povšimněme si, že triviální algoritmus dosáhl poměrně zajímavého aproximačního poměru a to se ani nedíval na vstup. +Předešlý algoritmus lze derandomizovat, jak popisuje Dimitrakakis [@maxcut-derandom]. +Výsledný algoritmus pak vždy najde řešení obsahující alespoň $1/2$ hran, tedy alespoň $1/2$ optima. + Lepšího aproximačního poměru můžeme dosáhnout -Goemans-Williamsonovým algoritmem [@semidef] založeným na semidefinitním -programování. +Goemans-Williamsonovým algoritmem, založeným na semidefinitním +programování a proto popsaného mimo jiné v již dříve zmíněném úvodu do semidefinitního programování [@semidef]. Naivní implementace je, že si pro každý vrchol $u$ vyrobíme proměnnou $x_u$, která může nabývat hodnot $\pm 1$, která bude říkat, do jaké množiny máme vrchol umístit. @@ -578,12 +541,17 @@ Již ale současně neumíme zařídit, aby tyto vektory byly buď $(1,0,\dots,0 Můžeme ale přidat podmínku na to, aby délka každého vektoru byla $1$. Tím jsme vyrobili relaxaci výše uvedeného programu, protože za těchto podmínek může vektor nabývat i jiných poloh než $(\pm 1,0,\dots,0)$. +Celý algoritmus pak vypadá následovně: -Získali jsme tedy následující program: +::: {c=box t=algo name="Goemans-Williamsonův"} +Vyřešíme následující semidefinitní program v dekomponovaném tvaru: $$\progline{maximalizuj}{\sum_{uv \in E} -h(u,v)\vec{y_u}^{\rm T} \vec{y_v}}{}$$ -$$\progline{za podmínek}{|y_i| = 1}{\forall i}$$ +$$\progline{za podmínek}{|y_i| = 1}{0 \le i < |V|}$$ +Dále uniformě náhodně zvolíme jednotkový vektor vektor $z\in \R^n$ +a do jedné množiny vybereme právě ty vrcholy $v$, pro které $y_v^{\rm T} z \ge 0$. +::: -To si lze představit jako umísťování $n$ bodů na +Semidefinitní program v algoritmu si lze představit jako umísťování $n$ bodů na $n-1$ dimenzionální sféru v $\R^n$. Účelová funkce se snaží umístit body vrcholů spojených hranou co nejdále od sebe. @@ -594,17 +562,25 @@ Na to můžeme rovnoměrně náhodně zvolit nadrovinu procházející počátkem a rozdělit body do množin podle toho, do které z polorovin určených danou nadrovinou patří.[^1] -[^1]: Předpokládejme, že žádný z bodů neleží na nadrovině, což má pravděpodobnost $0$. -Pokud se tak stane, můžeme vložit všechny vrcholy do jedné množiny nebo zvolit nadrovinu znovu. +[^1]: Předpokládejme, že žádný z bodů neleží na nadrovině. Pravděpodobnost náležení nadrovině je $0$. +Pokud se tak stane, je vcelku jedno, do jaké množiny ho vložíme. To nám zaručí, že dvojice bodů daleko od sebe budou mít velkou pravděpodobnost toho, že budou v různých poloprostorech. Semidefinitní programování se tedy snaží dostat dvojice bodů odpovídající vrcholům spojených hranou daleko od sebe a podle toho se zvyšuje pravděpodobnost toho, že vrcholy budou v jiných množinách a tedy hrana bude v řezu. -Dále spočteme pravděpodobnost toho, že se dvojice bodů (vektorů) $\vec{u}$, +Výběr nadroviny a rozdělování bodů jde implementovat pomocí výběru vektoru $\vec{z}$ kolmého na nadrovinu. Pro každý bod pak stačí +spočítat skalární součin se $\vec{z}$ a podle znaménka víme, +do kterého poloprostoru patří. +Pokud vybereme uniformě náhodný jednotkový vektor, tak jsme uniformám náhodně vybrali nadrovinu. +Jednotkový vektor můžeme generovat tak, že vygenerujeme náhodný vektor z normálního rozdělení a pak ho znormujeme. +Povšimne si, že normalizace ani není potřeba, +protože to na znaménku součinů nic nemění. + +Nyní pojďme precizněji spočítat pravděpodobnost toho, že se dvojice bodů (vektorů) $\vec{u}$, $\vec{v}$ rozdělí náhodnou nadrovinou $\rho$ v závislosti na hodnotě skalárního součinu mezi nimi. -Můžeme se podívat na rovinu, ve které leží počátek a oba vektoru $\vec{u}$, $\vec{v}$. +Můžeme se podívat na rovinu, ve které leží počátek a oba vektory $\vec{u}$, $\vec{v}$. Průnik náhodné nadroviny s touto rovinou tvoří rovnoměrně náhodně vybranou přímku procházející počátkem. ::: {#gw-cut c=figure} @@ -622,14 +598,14 @@ label("$\vec{v}$", v, E); draw(scale(0.2)*rotate(-15)*subpath(unitcircle, 0, 85/90)); label("$\alpha$", (0.2, 0), 0.7*ENE); ``` -Znázornění řezu rovinou obsahující $\vec{u}$ i $\vec{v}$. +Znázornění řezu rovinou obsahující $vec{u}$ i $vec{v}$. ::: Zajímá nás tedy, jaká je pravděpodobnost toho, že jedno z ramen nadroviny bude uvnitř konvexního úhlu mezi $\vec{u}$ a $\vec{v}$. Velikost tohoto úhlu označme $\alpha$. -Víme, že $\vec{u}^{\rm\, T}\vec{v} = 1 \cdot 1 \cdot \cos a$. +Víme, že $\vec{u}^{\rm\, T}\vec{v} = 1 \cdot 1 \cdot \cos a$. Náhodnou přímku můžeme vygenerovat jako náhodný úhel $\beta$ mezi $0$ a $2\pi$ s tím, že přímka pak povede směrem $\beta$ a $\beta + \pi \mod 2\pi$. Nikdy však uvnitř konvexního úhlu nebudou obě ramena přímky, tedy pravděpodobnost, že alespoň jedno bude uvnitř a tedy body budou oddělené je: @@ -647,12 +623,12 @@ r = plot([1/2 - x/2, arccos(x)/pi], xmin=-1, xmax=1) Graf funkcí pravděpodobnosti řezu a účelové funkce. ::: -Nyní se podívejme na poměr mezi pravděpodobností toho, že hrana bude v řezu, a účelovou funkcí před vynásobením hodnotou hrany jakožto funkci proměnné $x = \vec{u}^{\rm\,T} \vec{v}$ v intervalu $\left<-1, 1\right>$: +Nyní se podívejme na poměr mezi pravděpodobností toho, že hrana bude v řezu, a účelovou funkcí před vynásobením hodnotou hrany jakožto funkci proměnné $x = \vec{u}^{\rm\,T} \vec{v}$ v intervalu $\left[ -1, 1 \right]$: $$ -\frac{\frac{\arccos \vec{u}^{\rm\,T} \vec{v}}{\pi}}{\frac{1}{2} - \frac{\vec{y_u}^{\rm T}\vec{y_v}}{2}} +\frac{\arccos \vec{u}^{\rm\,T} \vec{v}}{\pi} / \frac{1 - \vec{y_u}^{\rm T}\vec{y_v}}{2} = -\frac{\frac{\arccos x}{\pi}}{\frac{1}{2} - \frac{x}{2}} +\frac{\arccos x}{\pi} / \frac{1 - x}{2} $$ ::: {#gw-frac c=figure} @@ -664,8 +640,8 @@ Graf poměru pravděpodobnosti řezu a účelové funkce. ::: ::: {c=box t=fact} -Pro každé $x\in\left<-1,1\right>$ platí: -$$\frac{\frac{\arccos x}{\pi}}{\frac{1}{2} - \frac{x}{2}} > 0.8785 $$ +Pro každé $x\in\left[-1,1\right]$ platí: +$$\frac{\arccos x}{\pi} / \frac{1-x}{2} > 0.8785 $$ ::: Označme tuto hodnotu $c = 0.8785$. @@ -678,36 +654,34 @@ střední hodnota součtu hran v řešení je $cR$, kde $R = \sum_{uv \in E} h(u Pokud tedy najdeme dobré řešení semidefinitního programu, ve střední hodnotě pak najdeme i dobré řešení maximálního řezu. Dále však musí platit, že optimální řešení semidefinitního programu je alespoň součet hran -optimálního řešení maximálního řezu (pokud za účelovou funkci považujeme $\sum_{uv \in E} h(u,v)\cdot\left(\frac 12 - \frac{\vec{y_u}^{\rm T}\vec{y_v}}2\right)$. +optimálního řešení maximálního řezu, když za účelovou funkci považujeme $\sum_{uv \in E} h(u,v)\cdot\left(\frac 12 - \frac{\vec{y_u}^{\rm T}\vec{y_v}}2\right)$. Jedno z možných řešení totiž snadno sestrojíme z maximálního řezu: Vrcholům jedné množiny přidělíme vektory $(1,0,\dots,0)$ a druhé $(-1,0,\dots,0)$. Účelová funkce pak přičte $h(u,v)$ za každou hranu v řezu a $0$ jinak. Bohužel na rozdíl od lineárního programování, u semidefinitního programování nejsme schopní v polynomiálním čase najít optimální řešení. -Naštěstí však platí, že v polynomiálním čase jsme schopní se mu libovolně přiblížit. +Naštěstí však platí, že v polynomiálním čase za určitých podmínek jsme schopní se mu libovolně přiblížit. Přesněji řečeno, pro každé $\varepsilon > 0$ jsme schopní najít řešení s účelovou funkcí nejdále $\varepsilon$ od optima. +Ovšem musí platit, že všechny přípustná řešení jsou dostatečně málá. +Přesněji řečeno, musí platit, že Fobeniova norma všech přípustných matic je omezena konstantou s polinomiální délkou zápisu. +Tohoto výsledku jde dosáhnout pomocí elipsoidové metody, která má nejlepší teoretické výsledky. V prakxi se však často používají jiné algoritmy. +Všechny naše programy budou splňovat podmínky na řešení, protože každá z hodnot hledané matice nutně bude ležet v intervalu $[-1, -1]$. -TODO toto víc popsat u řešení semidefinitních programů - -Spojením předchozích pozorování získáme: - +::: {c=box t=theorem} +Goemans-Williamsonův algoritmus je $0.878$ pravděpodobnostní aproximační algoritmus. +::: +::: {c=proof} +Využitím předešlých pozorování a elipsoidové metody získáme: $$ \E[\hbox{Řešení MC}] \ge c\cdot\,\hbox{Řešení SDP} \ge c(1-\varepsilon)\cdot\,\hbox{Optim. SDP} \ge c(1-\varepsilon)\cdot\,\hbox{Optim. MC}.$$ - Pro dostatečně malé $\varepsilon$ se tedy jedná o $0.878$ pravděpodobnostní aproximační algoritmus. - - -Řešení semidefinitních programů -------------------------------- - -TODO - +::: Řešení pomocí semidefinitního programování ========================================== Řešení vychází z Goemans-Williamsonova algoritmu na maximální řez. -Pro každé auto nám bude semidefinitní program umísťovat bod/vektor na jednotkovou sféru. +Pro každé auto nám bude semidefinitní program umísťovat bod (někdy také chápán jako vektor) na jednotkovou sféru. Poté náhodně rozřízneme nadrovinou sféru na dvě poloviny a podle toho, do které poloviny auto patří, zvolíme jeho barvu. @@ -716,27 +690,39 @@ vynutíme $\vec{y_i} = -\vec{y_j}$. Na to nám stačí jediná podmínka -- ří Účelovou funkcí pak řekneme, že sousední auta mají preferovat stejnou barvu, tedy jejich body na sféře mají být blízko sebe, což znamená, že skalární součin má být co největší. -Finální semidefinitní program v dekomponovaném tvaru tedy vypadá takto: +Finální program + +semidefinitní program v dekomponovaném tvaru tedy vypadá takto: +:::{c=box t=algo name="Řešení pomocí semidefinitního programování" notation="sdp"} +\hfil{\penalty-10000}\relax Vyřešíme následující semidefinitní program v dekomponovaném tvaru: $$\progline{maximalizuj}{\sum_{0\le i<2n-1} \vec{y_i}^{\rm T} \vec{y_{i+1}}}{}$$ $$\progline{za podmínek}{\vec{y_{a_{i,0}}} = -\vec{y_{a_{i,1}}}}{0\le i < n}$$ $$\progline{}{|y_i| = 1}{0\le i < 2n}$$ +Dále uniformě náhodně zvolíme jednotkový vektor $z\in \R^{2n}$ +a červeně obarvíme právě ty auta $i$, pro které $y_i^{\rm T} z \ge 0$. +Náhodných výběrů vektoru je možné provézt vícero a pak vybrat nejlepší nalezené řešení. +::: -Pro každou dvojici tedy do účelové funkce přičteme číslo mezi $-1$ a $1$, kde $1$ značí, že vektory jsou stejné, +Pro každou dvojici do účelové funkce přičteme číslo mezi $-1$ a $1$, kde $1$ značí, že vektory jsou stejné, a $-1$, že jsou protilehlé. Účelovou funkci můžeme ekvivalentně zapsat jako -$$ \hbox{minimalizuj}\qquad \sum_i^{2n-1} \frac{1}{2} - \frac{\vec{y_i}^{\rm T} \vec{y_{i+1}}}{2} = \frac{2n-1}2 - \frac12 \sum_i^{2n-1} \vec{y_i}^{\rm T} \vec{y_{i+1}} $$ +$$ \hbox{minimalizuj}\qquad \sum_{0\le i < 2n-1} \frac{1}{2} - \frac{\vec{y_i}^{\rm T} \vec{y_{i+1}}}{2} = \frac{2n-1}2 - \frac12 \sum_{0 \le i < 2n-1} \vec{y_i}^{\rm T} \vec{y_{i+1}} $$ Nyní tedy pro každou dvojici sousedních aut sčítáme číslo mezi $0$ a $1$, kde $0$ nastane pro stejné vektory mezi nimiž nikdy nebude změna barvy a $1$ nastane v případě opačných vektorů, mezi nimiž se nutně barva změní. Účelovou funkci se snažíme minimalizovat. -Z této formy snadno vykoukáme, že optimum semidefinitního programu je menší rovno počtu změn v optimálním obarvení aut. -Stačí se podívat na optimální obarvení aut a každému červenému autu přiřadit vektor $(1,0,\dots,0)$ a modrému $(-1,0,\dots,0)$. +::: {c=box t=theorem} +Optimum semidefinitního programu, který minimalizuje účelovou funkci $\frac{2n-1}2 - \frac12 \sum_{0 \le i < 2n-1} \vec{y_i}^{\rm T} \vec{y_{i+1}}$ je menší rovno počtu změn v optimálním obarvení aut. +::: +::: {c=proof} +Podíváme se na optimální obarvení aut a každému červenému autu přiřadit vektor $(1,0,\dots,0)$ a modrému $(-1,0,\dots,0)$. Toto je validní řešení semidefinitního programu. Účelová funkce za každou změnu barev přičte $1$ a zbytek součtu je $0$, takže její hodnota je přesně počet změn barev. +::: -Nyní by se hodilo odhadnout střední hodnotu počtu změn barev stejně jako u maximální řezu. +Nyní by se hodilo odhadnout střední hodnotu počtu změn barev stejně jako u maximálního řezu. Jeho důkaz vycházel z pozorování ohledně poměru pravděpodobností výběru a účelové funkce. Přesněji řečeno z toho, že tento poměr umíme zdola odhadnout. Ovšem v našem případě místo maximalizace děláme minimalizaci účelové funkce a pravděpodobnosti. @@ -745,7 +731,7 @@ potřebovali bychom horní odhad poměru. Ovšem tento poměr je neomezený (viz V okolí $x=1$ jsou obě funkce poblíž $0$, ovšem pravděpodobnost se k nule blíží mnohem strměji. Tedy pro dvojici vektorů poblíž sobě je skalární součin skoro 1, ovšem pravděpodobnost oddělení je libovolně krát větší než vzdálenost součinu od jedné. -O binárním paint shop problému je navíc známé, že je neaproximovatelný [TODO CITACE], takže nemožnost výše uvedeného +O binárním paint shop problému je navíc známé, že je za předpokladu Unique game conjecture a $\P\neq \NP$ je polynomiálně neaproximovatelný s konstantním faktorem [@neaprox], takže nemožnost výše uvedeného postupu by nás ani neměla zaskočit, protože v případě, že by šlo udělat odhad tímto způsobem, získali bychom pravděpodobnostní aproximační algoritmus. Místo toho se podíváme na rozdíl pravděpodobnosti a účelové funkce. @@ -759,7 +745,7 @@ Graf rozdílu pravděpodobnosti řezu a účelové funkce. ::: ::: {c=box t=lemma} -Pro každé $x\in\left<-1,1\right>$ platí: +Pro každé $x\in\left[-1,1\right]$ platí: $$ -0.1053 \le \frac{\arccos x}{\pi} - \left(\frac{1}{2} - \frac{x}{2}\right) \le 0.1053 $$ ::: :::::: {c=proof} @@ -782,14 +768,21 @@ a hodnota $h$ v nich je přibližně $\pm 0.105256$. Označme konstantu z předchozího lemmatu jako $d = 0.1053$. -Tedy když je účelová funkce pro sousední dvojici aut je $r$, tak pravděpodobnost změny barev je nejvýše $d + r$. +::: {c=box t=theorem} +Střední hodnota (vzhledem k náhodným bitům generovaným algoritmem) +počtu změn v $\algo{sdp}$ řešení je nejvýše o $0.212n$ horší než optimum. +::: +::: {c=proof} +Když je účelová funkce pro sousední dvojici aut je $r$, tak pravděpodobnost změny barev je nejvýše $d + r$. Sečtením přes všechny hrany (z linearity středních hodnot) tedy získáme, že střední hodnota součtu změn je nejvýše $c(2n-1) + R$, kde $R = \sum_i^{2n-1} \frac{1}{2} - \frac{\vec{y_i}^{\rm T} \vec{y_{i+1}}}{2}$, tedy jedno z ekvivalentních vyjádření účelové funkce. Celkově tedy víme: -$$ \hskip -2pt \E[\hbox{Řeš. BPS}] \le 2dn + \hbox{Řeš. SDP} \le 2dn + (1-\varepsilon)\,\hbox{Opt. SDP} \le 2dn + (1-\varepsilon)\,\hbox{Opt. BPS}\hskip -2pt$$ +$$ \hskip -2pt \E[\gamma_{\algo{sdp}}(\alpha)] \le 2dn + \hbox{Řeš. SDP} \le 2dn + \hbox{Opt. SDP} + \varepsilon \le 2dn + \gamma(\alpha) + \varepsilon$$ + +Pro vhodně zvolené $\varepsilon$ jsme tedy dokázali požadovanou vzdálenost od optima. +::: -Pro vhodně zvolené $\varepsilon$ tedy víme, že střední hodnota počtu změn v řešení je nejvýše o $0.212n$ horší než optimum. Na rozdíl od jiných řešení binárního paint shop problému, zde se jedná o střední hodnotu přes náhodné rozhodnutí algoritmu, nikoliv přes náhodnou distribuci na vstupech. @@ -805,16 +798,15 @@ Místo toho, abychom měli vektor pro každé auto, uděláme si jen vektor pro každou dvojici aut stejného typu. Ten bude odpovídat řekněme prvnímu autu z dvojice. Všimneme si, že účelovou funkci zvládneme stále vyjádřit. Kdykoliv jsme používali vektor druhého auta, stačí použít mínus vektor prvního auta. -Tedy stačí některé členy jednou až dvakrát vynásobit hodnotou $-1$. -Tím jednak čtyřikrát zmenšíme matici a navíc jsme odebrali $n$ podmínek. +Tedy stačí některé členy jednou až dvakrát vynásobit hodnotou $-1$. Výsledný program vypadá takto: $$\progline{maximalizuj}{\sum_{0\le i < 2n-1} \vec{y_{t_i}}^{\rm T} \vec{y_{t_{i+1}}} P_{i} P_{i+1}}{}$$ $$\progline{za podmínek}{|y_i| = 1}{0 \le i < n}$$ -Výhodou je, že je potřeba poloviční počet proměnných, -proto v implementační části práce jsem využíval této formy programu. +Výhodou je, že je potřeba poloviční počet proměnných, matice je čtvrtinová a odebrali jsme $n$ podmínek, +proto v implementační části práce využijeme této formy programu. Měření SDP řešení ================= @@ -882,6 +874,23 @@ všechny vektory v něm mají několik prvních souřadnic velké hodnoty a ve zbylých souřadnic mají hodnoty blízké nule. Tedy kdybychom vektory promítli na méně dimenzionální sféru (vzali místo nich nejbližší bod na ní), tak se účelová funkce moc nezmění. +::: {#max_coords_400 c=figure floatpage=400} +```python {c=plotly} +from bakalarka import g +fig = g.max_coords(400, range(1, 101)) +``` +Maximální hodnota v dané dimenzi pro $n=400$. +::: + +::: {#nonzero_coords_400 c=figure floatpage=400!} +```python {c=plotly} +from bakalarka import g +fig = g.nonzero_coords(400, range(1, 101)) +``` +Počet vektorů s danou souřadnicí větší než $0.05$ pro $n=400$. +::: + + ::: {#max_coords_200 c=figure floatpage=200} ```python {c=plotly} from bakalarka import g @@ -947,20 +956,19 @@ return processor.transform([pf.CodeBlock(sdp_visualize.visualize("semidef_prog_n Vizualizace jednoho z řešení pro $n=50$, které se vejde do 3D. ::: -Praktické řešení semidefinitních programů +Praktické řešení semidef. programů ----------------------------------------- - Ve své práci jsem se pokusil implementovat jednotlivé algoritmy řešící Binární paint shop problém. U triviálních algoritmů byla implementace poměrně přímočará. Ovšem u řešení semidefinitního programování je většina složitosti algoritmu schovaná právě v řešení semidefinitních programů, což už svojí složitostí nepatří mezi algoritmy, které bych chtěl (re)implementovat. Proto je nutné se spolehnout na funkčnost již existujících implementací. -Bohužel kvalita dostupných řešitelů semidefinitních programů je poměrně nízká. +Bohužel kvalita dostupných řešičů semidefinitních programů je poměrně nízká. ### SDPA-C Jedním z použitých programů byl SDPA-C [@sdpa-web]. -Jedná se o knihovnu c C++ (TODO sazba) +Jedná se o knihovnu v C`++` založenou na metodě vnitřních bodů v primárním a duálním problému. Dle autorů projektu [@sdpa-web]: ::: {.group lang=cs} @@ -985,7 +993,7 @@ Program už mnohokrát měl ukončit smyčku a doběhnout na konec funkce, ovše je vidět, že program cyklus opustí, provede příkazy mezi cyklem a koncem funkce a pak se zase objeví uprostřed cyklu. Problém byl v tom, že funkce vracející `void*` -dle normy [@cpp-norm] +dle normy [@cpp-norm] bodu 6.6.3 musí skončit pomocí `return` a nemůže jen tak opustit funkci dojitím na její konec. Pokud se tak stane, jedná se o nedefinované chování, nikoliv jen o nedefinovanou hodnotu navrácenou z funkce. @@ -1028,7 +1036,7 @@ Toto se stává například na seedu $18$ pro $n = 150$. Vzhledem k výše uvedeným problémům jsem se rozhodl přestat využívat SDPA-C a podívat se po alternativách. -## Sage +### Sage SageMath je dle oficiálních stránek [@sagemath] open-source software pro matematické výpočty založený na rozšířené syntaxi pythonu, takže je poměrně snadné ho využívat i jako programovací jazyk. @@ -1060,7 +1068,7 @@ a každá z nich se zapisuje pomocí matice $n \times n$. ```python {c=plotly} from bakalarka import g, data_lib -data = g.load("log") +data = g.load_main_test() d = data_lib.group_by_n(data.pipelines["semidef_prog_sage.sage(10, CVXOPT)"]) fig = go.Figure(data=[go.Box( @@ -1076,29 +1084,28 @@ fig.update_layout( ) ``` -Závislost skóre SDP řešení na velikosti vstupu. -TODO možná lépe říct, co měříme +Naměřená závislost skóre SDP řešení ($\delta_{\algo{sdp}}$) na velikosti vstupu. ::: ::: {#tmp2 c=figure} ```python {c=plotly} from bakalarka import g, data_lib -data = g.load("log") +data = g.load_main_test() d = data_lib.group_by_n(data.pipelines["semidef_prog_sage.sage(10, CVXOPT)"]) fig = go.Figure(data=[go.Box( x=[i.n for i in d], y=[i.resources_cpu_time_s for i in d], - ) for d in [ - data.pipelines["semidef_prog_sage.sage(10, CVXOPT)"], - data.pipelines["semidef_prog(10)"], + name=name + ) for d,name in [ + [data.pipelines["semidef_prog(10)"], "SDPA-C"], + [data.pipelines["semidef_prog_sage.sage(10, CVXOPT)"], "Sage"], ]]) fig.update_layout( xaxis=dict(showgrid=False, type="log"), yaxis=dict(type="log"), - showlegend=False ) ``` Závislost času řešení na velikosti vstupu. @@ -1129,13 +1136,29 @@ BPS Binární paint shop problém Závěr {-} ========= -TODO +V této práci jsem představil algoritmus ${\bf sdp}$ na BPS založený na semidefinitním programování. +Bohužel se nám nepodařilo dokázat žádný netriviální odhad na $\delta_{\algo{sdp}}^+$. +Nicméně dle naměřených dat můžeme soudit, že $\delta_{\algo{sdp}}^+$ se pohybuje okolo 0.33. +Místo toho jsme však dokázali, že pro libovolný vstup bude střední hodnota +(přes náhodné čísla generovaná algoritmem nikoliv přes vstup) +skóre řešení nejhůře $0.212 n$ od optima, tedy, že platí $$\forall \alpha:\qquad\E[\delta_{\algo{sdp}}(\alpha)] \le \delta(\alpha) + 0.212 n.$$ + +Toto řešení jsme dále dokonce dvakrát implementovali s využitím +různých implementací řešení semidefinitních programů, které jsme tímto i porovnali. +Z naměřených dat jsme jednak odhadli střední hodnotu skóre algoritmu přes náhodný vstup. +A druhak jsme si všimli, že dimenze řešení semidefinitního programování je poměrně malá, což jsme zformulovali jako hypotézu. + +Stále však zůstává otevřená otázka, kolik přesně je $\delta^+$ a $\delta^-$ (a případně zda se rovnají) +a jaké nejlepší $\delta^+_{\alg}$ jsme schopní dosáhnout polynomiálním algoritmem $\alg$. + Seznam použité literatury {-} ============================= +:::: {c=refs} ::: {#refs} ::: +:::: Seznam obrázků {-} ================== diff --git a/prace/bakalarka/sample.bib b/prace/bakalarka/sample.bib index 1d0974729af3519bb642a0ac85b6903e196cc689..a755e98c1d55493ef711e2eddf1fcfbc9e78d39a 100644 --- a/prace/bakalarka/sample.bib +++ b/prace/bakalarka/sample.bib @@ -153,3 +153,27 @@ isbn="978-3-642-40328-6" } +@online{maxcut-derandom, + author = {Alexander Dimitrakakis}, + title = {Lecture notes for Randomness and Computation, lecture 6}, + url = {https://people.csail.mit.edu/ronitt/COURSE/S20/NOTES/lec6-scribe.pdf}, + year = {2020}, + urldate = {2024-04-20} +} + + +@online{maxcut-np, + author = {Kevin Sun}, + title = {Lecture notes for Graph Algorithms, lecture 22}, + url = {https://people.csail.mit.edu/ronitt/COURSE/S20/NOTES/lec6-scribe.pdf}, + year = {2019}, + urldate = {2024-04-20} +} + +@online{cpp-norm, + author = {{ISO/IEC}}, + title = {Working Draft, Standard for Programming Language C++}, + url = {https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf}, + year = {2014}, + urldate = {2024-04-20} +}