diff --git a/tex/FormalLanguageConstrainedReachabilityLectureNotes.bib b/tex/FormalLanguageConstrainedReachabilityLectureNotes.bib index 2738d4b..2ab8151 100644 --- a/tex/FormalLanguageConstrainedReachabilityLectureNotes.bib +++ b/tex/FormalLanguageConstrainedReachabilityLectureNotes.bib @@ -1465,7 +1465,7 @@ @article{BEATTY1980193 @misc{VavilovGroups, language={russian}, - author = {{\CYRN}иколай Вавилов}, + author = {Николай Вавилов}, title = {КОНКРЕТНАЯ ТЕОРИЯ ГРУПП}, year = {2005}, url = {http://dobrochan.com/src/pdf/1512/Вавилов-Н.-Конкретная-теория-групп.-Основные-понят.pdf}, @@ -1475,7 +1475,7 @@ @misc{VavilovGroups @misc{VavilovRings, language={russian}, - author = {{\CYRN}иколай Вавилов}, + author = {Николай Вавилов}, title = {КОНКРЕТНАЯ ТЕОРИЯ КОЛЕЦ}, year = {2006}, url = {http://www.add3d.ru/wp-content/uploads/2019/10/Vavilov-Rings.pdf}, @@ -1483,7 +1483,7 @@ @misc{VavilovRings } @misc{das2018lower, - title={Lower bounds for Combinatorial Algorithms for Boolean Matrix Multiplication}, + title={Lower bounds for Combinatorial Algorithms for Boolean Matrix Multiplication}, author={Debarati Das and Michal Koucký and Michael Saks}, year={2018}, eprint={1801.05202}, @@ -1492,7 +1492,7 @@ @misc{das2018lower } @misc{alman2020refined, - title={A Refined Laser Method and Faster Matrix Multiplication}, + title={A Refined Laser Method and Faster Matrix Multiplication}, author={Josh Alman and Virginia Vassilevska Williams}, year={2020}, eprint={2010.05846}, @@ -1502,8 +1502,8 @@ @misc{alman2020refined @INPROCEEDINGS{5438580, author={Bansal, Nikhil and Williams, Ryan}, - booktitle={2009 50th Annual IEEE Symposium on Foundations of Computer Science}, - title={Regularity Lemmas and Combinatorial Algorithms}, + booktitle={2009 50th Annual IEEE Symposium on Foundations of Computer Science}, + title={Regularity Lemmas and Combinatorial Algorithms}, year={2009}, volume={}, number={}, @@ -1528,7 +1528,7 @@ @InProceedings{10.1007/978-3-662-47672-7_89 @article{ArlDinKro70, -author = {{\CYRV}. Арлазаров and {\CYRE}. Диниц and {\CYRM}. Кронрод and {\CYRI}. Фараджев}, +author = {В. Арлазаров and Е. Диниц and М. Кронрод and И. Фараджев}, title = {Об экономном построении транзитивного замыкания ориентированного графа}, journal = {Докл. АН СССР}, year = {1970}, @@ -1731,7 +1731,7 @@ @article{10.1145/3571252 } @misc{istomina2023finegrained, - title={Fine-grained reductions around CFL-reachability}, + title={Fine-grained reductions around CFL-reachability}, author={Aleksandra Istomina and Semyon Grigorev and Ekaterina Shemetova}, year={2023}, eprint={2306.15967}, @@ -1981,4 +1981,4 @@ @article{chomsky1958finite pages={91--112}, year={1958}, publisher={Elsevier} -} \ No newline at end of file +} diff --git a/tex/FormalLanguageTheoryIntro.tex b/tex/FormalLanguageTheoryIntro.tex index 5a18b26..fefb5ff 100644 --- a/tex/FormalLanguageTheoryIntro.tex +++ b/tex/FormalLanguageTheoryIntro.tex @@ -1,23 +1,23 @@ -\chapter[Общие сведения теории формальных языков]{Общие сведения теории формальных языков\footnote{В рамках данной работы мы будем говорить о ``типичных'' языках, элементами которых являются объекты, максимально похожие на строки. При этом будет оставлен за бортом тот факт, что базовое определение позволяет нам рассматривать в качестве ``строительных элементов'' (алфавита) практически произвольные объекты, а значит, создавать весьма нетривиальные конструкции в качестве слов языка. Примерами ``нестроковых'' языков могут послужить языки деревьев~\cite{tata2007} или языки графов~\cite{EHRIG1992557, Courcelle2009}.}}\label{chpt:FormalLanguageTheoryIntro} +\chapter[Общие сведения теории формальных языков]{Общие сведения теории формальных языков\sidenote[][*3]{В рамках данной работы мы будем говорить о ``типичных'' языках, элементами которых являются объекты, максимально похожие на строки. При этом будет оставлен за бортом тот факт, что базовое определение позволяет нам рассматривать в качестве ``строительных элементов'' (алфавита) практически произвольные объекты, а значит, создавать весьма нетривиальные конструкции в качестве слов языка. Примерами ``нестроковых'' языков могут послужить языки деревьев~\cite{tata2007} или языки графов~\cite{EHRIG1992557, Courcelle2009}.}}\label{chpt:FormalLanguageTheoryIntro} В данной главе мы рассмотрим основные понятия из теории формальных языков, которые пригодятся нам в дальнейшем изложении. Заметим, что мы рассмотрим лишь те результаты теории формальных языков,которые будут необходимы нам для дальнейшего изложения. Для более глубокого изучения именно теории формальных языков рекомендуется обратиться к классической литературе. -Например, к работам Харрисона~\cite{10.5555/578595}, Хопкрофта~\cite{hopcroft2001introduction} или другой подобной литературе. +Например, к работам Харрисона~\sidecite{10.5555/578595}, Хопкрофта~\sidecite{hopcroft2001introduction} или другой подобной литературе. \begin{definition} -\textit{Алфавит} --- это конечное множество. -Элементы этого множества будем называть \textit{символами}. + \textit{Алфавит} --- это конечное множество. + Элементы этого множества будем называть \textit{символами}. \end{definition} \begin{example} Примеры алфавитов - + \begin{itemize} \item Латинский алфавит $\Sigma = \{ a, b, c, \dots, z\}$ \item Кириллический алфавит $\Sigma = \{ \text{а, б, в, \dots, я}\}$ \item Алфавит натуральных чисел в шестнадцатеричной записи - $$\Sigma = \{0, 1, 2, 3, 4, 5, 6, 7 ,8,9, A, B, C, D, E, F \}$$ + $$\Sigma = \{0, 1, 2, 3, 4, 5, 6, 7 ,8,9, A, B, C, D, E, F \}$$ \end{itemize} \end{example} @@ -28,28 +28,28 @@ При записи выражений символ точки (обозначение операции конкатенации) часто будем опускать: $a \cdot b = ab$. \begin{definition} -\textit{Слово} над алфавитом $\Sigma$ --- это конечная конкатенация символов алфавита $\Sigma$: $\omega = a_0 \cdot a_1 \cdot \ldots \cdot a_m$, где $\omega$ --- слово, а $a_i \in \Sigma$ для любого $i$. -Для обозначения пустого слова (слова, содержащего ноль символов) будем использовать специальный символ $\varepsilon, \varepsilon \notin \Sigma$. + \textit{Слово} над алфавитом $\Sigma$ --- это конечная конкатенация символов алфавита $\Sigma$: $\omega = a_0 \cdot a_1 \cdot \ldots \cdot a_m$, где $\omega$ --- слово, а $a_i \in \Sigma$ для любого $i$. + Для обозначения пустого слова (слова, содержащего ноль символов) будем использовать специальный символ $\varepsilon, \varepsilon \notin \Sigma$. \end{definition} \begin{definition} -Пусть $\omega = a_0 \cdot a_1 \cdot \ldots \cdot a_m$ --- слово над алфавитом $\Sigma$. -Будем называть $m + 1$ \textit{длиной слова} и обозначать как $|\omega|$. Длина пустого слова равна нулю. + Пусть $\omega = a_0 \cdot a_1 \cdot \ldots \cdot a_m$ --- слово над алфавитом $\Sigma$. + Будем называть $m + 1$ \textit{длиной слова} и обозначать как $|\omega|$. Длина пустого слова равна нулю. \end{definition} \begin{definition} Пусть $\omega$ --- слово над алфавитом $\Sigma$. Пусть $t \in \Sigma$ --- некоторый символ из алфавита. Тогда будем обозначать количество вхождений символа $t$ в слове $\omega$ как $|\omega|_t$. - \end{definition} - +\end{definition} + \begin{definition} -\textit{Язык} над алфавитом $\Sigma$ --- это множество слов над алфавитом $\Sigma$. + \textit{Язык} над алфавитом $\Sigma$ --- это множество слов над алфавитом $\Sigma$. \end{definition} \begin{example} -Примеры языков. - + Примеры языков. + \begin{itemize} \item Язык целых чисел в двоичной записи $\{0, 1, -1, 10, 11, -10, -11, \dots\}.$ \item Язык всех правильных скобочных последовательностей $$\{(), (()), ()(), (())(), \dots\}.$$ @@ -58,17 +58,17 @@ Любой язык над алфавитом $\Sigma$ является подмножеством универсального множества $\Sigma^*$ --- множества всех слов над алфавитом $\Sigma$. -Заметим, что язык не обязан быть конечным множеством, в то время как алфавит в нашей области всегда конечен\footnote{Существуют ситуации, когда возникают бесконечные алфавиты.} и изучаем мы конечные слова\footnote{Существуют ситуации, когда возникают бесконечные слова. Например работы по обработке потоков.}. +Заметим, что язык не обязан быть конечным множеством, в то время как алфавит в нашей области всегда конечен\sidenote{Существуют ситуации, когда возникают бесконечные алфавиты.} и изучаем мы конечные слова\sidenote{Существуют ситуации, когда возникают бесконечные слова. Например работы по обработке потоков.}. Можно выделить следующие основные \textit{способы задания языков.} \begin{itemize} -\item Перечислить все элементы. Такой способ работает только для конечных языков. Перечислить бесконечное множество за конечное время не получится. -\item Задать генератор --- процедуру, которая возвращает очередное слово языка. -\item Задать распознаватель --- процедуру, которая по данному слову может определить, принадлежит оно заданному языку или нет. + \item Перечислить все элементы. Такой способ работает только для конечных языков. Перечислить бесконечное множество за конечное время не получится. + \item Задать генератор --- процедуру, которая возвращает очередное слово языка. + \item Задать распознаватель --- процедуру, которая по данному слову может определить, принадлежит оно заданному языку или нет. \end{itemize} Стоит отметить, что существуют и другие способы задания. -Например, язык может определяться как решение некоторого \textit{языкового уравнения}~\cite{Leiss1999}. +Например, язык может определяться как решение некоторого \textit{языкового уравнения}~\sidecite{Leiss1999}. \section{Теоретико-множественные операции над языками} @@ -82,45 +82,45 @@ \section{Теоретико-множественные операции над Но кроме этого, нам потребуются и относительно специальные операции, определённые ниже. \begin{definition} -Пусть дано множество $S$ с определённой на нём операцией $\odot: S \times S \to S$, $S_1 \subseteq S$, $S_2 \subseteq S$, тогда -$$ -S_1 \odot S_2 = \{ s_1 \odot s_2 \mid s_1 \in S_1, s_2 \in S_2\} -$$ + Пусть дано множество $S$ с определённой на нём операцией $\odot: S \times S \to S$, $S_1 \subseteq S$, $S_2 \subseteq S$, тогда + $$ + S_1 \odot S_2 = \{ s_1 \odot s_2 \mid s_1 \in S_1, s_2 \in S_2\} + $$ \end{definition} \begin{definition} -Пусть дано множество $S$ с определённой на нём операцией $\odot: S \times S \to S$, $S_1 \subseteq S$, тогда -$$ -S_1 ^ n = \{ \underbrace{s_1 \odot s_1 \odot \ldots \odot s_1}_{\text{n раз}} \mid s_1 \in S_1\} -$$ -При этом $S_1^0 = \{\varepsilon\}$\footnote{В данном случае нулевая степень тоже даёт единицу.}. + Пусть дано множество $S$ с определённой на нём операцией $\odot: S \times S \to S$, $S_1 \subseteq S$, тогда + $$ + S_1 ^ n = \{ \underbrace{s_1 \odot s_1 \odot \ldots \odot s_1}_{\text{n раз}} \mid s_1 \in S_1\} + $$ + При этом $S_1^0 = \{\varepsilon\}$\sidenote{В данном случае нулевая степень тоже даёт единицу.}. \end{definition} \begin{definition} -Пусть дано множество $S$ с определённой на нём операцией $\odot: S \times S \to S$, $S_1 \subseteq S$, тогда -$$ -S_1 ^ * = \bigcup_{n = 0}^{\infty} S_1^n -$$ + Пусть дано множество $S$ с определённой на нём операцией $\odot: S \times S \to S$, $S_1 \subseteq S$, тогда + $$ + S_1 ^ * = \bigcup_{n = 0}^{\infty} S_1^n + $$ \end{definition} Многие прикладные задачи, в которых возникают языки, достаточно естественным образом формулируются в теоретико-множественных терминах. Так, задача распознавания --- это задача проверки принадлежности элемента множеству. Далее мы рассмотрим прикладные задачи, решение которых требует, например, проверки включения одного языка в другой, или проверки непустоты пересечения двух языков. -Разрешимость таких задач, алгоритмы решения, их сложность и другие свойства, зависят от свойств языков. +Разрешимость таких задач, алгоритмы решения, их сложность и другие свойства, зависят от свойств языков. Это даёт дополнительную связь теоретико-языковых конструкций с решением прикладных задач, позволяя более аккуратно рассуждать о свойствах получаемых решений. \section{Производные} -Производные для языков предложил Януш Бжозовский в работе\cite{10.1145/321239.321249}. +Производные для языков предложил Януш Бжозовский в работе\sidecite{10.1145/321239.321249}. \begin{definition} Производная $\partial_c L = \{ w' \mid w \in L, w = cw'\}$ \end{definition} Заметим, что если для слова $w, |w|=n$ верно, что $$\varepsilon \in (\partial_{w[n-1]} \circ \ldots \circ \partial_{w[1]} \circ \partial_{w[0]}) (L)$$, то $w \in L$. -Таким образом, существует возможность использовать производные для проверки принадлежность слов заданному языку. -Данная возможность активно используется для регулярных языков~\cite{caron_champarnaud_mignot_2014}, языков, распознаваемых автоматами, управляемыми входом (Input Driven Pushdown Automata, IDPDA)~\cite{10.1145/3591472}, и контекстно-свободных языков~\cite{10.1145/2034773.2034801, 10.1145/3022671.2984026}. -Кроме этого, с помощью производных можно построить элегантный алгоритм построения конечного автомата по регулярному выражению~\cite{10.1017/S0956796808007090} и для выполнения регулярных запросов~\cite{10.1145/2949689.2949711}. +Таким образом, существует возможность использовать производные для проверки принадлежность слов заданному языку. +Данная возможность активно используется для регулярных языков~\sidecite{caron_champarnaud_mignot_2014}, языков, распознаваемых автоматами, управляемыми входом (Input Driven Pushdown Automata, IDPDA)~\sidecite{10.1145/3591472}, и контекстно-свободных языков~\sidecite{10.1145/2034773.2034801, 10.1145/3022671.2984026}. +Кроме этого, с помощью производных можно построить элегантный алгоритм построения конечного автомата по регулярному выражению~\sidecite{10.1017/S0956796808007090} и для выполнения регулярных запросов~\sidecite{10.1145/2949689.2949711}. \section{Распознаватели} @@ -140,7 +140,7 @@ \section{Генераторы} Один из базовых способов задать генератор языка опирается на \textit{системы переписывания строк}, из которых, в дальнейшем, можно получить так называемые \textit{порождающие грамматики}. \begin{definition} - \textit{Система переписывания (строк)}\footnote{Один из классически примеров систем переписывания строк --- это машины Маркова, или алгорифмы Маркова~\cite{markov1954theory}.} --- это пара $R = \langle \Sigma, P \rangle$, где $\Sigma$ --- алфавит, $P= \{p \mid p = w' \to w'', w' \in \Sigma^+, w'' \in \Sigma^*\}$ --- набор правил переписывания. + \textit{Система переписывания (строк)}\sidenote{Один из классически примеров систем переписывания строк --- это машины Маркова, или алгорифмы Маркова~\cite{markov1954theory}.} --- это пара $R = \langle \Sigma, P \rangle$, где $\Sigma$ --- алфавит, $P= \{p \mid p = w' \to w'', w' \in \Sigma^+, w'' \in \Sigma^*\}$ --- набор правил переписывания. \end{definition} Один шаг работы системы состоит из замены любого вхождения любой из левых частей правил на соответствующую правую часть правила. @@ -160,128 +160,128 @@ \section{Генераторы} \section{Классы языков} Иерархия языков, предложенная Ноамом Хомским (Noam Chomsky), является на текущий момент классической и представлена на рисунке~\ref{fig:Chomsky}. -Она основана на сопоставлении языкам тех или иных формальных вычислителей, способных их распознать. +Она основана на сопоставлении языкам тех или иных формальных вычислителей, способных их распознать. Например, для распознавания любого регулярного языка достаточно конечного автомата. Для контекстно-свободного --- магазинного автомата. И так далее. \begin{figure} \begin{center} - \includegraphics[width=0.9\textwidth]{figures/Chomsky.pdf} + \includegraphics[width=0.9\textwidth]{figures/Chomsky.pdf} \end{center} \caption{Иерархия языков по Хомскому} \label{fig:Chomsky} \end{figure} -Однако, данная иерархия постепенно теряет свою актуальность, так как появляются новые классы языков, свойства которых уже не удаётся адекватным образом отобразить, используя её. +Однако, данная иерархия постепенно теряет свою актуальность, так как появляются новые классы языков, свойства которых уже не удаётся адекватным образом отобразить, используя её. -Один из вариантов иерархии языков, более полно отображающий современное состояние дел, предложен Александром Охотиным\footnote{Иерархия и некоторые отражаемые ей свойства подробно обсуждаются в презентации Александра Охотина ``Underlying principles -and recurring ideas of formal grammars'' (\url{https://users.math-cs.spbu.ru/~okhotin/talks/grammars_lata_talk.pdf}). -Также, с данной презентацией рекомендуется ознакомиться чтобы представить себе состояние области в целом.}. -Вариация предложенной Александром Охотиным иерархии представлена на изображении~\ref{fig:hierarchyOkhotin}~\footnote{Данная вариация скомпонована из версии, представленной в презентации ``Underlying principles -and recurring ideas of formal grammars'' и версии, взятой из работы~\cite{MRYKHIN2023113829}.}. +Один из вариантов иерархии языков, более полно отображающий современное состояние дел, предложен Александром Охотиным\sidenote{Иерархия и некоторые отражаемые ей свойства подробно обсуждаются в презентации Александра Охотина ``Underlying principles + and recurring ideas of formal grammars'' (\url{https://users.math-cs.spbu.ru/~okhotin/talks/grammars_lata_talk.pdf}). + Также, с данной презентацией рекомендуется ознакомиться чтобы представить себе состояние области в целом.}. +Вариация предложенной Александром Охотиным иерархии представлена на изображении~\ref{fig:hierarchyOkhotin}~\sidenote{Данная вариация скомпонована из версии, представленной в презентации ``Underlying principles + and recurring ideas of formal grammars'' и версии, взятой из работы~\cite{MRYKHIN2023113829}.}. Представленная диаграмма содержит регулярные и контекстно-свободные. Так и подклассы, лежащие между ними. Вместе с этим, классы, лежащие выше контекстно-свободных: многокомпонентные контекстно-свободные, булевы, конъюнктивные, их подклассы. -\begin{figure} +\begin{figure*} \begin{center} - \begin{tikzpicture}[node distance=1.0cm,bend angle=45,auto] - \tikzstyle{lang}=[circle,thick,draw=blue!75,fill=blue!75,minimum size=1mm] - \node [lang] (reg) [label=below:\textit{Reg}] {}; - \node [right of = reg] (reg_dummy) {}; - \node [lang] (lllin) [right of=reg_dummy, label=below:\textit{LLLin}] {}; - \node [right of = lllin] (lllin_dummy) {}; - \node [lang] (lrlin) [right of=lllin_dummy, label=below:\textit{LRLin}] {}; - \node [right of = lrlin] (lrlin_dummy) {}; - \node [lang] (unamblin) [right of=lrlin_dummy, label=below:\textit{UnambLin}] {}; - \node [right of = unamblin] (unamblin_dummy) {}; - \node [lang] (lin) [right of=unamblin_dummy, label=below:\textit{Lin}] {}; - \node [right of = lin] (lin_dummy) {}; - \node [right of = lin_dummy] (lin_dummy_2) {}; - \node [right of = lin_dummy_2] (lin_dummy_3) {}; - \node [lang] (conj) [right of=lin_dummy_3, label=below:\textit{Conj}] {}; - \node [right of = conj] (conj_dummy) {}; - \node [lang] (bool) [right of=conj_dummy, label=right:\textit{Bool}] {}; - - \node [above of = lrlin] (lrlin_up_dummy) {}; - \node [lang] (ll) [above of=lrlin_up_dummy, label=above:\textit{LL}] {}; - \node [right of = ll] (ll_dummy) {}; - \node [lang] (lr) [right of=ll_dummy, label=above:\textit{LR}] {}; - \node [right of = lr] (lr_dummy) {}; - \node [lang] (unamb) [right of=lr_dummy, label=above:\textit{Unamb}] {}; - \node [right of = unamb] (unamb_dummy) {}; - \node [lang] (ordinary) [right of=unamb_dummy, label=right:\textit{Ordinary}] {}; - - \node [lang] (conjleftcontext) [above of=conj_dummy, label=right:\textit{Conj$+\lhd$}] {}; - - \node [below of = lrlin] (lrlin_down_dummy) {}; - \node [lang] (vpda) [below of=lrlin_down_dummy, label=below:\textit{VPDA}] {}; - \node [below of = lin] (lin_down_dummy_1) {}; - \node [below of = lin_down_dummy_1] (lin_down_dummy_2) {}; - \node [right of = lin_down_dummy_2] (lin_right_dummy_1) {}; - \node [lang] (linconj) [right of=lin_right_dummy_1, label=below:\textit{LinConj}] {}; - - \node [lang] (unambtag) [above of=unamb_dummy, label=above:\textit{UnambTAG}] {}; - \node [right of = unambtag] (unambtag_dummy) {}; - \node [lang] (tag) [right of=unambtag_dummy, label=above:\textit{TAG}] {}; - \node [right of = tag] (tag_dummy) {}; - \node [lang] (mcfl) [right of=tag_dummy, label=above:\textit{MCFL}] {}; - - \node [above of = linconj] (linconj_above_dummy) {}; - \node [lang] (unambconj) [right of=linconj_above_dummy, label=below:\textit{UnambConj}] {}; - \node [right of = unambconj] (unambconj_dummy) {}; - \node [lang] (unambbool) [right of=unambconj_dummy, label=right:\textit{UnambBool}] {}; - - \node [below of = linconj] (linconj_below_dummy) {}; - \node [lang] (rtca) [right of=linconj_below_dummy, label=below:\textit{RT-CA}] {}; - \node [right of = rtca] (rtca_dummy) {}; - \node [lang] (ltca) [right of=rtca_dummy, label=right:\textit{LT-CA}] {}; - - \path[->] - (reg) edge node {} (lllin) - (lllin) edge node {} (lrlin) - (lrlin) edge node {} (unamblin) - (unamblin) edge node {} (lin) - - (lllin) edge node {} (ll) - (ll) edge node {} (lr) - (ll) edge node {} (lr) - (lr) edge node {} (unamb) - (unamb) edge node {} (ordinary) - - (lrlin) edge node {} (lr) - (unamblin) edge node {} (unamb) - (lin) edge node {} (ordinary) - - (reg) edge node {} (vpda) - (vpda) edge node {} (lr) - (vpda) edge node {} (linconj) - - (ordinary) edge node {} (conj) - (conj) edge node {} (bool) - (conj) edge node {} (conjleftcontext) - - (unamb) edge node {} (unambtag) - (ordinary) edge node {} (tag) - (unambtag) edge node {} (tag) - (tag) edge node {} (mcfl) - - (lin) edge node {} (linconj) - (linconj) edge node {} (unambconj) - (unambconj) edge node {} (unambbool) - (unambconj) edge node {} (conj) - (unambbool) edge node {} (bool) - (unamb) edge node {} (unambconj) - - (linconj) edge node {} (rtca) - (rtca) edge node {} (ltca) - ; - \end{tikzpicture} -\end{center} -\caption{Иерархия. \textit{Reg} --- регулярные, \textit{LLLin}, \textit{LRLin}, \textit{UnambLin}, \textit{Lin}, \textit{LL}, \textit{LR}, \textit{Unamb} --- однозначные, \textit{Ordinary} --- обыкновенные (контекстно-свободные) -\textit{Conj}, \textit{Boolean}, \textit{UnamnbBool}, \textit{UnambConj}, \textit{VPDA}, \textit{LinConj}, \textit{UnambTAG}, \textit{TAG}, \textit{MCFL},} -\label{fig:hierarchyOkhotin} -\end{figure} + \begin{tikzpicture}[node distance=1.0cm,bend angle=45,auto] + \tikzstyle{lang}=[circle,thick,draw=blue!75,fill=blue!75,minimum size=1mm] + \node [lang] (reg) [label=below:\textit{Reg}] {}; + \node [right of = reg] (reg_dummy) {}; + \node [lang] (lllin) [right of=reg_dummy, label=below:\textit{LLLin}] {}; + \node [right of = lllin] (lllin_dummy) {}; + \node [lang] (lrlin) [right of=lllin_dummy, label=below:\textit{LRLin}] {}; + \node [right of = lrlin] (lrlin_dummy) {}; + \node [lang] (unamblin) [right of=lrlin_dummy, label=below:\textit{UnambLin}] {}; + \node [right of = unamblin] (unamblin_dummy) {}; + \node [lang] (lin) [right of=unamblin_dummy, label=below:\textit{Lin}] {}; + \node [right of = lin] (lin_dummy) {}; + \node [right of = lin_dummy] (lin_dummy_2) {}; + \node [right of = lin_dummy_2] (lin_dummy_3) {}; + \node [lang] (conj) [right of=lin_dummy_3, label=below:\textit{Conj}] {}; + \node [right of = conj] (conj_dummy) {}; + \node [lang] (bool) [right of=conj_dummy, label=right:\textit{Bool}] {}; + + \node [above of = lrlin] (lrlin_up_dummy) {}; + \node [lang] (ll) [above of=lrlin_up_dummy, label=above:\textit{LL}] {}; + \node [right of = ll] (ll_dummy) {}; + \node [lang] (lr) [right of=ll_dummy, label=above:\textit{LR}] {}; + \node [right of = lr] (lr_dummy) {}; + \node [lang] (unamb) [right of=lr_dummy, label=above:\textit{Unamb}] {}; + \node [right of = unamb] (unamb_dummy) {}; + \node [lang] (ordinary) [right of=unamb_dummy, label=right:\textit{Ordinary}] {}; + + \node [lang] (conjleftcontext) [above of=conj_dummy, label=right:\textit{Conj$+\lhd$}] {}; + + \node [below of = lrlin] (lrlin_down_dummy) {}; + \node [lang] (vpda) [below of=lrlin_down_dummy, label=below:\textit{VPDA}] {}; + \node [below of = lin] (lin_down_dummy_1) {}; + \node [below of = lin_down_dummy_1] (lin_down_dummy_2) {}; + \node [right of = lin_down_dummy_2] (lin_right_dummy_1) {}; + \node [lang] (linconj) [right of=lin_right_dummy_1, label=below:\textit{LinConj}] {}; + + \node [lang] (unambtag) [above of=unamb_dummy, label=above:\textit{UnambTAG}] {}; + \node [right of = unambtag] (unambtag_dummy) {}; + \node [lang] (tag) [right of=unambtag_dummy, label=above:\textit{TAG}] {}; + \node [right of = tag] (tag_dummy) {}; + \node [lang] (mcfl) [right of=tag_dummy, label=above:\textit{MCFL}] {}; + + \node [above of = linconj] (linconj_above_dummy) {}; + \node [lang] (unambconj) [right of=linconj_above_dummy, label=below:\textit{UnambConj}] {}; + \node [right of = unambconj] (unambconj_dummy) {}; + \node [lang] (unambbool) [right of=unambconj_dummy, label=right:\textit{UnambBool}] {}; + + \node [below of = linconj] (linconj_below_dummy) {}; + \node [lang] (rtca) [right of=linconj_below_dummy, label=below:\textit{RT-CA}] {}; + \node [right of = rtca] (rtca_dummy) {}; + \node [lang] (ltca) [right of=rtca_dummy, label=right:\textit{LT-CA}] {}; + + \path[->] + (reg) edge node {} (lllin) + (lllin) edge node {} (lrlin) + (lrlin) edge node {} (unamblin) + (unamblin) edge node {} (lin) + + (lllin) edge node {} (ll) + (ll) edge node {} (lr) + (ll) edge node {} (lr) + (lr) edge node {} (unamb) + (unamb) edge node {} (ordinary) + + (lrlin) edge node {} (lr) + (unamblin) edge node {} (unamb) + (lin) edge node {} (ordinary) + + (reg) edge node {} (vpda) + (vpda) edge node {} (lr) + (vpda) edge node {} (linconj) + + (ordinary) edge node {} (conj) + (conj) edge node {} (bool) + (conj) edge node {} (conjleftcontext) + + (unamb) edge node {} (unambtag) + (ordinary) edge node {} (tag) + (unambtag) edge node {} (tag) + (tag) edge node {} (mcfl) + + (lin) edge node {} (linconj) + (linconj) edge node {} (unambconj) + (unambconj) edge node {} (unambbool) + (unambconj) edge node {} (conj) + (unambbool) edge node {} (bool) + (unamb) edge node {} (unambconj) + + (linconj) edge node {} (rtca) + (rtca) edge node {} (ltca) + ; + \end{tikzpicture} + \end{center} + \caption{Иерархия. \textit{Reg} --- регулярные, \textit{LLLin}, \textit{LRLin}, \textit{UnambLin}, \textit{Lin}, \textit{LL}, \textit{LR}, \textit{Unamb} --- однозначные, \textit{Ordinary} --- обыкновенные (контекстно-свободные) + \textit{Conj}, \textit{Boolean}, \textit{UnamnbBool}, \textit{UnambConj}, \textit{VPDA}, \textit{LinConj}, \textit{UnambTAG}, \textit{TAG}, \textit{MCFL},} + \label{fig:hierarchyOkhotin} +\end{figure*} Для того, чтобы содержательно рассуждать про различные классы языков, необходимо иметь механизм, позволяющий чётко отделить один класс от другого. \textit{Лемма о накачке} для соответствующего класса --- один из классических таких механизмов. diff --git a/tex/GraphTheoryIntro.tex b/tex/GraphTheoryIntro.tex index 60df8cd..8f59ef6 100644 --- a/tex/GraphTheoryIntro.tex +++ b/tex/GraphTheoryIntro.tex @@ -1,4 +1,5 @@ \chapter{Некоторые сведения из теории графов}\label{chpt:GraphTheoryIntro} +\margintoc В данном разделе мы дадим определения базовым понятиям из теории графов, рассмотрим несколько классических задач из области анализа графов и алгоритмы их решения. Кроме этого, поговорим о связи между линейной алгеброй и некоторыми задачами анализа графов. @@ -7,7 +8,7 @@ \chapter{Некоторые сведения из теории графов}\lab \section{Основные определения} \begin{definition} - \textit{Помеченный ориентированный граф} $\mathcal{G} = \langle V, E, L \rangle$, где $V$ --- конечное множество вершин, $E$ --- конечное множество рёбер, т.ч. $E \subseteq V \times L \times V$, $L$ --- конечное множество меток на рёбрах. В некоторых случаях метки называют \textit{весами}\footnote{Весами метки называют, как правило, тогда, когда они берутся из какого-либо поля, например $\mathbb{R}$ или $\mathbb{N}$.} и тогда говорят о \textit{взвешенном} графе. + \textit{Помеченный ориентированный граф} $\mathcal{G} = \langle V, E, L \rangle$, где $V$ --- конечное множество вершин, $E$ --- конечное множество рёбер, т.ч. $E \subseteq V \times L \times V$, $L$ --- конечное множество меток на рёбрах. В некоторых случаях метки называют \textit{весами}\sidenote{Весами метки называют, как правило, тогда, когда они берутся из какого-либо поля, например $\mathbb{R}$ или $\mathbb{N}$.} и тогда говорят о \textit{взвешенном} графе. \end{definition} @@ -25,37 +26,37 @@ \section{Основные определения} \begin{example}[Пример графа и его графического представления] Пусть дан граф \begin{align*} - \mathcal{G} = \langle V&=\{0,1,2,3\},\\ - E&=\{(0,a,1), (1,a,2), (2,a,0), (2,b,3), (3,b,2)\}, \\ - L&=\{a,b\} \rangle. + \mathcal{G} = \langle V & =\{0,1,2,3\}, \\ + E & =\{(0,a,1), (1,a,2), (2,a,0), (2,b,3), (3,b,2)\}, \\ + L & =\{a,b\} \rangle. \end{align*} Графическое представление графа $\mathcal{G}$: \begin{center} - \input{figures/graph/graph0} + \input{figures/graph/graph0} \end{center} \end{example} \begin{example}[Пример рёбер графа] -$(0,a,1)$ и $(3,b,2)$ --- это рёбра графа $\mathcal{G}_1$. При этом $(3,b,2)$ $(2,b,3)$ --- это разные рёбра. + $(0,a,1)$ и $(3,b,2)$ --- это рёбра графа $\mathcal{G}_1$. При этом $(3,b,2)$ $(2,b,3)$ --- это разные рёбра. \end{example} \begin{definition} \textit{Путём} $\pi$ в графе $\mathcal{G}$ будем называть последовательность рёбер такую, что для любых двух последовательных рёбер $e_1=(u_1,l_1,v_1)$ и $e_2=(u_2,l_2,v_2)$ в этой последовательности, конечная вершина первого ребра является начальной вершиной второго, то есть $v_1 = u_2$. Будем обозначать путь из вершины $v_0$ в вершину $v_n$ как $v_0 \pi v_n$. Иными совами, $$v_0 \pi v_n = e_0,e_1, \dots, e_{n-1} = (v_0, l_0, v_1),(v_1,l_1,v_2),\dots,(v_{n-1},l_{n-1},v_n).$$ Часто для представления пути мы буем использовать следующие нотации: -\begin{center} - \input{figures/graph/path0.tex} -\end{center} + \begin{center} + \input{figures/graph/path0.tex} + \end{center} \end{definition} - или +или $$ -v_0 \xrightarrow[]{l_0} v_1 \xrightarrow[]{l_1} v_2 \xrightarrow[]{l_2} \ldots \xrightarrow[]{l_{n-2}} v_{n-1} \xrightarrow[]{l_{n-1}} v_n. + v_0 \xrightarrow[]{l_0} v_1 \xrightarrow[]{l_1} v_2 \xrightarrow[]{l_2} \ldots \xrightarrow[]{l_{n-2}} v_{n-1} \xrightarrow[]{l_{n-1}} v_n. $$ \begin{example}[Пример путей графа] -$(0,a,1),(1,a,2) = 0\pi_1 2$ --- путь из вершины 0 в вершину 2 в графе $\mathcal{G}_1$. -При этом $(0,a,1),(1,a,2),(2,b,3),(3,b,2) = 0\pi_2 2$ --- это тоже путь из вершины 0 в вершину 2 в графе $\mathcal{G}_1$, но он не равен $0\pi_1 2$. + $(0,a,1),(1,a,2) = 0\pi_1 2$ --- путь из вершины 0 в вершину 2 в графе $\mathcal{G}_1$. + При этом $(0,a,1),(1,a,2),(2,b,3),(3,b,2) = 0\pi_2 2$ --- это тоже путь из вершины 0 в вершину 2 в графе $\mathcal{G}_1$, но он не равен $0\pi_1 2$. \end{example} Кроме того, нам потребуется отношение, отражающее факт существования пути между двумя вершинами. @@ -89,30 +90,30 @@ \section{Основные определения} \input{figures/graph/graph1.tex} \end{center} -$\mathbb{G} = (S,\circ)$ в этом случае конструируется следующим образом. Во-первых, придётся предположить, что $L$ --- множество с одним элементом, скажем $s$, и считать, что все рёбра помечены им\footnote{А раз все рёбра имеют одинаковый заранее известный вес, то можно его и не писать для каждого ребра при задании графа. Поэтому привычное нам изображение получается достаточно логичным.}. Далее, $S = L \cup{\{n\}} = \{s,n\}$, где $n$ --- нейтральный элемент относительно $\circ$. Тогда $\circ$ можно определить поточечно следующим образом. -\begin{itemize} - \item $s \circ s = s$ - \item $s \circ n = n \circ s = s$ - \item $n \circ n = n$ -\end{itemize} + $\mathbb{G} = (S,\circ)$ в этом случае конструируется следующим образом. Во-первых, придётся предположить, что $L$ --- множество с одним элементом, скажем $s$, и считать, что все рёбра помечены им\sidenote{А раз все рёбра имеют одинаковый заранее известный вес, то можно его и не писать для каждого ребра при задании графа. Поэтому привычное нам изображение получается достаточно логичным.}. Далее, $S = L \cup{\{n\}} = \{s,n\}$, где $n$ --- нейтральный элемент относительно $\circ$. Тогда $\circ$ можно определить поточечно следующим образом. + \begin{itemize} + \item $s \circ s = s$ + \item $s \circ n = n \circ s = s$ + \item $n \circ n = n$ + \end{itemize} -Таким образом, матрица смежности данного графа выглядит следующим образом: -$$ -\begin{pmatrix} - n & s & s & n \\ - s & n & s & n \\ - s & s & n & s \\ - n & n & s & n -\end{pmatrix} -$$ -, что может показаться несколько непривычным. Однако заметим, что построенная нами структура $\mathbb{G} = (\{s,n\}, \circ)$ изоморфна $\mathbb{G}' = (\{1,0\}, \vee)$. При переходе к $\mathbb{G}'$ мы получим привычную нам булеву матрицу смежности: + Таким образом, матрица смежности данного графа выглядит следующим образом: + $$ + \begin{pmatrix} + n & s & s & n \\ + s & n & s & n \\ + s & s & n & s \\ + n & n & s & n + \end{pmatrix} + $$ + , что может показаться несколько непривычным. Однако заметим, что построенная нами структура $\mathbb{G} = (\{s,n\}, \circ)$ изоморфна $\mathbb{G}' = (\{1,0\}, \vee)$. При переходе к $\mathbb{G}'$ мы получим привычную нам булеву матрицу смежности: $$ - \begin{pmatrix} - 0 & 1 & 1 & 0 \\ - 1 & 0 & 1 & 0 \\ - 1 & 1 & 0 & 1 \\ - 0 & 0 & 1 & 0 - \end{pmatrix} + \begin{pmatrix} + 0 & 1 & 1 & 0 \\ + 1 & 0 & 1 & 0 \\ + 1 & 1 & 0 & 1 \\ + 0 & 0 & 1 & 0 + \end{pmatrix} $$ Заметим, что матрица смежности неориентированного графа всегда симметрична относительно главной диагонали. \end{example} @@ -120,17 +121,17 @@ \section{Основные определения} \begin{example}[Пример матрицы смежности ориентированного графа]\label{example:diGraph} Дан ориентированный граф: \begin{center} - \input{figures/graph/graph2.tex} + \input{figures/graph/graph2.tex} \end{center} Построить его булеву матрицу смежности можно применив рассуждения из предыдущего примера (\ref{exmpl:undirectedGraphMatrix}) и выглядеть она будет следующим образом: $$ - \begin{pmatrix} - 0 & 1 & 0 & 0 \\ - 0 & 0 & 1 & 0 \\ - 1 & 0 & 0 & 1 \\ - 0 & 0 & 1 & 0 - \end{pmatrix} + \begin{pmatrix} + 0 & 1 & 0 & 0 \\ + 0 & 0 & 1 & 0 \\ + 1 & 0 & 0 & 1 \\ + 0 & 0 & 1 & 0 + \end{pmatrix} $$ \end{example} @@ -143,12 +144,12 @@ \section{Основные определения} В данном случае $L = \{\{a\},\{b\}\}$, а $\mathbb{G} = ( \{\{a\},\{b\},\{a,b\},\varnothing\} ,\cup)$, где $\varnothing$ --- нейтральный элемент. Тогда матрица матрица смежности исходного графа выглядит следующим образом: $$ - \begin{pmatrix} - \varnothing & \{a\} & \varnothing & \varnothing \\ - \varnothing & \varnothing & \{a\} & \varnothing \\ - \{a\} & \varnothing & \varnothing & \{a,b\} \\ - \varnothing & \varnothing & \{b\} & \varnothing - \end{pmatrix} + \begin{pmatrix} + \varnothing & \{a\} & \varnothing & \varnothing \\ + \varnothing & \varnothing & \{a\} & \varnothing \\ + \{a\} & \varnothing & \varnothing & \{a,b\} \\ + \varnothing & \varnothing & \{b\} & \varnothing + \end{pmatrix} $$ \end{example} @@ -164,12 +165,12 @@ \section{Основные определения} В результате мы получим следующую матрицу смежности: $$ - \begin{pmatrix} - 0 & -1.4 & \infty & \infty \\ - \infty & 0 & 2.2 & \infty \\ - 0.5 & \infty & 0 & 1.85 \\ - \infty & \infty & -0.76 & 0 - \end{pmatrix} + \begin{pmatrix} + 0 & -1.4 & \infty & \infty \\ + \infty & 0 & 2.2 & \infty \\ + 0.5 & \infty & 0 & 1.85 \\ + \infty & \infty & -0.76 & 0 + \end{pmatrix} $$ \end{example} @@ -181,21 +182,21 @@ \section{Обход графа в ширину} Обход графа в ширину (Breadth-First Search, BFS) --- это одна из фундаментальных задач анализа графов, для решения которой существует соответствующий алгоритм, изложенный в классической литературе (подробнее, например, в~\cite{} или ~\cite{}). Данный алгоритм является основой для многих алгоритмов поиска в графе. -В общих чертах, задача заключается в том, чтобы начиная с некоторой заданной вершины графа (источника) обойти все достижимые из неё вершины в некотором порядке. +В общих чертах, задача заключается в том, чтобы начиная с некоторой заданной вершины графа (источника) обойти все достижимые из неё вершины в некотором порядке. Шаг --- просмотр все смежных. И так для всего фронта. Главное не посещать одну и ту же вершину несколько раз. Псевдокод классического алгоритма Пример. -Алгоритм обхода в ширину может быть переформулирован в терминах матрично-векторных операций следующим образом\footnote{ -Стоит отметить, что ситуация со не менее известным обходом в глубину (Depth-First Search, DFS) более сложная: -на момент написания текста не известно естественного выражения данного обхода в терминах линейной алгебры. -Доказательство невозможности такого построения также не предъявлены. -При этом, решения для частных случаев (деревья, ориентированные графы без циклов) предложены, например, в работе~\cite{10.1145/3315454.3329962}}. -Пусть фронт --- вектор размера $n$, а сам граф представлен матрицей смежности. -Тогда один шаг --- получение нового фронта --- это умножение текущего фронта на матрицу смежности. -Для того, чтобы отслеживать посещённые вершины нужна маска. +Алгоритм обхода в ширину может быть переформулирован в терминах матрично-векторных операций следующим образом\sidenote{ + Стоит отметить, что ситуация со не менее известным обходом в глубину (Depth-First Search, DFS) более сложная: + на момент написания текста не известно естественного выражения данного обхода в терминах линейной алгебры. + Доказательство невозможности такого построения также не предъявлены. + При этом, решения для частных случаев (деревья, ориентированные графы без циклов) предложены, например, в работе~\cite{10.1145/3315454.3329962}}. +Пусть фронт --- вектор размера $n$, а сам граф представлен матрицей смежности. +Тогда один шаг --- получение нового фронта --- это умножение текущего фронта на матрицу смежности. +Для того, чтобы отслеживать посещённые вершины нужна маска. Псевдокод алгоритма на ЛА @@ -204,86 +205,86 @@ \section{Обход графа в ширину} В качестве примера рассмотрим обход в ширину графа из примера~\ref{example:diGraph} начиная с вершины 2. Для обозначения текущего фронта будем использовать зелёный цвет, а для достижимых из него за один шаг --- жёлтый. -\begin{tabular}[t]{c | c } - \input{figures/graph/graph_BFS_1.tex} - & - \begin{minipage}{0.7\textwidth} - $ - \text{visited} = - \begin{pmatrix} - 0 & 0 & 0 & 0 - \end{pmatrix} - $ - \\ - $ - \begin{pmatrix} - 0 & 0 & 1 & 0 - \end{pmatrix} - \begin{pmatrix} - 0 & 1 & 0 & 0 \\ - 0 & 0 & 1 & 0 \\ - 1 & 0 & 0 & 1 \\ - 0 & 0 & 1 & 0 - \end{pmatrix} = - \begin{pmatrix} - 1 & 0 & 0 & 1 - \end{pmatrix} - $ - \\ - $ - \text{new\_front} = - \begin{pmatrix} - 1 & 0 & 0 & 1 - \end{pmatrix} - \begin{pmatrix} - 0 & 0 & 0 & 0 - \end{pmatrix} - = - \begin{pmatrix} - 1 & 0 & 0 & 1 - \end{pmatrix} - $ -\end{minipage} - \\ \hline - \input{figures/graph/graph_BFS_2.tex} - & - $ - \begin{pmatrix} - 1 & 0 & 0 & 1 - \end{pmatrix} - \begin{pmatrix} - 0 & 1 & 0 & 0 \\ - 0 & 0 & 1 & 0 \\ - 1 & 0 & 0 & 1 \\ - 0 & 0 & 1 & 0 - \end{pmatrix} = - \begin{pmatrix} - 0 & 1 & 1 & 0 - \end{pmatrix} - $ - \\ \hline - \input{figures/graph/graph_BFS_3.tex} - & - $ - \begin{pmatrix} - 0 & 1 & 0 & 0 - \end{pmatrix} - \begin{pmatrix} - 0 & 1 & 0 & 0 \\ - 0 & 0 & 1 & 0 \\ - 1 & 0 & 0 & 1 \\ - 0 & 0 & 1 & 0 - \end{pmatrix} = - \begin{pmatrix} - 0 & 0 & 1 & 0 - \end{pmatrix} - $ -\end{tabular} + \begin{tabular}[t]{c | c } + \input{figures/graph/graph_BFS_1.tex} + & + \begin{minipage}{0.7\textwidth} + $ + \text{visited} = + \begin{pmatrix} + 0 & 0 & 0 & 0 + \end{pmatrix} + $ + \\ + $ + \begin{pmatrix} + 0 & 0 & 1 & 0 + \end{pmatrix} + \begin{pmatrix} + 0 & 1 & 0 & 0 \\ + 0 & 0 & 1 & 0 \\ + 1 & 0 & 0 & 1 \\ + 0 & 0 & 1 & 0 + \end{pmatrix} = + \begin{pmatrix} + 1 & 0 & 0 & 1 + \end{pmatrix} + $ + \\ + $ + \text{new\_front} = + \begin{pmatrix} + 1 & 0 & 0 & 1 + \end{pmatrix} + \begin{pmatrix} + 0 & 0 & 0 & 0 + \end{pmatrix} + = + \begin{pmatrix} + 1 & 0 & 0 & 1 + \end{pmatrix} + $ + \end{minipage} + \\ \hline + \input{figures/graph/graph_BFS_2.tex} + & + $ + \begin{pmatrix} + 1 & 0 & 0 & 1 + \end{pmatrix} + \begin{pmatrix} + 0 & 1 & 0 & 0 \\ + 0 & 0 & 1 & 0 \\ + 1 & 0 & 0 & 1 \\ + 0 & 0 & 1 & 0 + \end{pmatrix} = + \begin{pmatrix} + 0 & 1 & 1 & 0 + \end{pmatrix} + $ + \\ \hline + \input{figures/graph/graph_BFS_3.tex} + & + $ + \begin{pmatrix} + 0 & 1 & 0 & 0 + \end{pmatrix} + \begin{pmatrix} + 0 & 1 & 0 & 0 \\ + 0 & 0 & 1 & 0 \\ + 1 & 0 & 0 & 1 \\ + 0 & 0 & 1 & 0 + \end{pmatrix} = + \begin{pmatrix} + 0 & 0 & 1 & 0 + \end{pmatrix} + $ + \end{tabular} \end{example} -multiple-source BFS. Тот же обход в ширину, только источников несколько и надо помнить, какая из вершин из какого источника достижима. Постановка задачи. Решение через линейную алгебру~\cite{9286186} Уже не вектор, а матрица: храним информацию про каждую стартовую вершину отдельно. +multiple-source BFS. Тот же обход в ширину, только источников несколько и надо помнить, какая из вершин из какого источника достижима. Постановка задачи. Решение через линейную алгебру~\sidecite{9286186} Уже не вектор, а матрица: храним информацию про каждую стартовую вершину отдельно. Псевдокод алгоритма на ЛА @@ -298,24 +299,24 @@ \section{Задачи поиска путей} С одной стороны, постановки различаются тем, что именно мы хотим получить в качестве результата. Здесь наиболее частыми являются следующие варианты. \begin{itemize} -\item Наличие хотя бы одного пути, удовлетворяющего ограничениям, в графе. В данном случае не важно, между какими вершинами существует путь, важно лишь наличие его в графе. + \item Наличие хотя бы одного пути, удовлетворяющего ограничениям, в графе. В данном случае не важно, между какими вершинами существует путь, важно лишь наличие его в графе. -\item Наличие пути, удовлетворяющего ограничениям, между некоторыми вершинами: задача достижимости. - При данной постановке задачи, нас интересует ответ на вопрос достижимости вершины $v_i$ из вершины $v_j$ по пути, удовлетворяющему ограничениям. - Такая постановка требует лишь проверить существование пути, но не его предоставления в явном виде. + \item Наличие пути, удовлетворяющего ограничениям, между некоторыми вершинами: задача достижимости. + При данной постановке задачи, нас интересует ответ на вопрос достижимости вершины $v_i$ из вершины $v_j$ по пути, удовлетворяющему ограничениям. + Такая постановка требует лишь проверить существование пути, но не его предоставления в явном виде. -\item Поиск одного пути, удовлетворяющего ограничениям: необходимо не только установить факт наличия пути, но и предъявить его. При этом часто подразумевается, что возвращается любой путь, являющийся решением, без каких-либо дополнительных ограничений. Хотя, например, в некоторых задачах дополнительное требование простоты или наименьшей длины выглядит достаточно естественным. + \item Поиск одного пути, удовлетворяющего ограничениям: необходимо не только установить факт наличия пути, но и предъявить его. При этом часто подразумевается, что возвращается любой путь, являющийся решением, без каких-либо дополнительных ограничений. Хотя, например, в некоторых задачах дополнительное требование простоты или наименьшей длины выглядит достаточно естественным. -\item Поиск всех путей: необходимо предоставить все пути, удовлетворяющие заданным ограничениям. + \item Поиск всех путей: необходимо предоставить все пути, удовлетворяющие заданным ограничениям. \end{itemize} С другой стороны, задачи могут различаться ещё и тем, как фиксируются множества стартовых и конечных вершин. Здесь возможны следующие варианты: \begin{itemize} -\item от одной вершины до всех, -\item между всеми парами вершин, -\item между фиксированной парой вершин, -\item между двумя множествами вершин $V_1$ и $V_2$, что подразумевает решение задачи для всех $(v_i,v_j) \in V_1 \times V_2$. + \item от одной вершины до всех, + \item между всеми парами вершин, + \item между фиксированной парой вершин, + \item между двумя множествами вершин $V_1$ и $V_2$, что подразумевает решение задачи для всех $(v_i,v_j) \in V_1 \times V_2$. \end{itemize} Стоит отметить, что последний вариант является самым общим и остальные --- лишь его частные случаи. @@ -323,27 +324,27 @@ \section{Задачи поиска путей} В итоге, перебирая возможные варианты желаемого результата и способы фиксации стартовых и финальных вершин, мы можем сформулировать достаточно большое количество задач. Например, задачу поиска всех путей между двумя заданными вершинами, задачу поиска одного пути от фиксированной стартовой вершины до каждой вершины в графе, или задачу достижимости между всеми парами вершин. -Часто поиск путей сопровождается изучением их свойств, что далее приводит к формулированию дополнительных ограничений на пути в терминах этих свойств. Например, можно потребовать, чтобы пути были простыми или не проходили через определённые вершины. Один из естественных способов описывать свойства и, как следствие, задавать ограничения --- это использовать ту алгебраическую структуру, из которой берутся веса рёбер графа\footnote{На самом деле здесь наблюдается некоторая двойственность. С одной стороны, действительно, удобно считать, что свойства описываются в терминах некоторой заданной алгебраической структуры. Но, вместе с этим, структура подбирается исходя из решаемой задачи.}. +Часто поиск путей сопровождается изучением их свойств, что далее приводит к формулированию дополнительных ограничений на пути в терминах этих свойств. Например, можно потребовать, чтобы пути были простыми или не проходили через определённые вершины. Один из естественных способов описывать свойства и, как следствие, задавать ограничения --- это использовать ту алгебраическую структуру, из которой берутся веса рёбер графа\sidenote{На самом деле здесь наблюдается некоторая двойственность. С одной стороны, действительно, удобно считать, что свойства описываются в терминах некоторой заданной алгебраической структуры. Но, вместе с этим, структура подбирается исходя из решаемой задачи.}. Предположим, что дан граф $\mathcal{G} = \langle V, E, L\rangle $, где $L = \langle S, \oplus, \otimes \rangle$ --- это полукольцо. Тогда изучение свойств путей можно описать следующим образом: \begin{equation} \label{eq:algPathProblem} \{(v_i, v_j, c) \mid \exists v_i \pi v_j, c = \bigoplus_{\forall v_i \pi v_j} \bigotimes_{(u,l,v) \in \pi } l \}. \end{equation} -Иными словами, для каждой пары вершин, для которой существует хотя бы один путь, их соединяющий, мы агрегируем (с помощью операции $\oplus$ из полукольца) информацию обо всех путях между этими вершинами. При этом информация о пути получается как свёртка меток рёбер пути с использованием операции $\otimes$\footnote{Заметим, что детали свёртки вдоль пути зависят от свойств полукольца (и от решаемой задачи). Так, если полукольцо коммутативно, то нам не обязательно соблюдать порядок рёбер. В дальнейшем мы увидим, что данные особенности полукольца существенно влияют на особенности алгоритмов решения соответствующих задач.}. +Иными словами, для каждой пары вершин, для которой существует хотя бы один путь, их соединяющий, мы агрегируем (с помощью операции $\oplus$ из полукольца) информацию обо всех путях между этими вершинами. При этом информация о пути получается как свёртка меток рёбер пути с использованием операции $\otimes$\sidenote{Заметим, что детали свёртки вдоль пути зависят от свойств полукольца (и от решаемой задачи). Так, если полукольцо коммутативно, то нам не обязательно соблюдать порядок рёбер. В дальнейшем мы увидим, что данные особенности полукольца существенно влияют на особенности алгоритмов решения соответствующих задач.}. Естественным требованием (хотя бы для прикладных задач, решаемых таким способом) является существование и конечность указанной суммы. На данном этапе мы не будем касаться того, какие именно свойства полукольца могут нам обеспечить данное свойство, однако в дальнейшем будем считать, что оно выполняется. Более того, будем стараться приводить частные для конкретной задачи рассуждения, показывающие, почему это свойство выполняется в рассматриваемых в задаче ограничениях. -Описанная выше задача общего вида называется анализом свойств путей алгебраическими методами (Algebraic Path Problem~\cite{Baras2010PathPI}) и предоставляет общий способ для решения широкого класса прикладных задач\footnote{В работе ``Path Problems in Networks''~\cite{Baras2010PathPI} собран действительно большой список прикладных задач с описанием соответствующих полуколец. Сводная таблица на страницах 58--59 содержит 29 различных прикладных задач и соответствующих полуколец.}. Наиболее известными являются такие задачи, как построение транзитивного замыкания графа и поиск кратчайших путей (All PAirs Shortest Path или APSP). Далее мы подробнее обсудим эти две задачи и предложим алгоритмы их решения. +Описанная выше задача общего вида называется анализом свойств путей алгебраическими методами (Algebraic Path Problem~\sidecite{Baras2010PathPI}) и предоставляет общий способ для решения широкого класса прикладных задач\sidenote{В работе ``Path Problems in Networks''~\cite{Baras2010PathPI} собран действительно большой список прикладных задач с описанием соответствующих полуколец. Сводная таблица на страницах 58--59 содержит 29 различных прикладных задач и соответствующих полуколец.}. Наиболее известными являются такие задачи, как построение транзитивного замыкания графа и поиск кратчайших путей (All PAirs Shortest Path или APSP). Далее мы подробнее обсудим эти две задачи и предложим алгоритмы их решения. \section{Алгоритм Флойда-Уоршелла} Наиболее естественным образом решение обсуждаемых выражается в терминах операций над матрицей смежности исходного графа. Поэтому предположим, что исходный граф задан матрицей над моноидом $\mathbb{G} = (S,\oplus)$. -Как мы видели ранее, операция $\oplus$ позволяет нам агрегировать информацию по всем параллельным рёбрам. Ровно она же и будет агрегировать информацию по всем путям между двумя вершинами\footnote{Вообще говоря, работая с матрицей смежности мы не видим разницу между путём и ребром, так как любая запись в матрице смежности в ячейке $[i,j]$ говорит нам только о том, что вершины $i$ и $j$ связаны и эта связь обладает некоторым свойством (значение в ячейке), и ничего не говорит о том, как эта связь устроена.}. Таким образом, осталось сконструировать операцию, отвечающую за агрегацию информации вдоль пути. Здесь мы будем исходить из того, что новый путь может быть получен из двух подпутей, а свойство нового пути зависит только от свойств исходных подпутей. +Как мы видели ранее, операция $\oplus$ позволяет нам агрегировать информацию по всем параллельным рёбрам. Ровно она же и будет агрегировать информацию по всем путям между двумя вершинами\sidenote{Вообще говоря, работая с матрицей смежности мы не видим разницу между путём и ребром, так как любая запись в матрице смежности в ячейке $[i,j]$ говорит нам только о том, что вершины $i$ и $j$ связаны и эта связь обладает некоторым свойством (значение в ячейке), и ничего не говорит о том, как эта связь устроена.}. Таким образом, осталось сконструировать операцию, отвечающую за агрегацию информации вдоль пути. Здесь мы будем исходить из того, что новый путь может быть получен из двух подпутей, а свойство нового пути зависит только от свойств исходных подпутей. -Таким образом, дополнительная операция, обозначим её $\otimes: S \times S \to S$\footnote{При первом рассмотрении такой выбор кажется контринтуитивным. Действительно, ведь при соединении путей мы как бы ``складываем'' их веса. Но при более детальном анализе поведения этой операции, в частности, относительно нейтрального элемента, становится понятно, что она ведёт себя очень похоже на умножение. Вероятно, стоит обратить внимание на операцию конкатенации, которая, с одной стороны, ``делает то, что нам нужно'', а с другой, (и неспроста) часто обозначается $\cdot$.}, должна вести себя следующим образом. Пусть $S$ --- носитель моноида, $\mathbb{0} \in S$ --- нейтральный элемент относительно $\oplus$. +Таким образом, дополнительная операция, обозначим её $\otimes: S \times S \to S$\sidenote{При первом рассмотрении такой выбор кажется контринтуитивным. Действительно, ведь при соединении путей мы как бы ``складываем'' их веса. Но при более детальном анализе поведения этой операции, в частности, относительно нейтрального элемента, становится понятно, что она ведёт себя очень похоже на умножение. Вероятно, стоит обратить внимание на операцию конкатенации, которая, с одной стороны, ``делает то, что нам нужно'', а с другой, (и неспроста) часто обозначается $\cdot$.}, должна вести себя следующим образом. Пусть $S$ --- носитель моноида, $\mathbb{0} \in S$ --- нейтральный элемент относительно $\oplus$. \begin{itemize}\label{itm:otimesIntro} \item $s_1 \otimes s_2 = s_3, s_i \in S, s_i \neq \mathbb{0}$ : если существует путь $i \pi j$ со свойством $s_1$ и путь $j \pi k$ со свойством $s_2$, то существует путь $i \pi k$ со свойством $s_3$. \item $s \otimes \mathbb{0} = \mathbb{0}$ : если существует путь $i \pi j$ со свойством $s$ и не существует пути $j \pi k$, то не существует и пути $i \pi k$. @@ -351,33 +352,33 @@ \section{Алгоритм Флойда-Уоршелла} \item $\mathbb{0} \otimes \mathbb{0} = \mathbb{0}$ : если не существует пути $i \pi j$ и не существует пути $j \pi k$, то не существует и пути $i \pi k$. \end{itemize} -Новую операцию добавим к моноиду и получим новую алгебраическую структуру $\mathbb{G}' = (S, \oplus,\otimes)$. Данная структура является коммутативным моноидом по сложению (по построению) с нейтральным элементом $\mathbb{0}$. Из построения $\otimes$ видно, что $\mathbb{0}$ является аннигилятором. Ничего более про операцию $\otimes$, а значит и про $\mathbb{G}'$ мы сказать, исходя из построения, не можем. Классический фреймворк для решения algebraic path problem подразумевает, что $\mathbb{G}'$ является полукольцом, однако далее мы увидим, что существуют задачи, в которых $\otimes$, например, не является ассоциативной\footnote{Такой будет рассматриваемая в данной работе задача достижимости с ограничениями в терминах формальных языков. Другие примеры можно найти в уже упоминавшейся работе~\cite{Baras2010PathPI}}. А значит, согласно нашему определению, $\mathbb{G}'$ полукольцом не является. +Новую операцию добавим к моноиду и получим новую алгебраическую структуру $\mathbb{G}' = (S, \oplus,\otimes)$. Данная структура является коммутативным моноидом по сложению (по построению) с нейтральным элементом $\mathbb{0}$. Из построения $\otimes$ видно, что $\mathbb{0}$ является аннигилятором. Ничего более про операцию $\otimes$, а значит и про $\mathbb{G}'$ мы сказать, исходя из построения, не можем. Классический фреймворк для решения algebraic path problem подразумевает, что $\mathbb{G}'$ является полукольцом, однако далее мы увидим, что существуют задачи, в которых $\otimes$, например, не является ассоциативной\sidenote{Такой будет рассматриваемая в данной работе задача достижимости с ограничениями в терминах формальных языков. Другие примеры можно найти в уже упоминавшейся работе~\cite{Baras2010PathPI}}. А значит, согласно нашему определению, $\mathbb{G}'$ полукольцом не является. Теперь, когда построена алгебраическая структура, обеспечивающая вычисление формулы~ -\ref{eq:algPathProblem}, мы можем предложить алгоритм вычисления этой формулы и данным алгоритмом в интересующих нас частных случаях будет являться алгоритм Флойда-Уоршелла~\cite{Floyd1962, Bernard1959, Warshall1962}. Псевдокод алгоритма представлен на листинге~\ref{lst:algoFloydWarxhall}, а его сложность $O(n^3)$. Он практически дословно основан на описанной выше идее сборки путей из двух подпутей: тройной вложенный цикл перебирает все возможные разбиения пути на две части, а в строке 7 как раз и происходит вычисление формулы~ +\ref{eq:algPathProblem}, мы можем предложить алгоритм вычисления этой формулы и данным алгоритмом в интересующих нас частных случаях будет являться алгоритм Флойда-Уоршелла~\sidecite{Floyd1962, Bernard1959, Warshall1962}. Псевдокод алгоритма представлен на листинге~\ref{lst:algoFloydWarxhall}, а его сложность $O(n^3)$. Он практически дословно основан на описанной выше идее сборки путей из двух подпутей: тройной вложенный цикл перебирает все возможные разбиения пути на две части, а в строке 7 как раз и происходит вычисление формулы~ \ref{eq:algPathProblem}. Необходимо обратить внимание на несколько вещей. Первая --- порядок обхода. Внешний цикл перебирает возможные точки разбиения (хотя мог бы, например, перебирать начальные вершины) для того, чтобы гарантировать правильный порядок вычисления подпутей (информация ни о каких подпутях не будет получена после того, как они поучаствовали в построении более длинного пути). Вторая --- количество итераций. В данном случае мы ограничились тройным вложенным циклом от 0 до $n$ и для наших задач этого будет достаточно, однако, как доказательство этого факта, так и построение аналогичного алгоритма для других задач требует аккуратного анализа решаемой задачи и последующего доказательства корректности построенного алгоритма. \begin{algorithm} \floatname{algorithm}{Listing} -\begin{algorithmic}[1] -\caption{Алгоритм Флойда-Уоршелла} -\label{lst:algoFloydWarxhall} -\Function{FloydWarshall}{$\mathcal{G}$} + \begin{algorithmic}[1] + \caption{Алгоритм Флойда-Уоршелла} + \label{lst:algoFloydWarxhall} + \Function{FloydWarshall}{$\mathcal{G}$} \State{$M \gets$ матрица смежности $\mathcal{G}$} \Comment{Матрица над $\mathbb{G}=(S,\oplus,\otimes)$} \State{$n \gets |V(\mathcal{G})|$} \For{k = 0; k < n; k++} - \For{i = 0; i < n; i++} - \For{j = 0; j < n; j++} - \State{$M[i,j] \gets M[i,j] \oplus (M[i,k] \otimes M[k,j])$} - \EndFor - \EndFor + \For{i = 0; i < n; i++} + \For{j = 0; j < n; j++} + \State{$M[i,j] \gets M[i,j] \oplus (M[i,k] \otimes M[k,j])$} + \EndFor + \EndFor \EndFor -\State \Return $M$ -\EndFunction -\end{algorithmic} + \State \Return $M$ + \EndFunction + \end{algorithmic} \end{algorithm} Хотя изначально данный алгоритм был предложен для решения задачи о кратчайших путях, при абстрагировании алгебраической структуры он превращается в алгоритм решения целого ряда задач. В частности --- нахождения транзитивного замыкания. Так, если возьмём тропическое полукольцо $(\mathbb{R}_{+\infty}, \min, +)$, то получим алгоритм для поиска кратчайших путей. Если же возьмём булево полукольцо, то получим алгоритм для построения транзитивного замыкания графа. @@ -390,12 +391,12 @@ \section{Алгоритм Флойда-Уоршелла} Его матрица смежности: $$ M = - \begin{pmatrix} - 0 & 1 & 0 & 0 \\ - 0 & 0 & 1 & 0 \\ - 1 & 0 & 0 & 1 \\ - 0 & 0 & 1 & 0 - \end{pmatrix} + \begin{pmatrix} + 0 & 1 & 0 & 0 \\ + 0 & 0 & 1 & 0 \\ + 1 & 0 & 0 & 1 \\ + 0 & 0 & 1 & 0 + \end{pmatrix} $$ Здесь мы считаем, что отношение достижимости не рефлексивно: все диагональные элементы матрицы $M$ равны 0. @@ -403,12 +404,12 @@ \section{Алгоритм Флойда-Уоршелла} Воспользовавшись алгоритмом из листинга~\ref{lst:algoFloydWarxhall}, специализированного на случай булева полукольца, можно получить следующую матрицу смежности. $$ M' = - \begin{pmatrix} - 1 & 1 & 1 & 1 \\ - 1 & 1 & 1 & 1 \\ - 1 & 1 & 1 & 1 \\ - 1 & 1 & 1 & 1 - \end{pmatrix} + \begin{pmatrix} + 1 & 1 & 1 & 1 \\ + 1 & 1 & 1 & 1 \\ + 1 & 1 & 1 & 1 \\ + 1 & 1 & 1 & 1 + \end{pmatrix} $$ А значит, транзитивным замыканием исходного графа является полный граф и он выглядит следующим образом. @@ -428,10 +429,10 @@ \section{Алгоритм Флойда-Уоршелла} \section{Анализ путей в графе и линейная алгебра} -В данной главе мы рассмотрим некоторые связи\footnote{Связь между графами и линейной алгеброй --- обширная область, в которой можно даже выделить отдельные направления, такие как спектральная теория графов. С точки зрения практики данная связь также подмечена давно и более полно с ней можно ознакомиться, например, в работах~\cite{doi:10.1137/1.9780898719918, Davis2018Algorithm9S}. Кроме этого, много полезной информации можно найти на сайте \url{https://graphblas.github.io/GraphBLAS-Pointers/}.} между графами и операциями над ними и матрицами и операциями над матрицами. +В данной главе мы рассмотрим некоторые связи\sidenote{Связь между графами и линейной алгеброй --- обширная область, в которой можно даже выделить отдельные направления, такие как спектральная теория графов. С точки зрения практики данная связь также подмечена давно и более полно с ней можно ознакомиться, например, в работах~\cite{doi:10.1137/1.9780898719918, Davis2018Algorithm9S}. Кроме этого, много полезной информации можно найти на сайте \url{https://graphblas.github.io/GraphBLAS-Pointers/}.} между графами и операциями над ними и матрицами и операциями над матрицами. Как мы видели, достаточно естественное представление графа --- это его матрица смежности. Далее можно заметить некоторое сходство между определением матричного умножения~\ref{def:MxM} и мыслями, которыми мы руководствовались, вводя операцию $\otimes$ (\ref{itm:otimesIntro}). -Действительно, пусть есть матрица $M$ размера $n \times n$ над $\mathbb{G} = (S,\oplus,\otimes)$\footnote{Здесь мы уже сталкиваемся с тем, что могут иметь смысл относительно экзотические алгебраические структуры. Действительно, как мы выяснили, матрица смежности может быть определена на чем-то более бедным, чем полукольцо, а матичное умножение мы определяли над полукольцом. Но если задуматься, то и для определения произведения матриц полукольцо вовсе необязательно, достаточно более бедной структуры.} --- матрица смежности графа. Умножим её саму на себя: вычислим $M'= M \cdot M$. Тогда, по~\ref{def:MxM}, $M'[i,j] = \bigoplus_{0 \leq l < n} M[i,l] \otimes M[l,j]$. Размер $M'$ также $n \times n$. То есть $M'$ задаёт такой граф, что в нём будет путь со свойством, являющимся агрегацией свойств всех путей, составленных из двух подпутей в исходном графе. А именно, если в исходном графе есть путь из $i$ в $l$ с некоторым свойством (его значение хранится в $M[i,l]$), и был путь из $l$ в $j$ (его значение хранится в $M[l,j]$), то в новом графе свойство $M[i,l] \otimes M[l,j]$ аддитивно (используя $\oplus$) учтётся в свойстве пути из $i$ в $j$. +Действительно, пусть есть матрица $M$ размера $n \times n$ над $\mathbb{G} = (S,\oplus,\otimes)$\sidenote{Здесь мы уже сталкиваемся с тем, что могут иметь смысл относительно экзотические алгебраические структуры. Действительно, как мы выяснили, матрица смежности может быть определена на чем-то более бедным, чем полукольцо, а матичное умножение мы определяли над полукольцом. Но если задуматься, то и для определения произведения матриц полукольцо вовсе необязательно, достаточно более бедной структуры.} --- матрица смежности графа. Умножим её саму на себя: вычислим $M'= M \cdot M$. Тогда, по~\ref{def:MxM}, $M'[i,j] = \bigoplus_{0 \leq l < n} M[i,l] \otimes M[l,j]$. Размер $M'$ также $n \times n$. То есть $M'$ задаёт такой граф, что в нём будет путь со свойством, являющимся агрегацией свойств всех путей, составленных из двух подпутей в исходном графе. А именно, если в исходном графе есть путь из $i$ в $l$ с некоторым свойством (его значение хранится в $M[i,l]$), и был путь из $l$ в $j$ (его значение хранится в $M[l,j]$), то в новом графе свойство $M[i,l] \otimes M[l,j]$ аддитивно (используя $\oplus$) учтётся в свойстве пути из $i$ в $j$. Таким образом, произведение матриц смежности соответствует обработке информации о путях интересующим нас образом. Это наблюдение позволяет предложить решение задач анализа свойств путей, основанное на операциях над матрицами. Рассмотрим такое решение для задачи о кратчайших путях. @@ -440,15 +441,15 @@ \section{Анализ путей в графе и линейная алгебр Таким образом, $D_1 = M$, где $M$ --- это матрица смежности исходного графа, а решением APSP является $D_{n-1}$, вычисляемая с помощью следующего рекуррентного соотношения: \begin{center} - $D(1) = M$ \\ - $D(2) = D(1) \cdot M = M^2$ \\ - $D(3) = D(2) \cdot M = M^3$ \\ - $\dots$ \\ - $D(n-1) = D(n-2) \cdot M = M^{(n - 1)}$ \\ + $D(1) = M$ \\ + $D(2) = D(1) \cdot M = M^2$ \\ + $D(3) = D(2) \cdot M = M^3$ \\ + $\dots$ \\ + $D(n-1) = D(n-2) \cdot M = M^{(n - 1)}$ \\ \end{center} -Здесь мы пользуемся той особенностью задачи, что кратчайший путь в ориентированном графе (без отрицательных циклов) не может быть длиннее $n$\footnote{Раз отрицательных циклов нету, то проходить через одну вершину, коих $n$, больше одного раза бессмысленно.}. -Более того, мы пользуемся тем, что используемая структура именно полукольцо, а исходное отношение рефлексивно\footnote{Тот факт, что в любой вершине есть петля с весом 0, а 0 --- нейтральный для $\otimes$, позволяет не суммировать матрицы. Итоговая матрица содержит данные о путях длины \textit{не больше чем} вычисляемая степень, хотя должна бы содержать данные о путях ровно и только такой длины. Предлагается самостоятельно исследовать данный феномен.}. +Здесь мы пользуемся той особенностью задачи, что кратчайший путь в ориентированном графе (без отрицательных циклов) не может быть длиннее $n$\sidenote{Раз отрицательных циклов нету, то проходить через одну вершину, коих $n$, больше одного раза бессмысленно.}. +Более того, мы пользуемся тем, что используемая структура именно полукольцо, а исходное отношение рефлексивно\sidenote{Тот факт, что в любой вершине есть петля с весом 0, а 0 --- нейтральный для $\otimes$, позволяет не суммировать матрицы. Итоговая матрица содержит данные о путях длины \textit{не больше чем} вычисляемая степень, хотя должна бы содержать данные о путях ровно и только такой длины. Предлагается самостоятельно исследовать данный феномен.}. Таким образом, решение APSP сведено к произведению матриц над тропическим полукольцом, однако вычислительная сложность решения слишком большая: $O(n K(n))$, где $K(n)$ --- сложность алгоритма умножения матриц. @@ -457,31 +458,31 @@ \section{Анализ путей в графе и линейная алгебр В итоге получим следующую последовательность вычислений: \begin{center} - $D_1 = M$ \\ - $D_2 = M^2 = M \cdot M$ \\ - $D_4 = M^4 = M^2 \cdot M^2$ \\ - $D_8 = M^8 = M^4 \cdot M^4$ \\ - $\dots$ \\ - $D_{2^{\log(n-1)}} = M^{2^{\log(n-1)}} = M^{2^{\log(n-1)} - 1} \cdot M^{2^{\log(n-1)} - 1}$ \\ - $D_{n-1} = D_{2^{\log(n-1)}}$ \\ + $D_1 = M$ \\ + $D_2 = M^2 = M \cdot M$ \\ + $D_4 = M^4 = M^2 \cdot M^2$ \\ + $D_8 = M^8 = M^4 \cdot M^4$ \\ + $\dots$ \\ + $D_{2^{\log(n-1)}} = M^{2^{\log(n-1)}} = M^{2^{\log(n-1)} - 1} \cdot M^{2^{\log(n-1)} - 1}$ \\ + $D_{n-1} = D_{2^{\log(n-1)}}$ \\ \end{center} -Теперь вместо $n$ итераций нам нужно $\log{n}$, а итоговая сложность решения --- $O(\log{n} K(n))$\footnote{Заметим, что это оценка для худшего случая. На практике при использовании данного подхода можно прекращать вычисления как только при двух последовательных шагах получились одинаковые матрицы ($D_i = D_{i-1}$). Это приводит нас к понятию \textit{неподвижной точки}, обсуждение которого лежит за рамками повествования.}. -Данный алгоритм называется \textit{repeated squaring}\footnote{Пример решения APSP с помощью repeated squaring: \url{http://users.cecs.anu.edu.au/~Alistair.Rendell/Teaching/apac_comp3600/module4/all_pairs_shortest_paths.xhtml}}. Здесь мы предполагаем, что $n-1 = 2^k$ для какого-то $k$. На практике такое верно далеко не всегда. Если это условие не выполняется, то необходимо взять ближайшую сверху степень двойки\footnote{Кажется, что это приведёт к избыточным вычислениям. Попробуйте оценить, на сколько много лишних вычислений будет сделано в худшем случае.}. +Теперь вместо $n$ итераций нам нужно $\log{n}$, а итоговая сложность решения --- $O(\log{n} K(n))$\sidenote{Заметим, что это оценка для худшего случая. На практике при использовании данного подхода можно прекращать вычисления как только при двух последовательных шагах получились одинаковые матрицы ($D_i = D_{i-1}$). Это приводит нас к понятию \textit{неподвижной точки}, обсуждение которого лежит за рамками повествования.}. +Данный алгоритм называется \textit{repeated squaring}\sidenote{Пример решения APSP с помощью repeated squaring: \url{http://users.cecs.anu.edu.au/~Alistair.Rendell/Teaching/apac_comp3600/module4/all_pairs_shortest_paths.xhtml}}. Здесь мы предполагаем, что $n-1 = 2^k$ для какого-то $k$. На практике такое верно далеко не всегда. Если это условие не выполняется, то необходимо взять ближайшую сверху степень двойки\sidenote{Кажется, что это приведёт к избыточным вычислениям. Попробуйте оценить, на сколько много лишних вычислений будет сделано в худшем случае.}. Таким образом, APSP сводится к умножению матриц над полукольцом, что, к сожалению, не позволяет этим путём получить истинно субкубический алгоритм для задачи. тем не менее, позволяет получить слегка субкубический. Приведем некоторые работы по APSP для ориентированных графов с вещественными весами (здесь $n$ --- количество вершин в графе), по которым можно более детально ознакомиться как с историей вопроса, так и с текущими результатами: \begin{itemize} - \item M.L. Fredman (1976) --- $O(n^3(\log \log n / \log n)^\frac{1}{3})$ --- использование дерева решений~\cite{FredmanAPSP1976} - \item W. Dobosiewicz (1990) --- $O(n^3 / \sqrt{\log n})$ --- использование операций на Word Random Access Machine~\cite{Dobosiewicz1990} - \item T. Takaoka (1992) --- $O(n^3 \sqrt{\log \log n / \log n})$ --- использование таблицы поиска~\cite{Takaoka1992} - \item Y. Han (2004) --- $O(n^3 (\log \log n / \log n)^\frac{5}{7})$~\cite{Han2004} - \item T. Takoaka (2004) --- $O(n^3 (\log \log n)^2 / \log n)$~\cite{Takaoka2004} - \item T. Takoaka (2005) --- $O(n^3 \log \log n / \log n)$~\cite{Takaoka2005} - \item U. Zwick (2004) --- $O(n^3 \sqrt{\log \log n} / \log n)$~\cite{Zwick2004} - \item T.M. Chan (2006) --- $O(n^3 / \log n)$ --- многомерный принцип ``разделяй и властвуй''~\cite{Chan2008} + \item M.L. Fredman (1976) --- $O(n^3(\log \log n / \log n)^\frac{1}{3})$ --- использование дерева решений~\sidecite{FredmanAPSP1976} + \item W. Dobosiewicz (1990) --- $O(n^3 / \sqrt{\log n})$ --- использование операций на Word Random Access Machine~\sidecite{Dobosiewicz1990} + \item T. Takaoka (1992) --- $O(n^3 \sqrt{\log \log n / \log n})$ --- использование таблицы поиска~\sidecite{Takaoka1992} + \item Y. Han (2004) --- $O(n^3 (\log \log n / \log n)^\frac{5}{7})$~\sidecite{Han2004} + \item T. Takoaka (2004) --- $O(n^3 (\log \log n)^2 / \log n)$~\sidecite{Takaoka2004} + \item T. Takoaka (2005) --- $O(n^3 \log \log n / \log n)$~\sidecite{Takaoka2005} + \item U. Zwick (2004) --- $O(n^3 \sqrt{\log \log n} / \log n)$~\sidecite{Zwick2004} + \item T.M. Chan (2006) --- $O(n^3 / \log n)$ --- многомерный принцип ``разделяй и властвуй''~\sidecite{Chan2008} \end{itemize} -Вопрос же о истинно субкубических алгоритмах решения APSP всё ещё открыт~\cite{Chan2010} и активно обсуждается в научном сообществе. +Вопрос же о истинно субкубических алгоритмах решения APSP всё ещё открыт~\sidecite{Chan2010} и активно обсуждается в научном сообществе. Аналогичным образом можно свести транзитивное замыкание к матричным операциям. Предлагаем проделать это самостоятельно, заодно обратив внимание на важность рефлексивности (в примере~\ref{exmpl:transitiveClosure} её нет). diff --git a/tex/Introduction.tex b/tex/Introduction.tex index 2c8c9e5..cbbfd81 100644 --- a/tex/Introduction.tex +++ b/tex/Introduction.tex @@ -1,11 +1,11 @@ -\chapter*{Введение\markboth{Введение}{}} +\chapter*{Введение} Теория формальных языков находит применение не только в ставших уже классическими задачах синтаксического анализа кода (языков программирования, искусственных языков) и естественных языков, но и в других областях, таких как статический анализ кода, графовые базы данных, биоинформатика, машинное обучение. -Например, в машинном обучении использование формальных грамматик позволяет передать искусственной генеративной нейронной сети, предназначенной для построения цепочек с определёнными свойствами, знания о синтаксической структуре этих цепочек, что позволяет существенно упростить процесс обучения и повысить качество результата~\cite{10.5555/3305381.3305582}. -Вместе с этим, развиваются подходы, позволяющие нейронным сетям наоборот извлекать синтаксическую структуру (строить дерево вывода) для входных цепочек~\cite{kasai-etal-2017-tag,kasai-etal-2018-end}. +Например, в машинном обучении использование формальных грамматик позволяет передать искусственной генеративной нейронной сети, предназначенной для построения цепочек с определёнными свойствами, знания о синтаксической структуре этих цепочек, что позволяет существенно упростить процесс обучения и повысить качество результата~\sidecite{10.5555/3305381.3305582}. +Вместе с этим, развиваются подходы, позволяющие нейронным сетям наоборот извлекать синтаксическую структуру (строить дерево вывода) для входных цепочек~\sidecite{kasai-etal-2017-tag,kasai-etal-2018-end}. -В биоинформатике формальные грамматики нашли широкое применение для описания особенностей вторичной структуры геномных и белковых последовательностей~\cite{Dyrka2019,WJAnderson2012,zier2013rna}. +В биоинформатике формальные грамматики нашли широкое применение для описания особенностей вторичной структуры геномных и белковых последовательностей~\sidecite{Dyrka2019,WJAnderson2012,zier2013rna}. Соответствующие алгоритмы синтаксического анализа используются при создании инструментов обработки данных. Таким образом, теория формальных языков выступает в качестве основы для многих прикладных областей, а алгоритмы синтаксического анализа применимы не только для обработки естественных языков или языков программирования. @@ -25,16 +25,16 @@ \chapter*{Введение\markboth{Введение}{}} Иными словами, задача поиска путей может быть сформулирована следующим образом: необходимо найти такие пути в графе, что слова, получаемые конкатенацией меток их рёбер, принадлежат заданному языку. Такой класс задач будем называть задачами поиска путей с ограничениям в терминах формальных языков. -Подобный класс задач часто возникает в областях, связанных с анализом граф-структурированных данных и активно исследуется~\cite{doi:10.1137/S0097539798337716,axelsson2011formal,10.1007/978-3-642-22321-1_24,Ward:2010:CRL:1710158.1710234,barrett2007label,doi:10.1137/S0097539798337716}. +Подобный класс задач часто возникает в областях, связанных с анализом граф-структурированных данных и активно исследуется~\sidecite{doi:10.1137/S0097539798337716,axelsson2011formal,10.1007/978-3-642-22321-1_24,Ward:2010:CRL:1710158.1710234,barrett2007label,doi:10.1137/S0097539798337716}. Исследуются как классы языков, применяемых для задания ограничений, так и различные постановки задачи. Граф-структурированные данные встречаются не только в графовых базах данных, но и при статическом анализе кода: по программе можно построить различные графы отображающие её свойства. Скажем, граф вызовов, граф потока данных и так далее. Оказывается, что поиск путей в специального вида графах с использованием ограничений в терминах формальных языков позволяет исследовать некоторые нетривиальные свойства программы. -Например проводить межпроцедурный анализ указателей или анализ псевдонимов (алиасов)~\cite{Zheng,10.1145/2001420.2001440,10.1145/2714064.2660213}, строить срезы программ~\cite{10.1145/193173.195287}, проводить анализ типов~\cite{10.1145/373243.360208}. +Например проводить межпроцедурный анализ указателей или анализ псевдонимов (алиасов)~\sidecite{Zheng,10.1145/2001420.2001440,10.1145/2714064.2660213}, строить срезы программ~\sidecite{10.1145/193173.195287}, проводить анализ типов~\sidecite{10.1145/373243.360208}. В данной работе представлен ряд алгоритмов для поиска путей с ограничениями в терминах формальных языков. -Основной акцент будет сделан на контекстно-свободных языках, однако будут затронуты и другие классы: регулярные, многокомпонентные контекстно-свободные (Multiple Context-Free Languages, MCFL~\cite{SEKI1991191}) и конъюнктивные языки. +Основной акцент будет сделан на контекстно-свободных языках, однако будут затронуты и другие классы: регулярные, многокомпонентные контекстно-свободные (Multiple Context-Free Languages, MCFL~\sidecite{SEKI1991191}) и конъюнктивные языки. Будет показано, что теория формальных языков и алгоритмы синтаксического анализа применимы не только для анализа языков программирования или естественных языков, а также для анализа графовых баз данных и статического анализа кода, что приводит к возникновению новых задач и переосмыслению старых. @@ -47,32 +47,35 @@ \chapter*{Введение\markboth{Введение}{}} Большинство алгоритмов будут основаны на классических алгоритмах синтаксического анализа, таких как CYK или LR. %Все главы, начиная с~\ref{chpt:GraphTheoryIntro}, снабжены списком вопросов и задач для самостоятельного решения и закрепления материала. -\begin{center} + +\begin{figure*} + \begin{center} \begin{tikzpicture}[shorten >=1pt,on grid,auto] - \node (q_linal) [text width=4cm] {Некоторые понятия линейной алгебры}; - \node (q_graphtheory) [below of=q_linal, text width=4cm] {Некоторые сведения из теории графов}; - \node (q_fortmallang) [right of=q_graphtheory, text width=4cm] {Общие сведения теории формальных языков}; - \node (q_reglang) [below of=q_fortmallang, text width=4cm] {Регулярные языки}; - \node (q_cflang) [right of=q_reglang, text width=4cm] {Контекстно-свободные языки и грамматики}; - \node (q_mcfl) [right of=q_cflang, text width=4cm] {Многокомпонентные контекстно-свободные языки}; - \node (q_flpq) [below of=q_graphtheory, text width=4cm] {Пути с ограничениями в терминах формальных языков}; - - \node (q_rpq) [below of=q_reglang, text width=4cm] {Поиск путей с регулярными ограничениями}; - \node (q_cfpq) [below of=q_cflang, text width=4cm] {Пути с ограничениями в терминах контекстно-свободных языков}; - \node (q_mcfpq) [below of=q_mcfl, text width=4cm] {Пути с ограничениями в терминах многокомпонентных контекстно-свободных языков}; - \path[->] - (q_linal) edge node {} (q_graphtheory) - (q_graphtheory) edge node {} (q_flpq) - (q_fortmallang) edge node {} (q_flpq) - (q_fortmallang) edge node {} (q_reglang) - (q_fortmallang) edge node {} (q_cflang) - (q_fortmallang) edge node {} (q_mcfl) - (q_reglang) edge node {} (q_rpq) - (q_cflang) edge node {} (q_cfpq) - (q_mcfl) edge node {} (q_mcfpq) - (q_flpq) edge node {} (q_rpq) - (q_flpq) edge node {} (q_cfpq) - (q_flpq) edge node {} (q_mcfpq) - ; + \node (q_linal) [text width=4cm] {Некоторые понятия линейной алгебры}; + \node (q_graphtheory) [below of=q_linal, text width=4cm] {Некоторые сведения из теории графов}; + \node (q_fortmallang) [right of=q_graphtheory, text width=4cm] {Общие сведения теории формальных языков}; + \node (q_reglang) [below of=q_fortmallang, text width=4cm] {Регулярные языки}; + \node (q_cflang) [right of=q_reglang, text width=4cm] {Контекстно-свободные языки и грамматики}; + \node (q_mcfl) [right of=q_cflang, text width=4cm] {Многокомпонентные контекстно-свободные языки}; + \node (q_flpq) [below of=q_graphtheory, text width=4cm] {Пути с ограничениями в терминах формальных языков}; + + \node (q_rpq) [below of=q_reglang, text width=4cm] {Поиск путей с регулярными ограничениями}; + \node (q_cfpq) [below of=q_cflang, text width=4cm] {Пути с ограничениями в терминах контекстно-свободных языков}; + \node (q_mcfpq) [below of=q_mcfl, text width=4cm] {Пути с ограничениями в терминах многокомпонентных контекстно-свободных языков}; + \path[->] + (q_linal) edge node {} (q_graphtheory) + (q_graphtheory) edge node {} (q_flpq) + (q_fortmallang) edge node {} (q_flpq) + (q_fortmallang) edge node {} (q_reglang) + (q_fortmallang) edge node {} (q_cflang) + (q_fortmallang) edge node {} (q_mcfl) + (q_reglang) edge node {} (q_rpq) + (q_cflang) edge node {} (q_cfpq) + (q_mcfl) edge node {} (q_mcfpq) + (q_flpq) edge node {} (q_rpq) + (q_flpq) edge node {} (q_cfpq) + (q_flpq) edge node {} (q_mcfpq) + ; \end{tikzpicture} -\end{center} \ No newline at end of file + \end{center} +\end{figure*} diff --git a/tex/LinearAlgebra.tex b/tex/LinearAlgebra.tex index d4733ba..ba10d3e 100644 --- a/tex/LinearAlgebra.tex +++ b/tex/LinearAlgebra.tex @@ -1,4 +1,4 @@ -\chapter[Некоторые понятия линейной алгебры]{Некоторые понятия линейной алгебры\footnote{Неообходимо понимать, что, с одной строны, в данном разделе рассматриваются самые базовые понятия, которые даются практически в любом учебнике алгебры. С другой же стороны, определения данных понятий оказываются весьма вариативными и часто вызывают дискуссии. Напрмиер, интересный анализ тонкостей определения группы можно найти в первом и втором параграфах первого раздела книги Николая Александровича Вавилова ``Конкретная теория групп''~\cite{VavilovGroups}. Мы же дадим определения, удобные для дальнейшего изложения материала.}}\label{chpt:LinAlIntro} +\chapter[Некоторые понятия линейной алгебры]{Некоторые понятия линейной алгебры\sidenote[][*3]{Неообходимо понимать, что, с одной строны, в данном разделе рассматриваются самые базовые понятия, которые даются практически в любом учебнике алгебры. С другой же стороны, определения данных понятий оказываются весьма вариативными и часто вызывают дискуссии. Напрмиер, интересный анализ тонкостей определения группы можно найти в первом и втором параграфах первого раздела книги Николая Александровича Вавилова ``Конкретная теория групп''~\cite{VavilovGroups}. Мы же дадим определения, удобные для дальнейшего изложения материала.}}\label{chpt:LinAlIntro} При изложении ряда алгоритмов будут активно использоваться некоторые понятия и инструменты линейной алгебры, такие как моноид, полукольцо или матрица. В данном разделе необходимые понятия будут определены и приведены некоторые примеры соответствующих конструкций. Для более глубокого изучения материала рекомендуются обратиться к соответствующим разделам алгебры. @@ -23,19 +23,19 @@ \section{Бинарные операции и их свойства} \begin{definition} Функцию, принимающую два аргумента, $f: S \times K \to Q$ будем называть \emph{двухместной} или \emph{функцией арности два}. -Для записи таких функций будем использовать типичную нотацию: $c = f(a,b)$. + Для записи таких функций будем использовать типичную нотацию: $c = f(a,b)$. \end{definition} \begin{definition} -\emph{Бинарная операция} --- это двухместная функция, от которой дополнительно требуется, чтобы оба аргумента и результат лежали в одном и том же множестве: $f: S \times S \to S$. В таком случае говорят, что бинарная операция определена на некотором множестве $S$. Для обозначения произвольной бинарной операции будем использовать символ $\circ$ и пользоваться инфиксной нотацией для записи: $c = a \circ b$. + \emph{Бинарная операция} --- это двухместная функция, от которой дополнительно требуется, чтобы оба аргумента и результат лежали в одном и том же множестве: $f: S \times S \to S$. В таком случае говорят, что бинарная операция определена на некотором множестве $S$. Для обозначения произвольной бинарной операции будем использовать символ $\circ$ и пользоваться инфиксной нотацией для записи: $c = a \circ b$. \end{definition} \begin{definition} -\emph{Внешняя бинарная операция} --- это бинарная операция, у которой аргументы лежат в разных множествах, при этом результат --- в одном из этих множеств. Иными словами $\circ: K \times S \to S$, где $K$ может не совпадать с $S$ --- внешняя бинарная операция. + \emph{Внешняя бинарная операция} --- это бинарная операция, у которой аргументы лежат в разных множествах, при этом результат --- в одном из этих множеств. Иными словами $\circ: K \times S \to S$, где $K$ может не совпадать с $S$ --- внешняя бинарная операция. \end{definition} @@ -46,7 +46,7 @@ \section{Бинарные операции и их свойства} \begin{definition} -Бинарная операция $\circ : S \times S \to S$ называется \emph{коммутативной}, если для любых $x_1 \in S, x_2 \in S$ верно, что $x_1 \circ x_2 = x_2 \circ x_1$. + Бинарная операция $\circ : S \times S \to S$ называется \emph{коммутативной}, если для любых $x_1 \in S, x_2 \in S$ верно, что $x_1 \circ x_2 = x_2 \circ x_1$. \end{definition} \begin{example} Рассмотрим несколько примеров коммутативных и некоммутативных операций. @@ -55,35 +55,35 @@ \section{Бинарные операции и их свойства} \item Операция конкатенации на строках $\cdot$ не является коммутативной: $$``ab" \cdot ``c" \, = ``abc" \neq ``cab" \, = ``c" \cdot ``ab".$$ \item Операция умножения на целых числах является коммутативной: известный ещё со школы перестановочный закон умножения. \item Операция умножения матриц (над целыми числами) $\cdot$ не является коммутативной: - $$\begin{pmatrix} - 1 & 1 \\ 0 & 0 - \end{pmatrix} - \cdot - \begin{pmatrix} - 0 & 0 \\ 1 & 1 - \end{pmatrix} - = - \begin{pmatrix} - 1 & 1 \\ 0 & 0 - \end{pmatrix} - \neq - \begin{pmatrix} - 0 & 0 \\ 1 & 1 - \end{pmatrix} - = - \begin{pmatrix} - 0 & 0 \\ 1 & 1 - \end{pmatrix} - \cdot - \begin{pmatrix} - 1 & 1 \\ 0 & 0 - \end{pmatrix} - .$$ + $$\begin{pmatrix} + 1 & 1 \\ 0 & 0 + \end{pmatrix} + \cdot + \begin{pmatrix} + 0 & 0 \\ 1 & 1 + \end{pmatrix} + = + \begin{pmatrix} + 1 & 1 \\ 0 & 0 + \end{pmatrix} + \neq + \begin{pmatrix} + 0 & 0 \\ 1 & 1 + \end{pmatrix} + = + \begin{pmatrix} + 0 & 0 \\ 1 & 1 + \end{pmatrix} + \cdot + \begin{pmatrix} + 1 & 1 \\ 0 & 0 + \end{pmatrix} + .$$ \end{itemize} \end{example} \begin{definition} -Бинарная операция $\circ : S \times S \to S$ называется \emph{ассоциативной}, если для любых $x_1 \in S, x_2 \in S, x_3 \in S$ верно, что $(x_1 \circ x_2) \circ x_3 = x_1 \circ (x_2 \circ x_3)$. Иными словами, для ассоциативной операции результат вычислений не зависит от порядка применения операций. + Бинарная операция $\circ : S \times S \to S$ называется \emph{ассоциативной}, если для любых $x_1 \in S, x_2 \in S, x_3 \in S$ верно, что $(x_1 \circ x_2) \circ x_3 = x_1 \circ (x_2 \circ x_3)$. Иными словами, для ассоциативной операции результат вычислений не зависит от порядка применения операций. \end{definition} \begin{example} Рассмотрим несколько примеров ассоциативных и неассоциативных операций. @@ -92,53 +92,53 @@ \section{Бинарные операции и их свойства} \item Операция умножения на целых числах является ассоциативной. \item Операция конкатенации на строках $\cdot$ является ассоциативной: $$(``a" \cdot ``b") \cdot ``c" \, = ``a" \cdot (``b" \cdot ``c") = ``abc" .$$ \item Операция возведения в степень (над целыми числами) $\hat{\mkern6mu}$ не является ассоциативной: - $$(2\hat{\mkern6mu}2)\hat{\mkern6mu}3 = 4 \hat{\mkern6mu} 3 = 64 \neq 256 = 2 \hat{\mkern6mu} 8 = 2\hat{\mkern6mu}(2\hat{\mkern6mu}3).$$ + $$(2\hat{\mkern6mu}2)\hat{\mkern6mu}3 = 4 \hat{\mkern6mu} 3 = 64 \neq 256 = 2 \hat{\mkern6mu} 8 = 2\hat{\mkern6mu}(2\hat{\mkern6mu}3).$$ \end{itemize} \end{example} \begin{definition} -Говорят, что бинарная операция $\otimes : S \times S \to S$ является \emph{дистрибутивной} относительно бинарной операции $\oplus : S \times S \to S$, если -\begin{enumerate} - \item Для любых $x_1,x_2,x_3 \in S, x_1 \otimes (x_2 \oplus x_3) = (x_1 \otimes x_2) \oplus (x_1 \otimes x_3)$ (дистрибутивность слева). - \item Для любых $x_1,x_2,x_3 \in S, (x_2 \oplus x_3) \otimes x_1 = (x_2 \otimes x_1) \oplus (x_3 \otimes x_1)$ (дистрибутивность справа). -\end{enumerate} + Говорят, что бинарная операция $\otimes : S \times S \to S$ является \emph{дистрибутивной} относительно бинарной операции $\oplus : S \times S \to S$, если + \begin{enumerate} + \item Для любых $x_1,x_2,x_3 \in S, x_1 \otimes (x_2 \oplus x_3) = (x_1 \otimes x_2) \oplus (x_1 \otimes x_3)$ (дистрибутивность слева). + \item Для любых $x_1,x_2,x_3 \in S, (x_2 \oplus x_3) \otimes x_1 = (x_2 \otimes x_1) \oplus (x_3 \otimes x_1)$ (дистрибутивность справа). + \end{enumerate} -Если операция $\otimes$ является коммутативной, то дистрибутивность слева и справа равносильны. + Если операция $\otimes$ является коммутативной, то дистрибутивность слева и справа равносильны. \end{definition} \begin{example} Рассмотрим несколько примеров дистрибутивных операций. -\begin{itemize} - \item Умножение целых чисел дистрибутивно относительно сложения и вычитания: классический \textit{распределительный закон}, знакомый всем со школы. - \item Операция деления (допустим, на действительных числах) не коммутативна. При этом, она дистрибутивна справа относительно сложения и вычитания, но не дистрибутивна слева. - $$(a + b) / c = (a / c) + (b / c) $$ - но - $$c / (a + b) \neq (c / a) + (c / b)\footnote{Здесь может быть уместно вспомнить правила сложения дробей. Дроби с общим знаминателем складывать проще как раз из-за дистрибутивности справа.}.$$ -\end{itemize} + \begin{itemize} + \item Умножение целых чисел дистрибутивно относительно сложения и вычитания: классический \textit{распределительный закон}, знакомый всем со школы. + \item Операция деления (допустим, на действительных числах) не коммутативна. При этом, она дистрибутивна справа относительно сложения и вычитания, но не дистрибутивна слева. + $$(a + b) / c = (a / c) + (b / c) $$ + но + $$c / (a + b) \neq (c / a) + (c / b)\sidenote{Здесь может быть уместно вспомнить правила сложения дробей. Дроби с общим знаминателем складывать проще как раз из-за дистрибутивности справа.}.$$ + \end{itemize} \end{example} \begin{definition} -Бинарная операция $\circ : S \times S \to S$ называется \emph{идемпотентной}, если для любого $x \in S$ верно, что $x \circ x = x$. + Бинарная операция $\circ : S \times S \to S$ называется \emph{идемпотентной}, если для любого $x \in S$ верно, что $x \circ x = x$. \end{definition} \begin{example} Рассмотрим несколько примеров идемпотентных операций. -\begin{itemize} - \item Операция объединения множеств $\cup$ является идемпотентной: для любого множества $S$ верно, что $S \cup S = S$. - \item Операция сложения на целых числах не является идемпотентной. - \item Операции ``логическое и'' $\wedge$ и ``логическое или'' $\vee$ являются идемпотентными. - \item Операция ``исключающее или'' (\texttt{XOR}) не является идемпотентной. -\end{itemize} + \begin{itemize} + \item Операция объединения множеств $\cup$ является идемпотентной: для любого множества $S$ верно, что $S \cup S = S$. + \item Операция сложения на целых числах не является идемпотентной. + \item Операции ``логическое и'' $\wedge$ и ``логическое или'' $\vee$ являются идемпотентными. + \item Операция ``исключающее или'' (\texttt{XOR}) не является идемпотентной. + \end{itemize} \end{example} \begin{definition} -Пусть есть коммутативная бинарная операция $\circ$ на множестве $S$. Говорят, что $x\in S$ является \emph{нейтральным элементом} по операции $\circ$, если для любого $y\in S$ верно, что $x \circ y = y \circ x = y$. Если бинарная операция не является коммутативной, то можно определить \textit{нейтральный слева} и \textit{нейтральный справа} элементы по аналогии. + Пусть есть коммутативная бинарная операция $\circ$ на множестве $S$. Говорят, что $x\in S$ является \emph{нейтральным элементом} по операции $\circ$, если для любого $y\in S$ верно, что $x \circ y = y \circ x = y$. Если бинарная операция не является коммутативной, то можно определить \textit{нейтральный слева} и \textit{нейтральный справа} элементы по аналогии. \end{definition} @@ -146,17 +146,17 @@ \section{Полугруппа} \begin{definition} -Множество $S$ с заданной на нём ассоциативной бинарной операцией $\cdot : S \times S \to S$ называется \emph{полугруппой} и обозначается $(S, \cdot)$. -Если операция $\cdot$ является коммутативной, то говорят о \textit{коммутативной полугруппе}. + Множество $S$ с заданной на нём ассоциативной бинарной операцией $\cdot : S \times S \to S$ называется \emph{полугруппой} и обозначается $(S, \cdot)$. + Если операция $\cdot$ является коммутативной, то говорят о \textit{коммутативной полугруппе}. \end{definition} \begin{example} Приведём несколько примеров полугрупп. -\begin{itemize} - \item Множество положительных целых чисел с операцией сложения является коммутативной полугруппой. - \item Множество целых чисел с операцией взятия наибольшего из двух ($\max$) является коммутативной полугруппой. - \item Множество всех строк конечной длины без пустой строки\footnote{Множество всех строк конечной длины c пустой строкой также является полугруппой. Однако, такая структура является ещё и моноидом, что будет показано далее.} над фиксированным алфавитом $\Sigma$ с операцией конкатенации является полугруппой. Так как конкатенация на строках не является коммутативной операцией, то и полугруппа не является коммутативной. -\end{itemize} + \begin{itemize} + \item Множество положительных целых чисел с операцией сложения является коммутативной полугруппой. + \item Множество целых чисел с операцией взятия наибольшего из двух ($\max$) является коммутативной полугруппой. + \item Множество всех строк конечной длины без пустой строки\sidenote{Множество всех строк конечной длины c пустой строкой также является полугруппой. Однако, такая структура является ещё и моноидом, что будет показано далее.} над фиксированным алфавитом $\Sigma$ с операцией конкатенации является полугруппой. Так как конкатенация на строках не является коммутативной операцией, то и полугруппа не является коммутативной. + \end{itemize} \end{example} @@ -169,128 +169,128 @@ \section{Моноид} \begin{example} Приведём примеры моноидов, построенных на основе полугрупп из предыдущего раздела. -\begin{itemize} - \item Неотрицательные целые числа (или же натуральные числа с нулём) с операцией сложения являются моноидом. Нейтральный элемент --- $0$. - \item Целые числа, дополненные значением $-\infty$ (``минус-бесконечность'') с операцией взятия наибольшего из двух ($\max$) являются моноидом. Нейтральный элемент --- $-\infty$. - \item Множество всех строк конечной длины с пустой строкой (строка длины 0) над фиксированным алфавитом $\Sigma$ и операцией конкатенации является моноидом. Нейтральный элемент --- пустая строка. - \item Квадратные неотрицательные матрицы\footnote{Неотрицательной называется матрица, все элементы которой не меньше нуля.} фиксированного размера с операцией умножения задают моноид. Нейтральный элемент --- единичная матрица. -\end{itemize} + \begin{itemize} + \item Неотрицательные целые числа (или же натуральные числа с нулём) с операцией сложения являются моноидом. Нейтральный элемент --- $0$. + \item Целые числа, дополненные значением $-\infty$ (``минус-бесконечность'') с операцией взятия наибольшего из двух ($\max$) являются моноидом. Нейтральный элемент --- $-\infty$. + \item Множество всех строк конечной длины с пустой строкой (строка длины 0) над фиксированным алфавитом $\Sigma$ и операцией конкатенации является моноидом. Нейтральный элемент --- пустая строка. + \item Квадратные неотрицательные матрицы\sidenote{Неотрицательной называется матрица, все элементы которой не меньше нуля.} фиксированного размера с операцией умножения задают моноид. Нейтральный элемент --- единичная матрица. + \end{itemize} \end{example} \section{Группа} \begin{definition} -Непустое\footnote{Требование непустоты здесь, как и далее, в определениях полукольца и кольца --- дискуссионный вопрос.} множество $G$ с заданной на нём бинарной операцией $\circ: {G} \times {G} \to {G}$ называется \emph{группой} $(G ,\circ)$, если выполнены следующие аксиомы: -\begin{enumerate} -\item ассоциативность: $\forall (a,b,c\in G)\colon (a\circ b)\circ c = a\circ (b \circ c)$; -\item наличие нейтрального элемента: $ \exists e \in G \quad \forall a\in G\colon (e \circ a = a \circ e = a)$; -\item наличие обратного элемента: $ \forall a\in G\quad \exists a^{-1}\in G\colon (a \circ a^{-1}=a^{-1} \circ a = e)$. -\end{enumerate} - -Иными словами, группа --- это моноид с дополнительным требованием наличия обратных элементов. + Непустое\sidenote{Требование непустоты здесь, как и далее, в определениях полукольца и кольца --- дискуссионный вопрос.} множество $G$ с заданной на нём бинарной операцией $\circ: {G} \times {G} \to {G}$ называется \emph{группой} $(G ,\circ)$, если выполнены следующие аксиомы: + \begin{enumerate} + \item ассоциативность: $\forall (a,b,c\in G)\colon (a\circ b)\circ c = a\circ (b \circ c)$; + \item наличие нейтрального элемента: $ \exists e \in G \quad \forall a\in G\colon (e \circ a = a \circ e = a)$; + \item наличие обратного элемента: $ \forall a\in G\quad \exists a^{-1}\in G\colon (a \circ a^{-1}=a^{-1} \circ a = e)$. + \end{enumerate} + + Иными словами, группа --- это моноид с дополнительным требованием наличия обратных элементов. \end{definition} \begin{definition} -Если операция $\circ$ коммутативна, то говорят, что группа \textit{Абелева}. + Если операция $\circ$ коммутативна, то говорят, что группа \textit{Абелева}. \end{definition} \begin{example} -Рассмотрим несколько примеров групп. -\begin{itemize} - \item Целые числа $\mathbb{Z}$ с операцией сложения $+$ являются группой. Получается дополнением моноида из предыдущего раздела обратными по сложению элементами. - \item Целые числа $\mathbb{Z}$ без нуля\footnote{При наличии нуля возникают трудности с нейтральным элементом. Логично считать $1$ нейтральным по умножению, однако $0\cdot1 = 0$, а не 1, как того требует определение.} с операцией умножения $\cdot$ не являются группой, так как нет обратных по умножению. Действительно, возьмём $a = 3$, тогда должен существовать $a^{-1} \in \mathbb{Z}$, такой что $3 \cdot a^{-1} = 1$. Видим, что $a^{-1} = \frac{1}{3}$, но $\frac{1}{3} \notin \mathbb{Z}$. - \item Множество обратимых\footnote{Квадратная матрица $M$ называется обратимой, если существует матрица $N$, называемая обратной, такая что $M \cdot N = N \cdot M = I$, где $I$ --- единичная матрица. К сожалению, не все матрицы являются обратимыми, потому, чтобы сконструировать группу, нам приходится требовать обратимость явно.} матриц с операцией матричного умножения задают группу. -\end{itemize} + Рассмотрим несколько примеров групп. + \begin{itemize} + \item Целые числа $\mathbb{Z}$ с операцией сложения $+$ являются группой. Получается дополнением моноида из предыдущего раздела обратными по сложению элементами. + \item Целые числа $\mathbb{Z}$ без нуля\sidenote{При наличии нуля возникают трудности с нейтральным элементом. Логично считать $1$ нейтральным по умножению, однако $0\cdot1 = 0$, а не 1, как того требует определение.} с операцией умножения $\cdot$ не являются группой, так как нет обратных по умножению. Действительно, возьмём $a = 3$, тогда должен существовать $a^{-1} \in \mathbb{Z}$, такой что $3 \cdot a^{-1} = 1$. Видим, что $a^{-1} = \frac{1}{3}$, но $\frac{1}{3} \notin \mathbb{Z}$. + \item Множество обратимых\sidenote{Квадратная матрица $M$ называется обратимой, если существует матрица $N$, называемая обратной, такая что $M \cdot N = N \cdot M = I$, где $I$ --- единичная матрица. К сожалению, не все матрицы являются обратимыми, потому, чтобы сконструировать группу, нам приходится требовать обратимость явно.} матриц с операцией матричного умножения задают группу. + \end{itemize} \end{example} \section{Полукольцо} \begin{definition} -Непустое множество $R$ с двумя бинарными операциями $\oplus\colon R \times R \to R$ (часто называют сложением) и $\otimes \colon R \times R \to R$ (часто называют умножением) называется \emph{полукольцом}, если выполнены следующие условия. -\begin{enumerate} + Непустое множество $R$ с двумя бинарными операциями $\oplus\colon R \times R \to R$ (часто называют сложением) и $\otimes \colon R \times R \to R$ (часто называют умножением) называется \emph{полукольцом}, если выполнены следующие условия. + \begin{enumerate} -\item $(R, \oplus)$ --- это коммутативный моноид, нейтральный элемент которого --- $\mathbb{0}$. Для любых $a,b,c \in R$: -\begin{itemize} - \item $(a \oplus b) \oplus c = a \oplus (b \oplus c)$ - \item $\mathbb{0} \oplus a = a \oplus \mathbb{0} = a$ - \item $a \oplus b = b \oplus a$ -\end{itemize} + \item $(R, \oplus)$ --- это коммутативный моноид, нейтральный элемент которого --- $\mathbb{0}$. Для любых $a,b,c \in R$: + \begin{itemize} + \item $(a \oplus b) \oplus c = a \oplus (b \oplus c)$ + \item $\mathbb{0} \oplus a = a \oplus \mathbb{0} = a$ + \item $a \oplus b = b \oplus a$ + \end{itemize} -\item $(R, \otimes)$ --- это моноид, нейтральный элемент которого --- $\mathbb{1}$. Для любых $a,b,c \in R$: -\begin{itemize} - \item $(a \otimes b) \otimes c = a \otimes (b \otimes c)$ - \item $\mathbb{1} \otimes a = a \otimes \mathbb{1} = a$ -\end{itemize} + \item $(R, \otimes)$ --- это моноид, нейтральный элемент которого --- $\mathbb{1}$. Для любых $a,b,c \in R$: + \begin{itemize} + \item $(a \otimes b) \otimes c = a \otimes (b \otimes c)$ + \item $\mathbb{1} \otimes a = a \otimes \mathbb{1} = a$ + \end{itemize} -\item $\otimes$ дистрибутивно слева и справа относительно $\oplus$: -\begin{itemize} - \item $a \otimes (b \oplus c) = (a \otimes b) \oplus (a \otimes c)$ - \item $(a \oplus b) \otimes c = (a \otimes c) \oplus (b \otimes c)$ -\end{itemize} + \item $\otimes$ дистрибутивно слева и справа относительно $\oplus$: + \begin{itemize} + \item $a \otimes (b \oplus c) = (a \otimes b) \oplus (a \otimes c)$ + \item $(a \oplus b) \otimes c = (a \otimes c) \oplus (b \otimes c)$ + \end{itemize} -\item $\mathbb{0}$ является \textit{аннигилятором} по умножению: -\begin{itemize} - \item $\forall a \in R: \mathbb{0} \otimes a = a \otimes \mathbb{0} = \mathbb{0}$ -\end{itemize} + \item $\mathbb{0}$ является \textit{аннигилятором} по умножению: + \begin{itemize} + \item $\forall a \in R: \mathbb{0} \otimes a = a \otimes \mathbb{0} = \mathbb{0}$ + \end{itemize} -\end{enumerate} + \end{enumerate} -Если операция $\otimes$ коммутативна, то говорят о коммутативном полукольце. -Если операция $\oplus$ идемпотентна, то говорят об идемпотентном полукольце. + Если операция $\otimes$ коммутативна, то говорят о коммутативном полукольце. + Если операция $\oplus$ идемпотентна, то говорят об идемпотентном полукольце. \end{definition} \begin{example}\label{exmpl:semiring} -Рассмотрим пример полукольца, а заодно покажем, что левая и правая дистрибутивность могут существовать независимо для некоммутативного умножения\footnote{Хороший пример того, почему левую и правую дистрибутивность в случае некоммутативного умножения нужно проверять независимо (правда, для колец), приведён Николаем Александровичем Вавиловым в книге ``Конкретная теория колец'' на странице 6~\cite{VavilovRings}.}. + Рассмотрим пример полукольца, а заодно покажем, что левая и правая дистрибутивность могут существовать независимо для некоммутативного умножения\sidenote{Хороший пример того, почему левую и правую дистрибутивность в случае некоммутативного умножения нужно проверять независимо (правда, для колец), приведён Николаем Александровичем Вавиловым в книге ``Конкретная теория колец'' на странице 6~\cite{VavilovRings}.}. -В качестве $R$ возьмём множество множеств строк конечной длины над некоторым алфавитом $\Sigma$. В качестве сложения возьмём теоретико-множественное объединение: $\oplus \equiv \cup$. Нейтральный элемент по сложению --- это пустое множество ($\varnothing$). -В качестве умножения возьмём конкатенацию множеств ($\otimes \equiv \odot$) и определим её следующим образом: -$$ S_1 \odot S_2 = \{ w_1 \cdot w_2 \mid w_1 \in S_1, w_2 \in S_2\}$$, где $\cdot$ --- конкатенация строк. Нейтральным элементом по умножению будет являться множество из пустой строки: $\{\varepsilon\}$, где $\varepsilon$ --- обозначение для пустой строки. + В качестве $R$ возьмём множество множеств строк конечной длины над некоторым алфавитом $\Sigma$. В качестве сложения возьмём теоретико-множественное объединение: $\oplus \equiv \cup$. Нейтральный элемент по сложению --- это пустое множество ($\varnothing$). + В качестве умножения возьмём конкатенацию множеств ($\otimes \equiv \odot$) и определим её следующим образом: + $$ S_1 \odot S_2 = \{ w_1 \cdot w_2 \mid w_1 \in S_1, w_2 \in S_2\}$$, где $\cdot$ --- конкатенация строк. Нейтральным элементом по умножению будет являться множество из пустой строки: $\{\varepsilon\}$, где $\varepsilon$ --- обозначение для пустой строки. -Проверим, что $(R, \cup, \odot)$ действительно полукольцо по нашему определению. + Проверим, что $(R, \cup, \odot)$ действительно полукольцо по нашему определению. -\begin{enumerate} + \begin{enumerate} -\item $(R, \cup)$ --- действительно коммутативный моноид с нейтральным элементом $\varnothing$. Для любых $a,b,c \in R$ по свойствам теоретико-множественного объединения верно: -\begin{itemize} - \item $(a \cup b) \cup c = a \cup (b \cup c)$ - \item $\varnothing \cup a = a \cup \varnothing = a$ - \item $a \cup b = b \cup a$. -\end{itemize} + \item $(R, \cup)$ --- действительно коммутативный моноид с нейтральным элементом $\varnothing$. Для любых $a,b,c \in R$ по свойствам теоретико-множественного объединения верно: + \begin{itemize} + \item $(a \cup b) \cup c = a \cup (b \cup c)$ + \item $\varnothing \cup a = a \cup \varnothing = a$ + \item $a \cup b = b \cup a$. + \end{itemize} -\item $(R, \odot)$ --- действительно моноид с нейтральным элементом $\{\varepsilon\}$. Для любых $a,b,c \in R$: -\begin{itemize} - \item $(a \odot b) \odot c = a \odot (b \odot c)$ по определению $\odot$ - \item $\{\varepsilon\} \odot a = \{\varepsilon \cdot w \mid w \in a \} = \{w \mid w \in a \} = a \odot \{\varepsilon\} = a$ -\end{itemize} -Вообще говоря, сконструированный нами моноид не является коммутативным: легко проверить, например, что существуют непустые $a,b \in R, a \neq b, a \neq \{\varepsilon\}, b \neq \{\varepsilon\}$: $a \cdot b \neq b \cdot a$ по причине некоммутативности конкатенации строк. + \item $(R, \odot)$ --- действительно моноид с нейтральным элементом $\{\varepsilon\}$. Для любых $a,b,c \in R$: + \begin{itemize} + \item $(a \odot b) \odot c = a \odot (b \odot c)$ по определению $\odot$ + \item $\{\varepsilon\} \odot a = \{\varepsilon \cdot w \mid w \in a \} = \{w \mid w \in a \} = a \odot \{\varepsilon\} = a$ + \end{itemize} + Вообще говоря, сконструированный нами моноид не является коммутативным: легко проверить, например, что существуют непустые $a,b \in R, a \neq b, a \neq \{\varepsilon\}, b \neq \{\varepsilon\}$: $a \cdot b \neq b \cdot a$ по причине некоммутативности конкатенации строк. -\item $\odot$ дистрибутивно слева и справа относительно $\cup$: -\begin{itemize} - \item Сначала проверим дистрибутивность слева. - \begin{align*} - a \odot (b \cup c) & = \{ w_1 \cdot w_2 \mid w_1 \in a, w_2 \in b \cup c\} \\ - & = \{ w_1 \cdot w_2 \mid w_1 \in a, w_2 \in b \} \cup \{ w_1 \cdot w_2 \mid w_1 \in a, w_2 \in c \} \\ - & = (a \odot b) \cup (a \odot c) - \end{align*} - - \item Аналогично, $(a \cup b) \odot c = (a \odot c) \cup (b \odot c)$ -\end{itemize} -При этом, в общем случае, $a \odot (b \cup c) \neq (b \cup c) \odot a$ из-за некоммутативности операции $\odot$. Действительно, + \item $\odot$ дистрибутивно слева и справа относительно $\cup$: + \begin{itemize} + \item Сначала проверим дистрибутивность слева. + \begin{align*} + a \odot (b \cup c) & = \{ w_1 \cdot w_2 \mid w_1 \in a, w_2 \in b \cup c\} \\ + & = \{ w_1 \cdot w_2 \mid w_1 \in a, w_2 \in b \} \cup \{ w_1 \cdot w_2 \mid w_1 \in a, w_2 \in c \} \\ + & = (a \odot b) \cup (a \odot c) + \end{align*} + + \item Аналогично, $(a \cup b) \odot c = (a \odot c) \cup (b \odot c)$ + \end{itemize} + При этом, в общем случае, $a \odot (b \cup c) \neq (b \cup c) \odot a$ из-за некоммутативности операции $\odot$. Действительно, -\begin{align*} - & \{``a"\}\odot(\{``b"\} \cup \{``c"\}) = \{``a"\}\odot \{``b" \ ,``c" \} = \{``ab"\ ,``ac" \} \neq \\ - \neq & (\{``b"\} \cup \{``c"\}) \odot \{``a"\} = \{``b",``c" \} \odot \{``a"\} = \{``ba"\ ,``ca" \} -\end{align*} + \begin{align*} + & \{``a"\}\odot(\{``b"\} \cup \{``c"\}) = \{``a"\}\odot \{``b" \ ,``c" \} = \{``ab"\ ,``ac" \} \neq \\ + \neq & (\{``b"\} \cup \{``c"\}) \odot \{``a"\} = \{``b",``c" \} \odot \{``a"\} = \{``ba"\ ,``ca" \} + \end{align*} -\item $\varnothing$ является \textit{аннигилятором} по умножению: для любого $a \in R$ верно, что -$\varnothing \odot a = \{ w_1 \cdot w_2 \mid w_1 \in \varnothing, w_2 \in a \} = \{ w_1 \cdot w_2 \mid w_1 \in a, w_2 \in \varnothing \} = a \odot \varnothing = \varnothing$ + \item $\varnothing$ является \textit{аннигилятором} по умножению: для любого $a \in R$ верно, что + $\varnothing \odot a = \{ w_1 \cdot w_2 \mid w_1 \in \varnothing, w_2 \in a \} = \{ w_1 \cdot w_2 \mid w_1 \in a, w_2 \in \varnothing \} = a \odot \varnothing = \varnothing$ -\end{enumerate} + \end{enumerate} \end{example} @@ -299,46 +299,46 @@ \section{Кольцо} \begin{definition} -Непустое множество $R$ с двумя бинарными операциями $\oplus\colon R \times R \to R$ (умножение) и $\otimes \colon R \times R \to R$ (сложение) называется \emph{кольцом}, если выполнены следующие условия. -\begin{enumerate} - -\item $(R, \oplus)$ --- это Абелева группа, нейтральный элемент которой --- $\mathbb{0}$. Для любых $a,b,c \in R$: -\begin{itemize} - \item $(a \oplus b) \oplus c = a \oplus (b \oplus c)$ - \item $\mathbb{0} \oplus a = a \oplus \mathbb{0} = a$ - \item $a \oplus b = b \oplus a$ - \item для любого $a \in R$ существует $-a \in R$, такое что $a + (-a) = \mathbb{0}$. -\end{itemize} -В последнем пункте кроется отличие от полукольца. - -\item $(R, \otimes)$ --- это моноид, нейтральный элемент которого --- $\mathbb{1}$. Для любых $a,b,c \in R$: -\begin{itemize} - \item $(a \otimes b) \otimes c = a \otimes (b \otimes c)$ - \item $\mathbb{1} \otimes a = a \otimes \mathbb{1} = a$ -\end{itemize} - -\item $\otimes$ дистрибутивно слева и справа относительно $\oplus$: -\begin{itemize} - \item $a \otimes (b \oplus c) = (a \otimes b) \oplus (a \otimes c)$ - \item $(a \oplus b) \otimes c = (a \otimes c) \oplus (b \otimes c)$ -\end{itemize} - -\end{enumerate} - -Заметим, что мультипликативное свойство $\mathbb{0}$ (быть аннигилятором по умножению) не указыватеся явно, так как может быть выведено из остальных утверждений. Действительно, -\begin{enumerate} - \item $a \otimes \mathbb{0} = a \otimes (\mathbb{0} \oplus \mathbb{0})$, так как $\mathbb{0}$ --- нейтральный по сложению, то $\mathbb{0} \oplus \mathbb{0} = \mathbb{0}$ - \item Воспользуемся дистрибутивностью: $a \otimes (\mathbb{0} \oplus \mathbb{0}) = a \otimes \mathbb{0} \oplus a \otimes \mathbb{0}$. В итоге: $a \otimes \mathbb{0} = a \otimes \mathbb{0} \oplus a \otimes \mathbb{0}$ - \item Так как у нас есть группа по сложению, то для любого $a$ существует обратный элемент $a^{-1}, a \oplus a^{-1} = \mathbb{0}$. Прибавим $a^{-1} \otimes \mathbb{0}$ к левой и правой части равенства\footnote{Обычно данное действие воспринимается как очевидное, но, строго говоря, оно требует аккуратного введения структур с равенством и соответствующих аксиом.}, полученного на предыдущем шаге: - $$a \otimes \mathbb{0} \oplus a^{-1} \otimes \mathbb{0} = a \otimes \mathbb{0} \oplus a \otimes \mathbb{0} \oplus a^{-1} \otimes \mathbb{0}.$$ - \item Воспользуемся дистрибутивностью и ассоциативностью. - \begin{align*} - (a \oplus a^{-1}) \otimes \mathbb{0} & = a \otimes \mathbb{0} \oplus (a \oplus a^{-1}) \otimes \mathbb{0} \\ - \mathbb{0} \otimes \mathbb{0} & = a \otimes \mathbb{0} \oplus \mathbb{0} \otimes \mathbb{0} \\ - \mathbb{0} & = a \otimes \mathbb{0} - \end{align*} - \item Аналогично можно доказать, что $\mathbb{0} = \mathbb{0} \otimes a$. -\end{enumerate} + Непустое множество $R$ с двумя бинарными операциями $\oplus\colon R \times R \to R$ (умножение) и $\otimes \colon R \times R \to R$ (сложение) называется \emph{кольцом}, если выполнены следующие условия. + \begin{enumerate} + + \item $(R, \oplus)$ --- это Абелева группа, нейтральный элемент которой --- $\mathbb{0}$. Для любых $a,b,c \in R$: + \begin{itemize} + \item $(a \oplus b) \oplus c = a \oplus (b \oplus c)$ + \item $\mathbb{0} \oplus a = a \oplus \mathbb{0} = a$ + \item $a \oplus b = b \oplus a$ + \item для любого $a \in R$ существует $-a \in R$, такое что $a + (-a) = \mathbb{0}$. + \end{itemize} + В последнем пункте кроется отличие от полукольца. + + \item $(R, \otimes)$ --- это моноид, нейтральный элемент которого --- $\mathbb{1}$. Для любых $a,b,c \in R$: + \begin{itemize} + \item $(a \otimes b) \otimes c = a \otimes (b \otimes c)$ + \item $\mathbb{1} \otimes a = a \otimes \mathbb{1} = a$ + \end{itemize} + + \item $\otimes$ дистрибутивно слева и справа относительно $\oplus$: + \begin{itemize} + \item $a \otimes (b \oplus c) = (a \otimes b) \oplus (a \otimes c)$ + \item $(a \oplus b) \otimes c = (a \otimes c) \oplus (b \otimes c)$ + \end{itemize} + + \end{enumerate} + + Заметим, что мультипликативное свойство $\mathbb{0}$ (быть аннигилятором по умножению) не указыватеся явно, так как может быть выведено из остальных утверждений. Действительно, + \begin{enumerate} + \item $a \otimes \mathbb{0} = a \otimes (\mathbb{0} \oplus \mathbb{0})$, так как $\mathbb{0}$ --- нейтральный по сложению, то $\mathbb{0} \oplus \mathbb{0} = \mathbb{0}$ + \item Воспользуемся дистрибутивностью: $a \otimes (\mathbb{0} \oplus \mathbb{0}) = a \otimes \mathbb{0} \oplus a \otimes \mathbb{0}$. В итоге: $a \otimes \mathbb{0} = a \otimes \mathbb{0} \oplus a \otimes \mathbb{0}$ + \item Так как у нас есть группа по сложению, то для любого $a$ существует обратный элемент $a^{-1}, a \oplus a^{-1} = \mathbb{0}$. Прибавим $a^{-1} \otimes \mathbb{0}$ к левой и правой части равенства\sidenote{Обычно данное действие воспринимается как очевидное, но, строго говоря, оно требует аккуратного введения структур с равенством и соответствующих аксиом.}, полученного на предыдущем шаге: + $$a \otimes \mathbb{0} \oplus a^{-1} \otimes \mathbb{0} = a \otimes \mathbb{0} \oplus a \otimes \mathbb{0} \oplus a^{-1} \otimes \mathbb{0}.$$ + \item Воспользуемся дистрибутивностью и ассоциативностью. + \begin{align*} + (a \oplus a^{-1}) \otimes \mathbb{0} & = a \otimes \mathbb{0} \oplus (a \oplus a^{-1}) \otimes \mathbb{0} \\ + \mathbb{0} \otimes \mathbb{0} & = a \otimes \mathbb{0} \oplus \mathbb{0} \otimes \mathbb{0} \\ + \mathbb{0} & = a \otimes \mathbb{0} + \end{align*} + \item Аналогично можно доказать, что $\mathbb{0} = \mathbb{0} \otimes a$. + \end{enumerate} \end{definition} @@ -353,29 +353,29 @@ \section{Матрицы и вектора} \begin{definition} -Предположим, что у нас есть некоторая алгебраическая структура с носителем $S$. Тогда \emph{матрицей} будем называть прямоугольный массив размера $n\times m, n > 0, m > 0$, заполненный элементами из $S$. + Предположим, что у нас есть некоторая алгебраическая структура с носителем $S$. Тогда \emph{матрицей} будем называть прямоугольный массив размера $n\times m, n > 0, m > 0$, заполненный элементами из $S$. -Говорят, что $n$ --- это высота матрицы или количество строк в ней, а $m$ --- ширина матрицы или количество столбцов. + Говорят, что $n$ --- это высота матрицы или количество строк в ней, а $m$ --- ширина матрицы или количество столбцов. \end{definition} -При доступе к элементам матрицы используются их индексы. При этом нумерация ведётся с левого верхнего угла, первым указывается строка, вторым --- столбец. В нашей работе мы будем использовать ``программистскую'' традицию и нумеровать строки и столбцы с нуля\footnote{В противоположность ``математической'' традиции нумеровать строки и столбцы с единицы. Стоит, правда, отметить, что в некоторых языках программирования (например, Fortran или COBOL) жива ``математическая'' традиция.}. +При доступе к элементам матрицы используются их индексы. При этом нумерация ведётся с левого верхнего угла, первым указывается строка, вторым --- столбец. В нашей работе мы будем использовать ``программистскую'' традицию и нумеровать строки и столбцы с нуля\sidenote{В противоположность ``математической'' традиции нумеровать строки и столбцы с единицы. Стоит, правда, отметить, что в некоторых языках программирования (например, Fortran или COBOL) жива ``математическая'' традиция.}. \begin{example}[Матрица] -Пусть есть моноид $(S,\cdot)$, где $S$ --- множество строк конечной длины над алфавитом \{a,b,c\}. -Тогда можно построить, например, следующую матрицу $2\times 3$. -$$ -M_{2\times 3} = -\begin{pmatrix} -``a" & ``ba" & ``cb" \\ -``ac" & ``bab" & ``b" \\ -\end{pmatrix} -$$ + Пусть есть моноид $(S,\cdot)$, где $S$ --- множество строк конечной длины над алфавитом \{a,b,c\}. + Тогда можно построить, например, следующую матрицу $2\times 3$. + $$ + M_{2\times 3} = + \begin{pmatrix} + ``a" & ``ba" & ``cb" \\ + ``ac" & ``bab" & ``b" \\ + \end{pmatrix} + $$ -$$ -M_{2\times 3}[1,1] = ``bab" -$$ + $$ + M_{2\times 3}[1,1] = ``bab" + $$ \end{example} @@ -383,7 +383,7 @@ \section{Матрицы и вектора} \begin{definition} -\emph{Вектором} будем называть матрицу, хотя бы один из размеров которой равен единице. Если единице равна высота матрицы, то это \textit{вектор-строка}, если же единице равна ширина матрицы, то это \textit{вектор-столбец}. + \emph{Вектором} будем называть матрицу, хотя бы один из размеров которой равен единице. Если единице равна высота матрицы, то это \textit{вектор-строка}, если же единице равна ширина матрицы, то это \textit{вектор-столбец}. \end{definition} @@ -397,81 +397,81 @@ \section{Матрицы и вектора} Примерами структурных операций является \textit{транспонирование}, \textit{взятие подматрицы} и \textit{взятие элемента по индексу}. \begin{definition}[Транспонирование матрицы] -Пусть дана матрица $M_{n\times m}$. Тогда результат её \emph{транспонирования}, это такая матрица $M'_{m\times n}$, что $M'[i,j] = M[j,i]$ для всех $0\leq i \leq m - 1$ и $0\leq j \leq n - 1$. + Пусть дана матрица $M_{n\times m}$. Тогда результат её \emph{транспонирования}, это такая матрица $M'_{m\times n}$, что $M'[i,j] = M[j,i]$ для всех $0\leq i \leq m - 1$ и $0\leq j \leq n - 1$. -Операцию транспонирования принято обозначать как $M^{T}$. + Операцию транспонирования принято обозначать как $M^{T}$. \end{definition} \begin{example} -$$ -\begin{pmatrix} -``a" & ``ba" & ``cb" \\ -``ac" & ``bab" & ``b" \\ -\end{pmatrix}^T = -\begin{pmatrix} -``a" & ``ac" \\ -``ba" & ``bab" \\ -``cd" & ``b" \\ -\end{pmatrix} -$$ + $$ + \begin{pmatrix} + ``a" & ``ba" & ``cb" \\ + ``ac" & ``bab" & ``b" \\ + \end{pmatrix}^T = + \begin{pmatrix} + ``a" & ``ac" \\ + ``ba" & ``bab" \\ + ``cd" & ``b" \\ + \end{pmatrix} + $$ \end{example} \begin{definition}[Прямая сумма матриц] Пусть даны матрицы $M_{n_1\times m_1}$ и $N_{n_2\times m_2}$. Тогда \emph{прямой суммой} этих матриц называется матрица $L_{n_1+n_2 \times m_1+m_2}$ вида $$ - L = - \left[ + L = + \left[ \begin{matrix} M & 0 \\ 0 & N \end{matrix} - \right] + \right] $$ - + Где 0 обозначает нулевой блок. Прямая сумма обозначается $L = M \bigoplus N$. - -\end{definition} + +\end{definition} \begin{definition}[Взятие подматрицы] -Пусть дана матрица $M_{n\times m}$. Тогда -$ -M_{n\times m}[i_0..i_1,j_0..j_1] -$ - --- это такая $M'_{i_1 - i_0 + 1, j_1 - j_0 + 1}$ что $M'[i,j] = M[i_0 + i,j_0 + j]$ для всех $0\leq i \leq i_1 - i_0 + 1$ и $0\leq j \leq j_1 - j_0 + 1$. + Пусть дана матрица $M_{n\times m}$. Тогда + $ + M_{n\times m}[i_0..i_1,j_0..j_1] + $ + --- это такая $M'_{i_1 - i_0 + 1, j_1 - j_0 + 1}$ что $M'[i,j] = M[i_0 + i,j_0 + j]$ для всех $0\leq i \leq i_1 - i_0 + 1$ и $0\leq j \leq j_1 - j_0 + 1$. \end{definition} \begin{example} -$$ -\begin{pmatrix} -``a" & ``ba" & ``cb" \\ -``ac" & ``bab" & ``b" \\ -\end{pmatrix}[0..1,1..2] = -\begin{pmatrix} -``ba" & ``cb" \\ -``bab" & ``b" \\ -\end{pmatrix} -$$ + $$ + \begin{pmatrix} + ``a" & ``ba" & ``cb" \\ + ``ac" & ``bab" & ``b" \\ + \end{pmatrix}[0..1,1..2] = + \begin{pmatrix} + ``ba" & ``cb" \\ + ``bab" & ``b" \\ + \end{pmatrix} + $$ \end{example} \begin{definition} -\emph{Взятие элемента по индексу} --- это частный случай взятия подматрицы, когда начало и конец ``среза'' совпадают: -$ -M[i,j] = M[i..i,j..j] -$ + \emph{Взятие элемента по индексу} --- это частный случай взятия подматрицы, когда начало и конец ``среза'' совпадают: + $ + M[i,j] = M[i..i,j..j] + $ \end{definition} \begin{example} -$$ -\begin{pmatrix} -``a" & ``ba" & ``cb" \\ -``ac" & ``bab" & ``b" \\ -\end{pmatrix}[0,1] = ``ba" -$$ + $$ + \begin{pmatrix} + ``a" & ``ba" & ``cb" \\ + ``ac" & ``bab" & ``b" \\ + \end{pmatrix}[0,1] = ``ba" + $$ \end{example} Из алгебраических операций над матрицами нас в дальнейшем будут интересовать \textit{поэлементные операции}, \textit{скалярные операции}, \textit{матричное умножение}, \textit{произведение Кронекера}. @@ -479,249 +479,249 @@ \section{Матрицы и вектора} \begin{definition}[Поэлементные операции] -Пусть $G = (S,\circ)$ --- полугруппа\footnote{Здесь, как и в дальнейшем, требование к структуре быть полугруппой не обязательно. Оно лишь позволяет нам получить ассоциативность соответствующих операций над матрицами, что может оказаться полезным при дальнейшей работе.}, $M_{n \times m}, N_{n\times m}$ --- две матрицы одинакового размера над этой полугруппой. -Тогда -$ -ewise(M,N,\circ) = P_{n \times m} -$ -,такая, что $P[i,j] = M[i,j] \circ N[i,j]$. + Пусть $G = (S,\circ)$ --- полугруппа\sidenote{Здесь, как и в дальнейшем, требование к структуре быть полугруппой не обязательно. Оно лишь позволяет нам получить ассоциативность соответствующих операций над матрицами, что может оказаться полезным при дальнейшей работе.}, $M_{n \times m}, N_{n\times m}$ --- две матрицы одинакового размера над этой полугруппой. + Тогда + $ + ewise(M,N,\circ) = P_{n \times m} + $ + ,такая, что $P[i,j] = M[i,j] \circ N[i,j]$. \end{definition} \begin{example} -Пусть $G$ --- полугруппа строк с конкатенацией $\cdot$, + Пусть $G$ --- полугруппа строк с конкатенацией $\cdot$, -$$ -M = -\begin{pmatrix} -``a" & ``ba" & ``cb" \\ -``ac" & ``bab" & ``b" \\ -\end{pmatrix}, -$$ + $$ + M = + \begin{pmatrix} + ``a" & ``ba" & ``cb" \\ + ``ac" & ``bab" & ``b" \\ + \end{pmatrix}, + $$ -$$ -N = -\begin{pmatrix} -``c" & ``aa" & ``b" \\ -``a" & ``bac" & ``bb" \\ -\end{pmatrix}. -$$ + $$ + N = + \begin{pmatrix} + ``c" & ``aa" & ``b" \\ + ``a" & ``bac" & ``bb" \\ + \end{pmatrix}. + $$ -Тогда + Тогда -$$ -ewise(M,N, \cdot) = -\begin{pmatrix} -``ac" & ``baaa" & ``cbb" \\ -``aca" & ``babbac" & ``bbb" \\ -\end{pmatrix}. -$$ + $$ + ewise(M,N, \cdot) = + \begin{pmatrix} + ``ac" & ``baaa" & ``cbb" \\ + ``aca" & ``babbac" & ``bbb" \\ + \end{pmatrix}. + $$ \end{example} \begin{definition}[Скалярная операция] -Пусть $G = (S,\circ)$ --- полугруппа, $M_{n \times m}$ --- матрица над этой полугруппой, $x \in S$. -Тогда -$ -scalar(M,x,\circ) = P_{n \times m} -$ -, такая, что $P[i,j] = M[i,j] \circ x$, а -$ -scalar(x,M,\circ) = P_{n \times m} -$ -, такая, что $P[i,j] = x \circ M[i,j]$. + Пусть $G = (S,\circ)$ --- полугруппа, $M_{n \times m}$ --- матрица над этой полугруппой, $x \in S$. + Тогда + $ + scalar(M,x,\circ) = P_{n \times m} + $ + , такая, что $P[i,j] = M[i,j] \circ x$, а + $ + scalar(x,M,\circ) = P_{n \times m} + $ + , такая, что $P[i,j] = x \circ M[i,j]$. \end{definition} \begin{example} -Пусть $G$ --- полугруппа строк с конкатенацией $\cdot$, $x = ``c"$, + Пусть $G$ --- полугруппа строк с конкатенацией $\cdot$, $x = ``c"$, -$$ -M = -\begin{pmatrix} -``a" & ``ba" & ``cb" \\ -``ac" & ``bab" & ``b" \\ -\end{pmatrix}. -$$ + $$ + M = + \begin{pmatrix} + ``a" & ``ba" & ``cb" \\ + ``ac" & ``bab" & ``b" \\ + \end{pmatrix}. + $$ -Тогда -$$ -scalar(M,x, \cdot) = -\begin{pmatrix} -``ac" & ``bac" & ``cbc" \\ -``acc" & ``babc" & ``bc" \\ -\end{pmatrix}, -$$ + Тогда + $$ + scalar(M,x, \cdot) = + \begin{pmatrix} + ``ac" & ``bac" & ``cbc" \\ + ``acc" & ``babc" & ``bc" \\ + \end{pmatrix}, + $$ -$$ -scalar(x, M, \cdot) = -\begin{pmatrix} -``ca" & ``cba" & ``ccb" \\ -``cac" & ``cbab" & ``cb" \\ -\end{pmatrix}. -$$ + $$ + scalar(x, M, \cdot) = + \begin{pmatrix} + ``ca" & ``cba" & ``ccb" \\ + ``cac" & ``cbab" & ``cb" \\ + \end{pmatrix}. + $$ \end{example} \begin{definition}[Матричное умножение]\label{def:MxM} -Пусть $G = (S,\oplus, \otimes)$ --- полукольцо, $M_{n \times m}, N_{m\times k}$ --- две матрицы над этим полукольцом. -Тогда -$ -M\cdot N = P_{n \times k} -$ -, такая, что $P[i,j] = \bigoplus_{0 \leq l < m} M[i,l] \otimes N[l,j]$. + Пусть $G = (S,\oplus, \otimes)$ --- полукольцо, $M_{n \times m}, N_{m\times k}$ --- две матрицы над этим полукольцом. + Тогда + $ + M\cdot N = P_{n \times k} + $ + , такая, что $P[i,j] = \bigoplus_{0 \leq l < m} M[i,l] \otimes N[l,j]$. \end{definition} \begin{example} -Пусть $G$ --- полукольцо из примера~\ref{exmpl:semiring}, -$$ M = -\begin{pmatrix} -\{``a"\} & \{``a"\}\\ -\{``b"\} & \{``b"\}\\ -\end{pmatrix}, -$$ -$$ N = -\begin{pmatrix} -\{``c"\} \\ -\{``d"\} \\ -\end{pmatrix}. -$$ + Пусть $G$ --- полукольцо из примера~\ref{exmpl:semiring}, + $$ M = + \begin{pmatrix} + \{``a"\} & \{``a"\} \\ + \{``b"\} & \{``b"\} \\ + \end{pmatrix}, + $$ + $$ N = + \begin{pmatrix} + \{``c"\} \\ + \{``d"\} \\ + \end{pmatrix}. + $$ -Тогда -$$ -M \cdot N = -\begin{pmatrix} -\{``a" \cdot ``c"\} \cup \{``a" \cdot ``d"\} \\ -\{``b" \cdot ``c"\} \cup \{``b" \cdot ``d"\} -\end{pmatrix}= -\begin{pmatrix} -\{``ac" \ , ``ad"\} \\ -\{``bc" \ , ``bd"\} -\end{pmatrix}. -$$ + Тогда + $$ + M \cdot N = + \begin{pmatrix} + \{``a" \cdot ``c"\} \cup \{``a" \cdot ``d"\} \\ + \{``b" \cdot ``c"\} \cup \{``b" \cdot ``d"\} + \end{pmatrix}= + \begin{pmatrix} + \{``ac" \ , ``ad"\} \\ + \{``bc" \ , ``bd"\} + \end{pmatrix}. + $$ \end{example} \begin{definition}[Произведение Кронекера] -Пусть $G = (S,\circ)$ --- полугруппа, $M_{m\times n}$ и $N_{p\times q}$ --- две матрицы над этой полугруппой. -Тогда произведение Кронекера или тензорное произведение матриц $M$ и $N$ --- это блочная матрица $C$ размера $mp \times nq$, вычисляемая следующим образом: -$$ -C = A \otimes B = -\begin{pmatrix} -scalar(M[0,0],N,\circ) & \cdots & scalar(M[0,n-1],N,\circ) \\ -\vdots & \ddots & \vdots \\ -scalar(M[m-1,0],N,\circ) & \cdots & scalar(M[m-1,n-1],N,\circ) -\end{pmatrix} -$$ + Пусть $G = (S,\circ)$ --- полугруппа, $M_{m\times n}$ и $N_{p\times q}$ --- две матрицы над этой полугруппой. + Тогда произведение Кронекера или тензорное произведение матриц $M$ и $N$ --- это блочная матрица $C$ размера $mp \times nq$, вычисляемая следующим образом: + $$ + C = A \otimes B = + \begin{pmatrix} + scalar(M[0,0],N,\circ) & \cdots & scalar(M[0,n-1],N,\circ) \\ + \vdots & \ddots & \vdots \\ + scalar(M[m-1,0],N,\circ) & \cdots & scalar(M[m-1,n-1],N,\circ) + \end{pmatrix} + $$ \end{definition} -\begin{note}\label{note:KronIsNotCommutative} -Произведение Кронекера не является коммутативным. -При этом всегда существуют две матрицы перестановок $P$ и $Q$ такие, что $A \otimes B = P(B \otimes A)Q$. -\end{note} +\begin{assumption}\label{assumption:KronIsNotCommutative} + Произведение Кронекера не является коммутативным. + При этом всегда существуют две матрицы перестановок $P$ и $Q$ такие, что $A \otimes B = P(B \otimes A)Q$. +\end{assumption} \newcommand{\examplemtrx} { -\begin{pmatrix} -5 & 6 & 7 & 8 \\ -9 & 10 & 11 & 12 \\ -13 & 14 & 15 & 16 -\end{pmatrix} + \begin{pmatrix} + 5 & 6 & 7 & 8 \\ + 9 & 10 & 11 & 12 \\ + 13 & 14 & 15 & 16 + \end{pmatrix} } \begin{example} -Возьмём в качестве полугруппы целые числа с умножением. -$$M= -\begin{pmatrix} -1 & 2 \\ -3 & 4 -\end{pmatrix} -$$ -$$N=\examplemtrx -$$ -Тогда -\begin{align} -M \otimes N & = -\begin{pmatrix} -1 & 2 \\ -3 & 4 -\end{pmatrix} -\otimes -\examplemtrx = \notag \\ &= -\begin{pmatrix} -1\examplemtrx & 2\examplemtrx \\ -3\examplemtrx & 4\examplemtrx -\end{pmatrix} -=\notag \\ -&= -\left(\begin{array}{c c c c | c c c c} -5 & 6 & 7 & 8 & 10 & 12 & 14 & 16 \\ -9 & 10 & 11 & 12 & 18 & 20 & 22 & 24 \\ -13 & 14 & 15 & 16 & 26 & 28 & 30 & 32 \\ -\hline -15 & 18 & 21 & 24 & 20 & 24 & 28 & 32 \\ -27 & 30 & 33 & 36 & 36 & 40 & 44 & 48 \\ -39 & 42 & 45 & 48 & 52 & 56 & 60 & 64 -\end{array}\right) -\end{align} + Возьмём в качестве полугруппы целые числа с умножением. + $$M= + \begin{pmatrix} + 1 & 2 \\ + 3 & 4 + \end{pmatrix} + $$ + $$N=\examplemtrx + $$ + Тогда + \begin{align} + M \otimes N & = + \begin{pmatrix} + 1 & 2 \\ + 3 & 4 + \end{pmatrix} + \otimes + \examplemtrx = \notag \\ &= + \begin{pmatrix} + 1\examplemtrx & 2\examplemtrx \\ + 3\examplemtrx & 4\examplemtrx + \end{pmatrix} + =\notag \\ + & = + \left(\begin{array}{c c c c | c c c c} + 5 & 6 & 7 & 8 & 10 & 12 & 14 & 16 \\ + 9 & 10 & 11 & 12 & 18 & 20 & 22 & 24 \\ + 13 & 14 & 15 & 16 & 26 & 28 & 30 & 32 \\ + \hline + 15 & 18 & 21 & 24 & 20 & 24 & 28 & 32 \\ + 27 & 30 & 33 & 36 & 36 & 40 & 44 & 48 \\ + 39 & 42 & 45 & 48 & 52 & 56 & 60 & 64 + \end{array}\right) + \end{align} \end{example} \section{Теоретическая сложность умножения матриц} -В рамках такого раздела теории сложности, как мелкозернистая сложность (fine-grained complexity) задача умножения двух матриц оказалась достаточно важной, так как через вычислительную сложность этой задачи можно оценить сложность большого класса различных задач. С примерами таких задач можно ознакомиться в работе~\cite{Williams:2010:SEP:1917827.1918339}. Поэтому рассмотрим алгоритмы нахождения произведения двух матриц более подробно. Далее для простоты мы будем предполагать, что перемножаются две квадратные матрицы одинакового размера $n \times n$. +В рамках такого раздела теории сложности, как мелкозернистая сложность (fine-grained complexity) задача умножения двух матриц оказалась достаточно важной, так как через вычислительную сложность этой задачи можно оценить сложность большого класса различных задач. С примерами таких задач можно ознакомиться в работе~\sidecite{Williams:2010:SEP:1917827.1918339}. Поэтому рассмотрим алгоритмы нахождения произведения двух матриц более подробно. Далее для простоты мы будем предполагать, что перемножаются две квадратные матрицы одинакового размера $n \times n$. Для начала построим наивный алгоритм, сконструированный на основе определении произведения матриц. Такой алгоритм представлен на листинге~\ref{algo:MxM}. Его работу можно описать следующим образом: для каждой строки в первой матрице и для каждого столбца в второй матрице найти сумму произведений соответствующих элементов. Данная сумма будет значением соответствующей ячейки результирующей матрицы. \begin{algorithm} - \floatname{algorithm}{Listing} -\begin{algorithmic}[1]\label{algo:MxM} -\caption{Наивное перемножение матриц} -\Function{MatrixMult}{$M_1, M_2, G=(S,\oplus,\otimes)$} - \State{$M_3 =$ empty matrix of size $n \times n$} - \For {$i \in 0..n-1$} - \For {$j \in 0..n-1$} - \For {$k \in 0..n-1$} - \State{$M_3[i,j] = M_3[i,j] \oplus ( M_1[i,k] \otimes M_2[k,j])$} - \EndFor - \EndFor - \EndFor - \State{\Return $M_3$} - -\EndFunction -\end{algorithmic} + \floatname{algorithm}{Listing} + \begin{algorithmic}[1]\label{algo:MxM} + \caption{Наивное перемножение матриц} + \Function{MatrixMult}{$M_1, M_2, G=(S,\oplus,\otimes)$} + \State{$M_3 =$ empty matrix of size $n \times n$} + \For {$i \in 0..n-1$} + \For {$j \in 0..n-1$} + \For {$k \in 0..n-1$} + \State{$M_3[i,j] = M_3[i,j] \oplus ( M_1[i,k] \otimes M_2[k,j])$} + \EndFor + \EndFor + \EndFor + \State{\Return $M_3$} + + \EndFunction + \end{algorithmic} \end{algorithm} -Сложность наивного произведения двух матриц составляет $O(n^3)$ из-за тройного вложенного цикла, где каждый уровень вложенности привносит $n$ итераций. Но можно ли улучшить этот алгоритм? Первый положительный ответ был опубликовал Ф. Штрассен в 1969 году~\cite{Strassen1969}. Сложность предложенного им алгоритма --- $O(n^{\log_2 7}) \approx O(n^{2.81})$. Основная идея --- рекурсивное разбиение исходных матриц на блоки и вычисление их произведения с помощью только 7 умножений, а не 8. +Сложность наивного произведения двух матриц составляет $O(n^3)$ из-за тройного вложенного цикла, где каждый уровень вложенности привносит $n$ итераций. Но можно ли улучшить этот алгоритм? Первый положительный ответ был опубликовал Ф. Штрассен в 1969 году~\sidecite{Strassen1969}. Сложность предложенного им алгоритма --- $O(n^{\log_2 7}) \approx O(n^{2.81})$. Основная идея --- рекурсивное разбиение исходных матриц на блоки и вычисление их произведения с помощью только 7 умножений, а не 8. Рассмотрим алгоритм Штрассена более подробно. Пусть $A$ и $B$ --- две квадратные матрицы размера $2^n \times 2^n$ над кольцом $R=(S,\oplus,\otimes)$. Если размер умножаемых матриц не является натуральной степенью двойки, то дополняем исходные матрицы дополнительными нулевыми строками и столбцами. Наша задача найти матрицу $C = A \cdot B$. Разделим матрицы $A, B$ и $C$ на четыре равные по размеру блока. $$ -A = -\begin{pmatrix} - A_{1,1} & A_{1,2} \\ - A_{2,1} & A_{2,2} - \end{pmatrix} \mbox{ , } - B = - \begin{pmatrix} - B_{1,1} & B_{1,2} \\ - B_{2,1} & B_{2,2} - \end{pmatrix} \mbox{ , } - C = - \begin{pmatrix} - C_{1,1} & C_{1,2} \\ - C_{2,1} & C_{2,2} - \end{pmatrix} + A = + \begin{pmatrix} + A_{1,1} & A_{1,2} \\ + A_{2,1} & A_{2,2} + \end{pmatrix} \mbox{ , } + B = + \begin{pmatrix} + B_{1,1} & B_{1,2} \\ + B_{2,1} & B_{2,2} + \end{pmatrix} \mbox{ , } + C = + \begin{pmatrix} + C_{1,1} & C_{1,2} \\ + C_{2,1} & C_{2,2} + \end{pmatrix} $$ По определению произведения матриц выполняются следующие равенства. @@ -755,15 +755,15 @@ \section{Теоретическая сложность умножения мат При таком способе вычисления мы получаем на одно умножение подматриц меньше, чем при наивном подходе. Это и приводит, в конечном итоге, к улучшению сложности всего алгоритма, который основывается на рекурсивном повторении проделанной выше процедуры. -Впоследствии сложность постепенно понижалась в ряде работ, таких как ~\cite{Pan1978,BiniCapoRoma1979,Schonhage1981,CoppWino1982,CoppWino1990}. Было введено специальное обозначение для показателя степени в данной оценке: $\omega$. То есть сложность умножения матриц --- это $O(n^\omega)$, и задача сводится к уменьшению значения $\omega$. В настоящее время работа над уменьшением показателя степени продолжается и сейчас уже предложены решения с $\omega < 2.373$\footnote{В данной области достаточно регулярно появляются новые результаты, дающие сравнительно небольшие, в терминах абсолютных величин, изменения. Так, в 2021 была представлена работа, улучшающая значение $\omega$ в пятом знаке после запятой~\cite{alman2020refined}. Несмотря на кажущуюся несерьёзность результата, подобные работы имеют большое теоретическое значение, так как улучшают наше понимание исходной задачи и её свойств.}. +Впоследствии сложность постепенно понижалась в ряде работ, таких как ~\sidecite{Pan1978,BiniCapoRoma1979,Schonhage1981,CoppWino1982,CoppWino1990}. Было введено специальное обозначение для показателя степени в данной оценке: $\omega$. То есть сложность умножения матриц --- это $O(n^\omega)$, и задача сводится к уменьшению значения $\omega$. В настоящее время работа над уменьшением показателя степени продолжается и сейчас уже предложены решения с $\omega < 2.373$\sidenote{В данной области достаточно регулярно появляются новые результаты, дающие сравнительно небольшие, в терминах абсолютных величин, изменения. Так, в 2021 была представлена работа, улучшающая значение $\omega$ в пятом знаке после запятой~\cite{alman2020refined}. Несмотря на кажущуюся несерьёзность результата, подобные работы имеют большое теоретическое значение, так как улучшают наше понимание исходной задачи и её свойств.}. Всё тем же Ф. Штрассеном ещё в 1969 году была выдвинута гипотеза о том, что для достаточно больших $n$ существует алгоритм, который для любого сколь угодно маленького наперёд заданного $\varepsilon$ перемножает матрицы за $O(n^{2+\varepsilon})$. На текущий момент ни доказательства, ни опровержения этой гипотезы не предъявлено. -Важной особенностью указанного выше направления улучшения алгоритмов является то, что оно допускает использования (и даже основывается на использовании) более богатых алгебраических структур, чем требуется для определения умножения двух матриц. Так, уже алгоритм Штрасеена использует операцию вычитания, что приводит к необходимости иметь обратные элементы по сложению, а значит определять матрицы над кольцом. Хотя для исходного определения (\ref{def:MxM}) достаточно более бедной структуры. При этом, часто, структуры, возникающие в прикладных задачах кольцами не являются. Примерами могут служить тропическое (или $\{min,+\}$) полукольцо, играющее ключевую роль в тропической математике, или булево ($\{\vee,\wedge\}$) полукольцо, возникающее, например, при работе с отношениями\footnote{Вообще говоря, в некоторых прикладных задачах возникают структуры, не являющиеся даже полукольцом. Предположим, что есть три различных множества $S_1, S_2$ и $S_3$ и две двухместные функции $f:S_1 \times S_2 \to S_3$ и $g: S_3 \times S_3 \to S_3$. Этого достаточно, чтобы определить произведение двух матриц $M_1$ и $M_2$, построенных из элементов множеств $S_1$ и $S_2$ соответственно. Результирующая матрица будет состоять из элементов $S_3$. Как видно, функции не являются бинарными операциями в смысле нашего определения. Несмотря на кажущуюся экзотичность, подобные структуры возникают на практике при работе с графами и учитываются, например, в стандарте GraphBLAS (\url{https://graphblas.github.io/}), где, кстати, называются полукольцами, что выглядит не вполне корректно.}. Значит, описанные выше решения не применимы и вопрос о существовании алгоритма с менее чем кубической сложностью снова актуален. +Важной особенностью указанного выше направления улучшения алгоритмов является то, что оно допускает использования (и даже основывается на использовании) более богатых алгебраических структур, чем требуется для определения умножения двух матриц. Так, уже алгоритм Штрасеена использует операцию вычитания, что приводит к необходимости иметь обратные элементы по сложению, а значит определять матрицы над кольцом. Хотя для исходного определения (\ref{def:MxM}) достаточно более бедной структуры. При этом, часто, структуры, возникающие в прикладных задачах кольцами не являются. Примерами могут служить тропическое (или $\{min,+\}$) полукольцо, играющее ключевую роль в тропической математике, или булево ($\{\vee,\wedge\}$) полукольцо, возникающее, например, при работе с отношениями\sidenote{Вообще говоря, в некоторых прикладных задачах возникают структуры, не являющиеся даже полукольцом. Предположим, что есть три различных множества $S_1, S_2$ и $S_3$ и две двухместные функции $f:S_1 \times S_2 \to S_3$ и $g: S_3 \times S_3 \to S_3$. Этого достаточно, чтобы определить произведение двух матриц $M_1$ и $M_2$, построенных из элементов множеств $S_1$ и $S_2$ соответственно. Результирующая матрица будет состоять из элементов $S_3$. Как видно, функции не являются бинарными операциями в смысле нашего определения. Несмотря на кажущуюся экзотичность, подобные структуры возникают на практике при работе с графами и учитываются, например, в стандарте GraphBLAS (\url{https://graphblas.github.io/}), где, кстати, называются полукольцами, что выглядит не вполне корректно.}. Значит, описанные выше решения не применимы и вопрос о существовании алгоритма с менее чем кубической сложностью снова актуален. -В попытках ответить на этот вопрос появились так называемые комбинаторные алгоритмы умножения матриц\footnote{В противовес описанным выше, не являющимся комбинаторными. Стоит отметить, что строгое определение комбинаторных алгоритмов отсутствует, хотя этот термин и получил широкое употребление. В частности, Н.~Бансал (Nikhil Bansal) и Р.~Уильямс (Ryan Williams) в работе~\cite{5438580} дают определение комбинаторного алгоритма, но тут же замечают следующее: ``We would like to give a definition of ``combinatorial algorithm'', but this appears elusive. Although the term has been used in many of the cited references, nothing in the literature resembles a definition. For the purposes of this paper, let us think of a ``combinatorial algorithm'' simply as one that does not call an oracle for ring matrix multiplication.''. Ещё один вариант определения и его обсуждение можно найти в~\cite{das2018lower}.}. Классический результат в данной области --- это алгоритм четырёх русских, предложенный В. Л. Арлазаровым, Е. А. Диницем, М. А. Кронродом и И. А. Фараджевым в 1970 году~\cite{ArlDinKro70}, позволяющий перемножить матрицы над конечным полукольцом за $O(n^3/\log n)$. Лучшим результатом\footnote{В работе~\cite{das2018lower} предложен алгоритм со сложностью $\Omega(n^{7/3}/2^{O(\sqrt{\log n})})$, однако авторы утверждают, что сами не уверены в комбинаторности предложенного решения. По-видимому, полученные результаты ещё должны быть проверены сообществом.} в настоящее время является алгоритм со сложностью $\hat{O}(n^3/\log^4 n)$\footnote{Нотация $\hat{O}$ скрывает $poly(\log\log)$ коэффициенты.}~\cite{10.1007/978-3-662-47672-7_89}. +В попытках ответить на этот вопрос появились так называемые комбинаторные алгоритмы умножения матриц\sidenote{В противовес описанным выше, не являющимся комбинаторными. Стоит отметить, что строгое определение комбинаторных алгоритмов отсутствует, хотя этот термин и получил широкое употребление. В частности, Н.~Бансал (Nikhil Bansal) и Р.~Уильямс (Ryan Williams) в работе~\cite{5438580} дают определение комбинаторного алгоритма, но тут же замечают следующее: ``We would like to give a definition of ``combinatorial algorithm'', but this appears elusive. Although the term has been used in many of the cited references, nothing in the literature resembles a definition. For the purposes of this paper, let us think of a ``combinatorial algorithm'' simply as one that does not call an oracle for ring matrix multiplication.''. Ещё один вариант определения и его обсуждение можно найти в~\cite{das2018lower}.}. Классический результат в данной области --- это алгоритм четырёх русских, предложенный В. Л. Арлазаровым, Е. А. Диницем, М. А. Кронродом и И. А. Фараджевым в 1970 году~\sidecite{ArlDinKro70}, позволяющий перемножить матрицы над конечным полукольцом за $O(n^3/\log n)$. Лучшим результатом\sidenote{В работе~\cite{das2018lower} предложен алгоритм со сложностью $\Omega(n^{7/3}/2^{O(\sqrt{\log n})})$, однако авторы утверждают, что сами не уверены в комбинаторности предложенного решения. По-видимому, полученные результаты ещё должны быть проверены сообществом.} в настоящее время является алгоритм со сложностью $\hat{O}(n^3/\log^4 n)$\sidenote{Нотация $\hat{O}$ скрывает $poly(\log\log)$ коэффициенты.}~\cite{10.1007/978-3-662-47672-7_89}. -Как видим, особенности алгебраических структур накладывают серьёзные ограничения на возможности конструирования алгоритмов. Отметим, что, хотя, в указанных случаях и предлагаются решения лучшие, чем наивное кубическое, они обладают принципиально разной асимптотической сложностью. в первом случае сложность оценивается полиномом, степень которого меньше третьей. Такие решения принято называть \textit{истинно субкубическими} (truly subcubic). В то время как в случае комбинаторных алгоритмов степень полинома остается прежней, третьей, хотя сложность и уменьшается на логарифмический фактор. Такие решения принято называть \textit{слегка субкубическими} (mildly subcubic). Естественный вопрос о существовании истинно субкубического алгоритма перемножения матриц над полукольцами (или же комбинаторного перемножения матриц) всё ещё не решён\footnote{Один из кандидатов --- работа~\cite{das2018lower}, однако на текущий момент предложенное в ней решение требует проверки.}. +Как видим, особенности алгебраических структур накладывают серьёзные ограничения на возможности конструирования алгоритмов. Отметим, что, хотя, в указанных случаях и предлагаются решения лучшие, чем наивное кубическое, они обладают принципиально разной асимптотической сложностью. в первом случае сложность оценивается полиномом, степень которого меньше третьей. Такие решения принято называть \textit{истинно субкубическими} (truly subcubic). В то время как в случае комбинаторных алгоритмов степень полинома остается прежней, третьей, хотя сложность и уменьшается на логарифмический фактор. Такие решения принято называть \textit{слегка субкубическими} (mildly subcubic). Естественный вопрос о существовании истинно субкубического алгоритма перемножения матриц над полукольцами (или же комбинаторного перемножения матриц) всё ещё не решён\sidenote{Один из кандидатов --- работа~\cite{das2018lower}, однако на текущий момент предложенное в ней решение требует проверки.}. %Заметим, что скалярная операция --- это частный случай произвеления Кронекера: достаточно превратить элемент носителя полугруппы в матрицу размера $1\times 1$. diff --git a/tex/kao.sty b/tex/kao.sty new file mode 100644 index 0000000..53a61ce --- /dev/null +++ b/tex/kao.sty @@ -0,0 +1,1427 @@ +\ProvidesPackage{kao} + +%---------------------------------------------------------------------------------------- +% DECLARE KAO +%---------------------------------------------------------------------------------------- + +\DefineFamily{kao}% Define the family name +\DefineFamilyMember{kao}% Add a member to the family +\DefineFamilyKey{kao}{secnumdepth}[1]{\setcounter{secnumdepth}{#1}\FamilyKeyStateProcessed}% Define a key and a default value +\FamilyProcessOptions{kao}% Process the options + +%---------------------------------------------------------------------------------------- +% USEFUL PACKAGES AND COMMANDS +%---------------------------------------------------------------------------------------- + +\RequirePackage{kvoptions} % Handle package options +\RequirePackage{etoolbox} % Easy programming to modify TeX stuff +\RequirePackage{calc} % Make calculations +\RequirePackage[usenames,dvipsnames,table]{xcolor} % Colours +\RequirePackage{iftex} % Check whether XeTeX is being used +\RequirePackage{xifthen} % Easy conditionals +\RequirePackage{options} % Manage class options +\RequirePackage{xparse} % Parse arguments for macros +\RequirePackage{xpatch} % Patch LaTeX code in external packages +\RequirePackage{xstring} % Parse strings +\RequirePackage{afterpage} % Run commands after specific pages +\RequirePackage{imakeidx} % For the index; must be loaded before the 'caption' and 'hyperref' packages +\RequirePackage{varioref} % For the cross-references; must be loaded before the 'hyperref' and 'cleveref' packages +\AtEndPreamble{\RequirePackage{scrhack}} % Make some packages compatible with KOMAScript + +% Define \Ifthispageodd (with a capital 'i') to make kaobook compatible with older KOMAScript versions +\@ifpackagelater{scrbase}{2019/12/22}{% +}{% + \let\Ifthispageodd\ifthispageodd% +} + +%---------------------------------------------------------------------------------------- +% KAO-SPECIFIC OPTIONS +%---------------------------------------------------------------------------------------- + +% Set up the package options +\SetupKeyvalOptions{ + family = kao, + prefix = kao@ +} + +% https://tex.stackexchange.com/questions/47576/combining-ifxetex-and-ifluatex-with-the-logical-or-operation +% Introduce a command to find out whether the compiler is XeTeX or LuaTeX +\newif\ifxetexorluatex +\ifxetex + \xetexorluatextrue +\else + \ifluatex + \xetexorluatextrue + \else + \xetexorluatexfalse + \fi +\fi + +\ifxetexorluatex + \newcommand{\kao@defaultfontmethod}{modern} +\else + \newcommand{\kao@defaultfontmethod}{tex} +\fi + +% Set default based on rendering engine +\DeclareStringOption[\kao@defaultfontmethod]{fontmethod} + +\ProcessKeyvalOptions{kao} + +%---------------------------------------------------------------------------------------- +% TITLE AND AUTHOR MACROS +%---------------------------------------------------------------------------------------- + +% Provide an optional argument to the \title command in which to store a plain text title, without any formatting +% Usage: \title[Plain Title]{Actual Title} +\newcommand{\@plaintitle}{} +\renewcommand{\title}[2][]{% + \gdef\@title{#2} % Store the full title in @title + \ifthenelse{\isempty{#1}}{ % If there is no plain title + \renewcommand{\@plaintitle}{\@title} % Use full title + }{ % If there is a plain title + \renewcommand{\@plaintitle}{#1} % Use provided plain-text title + }% + \hypersetup{pdftitle={\@plaintitle}} % Set the PDF metadata title +} + +% Provide an optional argument to the \author command in which to store a plain text author, without any formatting +% Usage: \author[Plain Author]{Actual Author} +\newcommand{\@plainauthor}{} +\renewcommand{\author}[2][]{% + \gdef\@author{#2} % Store the full author in @author + \ifthenelse{\isempty{#1}}{ % If there is no plain author + \renewcommand{\@plainauthor}{\@author}% Use full author + }{ % If there is a plain author + \renewcommand{\@plainauthor}{#1}% Use provided plain-text author + }% + \hypersetup{pdfauthor={\@plainauthor}} % Set the PDF metadata author +} + +% Make a bookmark to the title page +\pretocmd{\maketitle}{\pdfbookmark[1]{\@plaintitle}{title}}{}{}% + +%---------------------------------------------------------------------------------------- +% PAGE LAYOUT +%---------------------------------------------------------------------------------------- + +% Define lengths to set the scale of the document. Changing these +% lengths should affect all the other pagesize-dependent elements in the +% layout, such as the geometry of the page, the spacing between +% paragraphs, and so on. (As of now, not all the elements rely on hscale +% and vscale; future work will address this shortcoming.) +\newlength{\hscale} +\newlength{\vscale} + +% By default, the scales are set to work for a4paper +\setlength{\hscale}{1mm} +\setlength{\vscale}{1mm} + +% Define hscale and vscale for all types of paper +\@ifclasswith{\@baseclass}{a0paper}{\setlength{\hscale}{4mm}\setlength{\vscale}{4mm}}{} +\@ifclasswith{\@baseclass}{a1paper}{\setlength{\hscale}{2.828mm}\setlength{\vscale}{2.828mm}}{} +\@ifclasswith{\@baseclass}{a2paper}{\setlength{\hscale}{2mm}\setlength{\vscale}{2mm}}{} +\@ifclasswith{\@baseclass}{a3paper}{\setlength{\hscale}{1.414mm}\setlength{\vscale}{1.414mm}}{} +\@ifclasswith{\@baseclass}{a4paper}{\setlength{\hscale}{1mm}\setlength{\vscale}{1mm}}{} +\@ifclasswith{\@baseclass}{a5paper}{\setlength{\hscale}{0.704mm}\setlength{\vscale}{0.704mm}}{} +\@ifclasswith{\@baseclass}{a6paper}{\setlength{\hscale}{0.5mm}\setlength{\vscale}{0.5mm}}{} +\@ifclasswith{\@baseclass}{b0paper}{\setlength{\hscale}{4.761mm}\setlength{\vscale}{4.761mm}}{} +\@ifclasswith{\@baseclass}{b1paper}{\setlength{\hscale}{3.367mm}\setlength{\vscale}{3.367mm}}{} +\@ifclasswith{\@baseclass}{b2paper}{\setlength{\hscale}{2.380mm}\setlength{\vscale}{2.380mm}}{} +\@ifclasswith{\@baseclass}{b3paper}{\setlength{\hscale}{1.681mm}\setlength{\vscale}{1.681mm}}{} +\@ifclasswith{\@baseclass}{b4paper}{\setlength{\hscale}{1.190mm}\setlength{\vscale}{1.190mm}}{} +\@ifclasswith{\@baseclass}{b5paper}{\setlength{\hscale}{0.837mm}\setlength{\vscale}{0.837mm}}{} +\@ifclasswith{\@baseclass}{b6paper}{\setlength{\hscale}{0.570mm}\setlength{\vscale}{0.570mm}}{} +\@ifclasswith{\@baseclass}{c0paper}{\setlength{\hscale}{4.367mm}\setlength{\vscale}{4.367mm}}{} +\@ifclasswith{\@baseclass}{c1paper}{\setlength{\hscale}{3.085mm}\setlength{\vscale}{3.085mm}}{} +\@ifclasswith{\@baseclass}{c2paper}{\setlength{\hscale}{2.180mm}\setlength{\vscale}{2.180mm}}{} +\@ifclasswith{\@baseclass}{c3paper}{\setlength{\hscale}{1.542mm}\setlength{\vscale}{1.542mm}}{} +\@ifclasswith{\@baseclass}{c4paper}{\setlength{\hscale}{1.090mm}\setlength{\vscale}{1.090mm}}{} +\@ifclasswith{\@baseclass}{c5paper}{\setlength{\hscale}{0.771mm}\setlength{\vscale}{0.771mm}}{} +\@ifclasswith{\@baseclass}{c6paper}{\setlength{\hscale}{0.542mm}\setlength{\vscale}{0.542mm}}{} +\@ifclasswith{\@baseclass}{b0j}{\setlength{\hscale}{4.904mm}\setlength{\vscale}{4.904mm}}{} +\@ifclasswith{\@baseclass}{b1j}{\setlength{\hscale}{3.467mm}\setlength{\vscale}{3.467mm}}{} +\@ifclasswith{\@baseclass}{b2j}{\setlength{\hscale}{2.452mm}\setlength{\vscale}{2.452mm}}{} +\@ifclasswith{\@baseclass}{b3j}{\setlength{\hscale}{1.733mm}\setlength{\vscale}{1.733mm}}{} +\@ifclasswith{\@baseclass}{b4j}{\setlength{\hscale}{1.226mm}\setlength{\vscale}{1.226mm}}{} +\@ifclasswith{\@baseclass}{b5j}{\setlength{\hscale}{0.867mm}\setlength{\vscale}{0.867mm}}{} +\@ifclasswith{\@baseclass}{b6j}{\setlength{\hscale}{0.613mm}\setlength{\vscale}{0.613mm}}{} +\@ifclasswith{\@baseclass}{ansiapaper}{\setlength{\hscale}{1.028mm}\setlength{\vscale}{0.939mm}}{} +\@ifclasswith{\@baseclass}{ansibpaper}{\setlength{\hscale}{1.328mm}\setlength{\vscale}{1.454mm}}{} +\@ifclasswith{\@baseclass}{ansicpaper}{\setlength{\hscale}{2.057mm}\setlength{\vscale}{1.882mm}}{} +\@ifclasswith{\@baseclass}{ansidpaper}{\setlength{\hscale}{2.662mm}\setlength{\vscale}{2.909mm}}{} +\@ifclasswith{\@baseclass}{ansiepaper}{\setlength{\hscale}{4.114mm}\setlength{\vscale}{3.764mm}}{} +\@ifclasswith{\@baseclass}{letterpaper}{\setlength{\hscale}{1.028mm}\setlength{\vscale}{0.939mm}}{} +\@ifclasswith{\@baseclass}{executivepaper}{\setlength{\hscale}{0.876mm}\setlength{\vscale}{0.898mm}}{} +\@ifclasswith{\@baseclass}{legalpaper}{\setlength{\hscale}{1.028mm}\setlength{\vscale}{1.198mm}}{} +\@ifclasswith{\@baseclass}{smallpocketpaper}{\setlength{\hscale}{0.571mm}\setlength{\vscale}{0.639mm}}{} +\@ifclasswith{\@baseclass}{pocketpaper}{\setlength{\hscale}{0.642mm}\setlength{\vscale}{0.723mm}}{} +\@ifclasswith{\@baseclass}{juvenilepaper}{\setlength{\hscale}{0.738mm}\setlength{\vscale}{0.740mm}}{} +\@ifclasswith{\@baseclass}{smallphotopaper}{\setlength{\hscale}{0.809mm}\setlength{\vscale}{0.572mm}}{} +\@ifclasswith{\@baseclass}{photopaper}{\setlength{\hscale}{1.00mm}\setlength{\vscale}{0.707mm}}{} +\@ifclasswith{\@baseclass}{appendixpaper}{\setlength{\hscale}{1.000mm}\setlength{\vscale}{0.505mm}}{} +\@ifclasswith{\@baseclass}{cookpaper}{\setlength{\hscale}{0.809mm}\setlength{\vscale}{0.740mm}}{} +\@ifclasswith{\@baseclass}{illustratedpaper}{\setlength{\hscale}{0.905mm}\setlength{\vscale}{0.909mm}}{} +\@ifclasswith{\@baseclass}{f24paper}{\setlength{\hscale}{0.762mm}\setlength{\vscale}{0.808mm}}{} +\@ifclasswith{\@baseclass}{a4paperlandscape}{\setlength{\hscale}{1.414mm}\setlength{\vscale}{0.707mm}}{} +\@ifclasswith{\@baseclass}{169paperlandscape}{\setlength{\hscale}{1.414mm}\setlength{\vscale}{0.562mm}}{} + +% Set the default page layout +\RequirePackage[ + paperwidth=210\hscale, + paperheight=297\vscale, +]{geometry} + +% Command to choose among the three possible layouts +\DeclareDocumentCommand{\pagelayout}{m}{% + \ifthenelse{\equal{margin}{#1}}{\marginlayout\marginfloatsetup}{}% + \ifthenelse{\equal{wide}{#1}}{\widelayout\widefloatsetup}{}% + \ifthenelse{\equal{fullwidth}{#1}}{\fullwidthlayout\widefloatsetup}{}% +} + +\newif\ifwidelayout% +\def\IfWideLayout{% + \ifwidelayout% + \expandafter\@firstoftwo% + \else% + \expandafter\@secondoftwo% + \fi% +} + +% Layout #1: large margins +\newcommand{\marginlayout}{% + \newgeometry{ + top=27.4\vscale, + bottom=27.4\vscale, + inner=24.8\hscale, + textwidth=107\hscale, + marginparsep=6.2\hscale, + marginparwidth=47.7\hscale, + }% + \recalchead% + \widelayoutfalse% +} + +% Layout #2: small, symmetric margins +\newcommand{\widelayout}{% + \newgeometry{ + top=27.4\vscale, + bottom=27.4\vscale, + inner=24.8\hscale, + outer=24.8\hscale, + marginparsep=0mm, + marginparwidth=0mm, + }% + \recalchead% + \widelayouttrue% +} + +% Layout #3: no margins and no space above or below the body +\newcommand{\fullwidthpage}{% + \newgeometry{ + top=0mm, + bottom=0mm, + inner=0mm, + outer=0mm, + marginparwidth=0mm, + marginparsep=0mm, + }% + \recalchead% + \widelayouttrue% +} + +% Set the default page layout +\AtBeginDocument{\pagelayout{margin}} + +%---------------------------------------------------------------------------------------- +% HEADERS AND FOOTERS +%---------------------------------------------------------------------------------------- + +\RequirePackage{scrlayer-scrpage} % Customise head and foot regions + +% Set the header height to prevent a warning +%\setlength{\headheight}{27.4\vscale} +% Increase the space between header and text +\setlength{\headsep}{11\vscale} + +% Define some LaTeX lengths used in the page headers +\newlength{\headtextwidth} % This is the width of the text +\newlength{\headmarginparsep} % This is the width of the whitespace between text and margin +\newlength{\headmarginparwidth} % This is the width of the margin +\newlength{\headtotal} % This is the total width of the header +\newlength{\contentwidth} % An alias for \headtotal +\newcommand{\recalchead}{% Command to recalculate the header-related length when needed + \setlength{\headtextwidth}{\textwidth}% + \setlength{\headmarginparsep}{\marginparsep}% + \setlength{\headmarginparwidth}{\marginparwidth}% + \setlength{\headtotal}{\headtextwidth+\headmarginparsep+\headmarginparwidth}% + \setlength{\contentwidth}{\headtotal}% +} + +\AtBeginDocument{% Recalculate the header-related lengths + \recalchead% +} + +% Header style with chapter number, chapter title, and page in the header (used throughout the document) +\renewpagestyle{scrheadings}{% + {\smash{\hspace{-\headmarginparwidth}\hspace{-\headmarginparsep}\makebox[\headtotal][l]{% + \makebox[7\hscale][r]{\thepage}% + \makebox[3\hscale]{}\rule[-1mm]{0.5pt}{19\vscale-1mm}\makebox[3\hscale]{}% + \makebox[\headtextwidth][l]{\leftmark}}}}% + {\smash{\makebox[0pt][l]{\makebox[\headtotal][r]{% + \makebox[\headtextwidth][r]{\hfill\rightmark}% + \makebox[3\hscale]{}\rule[-1mm]{0.5pt}{19\vscale-1mm}\makebox[3\hscale]{}% + \makebox[7\hscale][l]{\thepage}}}}}% + {\smash{\makebox[0pt][l]{\makebox[\headtotal][r]{% + \makebox[\headtextwidth][r]{\hfill\rightmark}% + \makebox[3\hscale]{}\rule[-1mm]{0.5pt}{19\vscale-1mm}\makebox[3\hscale]{}% + \makebox[7\hscale][l]{\thepage}}}}}% +}{% + {}% + {}% + {}% +} + +% Header style with neither header nor footer (used for special pages) +\renewpagestyle{plain.scrheadings}{% + {}% + {}% + {}% +}{% + {}% + {}% + {}% +} + +% Header style with an empty header and the page number in the footer +\newpagestyle{pagenum.scrheadings}{% + {}% + {}% + {}% +}{% + {\makebox[\textwidth][r]{\thepage}}% + {\makebox[\textwidth][l]{\thepage}}% + {\makebox[\textwidth][l]{\thepage}}% +} + +% Header style with an empty header and the page number in the footer +\newpagestyle{centeredpagenum.scrheadings}{% + {}% + {}% + {}% +}{% + {\hspace{-\headmarginparwidth}\hspace{-\headmarginparsep}\makebox[\headtotal][l]{\hfill\thepage\hfill}} + {\makebox[0pt][l]{\makebox[\headtotal][r]{\hfill\thepage\hfill}}}% + {\makebox[0pt][l]{\makebox[\headtotal][r]{\hfill\thepage\hfill}}}% +} + +% Command to print a blank page +\newcommand\blankpage{% + \null% + \thispagestyle{empty}% + \newpage% +} + +% Set the default page style +\pagestyle{plain.scrheadings} + +%---------------------------------------------------------------------------------------- +% PARAGRAPH FORMATTING +%---------------------------------------------------------------------------------------- + +\RequirePackage{ragged2e} % Required to achieve better ragged paragraphs +\RequirePackage{setspace} % Required to easily set the space between lines +\RequirePackage{hyphenat} % Hyphenation for special fonts +\RequirePackage{microtype} % Improves character and word spacing +\RequirePackage{needspace} % Required to prevent page break right after a sectioning command +\RequirePackage{xspace} % Better print trailing whitespace + +% TODO: recognize space/indent justified/raggedright class options + +% Settings for a normal paragraph +\newcommand{\@body@par}{% + \justifying% Justify text + \singlespacing% Set the interline space to a single line + \frenchspacing% No additional space after periods + \normalfont% Use the default font + \normalsize% Use the default size +} + +% Settings for paragraphs in the margins +\newcommand{\@margin@par}{% + \justifying% justify text + \setlength{\RaggedRightParindent}{0em}% Suppress indentation + \setlength{\parindent}{0em}% Suppress indentation + \setlength{\parskip}{0.5pc}% Set the space between paragraphs + %\singlespacing% Set the space between lines + \frenchspacing% No additional space after periods + \normalfont% Use the default font + \footnotesize% Use a smaller size +} + +% By default, use @body@par settings +\@body@par + +%---------------------------------------------------------------------------------------- +% WIDE PARAGRAPHS +%---------------------------------------------------------------------------------------- + +% Environment for a wide paragraph +\NewDocumentEnvironment{widepar}{}{% + \if@twoside% + \Ifthispageodd{% + \begin{addmargin}[0cm]{-\marginparwidth-\marginparsep}% + }{% + \begin{addmargin}[-\marginparwidth-\marginparsep]{0cm}% + }% + \else% + \begin{addmargin}[0cm]{-\marginparwidth-\marginparsep}% + \fi% + }{% + \end{addmargin}% +} + +% Environment for a full width paragraph +\NewDocumentEnvironment{fullwidthpar}{}{% + \if@twoside% + \Ifthispageodd{% + \begin{addmargin}[-1in-\hoffset-\oddsidemargin]{-\paperwidth+1in+\hoffset+\oddsidemargin+\textwidth}% + }{% + \begin{addmargin}[-\paperwidth+1in+\hoffset+\oddsidemargin+\textwidth]{-\paperwidth+1in+\hoffset+\oddsidemargin+\marginparsep+\marginparwidth+\textwidth}% + }% + \else% + \begin{addmargin}[-1in-\hoffset-\oddsidemargin]{-\paperwidth+1in+\hoffset+\oddsidemargin+\textwidth}% + \fi% + }{% + \end{addmargin}% +} + +% Environment for a wide equation +\NewDocumentEnvironment{wideequation}{}{% + \begin{widepar}% + \begin{equation}% + }{% + \end{equation}% + \end{widepar}% +} + +%---------------------------------------------------------------------------------------- +% FOOTNOTES, MARGINNOTES AND SIDENOTES +%---------------------------------------------------------------------------------------- + +\RequirePackage[section]{placeins} % Prevent floats to cross sections +\extrafloats{100} % Require more floats + +\RequirePackage{marginnote} % Provides options for margin notes +%\RequirePackage{marginfix} % Make marginpars float freely; it should not be loaded as it prevents the marginnotes to stay aligned with the main text +\RequirePackage{sidenotes} % Use sidenotes +\RequirePackage{chngcntr} % Reset counters at sections + +% TODO: see also page 440 of the KOMA-script guide +\RequirePackage[ + bottom, + symbol*, + hang, + flushmargin, + % perpage, + stable, +]{footmisc} % Required to set up the footnotes +\RequirePackage{footnotebackref} % Creates back references from footnotes to text + +% Fix the color of the footnote marker when back-referenced +\patchcmd{\footref}{\ref}{\hypersetup{colorlinks=black}\ref}{}{}% +% Workaround to fix back references +\edef\BackrefFootnoteTag{bhfn:\theBackrefHyperFootnoteCounter}% + +% FIXME: I am not able to choose the paragraph layout of footnotes, probably the footnotes package conflicts with scrbook. +%\renewcommand{\footnotelayout}{\@margin@par} + +%---------------------------------------------------------------------------------------- + +% Justify and format margin notes +\renewcommand*{\raggedleftmarginnote}{} % Suppress left margin +\renewcommand*{\raggedrightmarginnote}{} % Suppress right margin +\renewcommand*{\marginfont}{\@margin@par} % Format marginnotes according to \@marginpar (see above) +\renewcommand{\marginnotevadjust}{0.8\vscale} % Bring all marginnotes downwards a bit +%\marginposadjustment=1\vscale % Bring downwards also the marginpars +%\marginheightadjustment=10cm % Adjust the height of the margins for each page +%\RequirePackage[marginnote=true]{snotez} % Provides options for sidenotes + +% Copied from snotez's \sidenote +\def\kao@if@nblskip#1{% + \expandafter\ifx\@car#1\@nil*% + \expandafter\@firstoftwo% + \else% + \expandafter\@secondoftwo% + \fi% +} + +% Command to detect whether we are inside a tcolorbox environment +\newif\ifinfloat % First, set this flag whenever we are in a tcolorbox environment... +\AtBeginEnvironment{tcolorbox}{\infloattrue\renewcommand{\marginnotevadjust}{-1.4\vscale}} +\AtBeginEnvironment{minipage}{\infloattrue} + +\def\IfInFloatingEnvir{% ...Then, detect the flag + \ifinfloat% + \expandafter\@firstoftwo% + \else% + \expandafter\@secondoftwo% + \fi% +} + + +% Redefine the command to print marginnotes: +% (a) the optional offset argument goes at the first position +% (b) the offset can also be a multiple of baselineskip, like for snotez's \sidenote +% Usage: \marginnote[]{Text of the note.} +\let\oldmarginnote\marginnote% +\RenewDocumentCommand\marginnote{ o m }{% + \IfNoValueOrEmptyTF{#1}{% + \IfInFloatingEnvir{% + \oldmarginnote{#2}% + }{% + \marginpar{\@margin@par#2}% + }% + }{% + \oldmarginnote{#2}[\kao@if@nblskip{#1}{\@cdr#1\@nil\baselineskip}{#1}]% + }% +} + +% Initially set the sidenote counter to zero instead of 1, and update it before printing the sidenote. +\setcounter{sidenote}{0}% +\RenewDocumentCommand\sidenote{ o o +m }{% + \IfNoValueOrEmptyTF{#1}{% + \refstepcounter{sidenote}% This command has been moved here + }{% + }% + \sidenotemark[#1]% + \sidenotetext[#1][#2]{#3}% + \@sidenotes@multimarker% +} + +% Formatting sidenote markers +\RenewDocumentCommand\@sidenotes@thesidenotemark{ m }{% Format the marker + \leavevmode% + \ifhmode% + \edef\@x@sf{\the\spacefactor}% + \nobreak% + \fi% + \hbox{\@textsuperscript{\normalfont#1}}% + \ifhmode% + \spacefactor\@x@sf% + \fi% + \relax% +}% + +% Formatting the sidenote text +\RenewDocumentCommand\sidenotetext{ o o +m }{% number, offset, text + \IfNoValueOrEmptyTF{#1}{% + \marginnote[#2]{\thesidenote:\enskip#3}% + }{% + \marginnote[#2]{#1:\enskip#3}% + }% +} + +%---------------------------------------------------------------------------------------- +% FIGURES, TABLES, LISTINGS AND CAPTIONS +%---------------------------------------------------------------------------------------- + +\RequirePackage{graphicx} % Include figures +\setkeys{Gin}{width=\linewidth,totalheight=\textheight,keepaspectratio} % Improves figure scaling +\RequirePackage{tikz} % Allows to draw custom shapes +\RequirePackage{tikzpagenodes} % Allows to anchor tikz nodes to page elements +\RequirePackage{booktabs} % Nicer tables +\RequirePackage{multirow} % Cells occupying multiple rows in tables +\RequirePackage{multicol} % Multiple columns in dictionary +\RequirePackage{rotating} % Allows tables and figures to be rotated +\RequirePackage{listings} % Print code listings +%\RequirePackage{minted} +\RequirePackage[hypcap=true]{caption} % Correctly placed anchors for hyperlinks +% \RequirePackage{atbegshi} +% \RequirePackage{perpage} +\let\c@abspage\relax +% \newcommand{\pp@g@sidenote}{} +\RequirePackage{floatrow} % Set up captions of floats +%\RequirePackage{dblfloatfix} % Better positioning of wide figures and tables + +% Improve the figure placing (see https://www.overleaf.com/learn/latex/Tips) +\def\topfraction{.9}% +\def\textfraction{0.35}% +\def\floatpagefraction{0.8}% + +% Set the space between floats and main text +\renewcommand\FBaskip{.4\topskip}% +\renewcommand\FBbskip{\FBaskip}% + +% Tighten up space between displays (e.g., equations) and make symmetric (from tufte-latex) +\setlength\abovedisplayskip{6pt plus 2pt minus 4pt}% +\setlength\belowdisplayskip{6pt plus 2pt minus 4pt}% +\abovedisplayskip 10\p@ \@plus2\p@ \@minus5\p@% +\abovedisplayshortskip \z@ \@plus3\p@% +\belowdisplayskip \abovedisplayskip% +\belowdisplayshortskip 6\p@ \@plus3\p@ \@minus3\p@% + +\setlength\columnseprule{.4pt} % Set the width of vertical rules in tables + +% The marginfix package prevents the margin notes to stay aligned with the main text, so it cannot be used. However, we define the \marginskip command, which is the only command we need from that package. +\newcommand\marginskip[1]{% + \marginpar{\@margin@par\vspace{#1 - \baselineskip}}% We subtract the \baselineskip that we have in margin pars. +} + +\newlength{\kaomarginskipabove} % Specify the space above a marginfigure, margintable or marginlisting +\newlength{\kaomarginskipbelow} % Specify the space below a marginfigure, margintable or marginlisting +\setlength{\kaomarginskipabove}{3mm plus 2pt minus 2pt} +\setlength{\kaomarginskipbelow}{3mm plus 2pt minus 2pt} + +% Environment to hold a margin figure (from the sidenotes package) +% We redefine it here because we want to use our own caption formatting. +\RenewDocumentEnvironment{marginfigure}{o}{% + \FloatBarrier% + \marginskip{\kaomarginskipabove}% + \begin{lrbox}{\@sidenotes@marginfigurebox}% + \begin{minipage}{\marginparwidth}% + \captionsetup{type=figure}% + }{% + \end{minipage}% + \end{lrbox}% + \marginnote[#1]{\usebox{\@sidenotes@marginfigurebox}}% + \marginskip{\kaomarginskipbelow}% +} + +% Environment to hold a margin table (from the sidenotes package) +\RenewDocumentEnvironment{margintable}{o}{% + \FloatBarrier% + \marginskip{\kaomarginskipabove}% + \begin{lrbox}{\@sidenotes@margintablebox}% + \begin{minipage}{\marginparwidth}% + \captionsetup{type=table}% + }{% + \end{minipage}% + \end{lrbox}% + \marginnote[#1]{\usebox{\@sidenotes@margintablebox}}% + \marginskip{\kaomarginskipbelow}% +} + +% Environment to hold a margin listing +\newsavebox{\@sidenotes@marginlistingbox}% +\NewDocumentEnvironment{marginlisting}{o}{% The optional parameter is the vertical offset + \FloatBarrier% + \marginskip{\kaomarginskipabove}% + \begin{lrbox}{\@sidenotes@marginlistingbox}% + \begin{minipage}{\marginparwidth}% + \captionsetup{type=lstlisting}% + }{% + \end{minipage}% + \end{lrbox}% + \marginnote[#1]{\usebox{\@sidenotes@marginlistingbox}}% + \marginskip{\kaomarginskipbelow}% +} + +% Change the position of the captions +\DeclareFloatSeparators{marginparsep}{\hskip\marginparsep}% + +% Detect whether there is a caption in the current environment by switching the kaocaption toggle when \caption is called. If there is no caption, reset the floatsetup. Without this fix, the floatrow package will align the environment to the main text if there is a caption, but to the margin if there is no caption. +\newtoggle{kaocaption} +\AtBeginEnvironment{figure}{% + \let\oldcaption\caption% + \RenewDocumentCommand{\caption}{s o m}{% + \IfBooleanTF{#1}{% + \oldcaption*{#3}% + }{% + \IfValueTF{#2}{% + \oldcaption[#2]{#3}% + }{% + \oldcaption{#3}% + }% + }% + \toggletrue{kaocaption}% + }% +} +\AtEndEnvironment{figure}{% + \iftoggle{kaocaption}{% + }{% + \RawFloats% + \centering% + }% + \togglefalse{kaocaption}% +} +\AtBeginEnvironment{table}{% + \let\oldcaption\caption% + \RenewDocumentCommand{\caption}{s o m}{% + \IfBooleanTF{#1}{% + \oldcaption*{#3}% + }{% + \IfValueTF{#2}{% + \oldcaption[#2]{#3}% + }{% + \oldcaption{#3}% + }% + }% + \toggletrue{kaocaption}% + }% +} +\AtEndEnvironment{table}{% + \iftoggle{kaocaption}{% + }{% + \RawFloats% + \centering% + }% + \togglefalse{kaocaption}% +} + +% Change the formatting of the captions +\addtokomafont{captionlabel}{\bfseries} % Bold font for the figure label +% Declare a new style to format the caption according to \@margin@par (see above) +\DeclareCaptionFormat{margin}{\@margin@par #1#2#3} +% Declare a new caption style for lstlistings +\newsavebox\mycap +\DeclareCaptionFormat{llap}{% + \begin{lrbox}{\mycap}% + \begin{minipage}{\marginparwidth}% + \@margin@par #1:#2#3% + \end{minipage}% + \end{lrbox}% + \marginnote[0.2cm]{\usebox\mycap}% +} +% Set the global caption style +\captionsetup{ + format=margin, % Use the style previously declared + strut=no,% + %hypcap=true, % Links point to the top of the figure + singlelinecheck=false,% + %width=\marginparwidth, + indention=0pt, % Suppress indentation + parindent=0pt, % Suppress space between paragraphs + aboveskip=6pt, % Increase the space between the figure and the caption + belowskip=6pt, % Increase the space between the caption and the table +} + +% Needed to have continued figures and tables (https://en.wikibooks.org/wiki/LaTeX/Floats,_Figures_and_Captions#Figures_in_multiple_parts) +\DeclareCaptionLabelFormat{cont}{#1~#2\alph{ContinuedFloat}} +\captionsetup[ContinuedFloat]{labelformat=cont} + +% Captions for the 'margin' layout +\NewDocumentCommand{\marginfloatsetup}{}{% + \if@twoside% + \floatsetup[figure]{% Captions for figures + margins=hangoutside,% Put captions in the margins + facing=yes,% + capposition=beside,% + capbesideposition={bottom,outside},% + capbesideframe=yes,% + capbesidewidth=\marginparwidth,% Width of the caption equal to the width of the margin + capbesidesep=marginparsep,% + floatwidth=\textwidth,% Width of the figure equal to the width of the text + }% + \floatsetup[widefigure]{% Captions for wide figures + margins=hangoutside,% Put captions below the figure + facing=yes,% + capposition=bottom% + }% + \floatsetup[table]{% Captions for tables + margins=hangoutside,% Put captions in the margin + facing=yes,% + capposition=beside,% + capbesideposition={top,outside},% + %capbesideposition=outside, + capbesideframe=yes,% + capbesidewidth=\marginparwidth,% Width of the caption equal to the width of the margin + capbesidesep=marginparsep,% + floatwidth=\textwidth,% Width of the figure equal to the width of the text + }% + \floatsetup[widetable]{% Captions for wide tables + margins=hangoutside,% Put captions above the table + facing=yes,% + capposition=above% + }% + \floatsetup[longtable]{% Captions for longtables + margins=raggedright,% Overwrite the hangright setting from the `table' environment + %LTcapwidth=table,% Set the width of the caption equal to the table's + }% + \floatsetup[lstlisting]{% Captions for lstlistings + margins=hangoutside,% Put captions in the margin + facing=yes,% + capposition=beside,% + capbesideposition={top,outside},% + %capbesideposition=outside, + capbesideframe=yes,% + capbesidewidth=\marginparwidth,% Width of the caption equal to the width of the margin + capbesidesep=marginparsep,% + floatwidth=\textwidth,% Width of the figure equal to the width of the text + }% + \floatsetup[listing]{% Captions for listings (minted package) + margins=hangoutside,% Put captions in the margin + facing=yes,% + capposition=beside,% + capbesideposition={top,outside},% + %capbesideposition=outside, + capbesideframe=yes,% + capbesidewidth=\marginparwidth,% Width of the caption equal to the width of the margin + capbesidesep=marginparsep,% + floatwidth=\textwidth,%Width of the figure equal to the width of the text + }% + \captionsetup*[lstlisting]{% + format=llap,% + labelsep=space,% + singlelinecheck=no,% + belowskip=-0.6cm,% + }% + \else% + \floatsetup[figure]{% Captions for figures + margins=hangright,% Put captions in the margins + facing=yes,% + capposition=beside,% + capbesideposition={bottom,right},% + capbesideframe=yes,% + capbesidewidth=\marginparwidth,% Width of the caption equal to the width of the margin + capbesidesep=marginparsep,% + floatwidth=\textwidth,% Width of the figure equal to the width of the text + }% + \floatsetup[widefigure]{% Captions for wide figures + margins=hangright,% Put captions below the figure + facing=no,% + capposition=bottom% + }% + \floatsetup[table]{% Captions for tables + margins=hangright,% Put captions in the margin + facing=yes,% + capposition=beside,% + capbesideposition={top,right},% + %capbesideposition=outside, + capbesideframe=yes,% + capbesidewidth=\marginparwidth,% Width of the caption equal to the width of the margin + capbesidesep=marginparsep,% + floatwidth=\textwidth,% Width of the figure equal to the width of the text + }% + \floatsetup[widetable]{% Captions for wide tables + margins=hangright,% Put captions above the table + facing=no,% + capposition=above% + }% + \floatsetup[longtable]{% Captions for longtables + margins=raggedright,% Overwrite the hangright setting from the `table' environment + %LTcapwidth=table,% Set the width of the caption equal to the table's + }% + \floatsetup[lstlisting]{% Captions for lstlisting + margins=hangright,% Put captions in the margin + facing=yes,% + capposition=beside,% + capbesideposition={top,right},% + %capbesideposition=outside, + capbesideframe=yes,% + capbesidewidth=\marginparwidth,% Width of the caption equal to the width of the margin + capbesidesep=marginparsep,% + floatwidth=\textwidth,% Width of the figure equal to the width of the text + }% + \floatsetup[listing]{% Captions for listing (minted package) + margins=hangright,% Put captions in the margin + facing=yes,% + capposition=beside,% + capbesideposition={top,right},% + %capbesideposition=outside, + capbesideframe=yes,% + capbesidewidth=\marginparwidth,% Width of the caption equal to the width of the margin + capbesidesep=marginparsep,% + floatwidth=\textwidth,% Width of the figure equal to the width of the text + }% + \captionsetup*[lstlisting]{% + format=llap,% + labelsep=space,% + singlelinecheck=no,% + belowskip=-0.6cm,% + }% + \fi% +} + +% Captions for the 'wide' layout +\NewDocumentCommand{\widefloatsetup}{}{% + \floatsetup[figure]{ % Captions for figures + capposition=bottom,% + margins=centering,% + floatwidth=\textwidth% + } + \floatsetup[widefigure]{ % Captions for wide figures + margins=hangoutside, % Put captions below the figure + facing=yes,% + capposition=bottom% + } + \floatsetup[table]{ % Captions for tables + capposition=above,% + margins=centering,% + floatwidth=\textwidth% + } + \floatsetup[widetable]{ % Captions for wide tables + margins=hangoutside, % Put captions above the table + facing=yes,% + capposition=above% + } + \floatsetup[lstlisting]{ % Captions for lstlistings + capposition=above,% + margins=centering,% + floatwidth=\textwidth% + } + \floatsetup[listing]{ % Captions for listings (minted package) + capposition=above,% + margins=centering,% + floatwidth=\textwidth% + } + \captionsetup*[lstlisting]{% Captions style for lstlistings + %format=margin,% + labelsep=colon,% + strut=no,% + singlelinecheck=false,% + indention=0pt,% + parindent=0pt,% + aboveskip=6pt,% + belowskip=6pt,% + belowskip=-0.1cm% + } +} + +%---------------------------------------------------------------------------------------- +% TOC, LOF & LOT +%---------------------------------------------------------------------------------------- + +\RequirePackage{tocbasic} % Required to customise the TOC + +% Show an entry for the TOC in the TOC +\setuptoc{toc}{totoc} + +% Choose the levels in table of contents +\setcounter{tocdepth}{\subsectiontocdepth} + +% Customise the list of listings +\renewcommand{\lstlistlistingname}{List of Listings}% Change the title +\newcommand{\lstlistingtocdepth}{\sectiontocdepth}% Set the depth +\newcommand{\listoflistings}{\lstlistoflistings}% Provide the alias \listoflistings +\newcommand{\listoflstlistings}{\lstlistoflistings}% Provide the alias \listoflstlistings + +% Define the style for toc entries +\@ifpackagelater{scrbase}{2019/10/11}{% + \DeclareTOCStyleEntries[indent=0em,numwidth=2em,dynnumwidth=yes,pagenumberwidth=2.1em]{tocline}{figure,table,lstlisting}% + \DeclareTOCStyleEntries[dynnumwidth=yes]{tocline}{subsubsection,subsection,section,chapter,part}% + \DeclareTOCStyleEntries[pagenumberwidth=2.5em]{tocline}{chapter,part}% + \DeclareTOCStyleEntries[pagenumberwidth=2.1em]{tocline}{subsubsection,subsection,section}% +}{% + \DeclareTOCStyleEntries[indent=0em,numwidth=2em,dynnumwidth=yes]{tocline}{figure,table,lstlisting}% + \DeclareTOCStyleEntries[dynnumwidth=yes]{tocline}{subsubsection,subsection,section,chapter,part}% +} + +% Define the names for the headings +% \renewcaptionname{english}{\contentsname}{Detailed Contents} +% \renewcaptionname{english}{\listfigurename}{Figures} +% \renewcaptionname{english}{\listtablename}{Tables} +% \newcaptionname{english}{\listtheoremname}{Theorems} + +%---------------------------------------------------------------------------------------- +% MARGIN TOC +%---------------------------------------------------------------------------------------- + +\RequirePackage{etoc} % Required to insert local tables of contents + +\newcounter{margintocdepth} % Set the depth of the margintoc +\setcounter{margintocdepth}{\subsectiontocdepth} % By default to subsections + +\newlength{\mtocshift} % Length of the vertical offset used for margin tocs +\setlength{\mtocshift}{1\vscale}% \mtocshift is overridden by \setchapterstyle + +% Optional title for margintoc (by hCarlFelix, +% https://github.com/fmarotta/kaobook/issues/101) +% We want to create an additional entries in the toc which is to be used for the margintoc +% We define these as mtocsection and mtocsubsection for section and subsection` +\newcommand{\mtocsection}[1]{ + \etoctoccontentsline{mtocsection}{% + \ifnum\value{secnumdepth}>0 \protect\numberline{\thesection}% + \else \protect\nonumberline% + \fi #1}% +} +\newcommand{\mtocsubsection}[1]{ + \etoctoccontentsline{mtocsubsection}{% + \ifnum\value{secnumdepth}>1 \protect\numberline{\thesubsection}% + \else \protect\nonumberline% + \fi #1}% +} + +% Next, we redefine \section and \subsection so that they accept an additional parameter +% \section[alternative-title-for-toc]{title-as-written-in-text}[alternative-title-for-margintoc] + +% Adapted from Frank Mittelbach's answer at Stackexchange +% https://tex.stackexchange.com/a/109560/226693 +\let\oldsection\section % save the old command +\let\oldsubsection\subsection % save the old command + +\RenewDocumentCommand\section{s o m o}{% + \IfBooleanTF{#1}{% + \oldsection*{#3} + \IfNoValueF{#2}{% if TOC arg is given create a TOC entry + \addxcontentsline{toc}{section}[\thesection]{#2}% + }% + }{% no star given + \IfNoValueTF{#2}{% + \oldsection{#3}% + }{% no TOC arg + \oldsection[#2]{#3}% + }% + \IfNoValueTF{#4}{% optional label given, if not we do nothing + % \mtocsection{#3}% + \IfNoValueTF{#2}{% + \mtocsection{#3}% when no optional toc title, use main title + }{% no TOC arg + \mtocsection{#2}% when toc optional title is given, use it + }% + }{% + \mtocsection{#4}% + }% + }% + } + +\RenewDocumentCommand\subsection{s o m o}{% + \IfBooleanTF{#1}{% + \oldsubsection*{#3}% + \IfNoValueF{#2}{% if TOC arg is given create a TOC entry + \addxcontentsline{toc}{subsection}[\thesubsection]{#2}% + }% + }{% no star given + \IfNoValueTF{#2}{% + \oldsubsection{#3}% + }{% no TOC arg + \oldsubsection[#2]{#3}% + }% + \IfNoValueTF{#4}{% optional label given, if not we do nothing + \IfNoValueTF{#2}{% + \mtocsubsection{#3}% when no optional toc title, use main title + }{% no TOC arg + \mtocsubsection{#2}% when toc optional title is given, use it + }% + }{% + \mtocsubsection{#4}% + }% + }% +} + +\etocsetlevel{mtocsection}{6}% dummy sectioning level +\etocsetlevel{mtocsubsection}{6}% dummy sectioning level + +% Command to print a table of contents in the margin +\NewDocumentCommand{\margintoc}{O{\mtocshift}}{ % The first parameter is the vertical offset; by default it is \mtocshift + \begingroup% + % Move regular section and subsection to level 6 so that they won't be included and instead set let the mtoc versions take their place. + % Adapted from https://tex.stackexchange.com/a/133559/226693 + \etocsetlevel{section}{6} + \etocsetlevel{subsection}{6} + \etocsetlevel{mtocsection}{1} + \etocsetlevel{mtocsubsection}{2} + + % Define default widths + \def\margintocnumwidth{-.8mm}% + \def\margintocpagenumwidth{8pt}% + \setlength{\RaggedRightParfillskip}{0pt} + + % Dry run to get the needed widths + \etocsetstyle{mtocsection}% + {}% + {\setbox0\hbox{{\usekomafont{section}\small\etocthenumber\kern.8mm}}%% + \setbox1\hbox{{\usekomafont{section}\small\etocthepage}}}% + {\ifdim\wd0>\margintocnumwidth \edef\margintocnumwidth{\the\wd0} \fi%% + \ifdim\wd1>\margintocpagenumwidth \edef\margintocpagenumwidth{\the\wd1} \fi}% + {}% + \etocsetstyle{mtocsubsection}% + {}% + {\setbox0\hbox{{\usekomafont{section}\small\mdseries\etocthenumber\kern.8mm}}% + \setbox1\hbox{{\usekomafont{section}\small\mdseries\etocthepage}}}% + {\ifdim\wd0>\margintocnumwidth \edef\margintocnumwidth{\the\wd0} \fi% + \ifdim\wd1>\margintocpagenumwidth \edef\margintocpagenumwidth{\the\wd1} \fi}% + {}% + \etocsetstyle{subsubsection}% + {}% + {}% + {}% + {}% + \etocsetstyle{paragraph}% + {}% + {}% + {}% + {}% + \etocsettocstyle{}{% + \global\let\margintocnumwidth\margintocnumwidth% + \global\let\margintocpagenumwidth\margintocpagenumwidth% + }% + \localtableofcontents% + + % Set the style for section entries + \etocsetstyle{mtocsection}% + {\parindent 0pt \parskip 2.5pt \parfillskip 0pt \RaggedRight}% + {\leftskip \margintocnumwidth \rightskip \margintocpagenumwidth}% + {\makebox[0pt][r]{\makebox[\margintocnumwidth][l]{\etocnumber}}\etocname\nobreak\leaders\hbox{\hbox to 1.5ex {\hss.\hss}}\hfill\rlap{\makebox[\margintocpagenumwidth][r]{\etocpage}}\par}% + {}% + % Set the style for subsection entries + \etocsetstyle{mtocsubsection}% + {\parindent 0pt \parskip 0pt \parfillskip 0pt \RaggedRight}% + {\leftskip \margintocnumwidth \rightskip \margintocpagenumwidth}% + {\makebox[0pt][r]{\makebox[\margintocnumwidth][l]{\mdseries\etocnumber}}{\mdseries\etocname\nobreak\leaders\hbox{\hbox to 1.5ex {\hss.\hss}}\hfill\rlap{\makebox[\margintocpagenumwidth][r]{\mdseries\etocpage}}}\par}% + {\parskip 2.5pt}% + % Set the global style of the toc + \etocsettocstyle{\usekomafont{section}\small}{}% + \etocsetnexttocdepth{\themargintocdepth}% + % Print the table of contents in the margin + \marginnote[#1]{\localtableofcontents}% + \FloatBarrier% + \endgroup% +} + +%---------------------------------------------------------------------------------------- +% ENCODING AND FONTS +%---------------------------------------------------------------------------------------- + +\newcommand{\kao@fontmethodModern}{% + \RequirePackage{amssymb} % Must be loaded before unicode-math + \RequirePackage[force]{filehook} % Fixes an error + \RequirePackage{unicode-math} % Math fonts in xetexorluatex + \setromanfont[ % Libertinus Serif font + Scale=1.04 + ]{Libertinus Serif} + \setsansfont[ % Libertinus Sans font + Scale=1 + ]{Libertinus Sans} + \setmonofont[ % Libertinus Mono font + Scale=.89 + ]{Liberation Mono} + \setmathfont{Libertinus Math} % Libertinus Math font + \ifluatex + \else + \RequirePackage{morewrites} % Fix some errors related to floats (not necessary with LuaLaTeX + \fi% +} +\newcommand{\kao@fontmethodTex}{% + \RequirePackage[utf8]{inputenc} % utf8 encoding in the input (.tex) file + \RequirePackage[T1]{fontenc} % utf8 encoding in the output (.pdf) file + + \RequirePackage{amssymb} % Math symbols, including \blacktriangleright, used for bullets + \RequirePackage[scaled=.97,helvratio=.93,p,theoremfont]{newpxtext} % Serif palatino font + \RequirePackage[vvarbb,smallerops,bigdelims]{newpxmath} % Math palatino font + \RequirePackage[scaled=.85]{beramono} % Monospace font + \RequirePackage[scr=rsfso,cal=boondoxo]{mathalfa} % Mathcal from STIX, unslanted a bit + \RequirePackage{morewrites} % Fix some errors related to floats +} + +\ifthenelse% +{\equal{modern}{\kao@fontmethod}}{\kao@fontmethodModern}% +{\ifthenelse% + {\equal{tex}{\kao@fontmethod}}{\kao@fontmethodTex}% + { + \PackageError{kao}{% + Invalid fontmethod choice \kao@fontmethod.% + }{% + Should be one of "modern" or "tex"% + } + }} + +% When using the Palatino (newpxtext) font, it is better to use a +% slightly larger stretch. +%\setstretch{1.10} +\linespread{1.07} % Give Palatino more leading (space between lines) + +% Fix for the subequation environment (https://tex.stackexchange.com/questions/27053/too-much-space-between-full-paragraph-and-subequations-env) +\preto\subequations{\ifhmode\unskip\fi} + +%---------------------------------------------------------------------------------------- +% HYPERREFERENCES +%---------------------------------------------------------------------------------------- + +\RequirePackage{hyperref} % Required for hyperlinks +\RequirePackage{bookmark} % Required for pdf bookmarks + +\PassOptionsToPackage{hyphens}{url} % Break long URLs and use hyphens to separate the pieces + +% Color settings should be done in the next \hypersetup +\hypersetup{ % Set up hyperref options + unicode, % Use unicode for links + pdfborder={0 0 0}, % Suppress border around pdf + %xetex, + %pagebackref=true, + %hyperfootnotes=false, % We already use footmisc + bookmarksdepth=section, + bookmarksopen=true, % Expand the bookmarks as soon as the pdf file is opened + %bookmarksopenlevel=4, + linktoc=all, % Toc entries and numbers links to pages + breaklinks=true, + colorlinks=true, +} + +% Define a new color for the footnote marks +\def\@footnotecolor{black} +\define@key{Hyp}{footnotecolor}{% + \HyColor@HyperrefColor{#1}\@footnotecolor% +} +\def\@footnotemark{% + \leavevmode + \ifhmode\edef\@x@sf{\the\spacefactor}\nobreak\fi + \stepcounter{Hfootnote}% + \global\let\Hy@saved@currentHref\@currentHref + \hyper@makecurrent{Hfootnote}% + \global\let\Hy@footnote@currentHref\@currentHref + \global\let\@currentHref\Hy@saved@currentHref + \hyper@linkstart{footnote}{\Hy@footnote@currentHref}% + \@makefnmark + \hyper@linkend + \ifhmode\spacefactor\@x@sf\fi + \relax +} + +% Redefine the \thanks command to allow users to use \label within \thanks without getting warnings +\let\oldthanks\thanks +\renewcommand\thanks[1]{% + \label{bhfn:0}% + \oldthanks{#1}% +} + +% Adjust the colour of the footnotes marks using the colour defined above +\renewcommand\@makefntext[1]{% + \renewcommand\@makefnmark{% + \mbox{\textsuperscript{\normalfont% + \hyperref[\BackrefFootnoteTag]{% + \color{\@footnotecolor}{\@thefnmark}% + }}\,% + }% + }% + \BHFN@OldMakefntext{#1}% +} + +%---------------------------------------------------------------------------------------- +% COLOURS +%---------------------------------------------------------------------------------------- + +% Uncomment to have coloured headings +%\addtokomafont{title}{\color{Maroon}} +%\addtokomafont{part}{\color{Maroon}} +%\addtokomafont{chapter}{\color{Maroon}} +%\addtokomafont{section}{\color{Maroon}} +%\addtokomafont{subsection}{\color{Maroon}} +%\addtokomafont{subsubsection}{\color{Maroon}} +%\addtokomafont{paragraph}{\color{Maroon}} +%\addtokomafont{captionlabel}{\color{Blue}} +%\addtokomafont{pagenumber}{\color{Maroon}} + +% Choose the default colors +\hypersetup{ + %allcolors=DarkGreen, + %anchorcolor=Red, + %citecolor=DarkOrange!70!black, + citecolor=OliveGreen, + filecolor=OliveGreen, + %linkcolor=Blue, + linkcolor=Black, + %pagecolor = Blue, + %menucolor=Red, + %runcolor=Red, + urlcolor=OliveGreen, +} + +%---------------------------------------------------------------------------------------- +% ITEMS +%---------------------------------------------------------------------------------------- + +\renewcommand{\labelitemi}{\small$\blacktriangleright$} % Use a black triangle for the first level of \item's +\renewcommand{\labelitemii}{\textbullet} % Use a bullet for the second level of \item's +\RequirePackage[inline]{enumitem} % Used to customise lists (in particular, we don't want to put whitespace between items) +\setlist[itemize]{noitemsep} +\setlist[enumerate]{noitemsep} +\setlist[description]{noitemsep} + +%---------------------------------------------------------------------------------------- +% SIMPLE BOXED ENVIRONMENT +%---------------------------------------------------------------------------------------- + +% kaobox +\RequirePackage[most]{tcolorbox} + +% Define a new environment using the style created above +\newtcolorbox{kaobox}[1][]{ + breakable, + before skip=1.5\topskip, + after skip=1.5\topskip, + left skip=0pt, + right skip=0pt, + left=4pt, + right=4pt, + top=2pt, + bottom=2pt, + lefttitle=4pt, + righttitle=4pt, + toptitle=2pt, + bottomtitle=2pt, + sharp corners, + boxrule=0pt, + titlerule=.4pt, + colback=RoyalBlue!25!White, + colbacktitle=RoyalBlue!25!White, + coltitle=black, + colframe=black, + fonttitle=\bfseries, + #1 +} + +%---------------------------------------------------------------------------------------- +% ENVIRONMENT WITH A COUNTER +%---------------------------------------------------------------------------------------- + +% Define an environment titled 'Comment' and numbered incrementally +\newenvironment{kaocounter}{ + \refstepcounter{kaocounter} + \begin{kaobox}[title=Comment~\thekaocounter\autodot] + }{ + \end{kaobox} +} + +% Define the commands to manage the counter for the 'kaocounter' environment +\newcounter{kaocounter} +\counterwithin{kaocounter}{section} +\newcommand*{\kaocounterformat}{% Format for the caption + Comment~\thekaocounter\csname autodot\endcsname} +\newcommand*{\fnum@kaocounter}{\kaocounterformat} + + +%---------------------------------------------------------------------------------------- +% FLOATING ENVIRONMENT WITH TOC ENTRIES +%---------------------------------------------------------------------------------------- + +% Define a floating environment +\newenvironment{kaofloating}{% + \@float{kaofloating}% +}{% + \end@float% +} + +% Configure the 'kaofloating' environment +\newcommand*{\fps@floatingbox}{tbph}% Allowed positions for the environment (top, bottom, own page, here) +\newcommand*{\ftype@floatingbox}{5}% Set the type of float (floats of the same type cannot change their order; figures and tables are type 1 and 2 respectively) +\newcommand*{\floatingboxformat}{% Set a title of the environment + Insight~\thefloatingbox\csname autodot\endcsname} +\newcommand*{\fnum@floatingbox}{\floatingboxformat}% Use the environment title +\newcommand*{\ext@floatingbox}{loi}% Choose the extension of the auxiliary file for this environment + +\addtotoclist[float]{loi}% Keep track of 'kaofloating' environments for a "List of Insights" +\newcommand*{\listofloiname}{List of Insights}% Choose the title for the "List of Insights" +\newcommand*{\l@floatingbox}{\l@figure}% Format the LOI +\newcommand*{\listofinsights}{\listoftoc{loi}}% User-friendly command to print the LOI + +%---------------------------------------------------------------------------------------- +% ADDITIONAL PACKAGES +%---------------------------------------------------------------------------------------- + +% Productivity +\RequirePackage{pdfpages} % Insert PDF pages +\RequirePackage{subfiles} % Adopt a modular structure +\RequirePackage{todonotes} % Add useful notes in the margins + +% Listings code +\RequirePackage{listings} % Code +%\RequirePackage{minted} (must be loaded before scrhack) + +% Configure the listings +\definecolor{listingkeywords}{rgb}{0.0, 0.5, 0.0} +\definecolor{listingidentifiers}{rgb}{0, 0, 0} +\definecolor{listingcomments}{rgb}{0.25, 0.5, 0.5} +\definecolor{listingstrings}{rgb}{0.73, 0.13, 0.13} +\definecolor{listingnumbers}{rgb}{0.25, 0.25, 0.25} +% Define a fancy style +\lstdefinestyle{kaolst}{ + aboveskip=0.7\topskip, + belowskip=0.1\topskip, + basicstyle=\small\ttfamily, + commentstyle=\color{listingcomments}\itshape, + keywordstyle=\color{listingkeywords}\bfseries, + numberstyle=\scriptsize\color{listingnumbers}\ttfamily, + stringstyle=\color{listingstrings}, + identifierstyle=\color{listingidentifiers}, + backgroundcolor=\color{White}, + breakatwhitespace=false, + breaklines=true, + captionpos=t, + keepspaces=true, + showspaces=false, + showstringspaces=false, + showtabs=false, + numbers=left, + numbersep=1em, + %frame=lines, + frame=l, + framerule=.7pt, + tabsize=4, + defaultdialect=[LaTeX]Tex, +} +% Define a plain style as well +\lstdefinestyle{kaolstplain}{ + aboveskip=0.6\topskip, + belowskip=-0.1\topskip, + basicstyle=\small\ttfamily, + commentstyle=\color{listingcomments}\itshape, + keywordstyle=\color{listingkeywords}\bfseries, + numberstyle=\scriptsize\color{listingnumbers}\ttfamily, + stringstyle=\color{listingstrings}, + identifierstyle=\color{listingidentifiers}, + backgroundcolor=\color{White}, + breakatwhitespace=false, + breaklines=true, + captionpos=b, + keepspaces=true, + showspaces=false, + showstringspaces=false, + showtabs=false, + numbers=none, + frame=none, + tabsize=4, + defaultdialect=[LaTeX]Tex, +} +\lstset{style=kaolst}% Use the fancy style + +% Verbatim +%\RequirePackage{fancyvrb} % Customization of verbatim environments +%\fvset{fontsize=\normalsize} % Change here the font size of all +%verbatim \preto{\@verbatim}{\topsep=0pt \partopsep=0pt } + +% Algorithms +% \RequirePackage[linesnumbered, ruled, vlined]{algorithm2e} % Algorithms + +% Special gliphs +\RequirePackage{ccicons} % Creative Commons icons + +% Index, glossary and nomenclature +\RequirePackage{imakeidx} +\RequirePackage[xindy,toc,numberedsection=nameref]{glossaries} +\RequirePackage[intoc]{nomencl} + +% Commands to print specific words always in the same way +% TODO: in \Command, automatically escape braces {} and replace backslashes with \textbackslash +\newcommand{\Class}[1]{\texttt{#1}} +\newcommand{\Package}[1]{\texttt{#1}} +\newcommand{\Option}[1]{\texttt{#1}} +\newcommand{\Command}[1]{\texttt{\textbackslash#1}} +\newcommand{\Environment}[1]{\texttt{#1}} +\newcommand{\Path}[1]{\texttt{#1}} + +% Print latin words in italics (The xspace package is required but we already loaded it in the class) +\newcommand{\hairsp}{\hspace{1pt}} % Command to print a very short space +\newcommand{\invitro}{\textit{in vitro}\xspace} +\newcommand{\invivo}{\textit{in vivo}\xspace} +\newcommand{\cis}{\textit{cis}\xspace} +\newcommand{\trans}{\textit{trans}\xspace} +\newcommand{\etal}{\textit{et al.}\xspace} +\newcommand{\denovo}{\textit{de novo}\xspace} +\newcommand{\adhoc}{\textit{ad hoc}\xspace} +\newcommand{\etcetera}{\textit{et cetera}\xspace} +\newcommand{\etc}{\textit{etc.}\xspace} +\newcommand{\ie}{\textit{i.\nobreak\hairsp{}e.}\xspace} +\newcommand{\eg}{\textit{e.\nobreak\hairsp{}g.}\xspace} +\newcommand{\vs}{\textit{vs}\xspace} +\newcommand{\cfr}{\textit{cfr.}\xspace} + +% Tables +\newcommand{\na}{\quad--} % Used in tables for N/A cells +\newcommand{\hangp}[1]{\makebox[0pt][r]{(}#1\makebox[0pt][l]{)}} % Create parentheses around text in tables which take up no horizontal space - this improves column spacing +\newcommand{\hangstar}{\makebox[0pt][l]{*}} % Create asterisks in tables which take up no horizontal space - this improves column spacing + +% A command to print the current month and year (from tufte-latex) +\newcommand{\monthyear}{\ifcase\month\or January\or February\or March\or + April\or May\or June\or July\or August\or September\or October\or + November\or December\fi\space\number\year} diff --git a/tex/kaobiblio.sty b/tex/kaobiblio.sty new file mode 100644 index 0000000..7ab8e50 --- /dev/null +++ b/tex/kaobiblio.sty @@ -0,0 +1,426 @@ +\ProvidesPackage{kaobiblio} + +%---------------------------------------------------------------------------------------- +% PACKAGE OPTIONS AND DEPENDENCIES +%---------------------------------------------------------------------------------------- + +\RequirePackage{etoolbox} % Easy programming to modify TeX stuff +\RequirePackage{perpage} % Reset counters +\RequirePackage{iflang} % Check the document language +\RequirePackage{xparse} % Parse arguments for macros +\RequirePackage{xstring} % Parse strings +\RequirePackage{hyperref} % Required for hyperlinks +\RequirePackage{kvoptions} % Handle package options + +% Set up the package options +\SetupKeyvalOptions{ + family = kaobiblio, + prefix = kaobiblio@ +} + +\DeclareBoolOption{addspace}% If true, automatically add a space before printing the citation marker +\DeclareBoolOption{linkeverything}% If true, the author name is a hyperlink in citation styles that support it + +% Choose the default options, which will be overwritten by the options +% passed to this package. +\PassOptionsToPackage{ + %style=numeric-comp, + %citestyle=authortitle-icomp, + citestyle=numeric-comp, + %bibstyle=authoryear, + bibstyle=numeric, + sorting=none, + %sorting=nyt, + %sortcites=true, + %autocite=footnote, + backend=biber, % Compile the bibliography with biber + hyperref=true, + backref=true, + citecounter=true, + pagetracker=true, + citetracker=true, + ibidtracker=context, + autopunct=true, + autocite=plain, +}{biblatex} + +% Pass the unknown options to biblatex, overwriting the previous settings. Avoid passing the kao-specific options. +\DeclareDefaultOption{% + \IfBeginWith{\CurrentOption}{addspace}{}{% + \IfBeginWith{\CurrentOption}{linkeverything}{}{% + \PassOptionsToPackage{\CurrentOption}{biblatex}% + }}% +} + +% Process the options +\ProcessKeyvalOptions{kaobiblio} + +% Load biblatex +\RequirePackage{biblatex} + +% Remove some unwanted entries from the bibliography +\AtEveryBibitem{ + \clearfield{issn} + \clearfield{isbn} + \clearfield{archivePrefix} + \clearfield{arxivId} + \clearfield{pmid} + \clearfield{eprint} + \ifentrytype{online}{}{\ifentrytype{misc}{}{\clearfield{url}}} + \ifentrytype{book}{\clearfield{doi}}{} +} + +% Convert months to integers +\DeclareSourcemap{ + \maps[datatype=bibtex]{ + \map[overwrite]{ + \step[fieldsource=month, match={jan}, replace=${1}] + \step[fieldsource=month, match={feb}, replace=${2}] + \step[fieldsource=month, match={mar}, replace=${3}] + \step[fieldsource=month, match={apr}, replace=${4}] + \step[fieldsource=month, match={may}, replace=${5}] + \step[fieldsource=month, match={jun}, replace=${6}] + \step[fieldsource=month, match={jul}, replace=${7}] + \step[fieldsource=month, match={aug}, replace=${8}] + \step[fieldsource=month, match={sep}, replace=${9}] + \step[fieldsource=month, match={oct}, replace=${10}] + \step[fieldsource=month, match={nov}, replace=${11}] + \step[fieldsource=month, match={dec}, replace=${12}] + } + } +} + +%---------------------------------------------------------------------------------------- +% BACK REFERENCES +%---------------------------------------------------------------------------------------- + +% Check if a string is in a comma-separated list +\newcommand\IfStringInList[2]{\IfSubStr{,#2,}{,#1,}} + +% Set the language-specific back reference strings +% #LANGUAGE +\@ifpackageloaded{polyglossia}{% + \IfLanguageName{danish}{% + \DefineBibliographyStrings{danish}{% + backrefpage = {citeret på side}, + backrefpages = {citeret på sider}, + } + }{} + \IfLanguageName{english}{% + \DefineBibliographyStrings{english}{% + backrefpage = {cited on page}, + backrefpages = {cited on pages}, + } + }{} + \IfLanguageName{italian}{% + \DefineBibliographyStrings{italian}{% + backrefpage = {citato a pag.}, + backrefpages = {citato a pagg.}, + } + }{} +}{ + \@ifpackageloaded{babel}{% + \IfStringInList{danish}{\bbl@loaded}{% + \DefineBibliographyStrings{danish}{% + backrefpage = {citeret på side}, + backrefpages = {citeret på sider}, + } + }{} + \IfStringInList{english}{\bbl@loaded}{% + \DefineBibliographyStrings{english}{% + backrefpage = {cited on page}, + backrefpages = {cited on pages}, + } + }{} + \IfStringInList{italian}{\bbl@loaded}{% + \DefineBibliographyStrings{italian}{% + backrefpage = {citato a pag.}, + backrefpages = {citato a pagg.}, + } + }{} + }{} +} + +%---------------------------------------------------------------------------------------- +% CITATION COMMANDS +%---------------------------------------------------------------------------------------- + +% Command to format the marginnote created for cited items +\NewDocumentCommand{\formatmargincitation}{m}{% The parameter is a single citation key + \parencite{#1}: \citeauthor*{#1} (\iffieldundef{year}{\bibsstring{nodate}}{\printfield{year}}), \citefield{#1}[emph]{title}% +} + +% Command to format the marginnote created for supercited items +\NewDocumentCommand{\formatmarginsupercitation}{m}{% The parameter is a single citation key + \supercite{#1} \citeauthor*{#1} (\iffieldundef{year}{\bibsstring{nodate}}{\printfield{year}})% +} + +% The following command needs to be redefined every time \sidecite is called in order for \DeclareCiteCommand's wrapper to work correctly +\NewDocumentCommand{\kaobiblio@marginnote}{m}{% + \marginnote{#1}% +} + +% biblatex-like commands that also print a citation in the margin +% Usage: + % First optional argument is always vertical shift and must be given as an (empty) argument when using following a postnote and/or prenote + % Second optional argument is always the postnote if the third argument isn't specified or is the prenote if the third argument is specified (same pattern as the biblatex commands) + % Third optional argument is always the postnote + % Mandatory argument is always the citation key(s) + +% Command to \cite and print a citation in the margin +% First optional argument: vertical shift +% Second optional argument: postnote if the third argument isn't specified; prenote if the third argument is specified (same pattern as the \textcite command) +% Third optional argument: postnote +% Mandatory argument: citation key +\NewDocumentCommand{\sidecite}{o o o m}{% + \RenewDocumentCommand{\kaobiblio@marginnote}{m}{% + \marginnote[#1]{##1}% + }% + \DeclareCiteCommand{\kaobiblio@sidecite}[\kaobiblio@marginnote]{% + }{% + \formatmargincitation{\thefield{entrykey}}% + }{% + \\% separator between multiple citations + }{% + }% + % With this we print the marker in the text and add the item to the bibliography at the end + \IfNoValueOrEmptyTF{#2}% + {\def\@tempa{\cite{#4}\kaobiblio@sidecite{#4}}}% + {\IfNoValueOrEmptyTF{#3}% + {\IfNoValueTF{#3}% + {\def\@tempa{\cite[#2]{#4}\kaobiblio@sidecite{#4}}}% + {\def\@tempa{\cite[#2][]{#4}\kaobiblio@sidecite{#4}}}% postnote is empty, so pass empty postnote + }% + {\def\@tempa{\cite[#2][#3]{#4}\kaobiblio@sidecite{#4}}}% + }% + \ifkaobiblio@addspace% + \unskip~\@tempa% + \else% + \@tempa% + \fi% +} + +% Command to \supercite and print a citation in the margin +% First optional argument: vertical shift +% Second optional argument: postnote if the third argument isn't specified; prenote if the third argument is specified (same pattern as the \textcite command) +% Third optional argument: postnote +% Mandatory argument: citation key +\NewDocumentCommand{\sidesupercite}{o o o m}{% + \RenewDocumentCommand{\kaobiblio@marginnote}{m}{% + \marginnote[#1]{##1}% + }% + \DeclareCiteCommand{\kaobiblio@sidesupercite}[\kaobiblio@marginnote]{% + }{% + \formatmarginsupercitation{\thefield{entrykey}}% + }{% + \\% separator between multiple citations + }{% + }% + % With this we print the marker in the text and add the item to the bibliography at the end + \IfNoValueOrEmptyTF{#2}% + {\def\@tempa{\supercite{#4}\kaobiblio@sidesupercite{#4}}}% + {\IfNoValueOrEmptyTF{#3}% + {\IfNoValueTF{#3}% + {\def\@tempa{\supercite[#2]{#4}\kaobiblio@sidesupercite{#4}}}% + {\def\@tempa{\supercite[#2][]{#4}\kaobook@sidesupercite{#4}}}% postnote is empty, so pass empty postnote + }% + {\def\@tempa{\supercite[#2][#3]{#4}\kaobiblio@sidesupercite{#4}}}% + }% + \@tempa% +} + +% Command to \textcite and print a citation in the margin +% First optional argument: vertical shift +% Second optional argument: postnote if the third argument isn't specified; prenote if the third argument is specified (same pattern as the \textcite command) +% Third optional argument: postnote +% Mandatory argument: citation key +\NewDocumentCommand{\sidetextcite}{o o o m}{% + \RenewDocumentCommand{\kaobiblio@marginnote}{m}{% + \marginnote[#1]{##1}% + }% + \DeclareCiteCommand{\kaobiblio@sidecite}[\kaobiblio@marginnote]{% + }{% + \formatmargincitation{\thefield{entrykey}}% + }{% + \\% separator between multiple citations + }{% + }% + % With this we print the marker in the text and add the item to the bibliography at the end + \IfNoValueOrEmptyTF{#2}% + {\def\@tempa{\textcite{#4}\kaobiblio@sidecite{#4}}}% + {\IfNoValueOrEmptyTF{#3}% + {\IfNoValueTF{#3}% + {\def\@tempa{\textcite[#2]{#4}\kaobiblio@sidecite{#4}}}% + {\def\@tempa{\textcite[#2][]{#4}\kaobook@sidecite{#4}}}% postnote is empty, so pass empty postnote + }% + {\def\@tempa{\textcite[#2][#3]{#4}\kaobiblio@sidecite{#4}}}% + }% + \ifkaobiblio@addspace% + \unskip~\@tempa% + \else% + \@tempa% + \fi% +} + +% Command to \parencite or \parencite* and print a citation in the margin +% First optional (star) argument: use \parencite* if included; otherwise use \parencite +% Second optional argument: vertical shift +% Third optional argument: postnote if the fourth argument isn't specified; prenote if the fourth argument is specified (same pattern as the \parencite command) +% Fourth optional argument: postnote +% Mandatory argument: citation key +\NewDocumentCommand{\sideparencite}{s o o o m}{% + \RenewDocumentCommand{\kaobiblio@marginnote}{m}{% + \marginnote[#2]{##1}% + }% + \DeclareCiteCommand{\kaobiblio@sidecite}[\kaobiblio@marginnote]{% + }{% + \formatmargincitation{\thefield{entrykey}}% + }{% + \\% separator between multiple citations + }{% + }% + % With this we print the marker in the text and add the item to the bibliography at the end + \IfBooleanTF#1% + {\IfNoValueOrEmptyTF{#3}% + {\parencite*{#5}\kaobiblio@sidecite{#5}}% + {\IfNoValueOrEmptyTF{#4}% + {\IfNoValueTF{#4}% + {\def\@tempa{\parencite*[#3]{#5}\kaobiblio@sidecite{#5}}}% + {\def\@tempa{\parencite*[#3][]{#5}\kaobiblio@sidecite{#5}}}% postnote is empty, so pass empty postnote + }% + {\def\@tempa{\parencite*[#3][#4]{#5}\kaobiblio@sidecite{#5}}}% + }% + }% + {\IfNoValueOrEmptyTF{#3}% + {\def\@tempa{\parencite{#5}\kaobiblio@sidecite{#5}}}% + {\IfNoValueOrEmptyTF{#4}% + {\IfNoValueTF{#4}% + {\def\@tempa{\parencite[#3]{#5}\kaobiblio@sidecite{#5}}}% + {\def\@tempa{\parencite[#3][]{#5}\kaobiblio@sidecite{#5}}}% postnote is empty, so pass empty postnote + }% + {\def\@tempa{\parencite[#3][#4]{#5}\kaobiblio@sidecite{#5}}}% + }% + }% + \ifkaobiblio@addspace% + \unskip~\@tempa% + \else% + \@tempa% + \fi% +} + + +%---------------------------------------------------------------------------------------- +% LINKING THE AUTHOR'S NAME +%---------------------------------------------------------------------------------------- + +% In biblatex, when citing with the style authoryear or using \textcite, only the year is linked to the reference in the bibliography. Despite the arguments of one of the mantainers of the biblatex package (https://github.com/plk/biblatex/issues/428), some users think that in the author* style the author name should be a link as well. The `linkeverything' option provides an easy way to activate this behaviour. + +\ifkaobiblio@linkeverything + \xpatchbibmacro{cite} + {\usebibmacro{cite:label}% + \setunit{\printdelim{nonameyeardelim}}% + \usebibmacro{cite:labeldate+extradate}} + {\printtext[bibhyperref]{% + \DeclareFieldAlias{bibhyperref}{default}% + \usebibmacro{cite:label}% + \setunit{\printdelim{nonameyeardelim}}% + \usebibmacro{cite:labeldate+extradate}}} + {} + {\PackageWarning{biblatex-patch} + {Failed to patch cite bibmacro}} + + % Include labelname in labelyear link + \xpatchbibmacro{cite} + {\printnames{labelname}% + \setunit{\printdelim{nameyeardelim}}% + \usebibmacro{cite:labeldate+extradate}} + {\printtext[bibhyperref]{% + \DeclareFieldAlias{bibhyperref}{default}% + \printnames{labelname}% + \setunit{\printdelim{nameyeardelim}}% + \usebibmacro{cite:labeldate+extradate}}} + {} + {\PackageWarning{biblatex-patch} + {Failed to patch cite bibmacro}} + + % Access hyperref's citation link start/end commands + \makeatletter + \protected\def\blx@imc@biblinkstart{% + \@ifnextchar[%] + {\blx@biblinkstart} + {\blx@biblinkstart[\abx@field@entrykey]}} + \def\blx@biblinkstart[#1]{% + \blx@sfsave\hyper@natlinkstart{\the\c@refsection @#1}\blx@sfrest} + \protected\def\blx@imc@biblinkend{% + \blx@sfsave\hyper@natlinkend\blx@sfrest} + \blx@regimcs{\biblinkstart \biblinkend} + \makeatother + + \newbool{cbx:link} + + % Include parentheses around labelyear in \textcite only in + % single citations without pre- and postnotes + \def\iflinkparens{% + \ifboolexpr{ test {\ifnumequal{\value{multicitetotal}}{0}} and + test {\ifnumequal{\value{citetotal}}{1}} and + test {\iffieldundef{prenote}} and + test {\iffieldundef{postnote}} }} + + \xpatchbibmacro{textcite} + {\printnames{labelname}} + {\iflinkparens + {\DeclareFieldAlias{bibhyperref}{default}% + \global\booltrue{cbx:link}\biblinkstart% + \printnames{labelname}} + {\printtext[bibhyperref]{\printnames{labelname}}}} + {} + {\PackageWarning{biblatex-patch} + {Failed to patch textcite bibmacro}} + + \xpatchbibmacro{textcite} + {\usebibmacro{cite:label}} + {\iflinkparens + {\DeclareFieldAlias{bibhyperref}{default}% + \global\booltrue{cbx:link}\biblinkstart% + \usebibmacro{cite:label}} + {\usebibmacro{cite:label}}} + {} + {\PackageWarning{biblatex-patch} + {Failed to patch textcite bibmacro}} + + \xpretobibmacro{textcite:postnote} + {\ifbool{cbx:link} + {\ifbool{cbx:parens} + {\bibcloseparen\global\boolfalse{cbx:parens}} + {}% + \biblinkend\global\boolfalse{cbx:link}} + {}} + {} + {\PackageWarning{biblatex-patch} + {Failed to patch textcite:postnote bibmacro}} +\else +\fi + +%---------------------------------------------------------------------------------------- +% CITATION ENVIRONMENTS +%---------------------------------------------------------------------------------------- + +% TODO: create a fancy environment for this. Perhaps printing also the +% abstract. + +% Cite commands (assuming biblatex is loaded) +\DeclareCiteCommand{\fullcite}{% + \defcounter{maxnames}{99}% + \usebibmacro{prenote}} + {\clearfield{url}% + \clearfield{pages}% + \clearfield{pagetotal}% + \clearfield{edition}% + \clearfield{issn}% + \clearfield{doi}% + \usedriver + {\DeclareNameAlias{sortname}{default}} + {\thefield{entrytype}} +} +{\multicitedelim} +{\usebibmacro{postnote}} diff --git a/tex/kaobook.cls b/tex/kaobook.cls new file mode 100644 index 0000000..1563434 --- /dev/null +++ b/tex/kaobook.cls @@ -0,0 +1,282 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% kaobook +% LaTeX Class +% Version 0.9.8 (2021/08/23) +% +% This template originates from: +% https://www.LaTeXTemplates.com +% +% For the latest template development version and to make contributions: +% https://github.com/fmarotta/kaobook +% +% Authors: +% Federico Marotta (federicomarotta@mail.com) +% Based on the doctoral thesis of Ken Arroyo Ohori (https://3d.bk.tudelft.nl/ken/en) +% and on the Tufte-LaTeX class. +% Modified for LaTeX Templates by Vel (vel@latextemplates.com) +% +% License: +% LPPL (see included MANIFEST.md file) +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%---------------------------------------------------------------------------------------- +% CLASS CONFIGURATION +%---------------------------------------------------------------------------------------- + +\NeedsTeXFormat{LaTeX2e} +\ProvidesClass{kaobook}[2021/08/23 v0.9.8 kaobook] +\newcommand{\@baseclass}{scrbook} % Base class name + +% Set the default options +\PassOptionsToClass{a4paper}{\@baseclass} +\PassOptionsToClass{fontsize=10pt}{\@baseclass} +\PassOptionsToClass{parskip=half}{\@baseclass} +\PassOptionsToClass{headings=optiontoheadandtoc}{\@baseclass} + +% Pass through any other options to the base class +\DeclareOption*{\PassOptionsToClass{\CurrentOption}{\@baseclass}} + +\ProcessOptions\relax % Process the options + +\LoadClass{\@baseclass} % Load the base class + +\RequirePackage{kao} % Load the code common to all classes + +%---------------------------------------------------------------------------------------- +% FRONT-, MAIN-, BACK- MATTERS BEHAVIOUR +%---------------------------------------------------------------------------------------- + +% Front matter +\let\oldfrontmatter\frontmatter % Store the old command +\renewcommand{\frontmatter}{% + \oldfrontmatter% First of all, call the old command + \pagestyle{plain.scrheadings}% Use a plain style for the header and the footer + \pagelayout{wide}% Use a wide page layout + \setchapterstyle{plain} % Choose the default chapter heading style + % \sloppy % Required to better break long lines +} + +%------------------------------------------------ + +% Main matter +\let\oldmainmatter\mainmatter % Store the old command +\renewcommand{\mainmatter}{% + \oldmainmatter% Call the old command + \pagestyle{scrheadings}% Use a fancy style for the header and the footer + \pagelayout{margin}% Use a 1.5 column layout + \setchapterstyle{kao} % Choose the default chapter heading style +} + +%------------------------------------------------ + +% Appendix +\let\oldappendix\appendix% Store the old command +\renewcommand{\appendix}{% + \oldappendix% Call the old command + \bookmarksetup{startatroot}% Reset the bookmark depth +} + +%------------------------------------------------ + +% Back matter +\let\oldbackmatter\backmatter% Store the old command +\renewcommand{\backmatter}{% + \oldbackmatter% Call the old command + \bookmarksetup{startatroot}% Reset the bookmark depth + \pagestyle{plain.scrheadings}% Use a plain style for the header and the footer + \pagelayout{wide}% Use a wide page layout + \setchapterstyle{plain} % Choose the default chapter heading style +} + +%---------------------------------------------------------------------------------------- +% CHAPTER HEADING STYLES +%---------------------------------------------------------------------------------------- + +% Command to easily switch between chapter styles +\DeclareDocumentCommand{\setchapterstyle}{m}{% + \ifthenelse{\equal{plain}{#1}}{\chapterstyleplain}{} + \ifthenelse{\equal{bar}{#1}}{\chapterstylebar}{} + \ifthenelse{\equal{lines}{#1}}{\chapterstylelines}{} + \ifthenelse{\equal{kao}{#1}}{\chapterstylekao}{} +} + +% The default definition in KOMA script +\DeclareDocumentCommand{\chapterstyleplain}{}{% + \renewcommand{\chapterlinesformat}[3]{% + \@hangfrom{##2}{##3}} + \renewcommand*{\chapterformat}{% + \mbox{\chapappifchapterprefix{\nobreakspace}\thechapter% + \autodot\IfUsePrefixLine{}{\enskip}}} + \RedeclareSectionCommand[beforeskip=0cm,afterskip=10\vscale]{chapter} + \setlength{\mtocshift}{-1\vscale} +} + +% Gray bar +\DeclareDocumentCommand{\chapterstylebar}{}{% + \renewcommand*{\chapterformat}{% + \mbox{\chapappifchapterprefix{\nobreakspace}\thechapter% + \autodot\IfUsePrefixLine{}{\enskip}}% + } + \renewcommand{\chapterlinesformat}[3]{% + \begin{tikzpicture}[remember picture, overlay] + \node[ + anchor=south west, + xshift=\dimexpr - \hoffset - \oddsidemargin - 1in -1mm,%-30\hscale, + yshift=4.3mm, + rectangle, + fill=gray!20!white, + fill opacity=0.8, + inner ysep=5\vscale, + inner xsep=\dimexpr \hoffset + \oddsidemargin + 1in,%30\hscale, + text opacity=1, + text width=\paperwidth-40\hscale, + ]{\@hangfrom{##2}{##3}}; + \end{tikzpicture} + } + \RedeclareSectionCommand[beforeskip=-55\vscale,afterskip=6\vscale]{chapter} + \setlength{\mtocshift}{-1\vscale} +} + +% Lines +\renewcommand{\hrulefill}[1][0.4pt]{% + \leavevmode\leaders\hrule height #1\hfill\kern\z@% +} +\DeclareDocumentCommand{\chapterstylelines}{}{% + \renewcommand*{\chapterformat}{% + \chapappifchapterprefix{\nobreakspace}\scalebox{3.5}{\thechapter\autodot}% + }% + \renewcommand\chapterlinesformat[3]{% + %\vspace*{-1cm}% + \leavevmode% + \makebox[0pt][l]{% + \makebox[\textwidth][l]{\hrulefill[1pt]##2}%\hfill%\par%\bigskip + \makebox[\marginparsep][l]{}% + \makebox[\marginparwidth][l]{}% + }\\ + %\vspace{.5cm} + \makebox[0pt][l]{% + \makebox[\textwidth][l]{##3}% + \makebox[\marginparsep][l]{}% + \makebox[\marginparwidth][l]{}% + }\\ + \makebox[0pt][l]{% + \makebox[\textwidth+\marginparsep+\marginparwidth][l]{\hrulefill[1.1pt]}% + }% + }% + \RedeclareSectionCommand[beforeskip=0cm,afterskip=10\vscale]{chapter} + \setlength{\mtocshift}{-1\vscale}% +} + +% The Kao style +\DeclareDocumentCommand{\chapterstylekao}{}{% + \IfWideLayout{% + \renewcommand*{\chapterformat}{% + \mbox{\chapappifchapterprefix{\nobreakspace}\scalebox{2.85}{\thechapter\autodot}}% + }% + \renewcommand\chapterlinesformat[3]{% + \vspace{3.5\vscale}% + \if@twoside% + \Ifthispageodd{% + \smash{\makebox[0pt][l]{% + \parbox[b]{\textwidth - 6.2\hscale}{\flushright{##3}}% + \makebox[6.2\hscale][c]{\rule[-2\vscale]{1pt}{27.4\vscale+\f@size mm}}% + \parbox[b]{\marginparwidth}{##2}% + }}% + }{ + \smash{\makebox[\textwidth + 6.2\hscale][r]{% + \parbox[b]{47.7\hscale + 6.2\hscale}{\flushright{##2}}% + \makebox[6.2\hscale][c]{\rule[-2\vscale]{1pt}{27.4\vscale+\f@size mm}}% + \parbox[b]{\textwidth}{\flushleft{##3}}% + }}% + } + \else% + \smash{\makebox[0pt][l]{% + \parbox[b]{\textwidth - 6.2\hscale}{\flushright{##3}}% + \makebox[6.2\hscale][c]{\rule[-2\vscale]{1pt}{27.4\vscale+\f@size mm}}% + \parbox[b]{\marginparwidth}{##2}% + }}% + \fi% + }% + }{% + \renewcommand*{\chapterformat}{% + \mbox{\chapappifchapterprefix{\nobreakspace}\scalebox{2.85}{\thechapter\autodot}}% + }% + \renewcommand\chapterlinesformat[3]{% + \vspace{3.5\vscale}% + \if@twoside% + \Ifthispageodd{% + \smash{\makebox[0pt][l]{% + \parbox[b]{\textwidth}{\flushright{##3}}% + \makebox[\marginparsep][c]{\rule[-2\vscale]{1pt}{27.4\vscale+\f@size mm}}% + \parbox[b]{\marginparwidth}{##2}% + }}% + }{ + \smash{\makebox[\textwidth][r]{% + \parbox[b]{\marginparwidth}{\flushright{##2}}% + \makebox[\marginparsep][c]{\rule[-2\vscale]{1pt}{27.4\vscale+\f@size mm}}% + \parbox[b]{\textwidth}{\flushleft{##3}}% + }}% + } + \else% + \smash{\makebox[0pt][l]{% + \parbox[b]{\textwidth}{\flushright{##3}}% + \makebox[\marginparsep][c]{\rule[-2\vscale]{1pt}{27.4\vscale+\f@size mm}}% + \parbox[b]{\marginparwidth}{##2}% + }}% + \fi% + }% + }% + \RedeclareSectionCommand[beforeskip=0cm,afterskip=10\vscale]{chapter}% + \setlength{\mtocshift}{-3.5\vscale}% +} + +% Takes as input the image path and optionally the "beforeskip" +\DeclareDocumentCommand{\setchapterimage}{O{55\vscale} m}{% + \setchapterpreamble[o]{% + \vspace*{-27\vscale}\hspace*{\dimexpr - \hoffset - \oddsidemargin - 1in}% + \includegraphics[width=\paperwidth,height=#1+27\vscale,keepaspectratio=false]{#2}% + }% + \chapterstylebar% + % beforeskip=-(figure_height-top_margin) + \RedeclareSectionCommand[beforeskip=-#1, afterskip=6\vscale]{chapter}% + \setlength{\mtocshift}{0cm}% +} + +% By default start with the plain style +\chapterstyleplain + +%---------------------------------------------------------------------------------------- +% FONTS AND STYLES +%---------------------------------------------------------------------------------------- + +% Set KOMA fonts for book-specific elements +\addtokomafont{part}{\normalfont\scshape\bfseries} +\addtokomafont{partentry}{\normalfont\scshape\bfseries} +\addtokomafont{chapter}{\normalfont\bfseries} +\addtokomafont{chapterentry}{\normalfont\bfseries} + +% Set KOMA fonts for elements common to all classes +\addtokomafont{section}{\normalfont\bfseries} +\addtokomafont{subsection}{\normalfont\bfseries} +\addtokomafont{subsubsection}{\normalfont\bfseries} +\addtokomafont{paragraph}{\normalfont\bfseries} +\setkomafont{descriptionlabel}{\normalfont\bfseries} + +%---------------------------------------------------------------------------------------- +% TOC, LOF & LOT +%---------------------------------------------------------------------------------------- + +% Set default options regarding the table of contents +\PassOptionsToClass{toc=listof}{\@baseclass} +\PassOptionsToClass{toc=index}{\@baseclass} +\PassOptionsToClass{toc=bibliography}{\@baseclass} + +%---------------------------------------------------------------------------------------- +% NUMBERING +%---------------------------------------------------------------------------------------- + +%\setcounter{secnumdepth}{\kao@secnumdepth} % Set section numbering depth + +\counterwithin*{sidenote}{chapter} % Uncomment to reset the sidenote counter at each chapter +%\counterwithout{sidenote}{chapter} % Uncomment to have one sidenote counter for the whole document diff --git a/tex/kaohandt.cls b/tex/kaohandt.cls new file mode 100644 index 0000000..a536c85 --- /dev/null +++ b/tex/kaohandt.cls @@ -0,0 +1,96 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% kaobook +% LaTeX Class +% Version 0.9.8 (2021/08/23) +% +% This template originates from: +% https://www.LaTeXTemplates.com +% +% For the latest template development version and to make contributions: +% https://github.com/fmarotta/kaobook +% +% Authors: +% Federico Marotta (federicomarotta@mail.com) +% Based on the doctoral thesis of Ken Arroyo Ohori (https://3d.bk.tudelft.nl/ken/en) +% and on the Tufte-LaTeX class. +% Modified for LaTeX Templates by Vel (vel@latextemplates.com) +% +% License: +% LPPL (see included MANIFEST.md file) +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%---------------------------------------------------------------------------------------- +% CLASS CONFIGURATION +%---------------------------------------------------------------------------------------- + +\NeedsTeXFormat{LaTeX2e} +\ProvidesClass{kaohandt}[2021/08/23 v0.9.8 kaohandt] +\newcommand{\@baseclass}{scrartcl} % Base class name + +% Set the default options +\PassOptionsToClass{a4paper}{\@baseclass} + +% Pass through any other options to the base class +\DeclareOption*{\PassOptionsToClass{\CurrentOption}{\@baseclass}} + +\ProcessOptions\relax % Process the options + +\LoadClass{\@baseclass} % Load the base class + +\RequirePackage{kao} % Load the code common to all classes + +%---------------------------------------------------------------------------------------- +% TITLE-RELATED SETTINGS +%---------------------------------------------------------------------------------------- + +% Left-align title, authors and date +\xpatchcmd{\@maketitle}{\begin{center}}{\begin{flushleft}}{}{} +\xpatchcmd{\@maketitle}{\end{center}}{\end{flushleft}}{}{} +\xpatchcmd{\@maketitle}{\begin{tabular}[t]{c}}{\begin{tabular}[t]{@{}l@{}}}{}{} + +% Set the font for the title +\addtokomafont{title}{\normalfont\bfseries} + +% Customise the abstract +\RequirePackage[style]{abstract} + +\setlength{\absleftindent}{0pt}% No indentation in the abstract +\if@abstrt + \renewcommand{\abstitlestyle}[1]{% + \vspace{-0.6cm}% + \begin{center}% + {\normalfont\bfseries\hspace{-3em} \abstractname\vspace{-.5em}\vspace{\z@}}% + \end{center}% + } +\else + \renewcommand{\abstitlestyle}[1]{\vspace{-.5em}\vspace{\z@}}% +\fi + +% Set KOMA fonts +\addtokomafont{section}{\normalfont\bfseries} +\addtokomafont{subsection}{\normalfont\bfseries} +\addtokomafont{subsubsection}{\normalfont\bfseries} +\addtokomafont{paragraph}{\normalfont\bfseries} +\setkomafont{descriptionlabel}{\normalfont\bfseries} + +%---------------------------------------------------------------------------------------- +% TOC +%---------------------------------------------------------------------------------------- + +% Adjust the positions of margintoc and marginnotes +\setlength{\mtocshift}{-0.6cm} +\renewcommand{\marginnotevadjust}{-4pt} + +% Do not add lists to the TOC +\PassOptionsToClass{toc=nolistof}{\@baseclass} +\unsettoc{toc}{totoc} + +%---------------------------------------------------------------------------------------- +% NUMBERING +%---------------------------------------------------------------------------------------- + +%\setcounter{secnumdepth}{\kao@secnumdepth} % Set section numbering depth + +\counterwithin*{sidenote}{section} % Uncomment to reset the sidenote counter at each section +%\counterwithout{sidenote}{section} % Uncomment to have one sidenote counter for the whole document diff --git a/tex/kaorefs.sty b/tex/kaorefs.sty new file mode 100644 index 0000000..92d32aa --- /dev/null +++ b/tex/kaorefs.sty @@ -0,0 +1,241 @@ +\ProvidesPackage{kaorefs} + +%---------------------------------------------------------------------------------------- +% PACKAGE OPTIONS AND DEPENDENCIES +%---------------------------------------------------------------------------------------- + +% Easily label and reference elements with this package +% Note that, in figures and tables, \label must appear after \caption +% Load this package last + +% Pass this package's options to hyperref and varioref +\DeclareOption*{\PassOptionsToPackage{\CurrentOption}{varioref}} +\DeclareOption*{\PassOptionsToPackage{\CurrentOption}{hyperref}} +\DeclareOption*{\PassOptionsToPackage{\CurrentOption}{cleveref}} +\ProcessOptions\relax + +\let\thmname\relax % Workaround to get rid of an annoying error +\RequirePackage{amsthm} % Needed by cleveref +\RequirePackage{varioref} +\RequirePackage{hyperref} +\RequirePackage[capitalise,nameinlink,noabbrev]{cleveref} + + +%---------------------------------------------------------------------------------------- +% LANGUAGE-SPECIFIC STRINGS +%---------------------------------------------------------------------------------------- + +% #LANGUAGE +\newcommand{\chapternameshort}{} +\newcommand{\sectionname}{} +\newcommand{\sectionnameshort}{} +\newcommand{\subsectionname}{} +\newcommand{\subsectionnameplural}{} +\newcommand{\subsectionnameshort}{} +\newcommand{\figurenameshort}{} +\newcommand{\tablenameshort}{} +\newcommand{\eqname}{} +\newcommand{\eqnameshort}{} +\newcommand{\defname}{} +\newcommand{\assumname}{} +\newcommand{\thmname}{} +\newcommand{\propname}{} +\newcommand{\lemmaname}{} +\newcommand{\remarkname}{} +\newcommand{\examplename}{} +\newcommand{\exercisename}{} + +\addto\captionsgerman{% + \renewcommand{\chapternameshort}{Kap.} + \renewcommand{\sectionname}{Abschnitt} + \renewcommand{\sectionnameshort}{Abschn.} + \renewcommand{\subsectionname}{Unterabschnitt} + \renewcommand{\subsectionnameplural}{Unterabschnitte} + \renewcommand{\subsectionnameshort}{Unterabschn.} + \renewcommand{\figurenameshort}{Abb.} + \renewcommand{\tablenameshort}{Tab.} + \renewcommand{\eqname}{Gleichung} + \renewcommand{\eqnameshort}{Gl.} + \renewcommand{\defname}{Definition} + \renewcommand{\assumname}{Hypothese} + \renewcommand{\thmname}{Satz} + \renewcommand{\propname}{Proposition} + \renewcommand{\lemmaname}{Lemma} + \renewcommand{\remarkname}{Bemerkung} + \renewcommand{\examplename}{Beispiel} + \renewcommand{\exercisename}{Übung} +} +\addto\captionsdanish{% + \renewcommand{\chapternameshort}{Kap.} + \renewcommand{\sectionname}{Sektion} + \renewcommand{\sectionnameshort}{Sek.} + \renewcommand{\subsectionname}{Undersektion} + \renewcommand{\subsectionnameplural}{Undersectioner} + \renewcommand{\subsectionnameshort}{Undersek.} + \renewcommand{\figurenameshort}{Fig.} + \renewcommand{\tablenameshort}{Tab.} + \renewcommand{\eqname}{Formel} + \renewcommand{\eqnameshort}{Frml.} + \renewcommand{\defname}{Definition} + \renewcommand{\assumname}{Hypotese} + \renewcommand{\thmname}{Sætning} + \renewcommand{\propname}{Postulat} + \renewcommand{\lemmaname}{Hjælpesætning} + \renewcommand{\remarkname}{Bemærkning} + \renewcommand{\examplename}{Eksempel} + \renewcommand{\exercisename}{Øvelse} +} +\addto\captionsenglish{% + \renewcommand{\chapternameshort}{Chap.} + \renewcommand{\sectionname}{Section} + \renewcommand{\sectionnameshort}{Sec.} + \renewcommand{\subsectionname}{Subsection} + \renewcommand{\subsectionnameplural}{Subsections} + \renewcommand{\subsectionnameshort}{Subsec.} + \renewcommand{\figurenameshort}{Fig.} + \renewcommand{\tablenameshort}{Tab.} + \renewcommand{\eqname}{Equation} + \renewcommand{\eqnameshort}{Eq.} + \renewcommand{\defname}{Definition} + \renewcommand{\assumname}{Assumption} + \renewcommand{\thmname}{Theorem} + \renewcommand{\propname}{Proposition} + \renewcommand{\lemmaname}{Lemma} + \renewcommand{\remarkname}{Remark} + \renewcommand{\examplename}{Example} + \renewcommand{\exercisename}{Exercise} +} +\addto\captionsitalian{% + \renewcommand{\chapternameshort}{Cap.} + \renewcommand{\sectionname}{Sezione} + \renewcommand{\sectionnameshort}{Sez.} + \renewcommand{\subsectionname}{Sottosezione} + \renewcommand{\subsectionnameplural}{Sottosezioni} + \renewcommand{\subsectionnameshort}{Sottosezione} + \renewcommand{\figurenameshort}{Fig.} + \renewcommand{\tablenameshort}{Tab.} + \renewcommand{\eqname}{Equazione} + \renewcommand{\eqnameshort}{Eq.} + \renewcommand{\defname}{Definizione} + \renewcommand{\assumname}{Assunzione} + \renewcommand{\thmname}{Teorema} + \renewcommand{\propname}{Proposizione} + \renewcommand{\lemmaname}{Lemma} + \renewcommand{\remarkname}{Osservazione} + \renewcommand{\examplename}{Esempio} + \renewcommand{\exercisename}{Esercizio} +} +% Do you speak other languages? Please, feel free to add the captions! + + +%---------------------------------------------------------------------------------------- +% LABELLING COMMANDS +%---------------------------------------------------------------------------------------- + +\newcommand{\labpage}[1]{\label{page:#1}} +\newcommand{\labpart}[1]{\label{part:#1}} +\newcommand{\labch}[1]{\label{ch:#1}} +\newcommand{\labsec}[1]{\label{sec:#1}} +\newcommand{\labsubsec}[1]{\label{subsec:#1}} +\newcommand{\labfig}[1]{\label{fig:#1}} +\newcommand{\labtab}[1]{\label{tab:#1}} +\newcommand{\labeq}[1]{\label{eq:#1}} +\newcommand{\labdef}[1]{\label{def:#1}} +\newcommand{\labthm}[1]{\label{thm:#1}} +\newcommand{\labassum}[1]{\label{assum:#1}} +\newcommand{\labprop}[1]{\label{prop:#1}} +\newcommand{\lablemma}[1]{\label{lemma:#1}} +\newcommand{\labremark}[1]{\label{remark:#1}} +\newcommand{\labexample}[1]{\label{example:#1}} +\newcommand{\labexercise}[1]{\label{exercise:#1}} + + +%---------------------------------------------------------------------------------------- +% REFERENCING COMMANDS +%---------------------------------------------------------------------------------------- + +\newcommand{\refpage}[1]{\hyperref[#1]{\pagename}\xspace\pageref{page:#1}} % Page 84 +\newcommand{\vrefpage}[1]{\vpageref*{page:#1}} % on the following page, on page 84 + +% For unnumbered parts +\newcommand{\arefpart}[1]{\hyperref[part:#1]{\partname}\xspace`\nameref{part:#1}'} % Part `Name of the Part' +\newcommand{\avrefpart}[1]{\hyperref[part:#1]{\partname}\xspace`\nameref{part:#1}' \vpageref{part:#1}} % Part `Name of the Part' on page 84 + +% For numbered parts +\newcommand{\refpart}[1]{\hyperref[part:#1]{\partname}\xspace\ref{part:#1}} % Part IV +\newcommand{\vrefpart}[1]{\hyperref[part:#1]{\partname}\xspace\vref{part:#1}} % Part IV, Part IV on the following page, Part IV on page 84 +\newcommand{\nrefpart}[1]{\hyperref[part:#1]{\partname}\xspace\ref{part:#1} (\nameref{part:#1})} +\newcommand{\frefpart}[1]{\hyperref[part:#1]{\partname\xspace\ref{part:#1} (\nameref{part:#1}) \vpageref{part:#1}}} % Part IV (Name of the Part), Part IV (Name of the Part) on the following page, Part IV (Name of the Part) on page 84) + +%\newcommand{\refch}[1]{\hyperref[#1]{\chaptername\xspace\usekomafont{chapter}\normalsize\nameref{ch:#1}}\xspace\vpageref{ch:#1}\,} +\newcommand{\refchshort}[1]{\hyperref[ch:#1]{\chapternameshort\xspace\ref{ch:#1}}} +\newcommand{\refch}[1]{\hyperref[ch:#1]{\chaptername\xspace\ref{ch:#1}}} +\newcommand{\vrefch}[1]{\hyperref[ch:#1]{\chaptername\xspace\ref{ch:#1} \vpageref{ch:#1}}} +\newcommand{\nrefch}[1]{\hyperref[ch:#1]{\chaptername\xspace\ref{ch:#1} (\nameref{ch:#1})}} +\newcommand{\frefch}[1]{\hyperref[ch:#1]{\chaptername\xspace\ref{ch:#1} (\nameref{ch:#1}) \vpageref{ch:#1}}} + +%\newcommand{\refsec}[1]{Section~{\usekomafont{section}\normalsize\nameref{sec:#1}}\xspace\vpageref{sec:#1}\,} +\newcommand{\refsecshort}[1]{\hyperref[sec:#1]{\sectionnameshort\xspace\ref{sec:#1}}} +\newcommand{\refsec}[1]{\hyperref[sec:#1]{\sectionname\xspace\ref{sec:#1}}} +\newcommand{\vrefsec}[1]{\hyperref[sec:#1]{\sectionname\xspace\vref{sec:#1}}} +\newcommand{\nrefsec}[1]{\hyperref[sec:#1]{\sectionname\xspace\ref{sec:#1} (\nameref{sec:#1})}} +\newcommand{\frefsec}[1]{\hyperref[sec:#1]{\sectionname\xspace\ref{sec:#1} (\nameref{sec:#1}) \vpageref{sec:#1}}} + +\newcommand{\refsubsecshort}[1]{\hyperref[subsec:#1]{\sectionnameshort\xspace\ref{subsec:#1}}} +\newcommand{\refsubsec}[1]{\hyperref[subsec:#1]{\subsectionname\xspace\ref{subsec:#1}}} +\newcommand{\vrefsubsec}[1]{\hyperref[subsec:#1]{\subsectionname\xspace\vref{subsec:#1}}} +\newcommand{\nrefsubsec}[1]{\hyperref[subsec:#1]{\subsectionname\xspace\ref{subsec:#1} (\nameref{subsec:#1})}} +\newcommand{\frefsubsec}[1]{\hyperref[subsec:#1]{\subsectionname\xspace\ref{subsec:#1} (\nameref{subsec:#1}) \vpageref{subsec:#1}}} + +%\newcommand{\reffig}[1]{{\hypersetup{colorlinks=false}\usekomafont{captionlabel}\hyperref[fig:#1]{Figure}\xspace\ref{fig:#1}}} +\newcommand{\reffigshort}[1]{\hyperref[fig:#1]{\figurenameshort\xspace\ref{fig:#1}}} +\newcommand{\reffig}[1]{\hyperref[fig:#1]{\figurename}\xspace\ref{fig:#1}} +\newcommand{\vreffig}[1]{\hyperref[fig:#1]{\figurename\xspace\vref{fig:#1}}} + +%\newcommand{\reftab}[1]{{\hypersetup{colorlinks=false}\usekomafont{captionlabel}\hyperref[tab:#1]{Table}\xspace\ref{tab:#1}}} +\newcommand{\reftab}[1]{\hyperref[tab:#1]{\tablename}\xspace\ref{tab:#1}} +\newcommand{\vreftab}[1]{\hyperref[tab:#1]{\tablename\xspace\vref{tab:#1}}} + +\newcommand{\refeqshort}[1]{\hyperref[eq:#1]\eqnameshort\xspace(\ref{eq:#1})} +\newcommand{\refeq}[1]{\hyperref[eq:#1]\eqname\xspace\ref{eq:#1}} +\newcommand{\vrefeq}[1]{\hyperref[eq:#1]\eqname\xspace\vref{eq:#1}} + +\newcommand{\refdef}[1]{\hyperref[def:#1]\defname\xspace\ref{def:#1}} +\newcommand{\vrefdef}[1]{\hyperref[def:#1]\defname\xspace\vref{def:#1}} + +\newcommand{\refassum}[1]{\hyperref[assum:#1]\assumname\xspace\ref{assum:#1}} +\newcommand{\vrefassum}[1]{\hyperref[assum:#1]\assumname\xspace\vref{assum:#1}} + +\newcommand{\refthm}[1]{\hyperref[thm:#1]\thmname\xspace\ref{thm:#1}} +\newcommand{\vrefthm}[1]{\hyperref[thm:#1]\thmname\xspace\vref{thm:#1}} + +\newcommand{\refprop}[1]{\hyperref[prop:#1]\propname\xspace\ref{prop:#1}} +\newcommand{\vrefprop}[1]{\hyperref[prop:#1]\propname\xspace\vref{prop:#1}} + +\newcommand{\reflemma}[1]{\hyperref[lemma:#1]\lemmaname\xspace\ref{lemma:#1}} +\newcommand{\vreflemma}[1]{\hyperref[lemma:#1]\lemmaname\xspace\vref{lemma:#1}} + +\newcommand{\refremark}[1]{\hyperref[remark:#1]\remarkname\xspace\ref{remark:#1}} +\newcommand{\vrefremark}[1]{\hyperref[remark:#1]\remarkname\xspace\vref{remark:#1}} + +\newcommand{\refexample}[1]{\hyperref[example:#1]\examplename\xspace\ref{example:#1}} +\newcommand{\vrefexample}[1]{\hyperref[example:#1]\examplename\xspace\vref{example:#1}} + +\newcommand{\refexercise}[1]{\hyperref[exercise:#1]\exercisename\xspace\ref{exercise:#1}} +\newcommand{\vrefexercise}[1]{\hyperref[exercise:#1]\exercisename\xspace\vref{exercise:#1}} + + +%---------------------------------------------------------------------------------------- +% CLEVEREF CUSTOMISATION +%---------------------------------------------------------------------------------------- + +% Hyperlink the page reference as well +\let\oldvpageref\vpageref +\renewcommand{\vpageref}[1]{\hyperref[#1]{\oldvpageref{#1}}} + +% Remove parentheses around equations +\creflabelformat{equation}{#2\textup{#1}#3} + +% Set the refname for subsections +\crefname{subsection}{\subsectionname}{\subsectionnameplural} +\Crefname{subsection}{\subsectionname}{\subsectionnameplural} diff --git a/tex/kaotheorems.sty b/tex/kaotheorems.sty new file mode 100644 index 0000000..43c160d --- /dev/null +++ b/tex/kaotheorems.sty @@ -0,0 +1,396 @@ +\ProvidesPackage{kaotheorems} + +%---------------------------------------------------------------------------------------- +% PACKAGE OPTIONS AND DEPENDENCIES +%---------------------------------------------------------------------------------------- + +\RequirePackage{kvoptions} % Handle package options +\SetupKeyvalOptions{ + family = kaotheorems, + prefix = kaotheorems@ +} + +\DeclareBoolOption{framed}% If true, put theorems into colorful boxes, otherwise write them like normal text + +% Define the options to finely tune the background color of each element. +% If only the 'background' option is specified, all types of theorem will have that background. If more specific options are set, the previous option will be overwritten. +\newcommand{\kaotheorems@defaultbg}{Goldenrod!45!white} +\DeclareStringOption[\kaotheorems@defaultbg]{background} +\DeclareStringOption[\kaotheorems@defaultbg]{theorembackground} +\DeclareStringOption[\kaotheorems@defaultbg]{propositionbackground} +\DeclareStringOption[\kaotheorems@defaultbg]{lemmabackground} +\DeclareStringOption[\kaotheorems@defaultbg]{corollarybackground} +\DeclareStringOption[\kaotheorems@defaultbg]{definitionbackground} +\DeclareStringOption[\kaotheorems@defaultbg]{assumptionbackground} +\DeclareStringOption[\kaotheorems@defaultbg]{remarkbackground} +\DeclareStringOption[\kaotheorems@defaultbg]{examplebackground} +\DeclareStringOption[\kaotheorems@defaultbg]{exercisebackground} + +\ProcessKeyvalOptions{kaotheorems} % Process the options + +\let\openbox\relax % Workaround to avoid a nasty error +\RequirePackage{amsmath} % Improved mathematics +\RequirePackage{amsthm} % Mathematical environments +\RequirePackage{thmtools} % Theorem styles + +%---------------------------------------------------------------------------------------- +% STYLE DEFINITIONS +%---------------------------------------------------------------------------------------- + +\ifkaotheorems@framed% Define the style of the mdframed boxes for theorems + \RequirePackage[most]{tcolorbox} + + % Box style + \tcbset{tcbkao/.style={ + breakable, + before skip=\topskip, + after skip=\topskip, + left skip=0pt, + right skip=0pt, + top=5pt, + bottom=3pt, + left=2pt, + right=2pt, + sharp corners, + boxrule=0pt, + frame hidden, + }} + + % Theorem styles + \declaretheoremstyle[ + %spaceabove=.5\thm@preskip, + %spacebelow=.5\thm@postskip, + %headfont=\normalfont\bfseries,%\scshape, + %notefont=\normalfont, notebraces={ (}{)}, + bodyfont=\normalfont\itshape, + %headformat={\NAME\space\NUMBER\space\NOTE}, + headpunct={}, + %postheadspace={.5em plus .1em minus .1em}, + %prefoothook={\hfill\qedsymbol} + ]{kaoplain} + \declaretheoremstyle[ + %spaceabove=.5\thm@preskip, + %spacebelow=.5\thm@postskip, + %headfont=\normalfont\bfseries,%\scshape, + %notefont=\normalfont, notebraces={ (}{)}, + bodyfont=\normalfont\itshape, + %headformat={\NAME\space\NUMBER\space\NOTE}, + headpunct={}, + postheadspace={.5em plus .1em minus .1em}, + %prefoothook={\hfill\qedsymbol} + ]{kaodefinition} + \declaretheoremstyle[ + %spaceabove=.5\thm@preskip, + %spacebelow=.5\thm@postskip, + %headfont=\normalfont\bfseries,%\scshape, + %notefont=\normalfont, notebraces={ (}{)}, + bodyfont=\normalfont\itshape, + %headformat={\NAME\space\NUMBER\space\NOTE}, + headpunct={}, + postheadspace={.5em plus .1em minus .1em}, + %prefoothook={\hfill\qedsymbol} + ]{kaoassumption} + \declaretheoremstyle[ + %spaceabove=.5\thm@preskip, + %spacebelow=.5\thm@postskip, + %headfont=\normalfont\bfseries, + %notefont=\normalfont, notebraces={ (}{)}, + %bodyfont=\normalfont, + %headformat={\footnotesize$\triangleright$\space\normalsize\NAME\space\NUMBER\space\NOTE}, + %headformat={\NAME\space\NUMBER\space\NOTE}, + headpunct={}, + postheadspace={.5em plus .1em minus .1em}, + %refname={theorem,theorems}, + %Refname={Theorem,Theorems}, + ]{kaoremark} + \declaretheoremstyle[ + %spaceabove=.5\thm@preskip, + %spacebelow=.5\thm@postskip, + %headfont=\normalfont\bfseries, + %notefont=\normalfont, notebraces={ (}{)}, + %bodyfont=\normalfont, + %headformat={\NAME\space\NUMBER\space\NOTE}, + headpunct={}, + postheadspace={.5em plus .1em minus .1em}, + %prefoothook={\hfill\qedsymbol} + %refname={theorem,theorems}, + %Refname={Theorem,Theorems}, + ]{kaoexample} + \declaretheoremstyle[ + %spaceabove=.5\thm@preskip, + %spacebelow=.5\thm@postskip, + %headfont=\normalfont\bfseries, + %notefont=\normalfont, notebraces={ (}{)}, + %bodyfont=\small, + %headformat={\NAME\space\NUMBER\space\NOTE}, + headpunct={}, + postheadspace={.5em plus .1em minus .1em}, + %prefoothook={\hfill\qedsymbol} + %refname={theorem,theorems}, + %Refname={Theorem,Theorems}, + ]{kaoexercise} + + % Theorems using the 'kaoplain' style + \theoremstyle{kaoplain} + \declaretheorem[ + name=Theorem, + style=kaoplain, + %refname={theorem,theorems}, + refname={Theorem,Theorems}, + Refname={Theorem,Theorems}, + numberwithin=section, + ]{theorem} + \tcolorboxenvironment{theorem}{ + colback=\kaotheorems@theorembackground,tcbkao + } + \declaretheorem[ + name=Proposition, + %refname={proposition,propositions}, + refname={Proposition,Propositions}, + Refname={Proposition,Propositions}, + sibling=theorem, + ]{proposition} + \tcolorboxenvironment{proposition}{ + colback=\kaotheorems@propositionbackground,tcbkao + } + \declaretheorem[ + name=Lemma, + %refname={lemma,lemmas}, + refname={Lemma,Lemmas}, + Refname={Lemma,Lemmas}, + sibling=theorem, + ]{lemma} + \tcolorboxenvironment{lemma}{ + colback=\kaotheorems@lemmabackground,tcbkao + } + \declaretheorem[ + name=Corollary, + %refname={corollary,corollaries}, + refname={Corollary,Corollaries}, + Refname={Corollary,Corollaries}, + sibling=theorem, + ]{corollary} + \tcolorboxenvironment{corollary}{ + colback=\kaotheorems@corollarybackground,tcbkao + } + + % Theorems using the 'kaodefinition' style + \theoremstyle{kaodefinition} + \declaretheorem[ + name=Definition, + %refname={definition,definitions}, + refname={Definition,Definitions}, + Refname={Definition,Definitions}, + numberwithin=section, + ]{definition} + \tcolorboxenvironment{definition}{ + colback=\kaotheorems@definitionbackground,tcbkao + } + + % Theorems using the 'kaoassumption' style + \theoremstyle{kaoassumption} + \declaretheorem[ + name=Assumption, + %refname={assumption,assumptions}, + refname={Assumption,Assumptions}, + Refname={Assumption,Assumptions}, + numberwithin=section, + ]{assumption} + \tcolorboxenvironment{assumption}{ + colback=\kaotheorems@assumptionbackground,tcbkao + } + + % Theorems using the 'kaoremark' style + \theoremstyle{kaoremark} + \declaretheorem[ + name=Remark, + %refname={remark,remarks}, + refname={Remark,Remarks}, + Refname={Remark,Remarks}, + numberwithin=section, + ]{remark} + \tcolorboxenvironment{remark}{ + colback=\kaotheorems@remarkbackground,tcbkao + } + + % Theorems using the 'kaoexample' style + \theoremstyle{kaoexample} + \declaretheorem[ + name=Example, + %refname={example,examples}, + refname={Example,Examples}, + Refname={Example,Examples}, + numberwithin=section, + ]{example} + \tcolorboxenvironment{example}{ + colback=\kaotheorems@examplebackground,tcbkao + } + + % Theorems using the 'kaoexercise' style + \theoremstyle{kaoexercise} + \declaretheorem[ + name=Exercise, + %refname={exercise,exercises}, + refname={Exercise,Exercises}, + Refname={Exercise,Exercises}, + numberwithin=section, + ]{exercise} + \tcolorboxenvironment{exercise}{ + colback=\kaotheorems@exercisebackground,tcbkao + } + + %\renewcommand{\thetheorem}{\arabic{chapter}.\arabic{section}.\arabic{theorem}} + %\renewcommand{\thetheorem}{\arabic{subsection}.\arabic{theorem}} + %\renewcommand{\qedsymbol}{$\blacksquare$} +\else % If not using mdframed + % Theorem styles + \declaretheoremstyle[ + spaceabove=.6\thm@preskip, + spacebelow=.1\thm@postskip, + %headfont=\normalfont\bfseries,%\scshape, + %notefont=\normalfont, notebraces={ (}{)}, + bodyfont=\normalfont\itshape, + %headformat={\NAME\space\NUMBER\space\NOTE}, + headpunct={}, + %postheadspace={.5em plus .1em minus .1em}, + %prefoothook={\hfill\qedsymbol} + ]{kaoplain} + \declaretheoremstyle[ + spaceabove=.6\thm@preskip, + spacebelow=.1\thm@postskip, + %headfont=\normalfont\bfseries,%\scshape, + %notefont=\normalfont, notebraces={ (}{)}, + bodyfont=\normalfont\itshape, + %headformat={\NAME\space\NUMBER\space\NOTE}, + headpunct={}, + %postheadspace={.5em plus .1em minus .1em}, + %prefoothook={\hfill\qedsymbol} + ]{kaodefinition} + \declaretheoremstyle[ + spaceabove=.6\thm@preskip, + spacebelow=.1\thm@postskip, + %headfont=\normalfont\bfseries,%\scshape, + %notefont=\normalfont, notebraces={ (}{)}, + bodyfont=\normalfont\itshape, + %headformat={\NAME\space\NUMBER\space\NOTE}, + headpunct={}, + %postheadspace={.5em plus .1em minus .1em}, + %prefoothook={\hfill\qedsymbol} + ]{kaoassumption} + \declaretheoremstyle[ + spaceabove=.6\thm@preskip, + spacebelow=.1\thm@postskip, + %headfont=\normalfont\bfseries, + %notefont=\normalfont, notebraces={ (}{)}, + %bodyfont=\normalfont, + %headformat={\footnotesize$\triangleright$\space\normalsize\NAME\space\NUMBER\space\NOTE}, + %headformat={\NAME\space\NUMBER\space\NOTE}, + headpunct={}, + %postheadspace={.5em plus .1em minus .1em}, + %refname={theorem,theorems}, + %Refname={Theorem,Theorems}, + ]{kaoremark} + \declaretheoremstyle[ + spaceabove=.6\thm@preskip, + spacebelow=.1\thm@postskip, + %headfont=\normalfont\bfseries, + %notefont=\normalfont, notebraces={ (}{)}, + %bodyfont=\normalfont, + %headformat={\NAME\space\NUMBER\space\NOTE}, + headpunct={}, + %postheadspace={.5em plus .1em minus .1em}, + %prefoothook={\hfill\qedsymbol} + %refname={theorem,theorems}, + %Refname={Theorem,Theorems}, + ]{kaoexample} + \declaretheoremstyle[ + %spaceabove=.5\thm@preskip, + %spacebelow=.5\thm@postskip, + %headfont=\normalfont\bfseries, + %notefont=\normalfont, notebraces={ (}{)}, + %bodyfont=\normalfont, + %headformat={\NAME\space\NUMBER\space\NOTE}, + headpunct={}, + postheadspace={.5em plus .1em minus .1em}, + %prefoothook={\hfill\qedsymbol} + %refname={theorem,theorems}, + %Refname={Theorem,Theorems}, + ]{kaoexercise} + + % Theorems using the 'kaoplain' style + \theoremstyle{kaoplain} + \declaretheorem[ + name=Theorem, + refname={Theorem,Theorems}, + Refname={Theorem,Theorems}, + numberwithin=section, + ]{theorem} + \declaretheorem[ + name=Proposition, + refname={Proposition,Propositions}, + Refname={Proposition,Propositions}, + sibling=theorem, + ]{proposition} + \declaretheorem[ + name=Lemma, + refname={Lemma,Lemmas}, + Refname={Lemma,Lemmas}, + sibling=theorem, + ]{lemma} + \declaretheorem[ + name=Corollary, + refname={Corollary,Corollaries}, + Refname={Corollary,Corollaries}, + sibling=theorem, + ]{corollary} + + % Theorems using the 'kaodefinition' style + \theoremstyle{kaodefinition} + \declaretheorem[ + name=Definition, + refname={Definition,Definitions}, + Refname={Definition,Definitions}, + numberwithin=section, + ]{definition} + + % Theorems using the 'kaoassumption' style + \theoremstyle{kaoassumption} + \declaretheorem[ + name=Assumption, + refname={Assumption,Assumptions}, + Refname={Assumption,Assumptions}, + numberwithin=section, + ]{assumption} + + % Theorems using the 'kaoremark' style + \theoremstyle{kaoremark} + \declaretheorem[ + name=Remark, + refname={Remark,Remarks}, + Refname={Remark,Remarks}, + numberwithin=section, + ]{remark} + + % Theorems using the 'kaoexample' style + \theoremstyle{kaoexample} + \declaretheorem[ + name=Example, + refname={Example,Examples}, + Refname={Example,Examples}, + numberwithin=section, + ]{example} + + % Theorems using the 'kaoexercise' style + \theoremstyle{kaoexercise} + \declaretheorem[ + name=Exercise, + refname={Exercise,Exercises}, + Refname={Exercise,Exercises}, + numberwithin=section, + ]{exercise} + + %\renewcommand{\thetheorem}{\arabic{chapter}.\arabic{section}.\arabic{theorem}} + %\renewcommand{\thetheorem}{\arabic{subsection}.\arabic{theorem}} + %\renewcommand{\qedsymbol}{$\blacksquare$} +\fi + diff --git a/tex/main.tex b/tex/main.tex new file mode 100644 index 0000000..5d4de84 --- /dev/null +++ b/tex/main.tex @@ -0,0 +1,66 @@ +\documentclass[ + a4paper, + twoside=false +]{kaobook} + +\ifxetexorluatex + \usepackage[babelshorthands]{polyglossia} + \setmainlanguage{russian} + \setotherlanguage{english} +\else + \usepackage[russian, english]{babel} +\fi +\usepackage[autostyle]{csquotes} + +\usepackage{microtype} + +\usepackage{kaobiblio} +\addbibresource{FormalLanguageConstrainedReachabilityLectureNotes.bib} + +\usepackage[framed=true]{kaotheorems} + +\usepackage{kaorefs} + +\usepackage{algpseudocode} +\usepackage{algorithm} +\usepackage{algorithmicx} + + +\usetikzlibrary{fit,calc,automata,positioning} +\usetikzlibrary{shapes.geometric} +\usetikzlibrary{decorations.pathmorphing} + +\tikzset{ + %->, % makes the edges directed + %>=stealth’, % makes the arrow heads bold + node distance=4cm, % specifies the minimum distance between two nodes. Change if necessary. + %every state/.style={thick, fill=gray!10}, % sets the properties for each ’state’ node + initial text=$ $, % sets the text that appears on the start arrow +} + +\title{О достижимости с ограничениями в терминах формальных языков} +\author{Семён Григорьев} +\date{\today} + +\begin{document} + +\frontmatter + +\maketitle +\tableofcontents + +\mainmatter +\setchapterstyle{kao} + +\input{List_of_contributors} +\input{Introduction} +\input{LinearAlgebra} +\input{GraphTheoryIntro} +\input{FormalLanguageTheoryIntro} + +\backmatter +\setchapterstyle{plain} + +\printbibliography + +\end{document}