\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[main=russian,english]{babel}
\usepackage{caption}
\usepackage{subcaption}
\usepackage{graphicx}
\usepackage{hyperref}
\usepackage{geometry} % Простой способ задавать поля
\geometry{top=15mm}
\geometry{bottom=15mm}
\geometry{left=30mm}
\geometry{right=15mm}
\title{Lab work $5+$\\ Neural ODE }

\author{Safiullin Robert}
\date{}
\begin{document}
\maketitle

\addtocontents{toc}{\setcounter{tocdepth}{-10}}

\subsection*{Motivation}
The motivation for this work was the desire to test how neural ODEs can be used to approximate the time series of solutions and phase portraits of a double pendulum.
\subsection*{Problem statement}
\begin{center}

\includegraphics[scale = 0.1]{pendula.png}
\end{center}

A system consisting of two pendulums of length L, masses m, connected by a spring of length l is described by the following system of equations of motion:
\begin{equation}
    m_1 L^2 \ddot{\theta_1} + m_1 g L \theta_1 = -kl^2(\theta_1 - \theta_2)
\end{equation}
\begin{equation}
    m_2 L^2 \ddot{\theta_2} + m_2 g L \theta_2 = kl^2(\theta_1 - \theta_2)
\end{equation}
Initial conditions: \\
\begin{center}

$\theta_1(0) = 0$ \\
$\theta_2(0) = 0.44 \pi$ \\
$\dot{\theta_1}(0) = 0$ \\
$\dot{\theta_2}(0) = 0$ \\
L = l \\
$m_1 = m_2 = m$
\end{center}

\newpage

System solutions depending on time under the aforementioned conditions looks like this: \\
\begin{figure}[h]
     \centering
     \begin{subfigure}[b]{0.46\textwidth}
         \centering
         \includegraphics[width=\textwidth]{phase1.png}
         \caption{Pendula 1}
         \label{fig:y equals x}
     \end{subfigure}
     \hfill
     \begin{subfigure}[b]{0.46\textwidth}
         \centering
         \includegraphics[width=\textwidth]{phase2.png}
         \caption{Pendula 2}
         \label{fig:three sin x}
     \end{subfigure}
     \hfill
     \begin{subfigure}[b]{0.45\textwidth}
         \centering
         \includegraphics[width=\textwidth]{angle.png}
         \caption{Solutions}
         \label{fig:five over x}
     \end{subfigure}
        % \caption{Three simple graphs}
        \label{fig:three graphs}
\end{figure}

Plot and approximate its phase portrait  using ODE-net is required

\newpage

\subsection*{Problem solution}
\textbf{ODE - net}

Let there be a process obeying some unknown ODE and let several observations of its trajectory $(z_i, t_i), i \in [1..M]$ be known:
\begin{equation}
    \frac{dz}{dt} = f(z(t), t)
\end{equation}

It is required to approximate with a model the evolution of the system from the state ($z_0, t_0$) to the state ($z_1, t_1$). Let the function $\hat{f}(z, t, \theta)$ - be our model for approximating the dynamic function f(z,t). We need to choose a parameter $\theta$ so that our function coincides with the evolution of the system from the state $(z_0, t_0)$ for the time $t_1-t_0$ by dynamic function f(z,t). The loss function in this case will be written as follows: \\
\begin{equation}
    L(z(t_1) = L(\int^{t_1}_{t_0} f(z(t), t, \theta) dt) = L(ODESolve(z(t_0), f, t_0, t_1, \theta))
\end{equation}
The back propagation of the gradient of the ODE solution for sequential observations is calculated using the following algorithm: \\

\begin{figure}[h]
\centering
\includegraphics[scale = 0.75]{odenet.png}
\caption{Algorithm \protect\footnotemark}
\end{figure}

\footnotetext{Neural Ordinary Differential Equations, Ricky T. Q. Chen and Yulia Rubanova and Jesse Bettencourt and David Duvenaud,2019
      eprint=1806.07366
}

\newpage
\subsection*{Experiment}
We examine the influence of the choice of a numerical method for solving the ODE on the error in approximating the dynamics function $\mathbf{f(z,t)}$. To begin with, let's consider how the approximation $\mathbf{\hat{f}(z, t, \theta)}$ is constructed during optimization: \\
\begin{figure}[h]
     \centering
     \begin{subfigure}[b]{0.48\textwidth}
         \centering
         \includegraphics[width=\textwidth]{1.png}
        %  \caption{Pendula 1}
         \label{fig:y equals x}
     \end{subfigure}
     \hfill
     \begin{subfigure}[b]{0.48\textwidth}
         \centering
         \includegraphics[width=\textwidth]{2.png}
        %  \caption{Pendula 2}
         \label{fig:three sin x}
     \end{subfigure}
     \hfill
     \begin{subfigure}[b]{0.48\textwidth}
         \centering
         \includegraphics[width=\textwidth]{3.png}
        %  \caption{Solutions}
         \label{fig:five over x}
     \end{subfigure}
     \hfill
     \begin{subfigure}[b]{0.48\textwidth}
         \centering
         \includegraphics[width=\textwidth]{4.png}
         \caption{Solutions}
         \label{fig:five over x}
     \end{subfigure}
        \caption{Parameters tuning}
        \label{fig:three graphs}
\end{figure}

\begin{figure}[h]
    \centering
    \includegraphics[scale = 0.3]{final.png}
\caption{Final approximation}
\end{figure}

\newpage
Next, we explore the influence of the selected numerical solutions on model quality using two methods with a fixed step and one with an adaptive one. Quantitatively, this process is presented in the following graph: \\
\begin{figure}[h]
\centering
\includegraphics[scale = 0.35]{losses.png}
\caption{}
\end{figure} \\
As we can see, the simplest Euler method converges poorly to a function $\mathbf{f(z,t)}$ while more advanced higher-order approximation methods provide a good result (as in the above figure)

\newpage
\subsection*{Supplementary}
\href{https://arxiv.org/abs/1806.07366}{Neural Ordinary Differential Equations
} \\
\href{https://github.com/roberts2510/MMoF}{Github}\\
\href{https://en.wikipedia.org/wiki/Pendulum_(mechanics)#Coupled_pendula}{Data}

\end{document}


\documentclass[11pt]{article}
\usepackage[top=2cm,bottom=2cm]{geometry}
\usepackage[T1]{fontenc}
\usepackage{url}
\usepackage{hyperref}
\usepackage{xcolor}
%
\usepackage{amsthm}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{ifthen}
\usepackage{mathpartir}
\usepackage{mathtools}
\input{../../slides/macros}
%
\begin{document}

\title{CO663 Part II: Worksheet 1}

\date{\vspace{-5ex}}
\maketitle

% \pagenumbering{gobble}

\newcommand{\answerbox}[1]{\framebox{\parbox[c][#1]{\textwidth}{
      \color{white}{h}%
    }}}

\section{Introduction}

The objective of this class is to put in practice the typing rules for
language $\lggeE$.
%

\section{Language $\lggeE$}

Here is the syntax and type system for language $\lggeE$ (same as in
the lecture slides).

\subsection{Syntax}

  \[
  \begin{array}{llclll}
    \TYPES & \tau & \Coloneqq & \enum{}  & \enum{} & \text{numbers}
    \\
           &&& \estr{} & \estr{} & \text{strings}
    \\
    \\
    %
    \EXPS & e & \Coloneqq  & \var{x} & \var{x} & \text{variable}
    \\
           &&& \enum{n} & n & \text{numeral}
    \\
           &&& \estr{s} & \litstr{s} & \text{literal}
    \\
           &&& \eplus{e_1}{e_2} & e_1 {+} e_2 & \text{addition}
    \\
           &&& \etimes{e_1}{e_2} & e_1 {*} e_2 & \text{multiplication}
    \\
           &&& \ecat{e_1}{e_2} & e_1 \concat e_2 & \text{concatenate}
    \\
           &&& \elen{e} & \lvert e \rvert & \text{length}
    \\
           &&& \elet{e_1}{x}{e_2} & \clet{e_1}{x}{e_2} & \text{definition}
  \end{array}
  \]
\subsection{Typing rules}

  \[
  \tyrule
  {\etyrulename{var}}
  {\,}
  {\tyjudge{\Gamma_1, \var{x}: \tau, \Gamma_2}{\var{x}}{\tau} }
  \]
  \[
  \tyrule
  {\etyrulename{str}}
  {\,}
  {\tyjudge{\Gamma}{\estr{s}}{\estr{}}}
  \qquad\qquad\qquad
  \tyrule
  {\etyrulename{num}}
  {\,}
  {\tyjudge{\Gamma}{\enum{n}}{\enum{}}}
  % \end{array}
  \]
  \[
  \tyrule
  {\etyrulename{plus}}
  {
    \tyjudge{\Gamma}{e_1}{\enum{}}
    \and
    \tyjudge{\Gamma}{e_2}{\enum{}}
  }
  {\tyjudge{\Gamma}{\eplus{e_1}{e_2}}{\enum{}}}
  \qquad\qquad\qquad
  \tyrule
  {\etyrulename{times}}
  {
    \tyjudge{\Gamma}{e_1}{\enum{}}
    \and
    \tyjudge{\Gamma}{e_2}{\enum{}}
  }
  {\tyjudge{\Gamma}{\etimes{e_1}{e_2}}{\enum{}}}
  %
  \]
  \[
  \tyrule
  {\etyrulename{cat}}
  {
    \tyjudge{\Gamma}{e_1}{\estr{}}
    \and
    \tyjudge{\Gamma}{e_2}{\estr{}}
  }
  {\tyjudge{\Gamma}{\ecat{e_1}{e_2}}{\estr{}}}
  \qquad\qquad\qquad
  \tyrule
  {\etyrulename{len}}
  {
    \tyjudge{\Gamma}{e}{\estr{}}
  }
  {\tyjudge{\Gamma}{\elen{e}}{\enum{}}}
  \]
  \[
  \tyrule
  {\etyrulename{let}}
  {
    \tyjudge{\Gamma}{e_1}{\tau_1}
    \and
    \tyjudge{\Gamma, \var{x} : \tau_1 }{e_2}{\tau}
  }
  {\tyjudge{\Gamma}{\elet{e_1}{x}{e_2}}{\tau}}
  \]

\section{Exercises}

\subsection{Typing derivation}

Perform the full typing derivation for the following $\lggeE$ programs:
  \begin{itemize}
  \item $\ecat
    {\ecat
      {\estr{\text{hello}}}
      {\estr{\text{world}}}
    }
    {\estr{\text{!}}}$ --- start with type $\estr{}$.
    %
  \item $\etimes
    {\elen{\estr{\text{hello}}}}
    {\eplus{\enum{1}}{\elen{\estr{\text{world}}}}}$
    --- start with type $\enum{}$.
    %
  \item $\elet{\estr{\text{mystring}}}{x}{\etimes{\elen{\var{x}}}{\enum{0}}}$
    --- start with type $\enum{}$.
    %
  \item $\elet
    {\estr{\text{anotherstring}}}
    {y}
    {\eplus{\var{y}}{\etimes{\enum{1}}{\enum{2}}}}$
    --- start with type $\enum{}$.
    %
  \item $\elet
    {\ecat{\estr{\text{anotherstring}}}{\var{y}}}
    {y}
    {\var{y}}$
    --- start with type $\estr{}$.
  \end{itemize}

  For instance, to check that program
  $\elet{\enum{42}}{z}{\eplus{\var{z}}{1}}$ has type $\enum{}$, you
  should construct the following tree (starting from the bottom,
  applying the appropriate rule at each node of the tree):

  {\small
  \[
  \tyrule{\etyrulename{let}}
  {
    \tyrule{\etyrulename{num}}
    {\,}
    {
      \tyjudge{\emptyset}
      {\enum{42}}
      {\enum{}}
    }
    \\
    \qquad   \qquad
    \tyrule{\etyrulename{plus}}
    {
      \tyrule{\etyrulename{var}}
      {\,}
      {
        \tyjudge{\var{z} : \enum{}}
        {\var{z}}
        {\enum{}}
      }
      \\
      \qquad   \qquad
      \tyrule{\etyrulename{num}}
      {\,}
      {
        \tyjudge{\var{z} : \enum{}}
        {\enum{1}}
        {\enum{}}
      }
    }
    {
      \tyjudge{\var{z} : \enum{}}
      {\eplus{\var{z}}{\enum{1}}}
      {\enum{}}
    }
  }
  {
    \tyjudge{\emptyset}
    {\elet{\enum{42}}{z}{\eplus{\var{z}}{\enum{1}}}}
    {\enum{}}
  }
  \]
  }

\subsection{Language extension}

Currently $\lggeE$ does not feature any conditional construct. What
would you need to add to the language (in terms of syntax and typing
rules) so that it supports a construct of the form:
\[
\csite{e}{e_1}{e_2}
\]

\section*{\LaTeX\ template}

If you would like to use \LaTeX\ to typeset your solution, you can use
the template here:
\url{https://github.com/ukc-co663/pl-design-latex-template}.

\end{document}

%%% Local Variables:
%%% mode: latex
%%% TeX-master: t
%%% End:


\documentclass{beamer}

\usetheme[runningtoc]{mabeamer}
\begin{filecontents}{_bib_mabeamer.bib}
@Book{AdamsFournier2003,
	Title    = {Sobolev spaces},
	Author   = {Adams, Robert A and Fournier, John JF},
	Year     = {2003},
}
\end{filecontents}
\addbibresource{_bib_mabeamer}

\title{The mabeamer theme}
\date{\today}
\author{Sören Wolfers}

\begin{document}
\maketitle

\section{Main Goals}
\begin{frame}{Light slides}
Light slides do not distract from important content.
\begin{columns}
	\begin{column}{0.5\textwidth}
		\begin{block}[Done]
		\begin{itemize}
		\item Reduce navigational or structural baggage
		\item Get rid of ugly itemizations
		\begin{itemize}
		\item First level: small squares
		\item Second level: smaller squares
		\end{itemize}
		\item Provide pretty blocks: plain, equations, alerts, ...
		\end{itemize}
		\end{block}
	\end{column}
	\begin{column}{0.5\textwidth}
		\begin{block}[To Do]
		\begin{itemize}
			\item Allow line breaks in \texttt{equationblock}\\
			 (\imply Obviate need for \texttt{equationsblock})
		\end{itemize}
		\end{block}
	\end{column}
\end{columns}
\end{frame}

\begin{frame}{Professional slides}
\begin{itemize}
	\item Fancy font lets you forget that these are Beamer slides

	\item Not {\color{purple}using} {\color{orange}playful} {\color{green}colors} {\color{red} protects} {\color{yellow}your} {\color{blue}eyes}

\end{itemize}
\end{frame}

\section{Example usage}
\subsection{Standard}

\begin{frame}{Mathematics}
\begin{theorem}
	There are irrational numbers $r$ and $s$ such that $r^s$ is rational.
\end{theorem}
\begin{proof}
	In my opinion, math such as $\sqrt{2}^{\sqrt{2}}$ or
	$$
	{\sqrt{2}^{\sqrt{2}}}^{\sqrt{2}}=\sqrt{2}^{2}=2
	$$ looks better in serif fonts, even in presentations
\end{proof}
\end{frame}
\begin{frame}{Mathematics}
\begin{itemize}
	\item Important equations can be put in an \texttt{equationblock}:
	\begin{equationblock}
        5^2\approx \int_{0}^{\infty} x^4\exp(-x)\;\mathrm{d}x
	\end{equationblock}
	\item Equations can be named and are automatically fitted:
	\begin{equationblock}[Rademacher's formula]
		p(n)=\frac{1}{\pi\sqrt{2}}\sum_{k=1}^{\infty}\sqrt{k}A_{k}(n)\frac{\mathrm{d}}{\mathrm{d}n}\left(\frac{1}{\sqrt{n-\frac{1}{24}}}\sinh\left[\frac{\pi}{k}\sqrt{\frac{2}{3}\left(n-\frac{1}{24}\right)}\right]\right)
	\end{equationblock}
	\item Alternatively, \texttt{equationsblock} allows linebreaks but doesn't adjust size:
	\begin{equationsblock}
		\Gamma(n+1)&=n\Gamma(n)\\
		  &=n(n-1)\Gamma(n-1)\\
		  &\dots\\
		  &=n!
	\end{equationsblock}
\end{itemize}
\end{frame}

\begin{frame}[fragile]{Alerts and Listings}
\begin{itemize}
	\item Alerts:
	\begin{alertblock}[\bigexclaim Alarm, Alarm \bigexclaim]
		To alert, use \texttt{alertblocks}. For code snippets use \texttt{lstlisting}. When used in itemizations, make sure you don't indent the code snippet, and use \verb|\begin{frame}[fragile]|
	\end{alertblock}
\item Listings:
	\begin{lstlisting}
\begin{alertblock}[\bigexclaim Alarm, Alarm \bigexclaim]
	To alert, use \texttt{alertblocks}. For code snippets use \texttt{lstlisting}. When used in itemizations, make sure you don't indent the code snippet, and use \verb|\begin{frame}[fragile]|
\end{alertblock}
	\end{lstlisting}
\end{itemize}
\end{frame}

\begin{frame}{Citations and Footnotes}
\begin{itemize}
	\item Foot citations \footcite{AdamsFournier2003} are more slick than in-text citations \citep{AdamsFournier2003}.

	\item Footnotes in slides are questionable but can be created using the footnote command\footnote{Check this out} and use the same counter as foot citations.
\end{itemize}
\end{frame}

\begin{frame}{Enumerations and itemizations}
\begin{enumerate}
	\item One
	\begin{enumerate}
		\item Oneone
		\begin{enumerate}
			\item Oneoneone
		\end{enumerate}
	\end{enumerate}
\end{enumerate}
\begin{itemize}
	\item Square
	\begin{itemize}
		\item Squaresquare
		\begin{itemize}
			\item Squaresquaresquare
		\end{itemize}
	\end{itemize}
\end{itemize}
\begin{itemize}
	\item[\summarize] Nice
	\begin{itemize}
	\item[\summarize] and clean
	\begin{itemize}
		\item[\summarize] and simple
	\end{itemize}
	\end{itemize}
\end{itemize}
\end{frame}

\begin{frame}{Figures}
\begin{figure}
	\scalebox{0.6}{\input{_runge}}
	\caption{Runge's function and polynomial approximations. Like theorems, figures don't need numbering.}
\end{figure}
\end{frame}

\begin{frame}{Theme options (and tables)}
\begin{table}[]
	\begin{tabularx}{\linewidth}{l>{\raggedright}XX}
			\toprule
			\textbf{Option}			& \textbf{Controls} & \textbf{Values} \tabularnewline
			\midrule
			\verb|header|		&  Frame headers & \verb|none|,\verb|section|, \verb|subsection|,\verb|both| \tabularnewline
			\verb|runningtoc|		& 	Table of contents at the beginning of sections and subsections & \verb|none|,\verb|preview|, \verb|current| \tabularnewline
			\verb|nocomments| & 	Don't show PDF comments \pdfcomment{<Your comment>} included with \verb|\pdfcomment{<Comment>}| & \verb|<notpassed>|, \verb|<passed>|  \tabularnewline
			\bottomrule
	\end{tabularx}
	\caption{Options that can be inserted in \texttt{\textbackslash usetheme[<option>]\{mabeamer\}}. Default value listed first.}
\end{table}
\end{frame}

\subsection{Special}

\begin{frame}[fragile]{Additional commands}
\begin{itemize}
	\item For remarks, 	use \texttt{remarkblock}:
    \begin{equationblock}[Pythagoras (right triangles)]
	\highlight{a^2}+\highlight[1]{b^2}=\highlight[2]{c^2}
	\end{equationblock}
	\begin{remarkblock}
		\centering Extension to general triangles is possible but beyond the scope of this presentation
	\end{remarkblock}

	\item For framed blocks, use \texttt{frameblock}:
	\begin{frameblock}
		I'm a simple man. I see Beamer themes, I star.\\
		\phantom{}\hfill ---A simple man
	\end{frameblock}

	\item Use \verb|equationblock*| for fitted equations without a frame
	\item \emph{Emphasize text} with \verb|\emph|
	\item Highlight math like $\highlight{a^2}$, $\highlight[1]{b^2}$ and $\highlight[2]{c^2}$ with \verb|\highlight<index>|
\end{itemize}
\end{frame}

\end{document}


\documentclass[]{article}
\usepackage{graphicx}
\usepackage{caption}
\graphicspath{ {./images/} }

% Minted
\usepackage[cache=false]{minted}
	\usemintedstyle{vs}
	\usepackage{xcolor}
		\definecolor{light-gray}{gray}{0.97}

\usepackage{enumitem}
\usepackage{hyperref}

\title{Data Mining: Exercise 3-1}
\author{Brandon Hosley}
\date{\today}

\begin{document}
\maketitle

\section*{Finding Frequent Itemsets}

\begin{minted}[breaklines,bgcolor=light-gray,fontsize=\footnotesize]{shell-session}
from pyspark.ml.fpm import FPGrowth
from pyspark.sql.functions import col, split

df0 = spark.read.text("/user/data/CSC533DM/groceries.csv").toDF("csv")
df = df0.withColumn("items", split(col("csv"), ",").cast("array<string>"))
\end{minted}

\subsection*{Q1: List 3 most frequent itemsets of any size \\ Note: you may need to adjust ‘min\_support’ to find frequent itemsets}

\begin{minted}[breaklines,bgcolor=light-gray,fontsize=\footnotesize]{shell-session}
fpGrowth = FPGrowth(itemsCol="items", minSupport=0.175, minConfidence=0.5)
model = fpGrowth.fit(df)
model.freqItemsets.show()
\end{minted}

\includegraphics[width=\linewidth]{image1}

\subsection*{Q2: Calculate support for the 3 itemsets above \\ Note: Round down to the nearest hundredth, e.g., 0.12.}

\begin{tabular}{r | l}
	rolls/buns:		& $ 1809 / 9835 = 0.18 $ \\
	other vegetables: & $ 1903 / 9835 = 0.19 $ \\
	whole milk:		& $ 2513 / 9835 = 0.26 $ \\
\end{tabular}

\subsection*{Q3: Given min\_support = 0.06 (=6\%), show the counts, e.g., [beer, diaper]: 100, for candidate itemsets of size 2. }

\begin{minted}[breaklines,bgcolor=light-gray]{shell-session}
fpGrowth = FPGrowth(itemsCol="items", minSupport=0.06, minConfidence=0.6)
model = fpGrowth.fit(df)
model.freqItemsets.show(truncate=False,n=100)
\end{minted}
\includegraphics[width=\linewidth]{image3}

[other vegetables, whole milk]: 736

\subsection*{Q4: Given min\_support = 0.05 (=5\%), show their counts, e.g., [beer, diaper]: 100, for candidate itemsets of size 2. Do we get more itemsets or less itemsets with lower min\_support (0.06 -> 0.05)? \\ Note: two questions}

\begin{minted}[breaklines,bgcolor=light-gray]{shell-session}
fpGrowth = FPGrowth(itemsCol="items", minSupport=0.05, minConfidence=0.6)
model = fpGrowth.fit(df)
model.freqItemsets.show(truncate=False,n=100)
\end{minted}
\includegraphics[width=\linewidth]{image3}

[rolls/buns, whole milk]: 557
[other vegetables, whole milk]: 736

\subsection*{Q5: 'rolls/buns' is purchased most frequently with what other product? \\	Note: you may need to adjust 'min\_support' to find frequent itemsets.}

Rolls/Buns are most frequently purchased with whole milk in 557 of 9835 transactions, or 5.8\% of total transactions; 557 of 1809 or 30.8\% of bun transactions.

\subsection*{Q6: 'root vegetables' is purchased most frequently with what other product? Note: you may need to adjust 'min\_support' to find frequent itemsets}

\begin{minted}[breaklines,bgcolor=light-gray]{shell-session}
fpGrowth = FPGrowth(itemsCol="items", minSupport=0.04, minConfidence=0.6)
model = fpGrowth.fit(df)
model.freqItemsets.show(truncate=False,n=100)
\end{minted}

[root vegetables, whole milk]: 481
Of 1072 transactions featuring root vegetables 481 also contain whole milk;
or 44.9\%.

\section*{Finding Association Rules}

\subsection*{Q7: What is the confidence for the rule: 'other vegetables' $\rightarrow$ 'whole milk' \\ Note: Round down to the nearest hundredth, e.g., 0.12. You may need to adjust 'min\_support' and 'min\_confidence' to find rules.}

\begin{minted}[breaklines,bgcolor=light-gray]{shell-session}
fpGrowth = FPGrowth(itemsCol="items", minSupport=0.04, minConfidence=0.3)
model = fpGrowth.fit(df)
model.associationRules.show()
\end{minted}
\includegraphics[width=\linewidth]{image7}

'other vegetables' $\rightarrow$ 'whole milk' Confidence: 0.39

\subsection*{Q8: What is the confidence for the rule: 'yogurt' $\rightarrow$ 'whole milk' \\	Note: Round down to the nearest hundredth, e.g., 0.12. You may need to adjust 'min\_support' and 'min\_confidence' to find rules.}

'yogurt' $\rightarrow$ 'whole milk' Confidence: 0.40

\section*{Predicting with Found Association Rules}

\subsection*{Q9: Given min\_support = 0.04 and min\_confidence = 0.2, what products might be purchased	with 'whole milk'?}

\begin{minted}[breaklines,bgcolor=light-gray]{shell-session}
fpGrowth = FPGrowth(itemsCol="items", minSupport=0.04, minConfidence=0.2)
model = fpGrowth.fit(df)
model.associationRules.show()
\end{minted}
\includegraphics[width=\linewidth]{image9}

Rolls/buns, Yogurt, Other Vegetables are associated to whole milk.

\subsection*{Q10: Given min\_support = 0.04 and min\_confidence = 0.1, what products might be purchased	with 'whole milk'?}

\begin{minted}[breaklines,bgcolor=light-gray]{shell-session}
fpGrowth = FPGrowth(itemsCol="items", minSupport=0.04, minConfidence=0.1)
model = fpGrowth.fit(df)
model.associationRules.show()
\end{minted}
\includegraphics[width=\linewidth]{image10}

Rolls/buns, Yogurt, Other Vegetables, tropical fruit, soda, and root vegetables are associated to whole milk.

\end{document}

\begin{minted}[breaklines,bgcolor=light-gray]{shell-session}
\end{minted}
\includegraphics[width=\linewidth]{image1}


\documentclass[../mit-general-chemistry.tex]{subfiles}
\begin{document}

\chapter{Spontaneous change and free energy}

A {\em spontaneous reaction} proceeds in the forward direction without
the need for outside intervention. It is {\em exorgonic}. A reaction
that does not do that is called {\em non-spontaneous} or {\em
  endorgonic}.

An example of a spontaneous reaction is the formation of rust
\ceeqstar{4Fe(s) + 3O2(g) -> 2Fe2O3(s)} with $\enthalpy^0 =
-824~\kjpm$, an exothermic reaction.

The autoionization of water \ceeqstar{H3O+(aq) + OH-(aq) -> 2H2O} is
also a sponatneous reaction. It has $\enthalpy^0 = -55.9~\kjpm$ and is
thus also an exothermic reaction.

Another reaction, extremly important in bio sciences, is the ATP
hydrolysis \ceeqstar{ATP^4-(aq) + 2H2O -> ADP^3-(aq) + HPO4^2-(aq) +
  H3O+} which drives large numbers of reactions in the cells. The
reaction has an $\enthalpy^0 = \SI{-24}{\kilo\joule\per\mol}$.

There are tons of exothermic reactions (with $\enthalpy < 0$) that are
spontaneous and it is easy to draw the conclusion that this is the
criterion for spontaneity, but that is not the case. Reactions can be
spontaneous without being exothermic. The following reactions, for
instance, are endothermic but also sponatneous.

The melting of ice, \ce{H2O (s) -> H2O(l)}, has $\enthalpy^0 =
+6.95~\kjpm$ and is endothermic.

So is \ceeqstar{NH4NO3(s) -> NH4+(aq) + NO3-(aq)} with $\enthalpy^0 =
\SI{+28}{\kilo\joule\per\mol}$.

So we see that enthalpy is not the key to spontaneity. Instead,
spontaneity depends on Gibb's free energy, \gibbs.

\section{Gibb's free energy}

We define Gibb's free energy as
\begin{equation}\label{eq:gibbs}
  \gibbs = \enthalpy - T \Delta S
\end{equation}
where $T$ is the temperature and $\Delta S$ is the change in entropy,
so it is clear why \enthalpy is closely related to \gibbs. The
equation is true for constant temperature and pressure.

The relationship to spontaneity is

\begin{center}
  \begin{tabular}{ll}
    $\gibbs < 0$ & reaction is spontaneous \\
    $\gibbs > 0$ & reaction is not spontaneous \\
    $\gibbs = 0$ & reaction has reached equilibrium  \\
  \end{tabular}
\end{center}

A negative change in energy, it is just like with enthalpy, means that
energy is released as the reaction progresses. That is going to be a
spontaneous reaction.

So how come we need Gibb's free energy and that enthalpy is not enough
to predict spontaneity? If we rewrite Equation~\ref{eq:gibbs} into
\begin{equation*}
  \enthalpy = \gibbs + T \Delta S
\end{equation*}

We see that the energy of a reaction, the enthalpy ($H$), consists of
a term that is the free energy (\gibbs), useful for work, and an
amount of energy that gets ``stuck'' in the system. That energy that
gets ``stuck'' is the $T \Delta S$ term.

\subsection{Entropy}

Entropy, $S$, is an amount of the disorder of a system. We write
$\Delta S$ for the change in entropy. Entropy is a state function.

If $\Delta S > 0$ we are {\em increasing the disorder} of a system
(decreasing the order).

For the phases, or states, of matter the entropy is greater for
gaseous matter than it is for liquid matter and solid matter have the
least entropy. We express this (somewhat loosely) as
\begin{equation*}
  \Delta S_g > \Delta S_l > \Delta S_s
\end{equation*}
for the different phases gaseous, liquid and solid.

Entropy for reactions, $\Delta S_r^0$, can be calculated from the
absolute entropy of the reactants and products in the same way as for
enthalpy.
\begin{equation*}
  \Delta S_r^0 = \sum~S^0_{\text{products}} - \sum~S^0_{\text{reactants}}
\end{equation*}
where $S^0$ is {\em absolute standard entropy}. Since $S = 0$ for the
perfect crystal at $T = \SI{0}{\kelvin}$, we can consider the
existence of the notion of an absolute measure of entropy.

\begin{remark}
  Note that measures of entropy tends to be much smaller than measures
  of enthalpy and other measures of energy. It is therefore common
  that they are given in joules instead of kilo joules and need to be
  converted into kilo joules when they are used in formulas.
\end{remark}

\subsubsection{Entropy and probability}

Entropy is more than disorder. It is, in fact, a clearly defined,
statistical measure of the arrangement of elements and their
likelihoods of occurrence.

In thermodynamics more likely (probable) states will predominate over
time (higher $S$). This is a consequence of the second law of
thermodynamics that states that the total entropy of an isolated
system never decreases over time. As time goes, entropy will increase
or remain the same.

The second law of thermodynamics has two paragraphs. It states that
entropy of an isolated system never decreases. For reversible
processes it may be constant, but for irreversible processes it will
increase. It also states that the total entropy of any system and of
it's surroundings will always increase.

This does not follow directly from the basic laws of physics, instead
it is a matter of probability and statistics. As there are many more
states with higher levels of entropy than there are with lower levels,
systems tend toward disorder if it changes state independently over
time. Then the changes of state will be a matter of probability where
there are more high-entropy states then there are low-entropy states,
which makes the high-entropy states more likely.

As an example of the second law of thermodynamics we intuitively know
that if we pump in gas in a container, the gas particles will
initially be close to the entry point. Over time the particles will
spread out all over the container. It is highly unlikely that the
particles will cluster back at the entry point again.

There are many more ways (arrangements) for the particles to be spread
out than there are to be ordered.

We are going to consider six coins as a small model. We define states
of the model as the number of heads that
show up. We have the sample space $\mathscr{S} = \{1H, 2H, 3H, 4H, 5H,
6H\}$ for $1H$ meaning a state where all coins but one is showing
``tails'', $2H$ all but two and so on. The number of arrangements in
each state is called the {\em likelihood} of that state and is denoted
by $W$.

We are going to consider the $1H$ (``concentrated'') state and the
$3H$ (``more spread out'') state. We realize that there are six
arrangements in the $1H$ state since there are six coins that can be
the one that is showing ``heads''. We can enumerate the arrangements
of the $1H$ state by simply flipping one coin at a time.

\begin{htable}\label{tbl:coins:states}

  \hspace*{\fill}
  \begin{tabular}{ll}
    HTTTTT & THTTTT \\
    TTHTTT & TTTHTT \\
    TTTTHT & TTTTTH \\
  \end{tabular}
  \hspace*{\fill}

  \vspace{2em}

  \hspace*{\fill}
  \begin{tabular}{llll}
    HHHTTT & HHTHTT & HHTTHT & HHTTTH \\
    HTHHTT & HTHTHT & HTHTTH & HTTHHT \\
    HTTHTH & HTTTHH & THHHTT & THHTHT \\
    THHTTH & THTHHT & THTHTH & THTTHH \\
    TTHHHT & TTHHTH & TTHTHH & TTTHHH \\
  \end{tabular}
  \hspace*{\fill}

  \caption{ An enumeration of the arrangements of the $1H$ state and
    of the $3H$ state. The conclusion is that there are so much higher
    numbers of arrangements in the $3H$ state than there are in the
    $1H$ state.}
\end{htable}

The $3H$ state, on the other hand, is the state with the most number
of arrangements. There are $\binom{6}{3} = 20$ arrangements where
there are three ``heads'' and three ``tails''.

We can see the arrangements of the two states in
Table~\ref{tbl:coins:states} which illustrates the point that there
are quite a few more arrangements in the $3H$ state than there are in
the $1H$ state. If we would just toss the six coins $3H$ would be the
most common result. In the language of thermodynamics and entropy we
could say that the $3H$ state will dominate over time.

Calling the number of arrangements in each state (6 and 20 in our
example) the {\em likelihood} of that state is a term coined by
Boltzmann.

Boltzmann's great insight was that entropy is related to $W$.
\begin{equation*}
  S = k_B \ln W
\end{equation*}
for Boltzmann's constant $k_B$, the gas constant over Avogadro's number
\begin{equation*}
  k_B = \frac{R_0}{N_A} = 1.38064852(79)\times 10^{−23} \si{\joule\per\kelvin}
\end{equation*}

We can use this formula to to calculate the entropy for the coin
tossing states $1H$ and $3H$.
\begin{align*}
  S_1 &= k_B \ln 6 = 2.47 \times 10^{-23} \\
  S_3 &= k_B \ln 20 = 4.14 \times 10^{-23} \\
  S_3 &> S_1 \\
\end{align*}
Note that the entropy does not depend directly on the total number of
arrangements like probability do.

We can calculate the entropy change ($\Delta S$) out of ``going from
one state to another'' and find that $\Delta S_{3\to 1} = S_3 - S_1 >
0$ and conversely $\Delta S_{1\to 3} = S_1 - S_3 < 0$, that there is
an increase in entropy as we go from he $1H$ state to the $3H$ state,

If we would repeat the coin tossing over an over again, we would find
that the $3H$ outcomes would start to spontaneously overwhelm the $1H$
outcomes.

Going from $1H$ to $3H$ is thus spontaneous as we saw above that
$\Delta S = S_1 - S_3 < 0$, this corresponds to predictions of
thermodynamics.

Let's move to a chemical example, carbonyl sulfide,
\chemfig{O=[,0.7]C=[,0.7]S}. This is a linear molecule with a carbon
atom in the middle bound to one oxygen atom and one sulfur atom in
each direction. At very low temperatures carbonyl sulfide form
crystals where the molecules are lined up, in parallel, next to each
other. In this arrangement, the sulfur atoms point one way or the
other. Let's call sulfur atoms pointing one way ``heads'' and the
other ``tails'' to see the resemblance to our coin tossing example. If
we study one ``line'' of parallel molecules it could be illustrated
such as in the figure below.

\begin{center}
  \begin{tikzpicture}[node distance=.2cm]
    \def\heads{\chemfig{C(=[:90]S)(=[:270]O)}}
    \def\tails{\chemfig{C(=[:90]O)(=[:270]S)}}
    \node (a) {\heads};
    \node[right=of a] (b) {\heads};
    \node[right=of b] (c) {\tails};
    \node[right=of c] (d) {\tails};
    \node[right=of d] (e) {\heads};
    \node[right=of e] (f) {\tails};
    \node[right=of f] (g) {$\cdots$};
    \node[left=of a] {$\cdots$};

    \node[above=1mm of a]{\textbf{H}};
    \node[above=1mm of b]{\textbf{H}};
    \node[above=1mm of c]{\textbf{T}};
    \node[above=1mm of d]{\textbf{T}};
    \node[above=1mm of e]{\textbf{H}};
    \node[above=1mm of f]{\textbf{T}};
  \end{tikzpicture}
\end{center}

In the diagram, the molecules we consider ``heads'' are denoted with
the letter H. The molecules we consider ``tails'' are denoted with the
letter T.

We are now going to consider a mole ($N_A = \num{6.022d23}$) of
molecules instead of six. We will consider the (unique) arrangement of
a perfect crystal with all sulfur atoms ``pointing'' in one direction
and call this heads. This is also a state associated with a single
arrangement, thus $W_{\text{perfect}} = 1$. We will compare this with
a ``random'' one where we don't know the configuration of the
atoms. In this state we have $\binom{N_A}{n}$ arrangements in each
state of $n$ heads. It is obvious that these are {\em huge} numbers.

We can tell that $S_{\text{perfect}} = 0$ since there is one unique
configuration where all the molecules point in one specific
direction.

Next consider the configuration that differs from the perfect crystal
in that one single molecule have been flipped. That is still pretty
ordered but already in that minor deviation (with $W = N_A$) we get $S
= k_B \ln N_A = \num{7.56d-22}$. The ``next'' state ``$2H$'' yields $W
= N_A(N_A - 1) = \num{1.51d-21}$, already ten times higher. The
expansion of $W_n$ ($n$ being the number of ``heads'') is in fact a
binomial expansion over $N_A$. If we are familiar with the {\em
  binomial theorem}, or willing to acquaint ourselves with it, it is
easy to see the astronomical numbers that will face us going
further.

It is however easy to see that the chances of ever reach other than
fairly random (high entropy) states are disappearingly small, instead,
probability leans toward a situation where will jump back and forth
between the states with the highest likelihood (entropy) as is
predicted by the second law of thermodynamics.

Now, imagine if we start flipping molecules, one at a time, randomly,
as we simulate the back and forth among chemical species in real
life. We will start see entropy increase as we flip molecules. The
only time entropy will decrease is if we happen to flip a ``tails''
back to ``heads''. To end up with another perfect arrangement we would
have to succeed in constantly picking ``tails'' as their numbers grow
smaller and smaller. Every time we would flip a ``heads'' back to
``tails'' entropy would increase again, if only by a miniscule
amount.

Probability theory tells us that we almost certainly never wil
end upp with the (or any of the two) perfect configurations, instead
we're probably changing back and forth among those most probable
configurations, those with the highest entropy. So, we are
spontaneously ending up in states with greater entropy, solely as a
matter of probability, without thermodynamics.

\subsection{Calculating the free energy}

For example, if we want to calculate $\gibbs^0_r$ for the reaction
when hydro peroxide turns to water and oxygen gas,

\ceeqstar{2H2O2(l) -> 2H2O(l) + O2(g)}
we calculate
\ceeqstar{\Delta S^0_r = [2 S^0(H2O) + S^0(O2)] - 2 S^0(H2O)}

We can look up these values in tables and find that

\begin{center}
  \begin{tabular}{ll}
    \toprule
    Species & $S^0$ \\
    & {\footnotesize\si{\joule\per\kelvin\per\mol}} \\
    \midrule
    \ce{H2O} & 70 \\
    \ce{O2} & 205 \\
    \ce{H2O2} & 110 \\
    \bottomrule
  \end{tabular}
\end{center}

We can use these figures to calculate entropy for the reaction as
$\Delta S^0_r = 2 \times 70 + 205 - 2 \times
110~\si{\joule\per\kelvin\per\mol} =
125~\si{\joule\per\kelvin\per\mol}$.

We notice that \dS\ is positive. This can be explained from the fact
that the reactant is a liquid whereas the products are liquid and a
gas and we learned earlier that gasses bring more entropy than do
liquids.

To predict whether this reaction is spontaneous or not we need to
calculate \gibbs for the reaction. We now know that $\Delta S^0_r =
125~\si{\joule\per\kelvin\per\mol}$ and from the lecture we get that
$\enthalpy^0 = -196~\kjpm$ so

\begin{equation*}
  \gibbs^0 = \SI{-196}{\kilo\joule\per\mol}
  - \SI{298.15}{\kelvin}
  \cdot \SI{0.125}{\kilo\joule\per\kelvin\per\mol}
  = \SI{-233}{\kilo\joule\per\mol}
\end{equation*}

Since $\gibbs^0 < 0$ we predict that the reaction occurs
spontaneously.

Note that the amount of the Gibb's free energy does not tell us
anything about the time frame (speed) of a reaction. If $\gibbs = -2$
or $\gibbs = -2000$ does not tell us more than that it is
spontaneous. Thermodynamics does not answer questions about this. The
field of kinetics, however, do, as we will see later.

Now consider melting of ice at room temperature.
\ceeqstar{H2O(s) -> H2O(l)}

We calculate the entropy
\ceeqstar{\dS^0_r = S^0(H2O(l)) - S^0(H2O(l)) = 69.91 - 41.32
  = \SI{28.59}{\joule\per\kelvin\per\mol}}
\dS\ is positive since the reaction is turning a solid into a liquid.

Now we can calculate the free energy
\begin{align*}
  \gibbs_r^0 &= 6.95~\kjpm
  - \SI{298.15}{\kelvin}
  \cdot \SI{2.859d-2}{\kilo\joule\per\kelvin\per\mol} \\
  &= \SI{-1.57}{\kilo\joule\per\mol}\\
\end{align*}

The result tells us that the reaction is spontaneous (at $T =
\SI{198.15}{\kelvin}$). A lot of people know from everyday experience
that this reaction is temperature dependent. We also see that the
reaction is spontaneous even though the enthalpy is positive.

\subsection{Free energy of formation}

We can also calculate the {\em free energy of formation}, $\gibbs_f$,
in a similar way as that of enthalpy of formation.

The standard Gibb's free energy of formation, $\gibbs^0_f$, is defined
by $\gibbs^0_f = \gibbs^0_r$ for formation of one mole of compound
from it's elements in their purest states, under standard conditions
($P = \SI{1}{\bar}, T = \SI{298.15}{\kelvin}$).

These values are tabulated, as was the enthalpy of formation, but the
standard Gibb's free energy of formation can also be calculated
through
\begin{equation*}
  \gibbs^0_f = \enthalpy^0_f - T \dS^0
\end{equation*}

\standardgibbsfreeenergyof is important because it
is a measure of a compunds stability relative to that of it's
elements.

If $\standardgibbsfreeenergyof < 0$ then the compound is
(thermodynamically) stable to it's elements. If we consider how we
started to reason about Gibb's free energy, we learned that a reaction
was going to be spontaneous if $\gibbs_r < 0$. From this we can draw
the conclusion that the elements will spontaneously form the
compound.

Conversely, if $\standardgibbsfreeenergyof > 0$, the compound is
thermodynamically unstable relative to it's elements.

Consider the free energy of formation for benzene.

\ceeq{6C(gr) + 3H2(g) -> C6H6(l)}

The free energy for formation for benzene is
$\standardgibbsfreeenergyof = \SI{124}{\kilo\joule\per\mol}$ so
benzene is unstable relative to it's compounds.

This means that the reverse reaction where we have decomposition of
benzene is going to be stable.

\ceeq{C6H6(l) -> 6C(gr) + 3H2(g)}

med $\standardgibbsfreeenergyof =
\SI{-124}{\kilo\joule\per\mol}$. Note that \standardgibbsfreeenergyof
has the same absolute value but the reverse sign, as it goes in the
other direction. Remember that Gibb's free energy is a state function
so differences between compounds and elements are the same, the
direction is given by the sign od the distance.

Benzene do however exist, so does that mean that the theory is wrong?
No, benzene do decompose but the reaction is very, very slow.

As we said before: Gibb's free energy of a reaction tells us whether
it will happen spontaneously or not. Gibb's free energy tells us
{\em nothing about the rate of that reaction}.

So we have two ways of calculating \gibbs for a reaction.

We can look up and suum up the $\gibbs_f$ for reactants and products,
respectively, and $\gibbs_r$ is then the differences between those
the sums
\begin{equation*}
  \gibbs^0_r = \sum\gibbs^0_f(\text{products}) - \sum\gibbs^0_f(\text{reactants})
\end{equation*}

The other way is to calculate it from
\begin{equation*}
  \gibbs^0_r = \enthalpy^0_r - T\dS
\end{equation*}

This last equation can be usefull when temperature is important. Let
us consider the decomposition of sodium bicarbonate (baking soda).

\ceeq{2NaHCO3(s) -> Na2CO3(s) + CO2(g) + H2O(g)}

We can look up the enthalpy for the reaction and doing so we find that
$\enthalpy_r^0 = \SI{+135.6}{\kilo\joule\per\mol}$ which tells us that
this is an endothermic reaction, it requires heat to occur. We also
can conclude that entropy is increasing ($\dS > 0$) since the left
hand side consists of one solid compound and there are two gasses
among the products, so entropy is increasing through the reaction. The
actual value is indeed positive, $\dS =
\SI{+0.334}{\kilo\joule\per\kelvin\per\mol}$. From this we can
calculate
\begin{equation*}\tag{a}
  \gibbs^0 = \enthalpy^0 - T \dS^0
  = \SI{+135.6}{\kilo\joule\per\mol}
  - T\cdot \SI{+0.334}{\kilo\joule\per\kelvin\per\mol}
\end{equation*}

Assuming that \dS\ and \enthalpy\ are independent of $T$,
$\gibbs^0$ is a linear function of $T$.

At room temperature $\gibbs^0 = \SI{36.1}{\kilo\joule\per\mol}$ so the
reaction will not occur spontaneously under those conditions. From the
equation we can see that
\begin{equation*}
  T > \frac{\SI{+135.6}{\kilo\joule\per\mol}}{\SI{+0.334}{\kilo\joule\per\kelvin\per\mol}} =
  \SI{406}{\kelvin}
  \implies
  \gibbs^0_r < 0
\end{equation*}

So at temperatures above \SI{406}{\kelvin} (\SI{133}{\celsius}) the
baking soda will start to decompose and release the gasses, for
instance inside some baked goods in an oven.

\begin{hfigure}
  \begin{center}
    \begin{tikzpicture}
      \begin{axis}[
          title={\gibbs when \enthalpy and \dS\ are positive},
          axis lines=middle,
          width=.67\textwidth,
          height=5cm,
          axis lines = middle,
          domain=0:600,
          ymin=-100,
          ymax=200,
          xmin = -50,
          xmax=750,
          %xtick=\empty,
          ytick={0, 100},
          xlabel=$T~(\si{\kelvin})$,
          ylabel=$\gibbs^0 (\kjpm)$,
          clip = false
        ]
        \addplot[blue, samples=100]{135.6 - 0.334*x};
        \draw[red,thin] (406, 10) -- (406, -50) node[at end,below,black]{$T^*$};
        \draw[red,thin] (-10, 135.6) -- (10, 135.6) node[at start,left,black]{$\enthalpy^0$};
      \end{axis}
    \end{tikzpicture}%
  \end{center}
  \caption{The spontaneity of the decomposition of baking soda and
    subsequent release of vapor and carbon dioxide is temperature
    dependent.}
\end{hfigure}

We can notice that whenever the enthalpy and the entropy of a reaction
have the same sign, we can control spontaneity of the reaction by
controlling the temperature.

In that situation we can find a $T^*$ for which $\gibbs^0 = 0$ and
then the reaction will be non-spontaneous ($\gibbs^0 > 0$) for all $T
< T^*$ and the reaction will be spontaneous ($\gibbs^0 < 0$) for all
$T > T^*$. In our example $T^* = \SI{406}{\kelvin}$.

We find $T^*$ by solving $\gibbs^0 = \enthalpy^0 - T \dS^0$ for
$\gibbs^0 = 0$ which give us
\begin{align*}
  \enthalpy^0 - T^* \dS^0 &= 0 \\
  T^* &= \frac{\enthalpy^0}{\dS^0} \\
\end{align*}
just as we did previously.

When both enthalpy and entropy are negative, we get a reversed
situation.

\begin{hfigure}
  \begin{center}
    \begin{tikzpicture}
      \begin{axis}[
          title={\gibbs when \enthalpy and \dS\ are negative},
          axis lines=middle,
          width=.67\textwidth,
          height=5cm,
          axis lines = middle,
          domain=0:600,
          ymax=150,
          ymin=-200,
          xmin=-50,
          xmax=750,
          %xtick=\empty,
          ytick={0, 100},
          xlabel=$T~(\si{\kelvin})$,
          ylabel=$\gibbs^0 (\kjpm)$,
          clip = false
        ]
        \addplot[blue, samples=100]{-135.6 + 0.334*x};
        \draw[red,thin] (406, 10) -- (406, -50) node[at end,below,black]{$T^*$};
        \draw[red,thin] (-10, -135.6) -- (10, -135.6) node[at start,left,black]{$\enthalpy^0$};
      \end{axis}
    \end{tikzpicture}%
  \end{center}

  \caption{The function $\gibbs = \enthalpy - T \dS$ for a negative
    \dS and negative \enthalpy. When \dS is negative, the straight
    line gets an upward slope and, for a negative \enthalpy, becomes
    spontaneous for lower temperatures, but non-spontaneous for
    temperatures above $T^*$.}
\end{hfigure}

Now the reaction is spontaneous for $T < T^*$, as $\gibbs < 0$ and for
$T > T^*$ the products are now less stable relative to their elements,
$\gibbs > 0$, and the reaction is no longer spontaneous.

Finally, if $\enthalpy^0 < 0$ and $\dS^0 > 0$ the spontaneity of the
reaction is independent of temperature. It is spontaneous for all
temperatures since $\gibbs^0 < 0$ for all temperatures. If
$\enthalpy^0 > 0$ and $\dS^0 < 0$, $\gibbs^0 > 0$ for all temperatures
so the reaction is non-spontaneous for all temperatures.

\begin{htable}
  \begin{center}
    \begin{tabularx}{.67\textwidth}{llX}
      \toprule
      Enthalpy & Entropy & Spontaneous or not \\
      \midrule

      $\enthalpy^0 < 0$ & $\dS^0 > 0$ & allways spontaneous,
      independently of $T$, since \gibbs is negative and decreasing. \\

      $\enthalpy^0 > 0$ & $\dS^0 < 0$ & never spontaneous since \gibbs
      is positive and increasing. \\

      $\enthalpy^0 > 0$ & $\dS^0 > 0$ & spontaneous for $T > T^*$ since
      \gibbs is positive and decreasing. \\

      $\enthalpy^0 < 0$ & $\dS^0 < 0$ & spontaneous for $T < T^*$ since
      \gibbs is negative and increasing. \\

      \bottomrule
    \end{tabularx}
  \end{center}
  \caption{ The linear dependence of \gibbs of \enthalpy and \dS
    give us some obvious consequences for \gibbs and spontaneity.  }
\end{htable}

These are simple consequences from the linear dependence between
Gibb's free energy, enthalpy and entropy. If the enthalpy is positive
at \SI{0}{\kelvin} and the entropy is positive the function of the
free energy is going to be a straight line with a downward slope. If
the enthalpy, on the other hand, is negative at \SI{0}{\kelvin} and
the entropy is negative the function of the free energy is going to be
a straight line with a upward slope. In both cases there's a straight
line, crossing the $x$ axis at $T^*$

\addsec{Summary}

A spontaneous reaction proceeds in the forward direction without the
need for outside intervention.

We could reason that if the enthalpy of a reaction is negative that
means that the system around the reaction would reach a more stable
energy level as the reaction proceeds. Enthalpy is however not enough
to predict spontaneity of a reaction as we saw spontaneous reactions
with positive enthalpy as well as non-spontaneous reactions with
negative enthalpy.

\end{document}


\documentclass[11pt]{article}
\usepackage[breaklinks]{hyperref}

\newcommand{\win}{\ensuremath{w_{\rm i}}}
\newcommand{\wout}{\ensuremath{w_{\rm o}}}

\begin{document}

\title{Some Notes on 3D Raytracing}
\author{Peter Erwin}

\maketitle

\section{Basics of Light Interaction with Surfaces}

We can divide the interactions of light into two basic types:
\textbf{radiative transfer through a medium} and \textbf{scattering}.
Scattering can take place in two ways: interactions with small particles
in a medium (e.g., interactions of light with fog, etc.), and scattering
at a boundary between media with different indices of refractions.

\subsection{Scattering (Reflection and Refraction) at a Planar Boundary}

Scattering at a (locally planar) boundary is \textit{most} of the
interesting effects in 3D rendering: it involves light reflecting,
scattering, and/or being refracted when light hits an object. The basic
math for this was worked out by Fresnel in the early 19th Century, and
is codified in the Fresnel equations. In simple terms (ignoring the role
of polarization), a light ray that intersects a planar boundary is
scattered in two discrete ways: reflection away from the boundary and
refraction through the boundary. Energy conservation means that the
sum of reflection and refraction must = incoming light.

\textit{Direct (or specular) reflection}, on a locally planar level, follows the
standard angle of incidence = angle of reflection model. For perfectly
flat surfaces, this is a single angle. For surfaces with microstructure,
the surfaces can be treated as a collection of locally flat regions (the
``microfacets'' model); the combined direct reflection will involve a
small range of angles about the mean direct reflection: generalzied
\textit{specular reflection.}

\textit{Refraction:} Refracted light travels into the second object/medium (at
an angle determined by Snell's Law). It then undergoes scattering and absorption
within the second object/medium.

For metals (conductors), the refracted light is absorbed almost immediately (apparently the free
electrons ensure this), and can thus be ignored (except, of course, in terms of
energy conservation: the refracted light is lost).

For dielectrics, the refracted light travels through the object/medium
and is subject to absorption and scattering. \textit{Some} of the
scattered light makes it way back out of the surface (e.g., after
multiple scatterings). This is knowns as ``subsurface scattering'', and
is in fact the origin of ``diffuse reflection''. Whether or not it
\textit{needs} to be explicitly modeled as subsurface scattering depends
on the scale of the scattering, including this scale relative to pixel
size. In some substances, the scattering is very local (presumably
because photons get absorbed too quickly to permit multiple scatterings
over longer ranges) and so the re-emergence of scattered photons from
the surface can be treated as Lambertian diffuse reflection. In other
(more translucent) substances, multiple scatterings without absorption
allow photons to re-emerge at large distances from the original
intersection point -- possibly with an asymmetric distribution, or even
on the other side of a sufficiently narrow object (thin edges of ears,
etc.).

\subsection{Reflection}

Reflection involves light scattering away from a surface. The \textit{amount} of light
that is scattered must always be $\le$ the incoming light; this can be
described using a single scalar $K_{r} \le 1$, or a spectrum of reflectance values.
For the standard RGB case, $\mathbf{K_{r}} = (K_{r,R}, K_{r,G}, K_{r,B})$.

If we imagine white light reflected diffusely from a surface, then
$\mathbf{L_{o}} = \mathbf{L_{i}} \mathbf{K_{r}} = (K_{r,R} L_{i,R},
K_{r,G} L_{i,G}, K_{r,B} L_{i,B})$, and $\mathbf{K_{r}}$ is then the
same as what we perceive as ``the'' color of the surface.

\section{Path-Tracing Basics}

``hit point'' = point on the surface where our current ray has intersected
an object, where we want to calculate the outgoing light (``outgoing'' = back
along the sequence of rays/paths toward the camera).

\textbf{Variables:}
\begin{itemize}
\item $L$ -- light traveling along a ray, in the form of Color [R,G,B float
components, positive but no upper limit]
\item $w$ -- a direction vector for a ray
\item $n$ -- a surface normal vector
\end{itemize}

Ignoring refraction for the moment, the rendering equation looks like this
\begin{equation}
L_{\rm out}(\wout) \; = \; L_{e}(\wout) \, + \, \int_{\Omega} f_{\rm brdf}(\win,\wout) \: L_{\rm in}(\win) \, (\win \cdot n) \, d{\win}
\end{equation}
where $L_{e}(\wout)$ is \textit{emission} from the local surface.

The second term (i.e., the integral) represents the contribution from
reflected (specular or diffuse) light, and in particular describes how
much of the \textit{incoming} light $L_{\rm in}$ is reflected. This can
be broken down into three pieces:
\begin{enumerate}
\item $L_{\rm in}(\win)$ -- amount of light coming in along
vector \win{} (e.g., from
background, or from previous reflection or refraction from further out) -- Color value;

\item $(\win \cdot n) = |\win| |n| \cos \theta_{i}$ -- the geometric dilution of that light
due to the angle between the incoming light and the surface normal -- float ;

\item $f_{\rm brdf}(\win,\wout)$ -- how much of the light is actually reflected by the surface
into the outgoing vector \wout{} -- Color value (or float for achromatic).
\end{enumerate}

Breaking this down, we can imagine calculating the reflected light for individual
incoming rays $\win$. In the classic ray-tracing case, this corresponds to one
incoming ray per (visible, non-shadowed) light. If there is an incoming reflection
ray, then this is also covered via the $f_{s}$ term.

In the idealized full integration, we simply sum up the contributions from all possible
incoming \win{} rays, distributed over the unit hemisphere above the hit point.
In practice, we approximate this with a Monte Carlo approach, shooting out
multiple rays to represent \win{} and summing up their contributions (weighted appropriately).

Put another way: ``The integral just means that we are going to take the
result of everything between those two symbols, and add them up for
every point in a hemisphere, multiplying each value by the fractional
size of the point’s area for the hemisphere. The hemisphere we are
talking about is the positive hemisphere surrounding the normal of the
surface we are looking at.''\footnote{\url{https://blog.demofox.org/2016/09/21/path-tracing-getting-started-with-diffuse-and-emissive/}}

\section{Environment Maps}

\subsection{Cubic Maps}

The basic idea is that when a ray (reflected or otherwise) goes to infinity without
intersecting an object, you can give it a color $L$ from:
\begin{enumerate}
\item A constant background color value $L_{\rm back}$ [what we do currently]

\item A background/environment image.
\end{enumerate}

The simplest and most popular modern approach is to use a cubic map, where each of the
$+$ and $-$ axes has one face of the cube associated with it.

How do we choose which face of the map to use? Simple: identify the largest component
of the ray in question and take its sign. Thus, for a ray like $(x, y, z) = (0.5, -0.1, 0.9)$,
you would choose the $+z$ axis and its face; for $(x, y, z) = (-0.5, -0.1, -0.4)$, you
would choose the $-x$ axis; and so forth.

How do we choose where in the individual-face image to get a pixel value? We take the
complementary component values of the ray and convert them into scaled coordinates on that face,
using the value of the other component to scale them.

Thus, in the case of $(x, y, z) = (0.5, -0.1, 0.9)$, where we're using the map associated
with the $+z$ face, we take $x/z = 0.5/0.9$ and $y/z = -0.1/0.9$ to get values on the $(-1,1)$
interval; then we map these into the $(0,1)$ interval by adding 1 to each and then dividing the
result by 2:
\begin{equation}
u = (x/z + 1)/2, \; \; v = (y/z + 1)/2 .
\end{equation}

Now the problem is one of mapping values on the $(0,1)$ interval into pixel values
in the image $u$ and $v$ axes.

\end{document}


\chapter{Introduction}\label{introduction}

\ifpdf
    \graphicspath{{Chapter1/Figs/Raster/}{Chapter1/Figs/PDF/}{Chapter1/Figs/}}
\else
    \graphicspath{{Chapter1/Figs/Vector/}{Chapter1/Figs/}}
\fi

\section{Motivation}

Load balancing has been an important topic for many decades, and it has gained even more attention recently with the prevalence cloud computing~\cite{mishra2020cloud}. In the usual setup, there are some servers, and whenever a job arrives, the goal is to allocate it to one of the servers such that no server is overloaded.

At first glance, it might seem that this is trivially solvable using round-robin scheduling (for homogeneous jobs and servers). The problem with this approach is that it requires a centralised load balancer. This load balancer is a single point of failure, reducing the robustness of the system, and decreasing performance due to its sequential nature (e.g. not all Google search requests can go through a single machine). An alternative is to use randomised load balancing. The idea is to allocate the jobs according to a randomised protocol -- the simplest being choosing a server uniformly at random -- that can be run independently on each client requesting the job, without a central load balancer. The key challenge is designing this randomised protocol so that it achieves a good balance. A groundbreaking result in this area was presented in~\cite{azar1999twochoice}. They showed that the \TwoChoice protocol, which queries the load of two servers chosen independently uniformly at random, and allocates the job into the lesser loaded of the two, achieves a maximum load of $(1+o(1))\frac{\ln\ln n}{\ln 2} + \frac{m}{n}$ with $n$ servers after $m$ jobs, with high probability (meaning that as $n$ goes to infinity, the probability converges to $1$). This result led to extensive further study of the topic (see e.g.~\cite{richa2001surveytwochoice}), and even several large companies, such as Twitter started using this idea, often called ``the power of two choices''~\cite{anderson2019twitter}.

There are several versions of the load balancing problem, making different assumptions about the jobs and the servers, so for consistency reasons, most of the research community adapted the following standard abstraction that I will use as well: the servers are bins, and the jobs are balls. This has the further advantage, that randomised protocols such as \TwoChoice have proved to be useful outside the field of load balancing too, such as hashing~\cite{azar1999twochoice} (see~\cite{wieder2017ballsintobinslandscape} for a comprehensive survey). I will provide a formal definition of the balls-into-bins abstraction in Chapter~\ref{preparation}.

There are other randomised protocols suggested, that under some circumstances are more realistic, or more efficient than \TwoChoice. For example, if both of the bins queried by \TwoChoice have very low load, then it was unnecessary to query both, leading to communication overhead and the interruption of servers, and querying only one of them would have been been enough. \OneChoice, however, which simply allocates the ball uniformly at random (``takes one sample and accepts that'') has been shown to have an exponentially worse maximum load of $(1+o(1))\sqrt{\frac{m\ln n}{n}}+\frac{m}{n}$, so it is often not sufficient~\cite{mitzenmacher2005probabilitybook}.

A process in-between \OneChoice and \TwoChoice is \TwoThinning~\cite{feldheim2021thinning}, which samples a primary bin uniformly at random, and either accepts that, or rejects that, in which case the ball is allocated uniformly at random into one of the bins (see Figure~\ref{two-thinning-intro}). On average, \TwoThinning requires less than $2$ queries per ball, but it also requires a \textit{decision strategy} (or just ``strategy'') for whether to accept or reject a bin. We will see in Section~\ref{my-approach} also that unlike \TwoChoice, \TwoThinning can naturally be implemented without communication from the servers to the clients.

This dissertation is about optimising decision strategies of ``parametric'' protocols like \TwoThinning according to some objective function measuring how balanced the load distribution is, such as the final maximum load of the bins after some number of balls have been allocated.

\begin{figure}
    \centering
    \includegraphics{Chapter1/Figs/two_thinning_intro.pdf}
    \caption{One step of the \TwoThinning protocol. The primary bin sampled is the fourth bin, so the strategy has to decide whether to place the ball there, or into a bin chosen uniformly at random. \protect\footnotemark}
    \label{two-thinning-intro}
\end{figure}

\footnotetext{Note that in both \TwoChoice and \TwoThinning we allow the two bin options to be the same, following common practice.}

\section{My Approach} \label{my-approach}
For the decision strategies, I compare heuristics (e.g.\ \MeanThinning) with strategies learnt by reinforcement learning (RL) or obtained by dynamic programming (DP). RL is a natural choice, since we have to make optimal decisions in a dynamic, stochastic process. RL adjusts the strategy by collecting rewards during training, which I will discuss in Section~\ref{dqn-implmentation-two-thinning}. RL has already been applied to load balancing, mostly related to networking~\cite{attiah2020RLcellular, yeo2021controller}, but those scenarios are considerably different from balls-into-bins.

The randomised balls-into-bins protocols that I will study received much attention in the academic community only recently, though there have been earlier, mostly empirical studies as well (see e.g.~\cite{derek1986twothinningfirstattempt}). At the moment, there are decision strategies that are proven to be \textit{asymptotically} optimal in terms of final maximum load. There are three reasons why most of these theoretical results are not directly applicable: 1) results may only hold for ``sufficiently large'' values of balls and bins, 2) constant factors in big-Oh notation are large, 3) suggested \textit{positive} integer parameter values used by the strategy would equal to $0$, e.g.\ $\floor{\ln(\ln(\ln(\mathrm{number\ of\ servers})))}$ from~\cite{feldheim2021longtermthinning}, which is usually $0$ even for large datacentres~\cite{uzaman2019datacentresize}.

To the best of my knowledge, my work is novel in several aspects. The decision strategies I find using RL and DP are optimised for specific values of balls and bins, not asymptotically. In particular, this is the first work analysing \textit{exactly} optimal strategies, which I will do using DP for moderate values of balls and bins.

In a practical implementation of \TwoThinning, it is often much more natural and effective if the queried server itself decides whether to take the job, rather than sending its current load value back to the client which makes the decision whether to accept of reject that server. Overall, the client chooses a server uniformly at random and then that server either completes the job or passes it on to a server chosen uniformly at random.

The servers need some ``reference'' to assess their load relative to others, which potentially requires some centralised information. There are several options, for example the servers could maintain the total number of jobs in the system, or they could synchronise their individual loads regularly (see e.g.~\cite{zhang2018datacenterloadbalancing} for efficient communication in datacentres). I will focus on the latter, which crucially allows servers to make their decisions based on the (possibly slightly outdated) loads of all the other ones. When a server decides to pass on a job to another server, the motivation for choosing the other server at random is that due to parallelism and the possibly outdated information, the seemingly least loaded server could quickly become the most overloaded if all the other servers pass the jobs to that one. This project being the first work on looking for exactly optimal strategies, I will try to solve a slightly simplified but still very challenging problem, where the strategy is always given the \textbf{exact load distribution} at the moment. In practice, the solutions for this simplified problem could be used to decide on a strategy right after a synchronisation, and that strategy can be followed until the next synchronisation. I further assume that all servers use the same strategy.

Overall, the intention of this more theoretical dissertation is to survey the applicability of RL and other approaches to balls-into-bins, and to gain a deeper insight into how optimal strategies look like. In the future, the insights could be fed back to building efficient, more directly applicable strategies.

\section{Outline}

The outline of the dissertation is as follows.

In Chapter~\ref{preparation}, I formally define the balls-into-bins model and the core protocols I will analyse in later chapters, and I explain the basics of RL.

In Chapter~\ref{implementation}, I explain the implementation considerations of the RL and DP algorithms and discuss the alternative strategies, for various protocols.

In Chapter~\ref{evaluation}, I compare the implemented approaches from various aspects, also providing several insights via a thorough training and hyperparameter analysis for RL, and lemmas and conjectures for the DP algorithm and other strategies.

In Chapter~\ref{conclusion}, I conclude with some future work ideas for improving the RL approaches, gaining better insights to optimal strategies, and extending the study to different protocols.


\documentclass[8pt]{beamer}
\usepackage[utf8x]{inputenc}
\usepackage{hyperref}
\usepackage{graphicx}
\usepackage[english]{babel}

\usepackage[T1]{fontenc}
\usepackage{FiraSans}
\usepackage{url}
\usepackage{mathtools}

\mode<presentation>
{
	\usetheme[progressbar=foot,numbering=fraction,background=light]{metropolis}
	\usecolortheme{default} % or try albatross, beaver, crane, ...
	\usefonttheme{default}  % or try serif, structurebold, ...
	\setbeamertemplate{navigation symbols}{}
	\setbeamertemplate{caption}[numbered]
	%\setbeamertemplate{frame footer}{My custom footer}
}

\newcommand\blfootnote[1]{%
	\begingroup
	\renewcommand\thefootnote{}\footnote{#1}%
	\addtocounter{footnote}{-1}%
	\endgroup
}

\usepackage{minted}

%
\title{Speeding up Python with Rust}
\subtitle{Summer school on modelling and complex systems 2021}
\author{Metodi Nikolov}
\date{10 July 2021}

\begin{document}
\maketitle

\begin{frame}{Contents}
\tableofcontents
\end{frame}

\section{Motivating Example}
\begin{frame}{A model}
Say that you have come up with a very interesting Bayesian model for the data you have. The model is not supported by the standard packages for inference (e.g. \texttt{PyMCMC}, \texttt{Stan}), so you will have to code it yourself.

\pause
\begin{block}{Scaled Student T Distribution}
Throughout this we will use a known model, with likelihood function based around the Scaled Student T Distribution, with priors as straightforward as they can be - the idea is to show work flow and ideas, not a specific model.
\end{block}

\begin{align*}
x &\sim t_\nu(\mu, \sigma^2) \\
\mu &\propto const. \\
\sigma^2 &\propto const.
\end{align*}

\pause
\begin{block}{Subordinate Representation}
	\[x \sim \mu + N\sqrt{\frac{\nu \sigma^2} {\chi^2_\nu}}\]
\end{block}
\end{frame}

\begin{frame}{A model}
\begin{block}{Another Representation}
	\begin{align*}
	x &\sim N(\mu, V) \\
	V &\sim \text{Inv-}\chi^2(\nu, \sigma^2)
	\end{align*}
\end{block}
\pause
NB: There is a $V$ for each data point!
\pause

We will cheat a bit (i.e. make the model better in terms of learning it) and extend the above to allow better mixing:
\begin{align*}
x &\sim N(\mu, \alpha^2U) \\
U &\sim \text{Inv-}\chi^2(\nu, \tau^2)
\end{align*}
\blfootnote{Source: \emph{Bayesian Data Analysis 3rd ed.} Gelman at al. pp. 295}
\end{frame}

\begin{frame}{A model}
Here, $\alpha^2U$ plays the role of $V$, and $\alpha\tau=\sigma$ -- $\alpha$ is a 'mixing' parameter, helps with MCMC.
The full conditional for Gibbs are as follows:
\begin{itemize}
	\item<3->\[ U_i| \alpha, \mu, \tau^2, \nu, \x \sim \text{Inv-}\chi^2\left(\nu+1, \frac{\nu\tau^2+ ((x_i-\mu)/\alpha)^2}{\nu+1}\right) \]
	\item<4->\[\mu|\alpha, \tau^2, U, \nu, x \sim N\left(\frac{\sum\frac{1}{\alpha^2U_i}x_i}{\sum\frac{1}{\alpha^2U_i}}, \frac{1}{\sum\frac{1}{\alpha^2U_i}} \right) \]
	\item<5->\[\tau^2 | \alpha, \mu, U, \nu, x \sim \text{Gamma}\left(\frac{\nu n}{2}, \frac{\nu}{2}\sum\frac{1}{U_i}\right)\]
	\item<6->\[\alpha^2| \mu, \tau^2, U, \nu, x \sim \text{Inv-}\chi^2\left(n, \frac{1}{n}\sum\frac{(x_i-\mu)^2}{U_i}\right)\]
\end{itemize}
\blfootnote{Source: \emph{Bayesian Data Analysis 3rd ed.} Gelman et al. pp. 295}
\end{frame}

\begin{frame}[fragile]{Python implementation}
\begin{minted}[fontsize=\scriptsize]{python}
class ScaledTModel(object):

	__slots__ = ['_data', '_data_size', '_nu',...]

	def __init__(self, data, nu):
		pass

	def run(self, burnin, sample_size):
		pass

	def get_mu(self):
		pass

	def get_sigma2(self):
		pass

	def _update_mu(self):
		pass

	def _update_tau2(self):
		pass

	def _update_alpha2(self):
		pass

	def _update_extended_vars(self):
		pass

	def _sampleScaledInvChiSquare(self, ni, scale):
		pass

\end{minted}
\end{frame}

\begin{frame}[fragile]{Pure Python implementation}
\begin{minted}[fontsize=\scriptsize]{python}
def __init__(self, data, nu):
	print("making a model")
	self._data = data
	self._data_size = len(data)
	self._nu = nu

	self._extended_vars = [0.0] * self._data_size
	self._tau2 = 1
	self._mu = sum(data) / self._data_size
	self._alpha2 = 1

	self._update_extended_vars()
\end{minted}
\end{frame}

\begin{frame}[fragile]{Pure Python implementation}
\begin{minted}[fontsize=\scriptsize]{python}
def _update_mu(self):
	variance = 0.0
	expected_value = 0.0
	for i in range(self._data_size):
		tmp = 1.0/self._extended_vars[i]
		variance += tmp
		expected_value += tmp * self._data[i]

	variance /= self._alpha2
	expected_value /= self._alpha2
	variance = 1.0 / variance
	expected_value = expected_value * variance
	self._mu = random.gauss(expected_value, math.sqrt(variance))
\end{minted}
\end{frame}

\begin{frame}[fragile]{Pure Python implementation}
\begin{minted}[fontsize=\scriptsize]{python}
def _update_tau2(self):
	x = 0.0
	for i in range(self._data_size):
		x += 1.0 / self._extended_vars[i]
	self._tau2 = random.gammavariate(
		self._data_size * self._nu / 2.0,
		2.0 / (self._nu * x),
	)

def _update_alpha2(self):
	x = 0.0
	for i in range(self._data_size):
		x += (self._data[i] - self._mu) *
			(self._data[i] - self._mu) / self._extended_vars[i]
	x /= self._data_size
	self._alpha2 = self._sampleScaledInvChiSquare(self._data_size, x)
\end{minted}
\end{frame}

\begin{frame}[fragile]{Pure Python implementation}
\begin{minted}[fontsize=\scriptsize]{python}
def _update_extended_vars(self):
	for i in range(self._data_size):
		x = (self._data[i] - self._mu) *
			(self._data[i] - self._mu) / self._alpha2
		self._extended_vars[i] = self._sampleScaledInvChiSquare(
			self._nu + 1, (self._nu * self._tau2 + x) / (self._nu + 1))

@property
def get_mu(self):
	return self._results_mu

@property
def get_sigma2(self):
	return self._results_sigma2
\end{minted}
\end{frame}

\begin{frame}[fragile]{Pure Python implementation}
\begin{minted}[fontsize=\scriptsize]{python}
def run(self, burn_in = 1000, sample_size = 2000):
	self._results_mu = [0.0] * sample_size
	self._results_sigma2 = [0.0] * sample_size
	for _ in range(burn_in):
		self._update_extended_vars()
		self._update_alpha2()
		self._update_mu()
		self._update_tau2

	for i in range(sample_size):
		self._update_extended_vars()
		self._update_alpha2()
		self._update_mu()
		self._update_tau2
		self._results_mu[i] = self._mu
		self._results_sigma2[i] = self._alpha2 * self._tau2
\end{minted}
\end{frame}

\begin{frame}[fragile]{Pure Python implementation}
\begin{minted}[fontsize=\scriptsize]{python}
from great_model.python_great_model import ScaledTModel as PythonModel
import numpy as np
from timeit import timeit

nu = 6
mu = -3.14
sigma2 = 30
data_size = 500
z = np.random.randn(data_size)
x = np.random.chisquare(nu, data_size)

t_data = mu + z * np.sqrt(sigma2 * nu / x)

p_model = PythonModel(t_data, nu)

exec_time = timeit('p_model.run(2000, 2000)',
globals=globals(), number = 10)
print(f"Average run time of Pure Python model: {exec_time * 1000 / 10:3.5f} ms")
Average run time of Pure Python model: 10404.53057 ms
\end{minted}
That's a bit more than 10 seconds.
\end{frame}

\begin{frame}[fragile]{Numpy implementation}
\begin{minted}[fontsize=\scriptsize]{python}
def __init__(self, data, nu):
	print("making a model")
	self._data = np.asarray(data)
	self._data_size = len(data)
	self._nu = nu

	self._rng = default_rng()
	# Some starting values
	self._extended_vars = np.zeros(self._data_size)
	self._tau2 = 1
	self._mu = sum(data) / self._data_size
	self._alpha2 = 1

	self._update_extended_vars()

	# temporary data holders, so that we reuse memory
	self._tmp_with_data_size = np.zeros(self._data_size)
	self._tmp_with_data_size2 = np.zeros(self._data_size)
\end{minted}
\end{frame}

\begin{frame}[fragile]{Numpy implementation}
\begin{minted}[fontsize=\scriptsize]{python}
def _update_mu(self):
	np.reciprocal(self._extended_vars, out=self._tmp_with_data_size)
	self._tmp_with_data_size2 = self._data * self._tmp_with_data_size

	variance = self._tmp_with_data_size.sum()
	expected_value = self._tmp_with_data_size2.sum()

	variance /= self._alpha2
	expected_value /= self._alpha2
	variance = 1.0 / variance
	expected_value = expected_value * variance
	self._mu = self._rng.normal(expected_value, math.sqrt(variance))
\end{minted}
\end{frame}

\begin{frame}[fragile]{Numpy implementation}
\begin{minted}[fontsize=\scriptsize]{python}
def _update_tau2(self):
	np.reciprocal(self._extended_vars, out=self._tmp_with_data_size)
	x = self._tmp_with_data_size.sum()
	self._tau2 = self._rng.gamma(self._data_size * self._nu / 2.0, 2.0 / (self._nu * x))

def _update_alpha2(self):
	x = 0.0
	self._tmp_with_data_size = self._data - self._mu
	self._tmp_with_data_size = (self._tmp_with_data_size *
		self._tmp_with_data_size) / self._extended_vars
	x = self._tmp_with_data_size.sum()
	x /= self._data_size
	self._alpha2 = self._sampleScaledInvChiSquare(self._data_size, x)
\end{minted}
\end{frame}

\begin{frame}[fragile]{Numpy implementation}
\begin{minted}[fontsize=\scriptsize]{python}
def _update_extended_vars(self):
	x = (self._data - self._mu) * (self._data - self._mu) / self._alpha2
	self._extended_vars =  self._sampleScaledInvChiSquareN(
		self._nu + 1,
		(self._nu * self._tau2 + x) / (self._nu + 1),
	)

def _sampleScaledInvChiSquareN(self, ni, scale):
	x = self._rng.chisquare(ni, size=len(scale))
	return ni * scale / x
\end{minted}
\end{frame}

\begin{frame}[fragile]{Numpy implementation}
\begin{minted}[fontsize=\scriptsize]{python}
def run(self, burn_in = 1000, sample_size = 2000):
	self._results_mu = np.zeros(sample_size)
	self._results_sigma2 = np.zeros(sample_size)
	for _ in range(burn_in):
		self._update_extended_vars()
		self._update_alpha2()
		self._update_mu()
		self._update_tau2

	for i in range(sample_size):
		self._update_extended_vars()
		self._update_alpha2()
		self._update_mu()
		self._update_tau2
		self._results_mu[i] = self._mu
		self._results_sigma2[i] = self._alpha2 * self._tau2
\end{minted}
\end{frame}

\begin{frame}[fragile]{Numpy implementation}
\begin{minted}[fontsize=\scriptsize]{python}
from great_model.numpy_great_model import ScaledTModel as NumpyModel
import numpy as np
from timeit import timeit

nu = 6
mu = -3.14
sigma2 = 30
data_size = 500
z = np.random.randn(data_size)
x = np.random.chisquare(nu, data_size)

t_data = mu + z * np.sqrt(sigma2 * nu / x)

n_model = NumpyModel(t_data, nu)

exec_time = timeit('n_model.run(2000, 2000)',
	globals=globals(), number = 10)
print(f"Average run time of Numpy model: {exec_time * 1000 / 10:3.5f} ms")
Average run time of Numpy model: 356.86459 ms
\end{minted}
That's more like it... Can we do better? And how much better?
\end{frame}

\section{Crash Course in Rust}
\begin{frame}{Rust is...}
\begin{block}{Good because}
	\begin{itemize}
	\item A compiled, strongly typed, systems programming language (thing C/C++)
	\item Fast - about the same performance as C/C++
	\item Memory safe
	\item With great interoperability
	\item Outstanding tooling
	\end{itemize}
\end{block}

\pause
\begin{block}{Bad because }
	\begin{itemize}
	\item Steep learning curve
	\item Long compile times
	\item A somewhat young language
	\end{itemize}
\end{block}

\blfootnote{Source: \texttt{\url{https://cheats.rs/}}}
\end{frame}

\begin{frame}{The Rust Foundation}
	\begin{figure}
		\centering
		\includegraphics[keepaspectratio=true,width=1\linewidth]{RustFoundation}
		\label{fig:rustfoundation}
	\end{figure}
\end{frame}

\begin{frame}[fragile]{Hello World for scientists}
\begin{minted}{rust}
fn main() {
	// the type is not necessary in this case
	let x: f64 = 1_000_000.0;

	// no type cast - it is infered by the compiler
	let y = {
		let z = x / 100.0;
		// notice the missing colon
		// this is the return value of the block
		z
	};

	println!("The value of y is {}", y);
}
\end{minted}
\end{frame}

\begin{frame}[fragile]{One more Hello World}
\begin{minted}{rust}
fn main() {
	// this variable we will want to change
	let mut x: f64 = 0.0;

	for i in 1..=10 {
		// we perform a cast, as i is not f64
		x += i as f64;
	}
	// we recreate the value x to remove mutability
	let x = x;
	// we take the address of the variable x
	let y = &x;

	// we pass a reference, but still get what we want
	println!("The sum of the first 10 natural numbers is {}", y);
}
\end{minted}
\end{frame}

\begin{frame}[fragile]{One more Hello World 2}
\begin{minted}[fontsize=\small]{rust}
struct MyStruct {
	has_value: bool,
	large_vector: Vec<f64>,
}

fn freeFlowFunction(x: &[f64]) -> f64 {
	unimplemented!();
}

impl MyStruct {
	// method functions for the struct
	fn increate_x(&mut self) {
		self.x += 1;
	}
}

impl fmt::Debug for MyStruct {
	// implement a trait for MyStruct - in this case,
	// how to present the struct in debug messages
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
		todo!()
		// almost never need to do this:
		// annotate the struct definition with
		// #[derive(Debug)]  and the compiler will handle it
	}
}
\end{minted}
\end{frame}

\begin{frame}[fragile]{One more Hello World 2f2f aka Family}
\begin{minted}{rust}

fn a_fun(x: String) {
	if x.len() % 2 == 0 {
		println!("Even");
		return;
	}
	println!("Odd");

}
fn main() {
	let x = "Summer School 2021".to_string();
	a_fun(x);
	println!("x was: '{}' ", x);
}
\end{minted}
\pause
\begin{figure}
	\centering
	\includegraphics[width=1\linewidth]{ExampleCompilerOutput}
	\caption{"Not a bad way to explain the error in the code"}
	\label{fig:examplecompileroutput}
\end{figure}
\end{frame}

\begin{frame}{Rules of ownership}
\begin{enumerate}
	\item Each object can be used only once - it is "moved" every time
	\item Out of scope objects are destroyed and cannot be used
	\item Each block produces a value that goes one scope up
	\item All objects have a lifetime that constrains which scopes they may be moved out of
\end{enumerate}
\pause
There are always exceptions to any rule...
\pause
\begin{enumerate}
	\item Object that implement the special trait \emph{Copy} (think as if on every "=" we do a copy)
	\item Reference borrowing - you can have as many as you like immutable references to an object or one mutable
\end{enumerate}
\blfootnote{Source: \texttt{\url{https://chrismorgan.info/blog/rust-ownership-the-hard-way/}}}
\end{frame}

\begin{frame}[fragile]
\frametitle{Cool Stuff in Rust as a language \tiny{Or how to shoot yourself in the foot in style}}
\begin{enumerate}
	\item Functional tools (could possibly be faster than loops)\begin{minted}[fontsize=\scriptsize]{rust}
		let sum_squares = a_vec.iter().map(|v| v * v).sum();
	\end{minted}
	\item Algebraic types \begin{minted}[fontsize=\scriptsize]{rust}
	enum IpAddr {
		V4(u8, u8, u8, u8),
		V6(String),
	}
	\end{minted}
	\item Destructuring and matching \begin{minted}[fontsize=\scriptsize]{rust}
	let as_string = match ip {
		IpAddr::V4(a, b, c, d) => format!("{}.{}.{}.{}", a, b, c, d),
		IpAddr::V6(s) => s.clone()
	};
	\end{minted}
	\item Anyone can implement a Trait for their Struct
\end{enumerate}
\end{frame}

\begin{frame}[fragile]{Two important Enums}
\begin{itemize}
	\item \begin{minted}{rust}
enum Result<T, E> {
	Ok(T),
	Err(E),
}
		\end{minted}
		You either get the value or get an error - Rust doesn't have exceptions that can get swept under the rug.
	\item \begin{minted}{rust}
enum Option<T> {
	None,
	Some(T),
}
	\end{minted}
	None is only part of this enum, again forcing you to handle missing values.
\end{itemize}
\end{frame}

\begin{frame}{Memory safety, concurrency}
\begin{itemize}
\item The ownership, type system and the borrow checker are some of what guarantees the memory safety in Rust. The compiler proves that no Segmentation Faults, memory leaks etc. cannot happen - otherwise, you get compile time error.
\item "Fearless concurrency" - the same checks are done when multiple threads are involved, so two threads accessing the same memory location with read and write is not possible (mostly).
\item If that was all, Rust would be too rigid and unusable, hence \mint{rust}{unsafe} code word. This signals to the compiler: "I, the human, checked this piece of code and it is fine." You are free to do whatever in these sections (e.g. pointer arithmetic).
\end{itemize}
\end{frame}

\begin{frame}{Tooling}
Some example tools for development (non exhaustive)
	\begin{itemize}
		\item \texttt{rustc} - the compiler (already saw the error messages)
		\item \texttt{rustup} - updater of the above
		\item \texttt{cargo} - package manager (crate in rust parlance)
		\item \texttt{cargofmt} - formatter (so the code looks nice)
		\item \texttt{clippy} - linter (helps find potential issues)
		\item \texttt{rust-analyzer} - IDE support (i.e. code completion) can integrate into your favorite text editor
	\end{itemize}
\end{frame}

\section{Motivating Example Revisited}
\begin{frame}{Extending Python}
	\begin{itemize}
		\item Python C Package - write directly C code (i.e. extend CPython)
		\item Cython - mixture of Python and C (C++) syntax - this is parsed to C and then compiled as above
		\item With enough dedication any language that can build a dynamic library (and some C files to be link the two) can be used for Python modules (e.g. GoLang)
	\end{itemize}
	\pause
	Enter PyO3:
	\begin{itemize}
		\item A Rust bindings for Python
		\item Most of the 'magic' happens with the help of annotations
		\item Several different ways to actually build the package.
	\end{itemize}
\end{frame}

\begin{frame}[fragile]{Definition}
\begin{minted}[fontsize=\small]{rust}
	#[pyclass]
	struct ScaledTModel {
		data_size: usize,
		nu: f64,
		tau2: f64,
		mu: f64,
		alpha2: f64,

		extended_vars: Vec<f64>,
		data: Vec<f64>,
		result_mu: Vec<f64>,
		result_sigma2: Vec<f64>,
	}
	#[pymodule]
	fn rust_great_model(_py: Python, m: &PyModule) -> PyResult<()> {
		m.add_class::<ScaledTModel>()?;

		Ok(())
	}
\end{minted}
\end{frame}

\begin{frame}[fragile]{Exposed methods}
	\begin{minted}[fontsize=\small]{rust}
#[pymethods]
impl ScaledTModel {
	#[new]
	fn new(data: Vec<f64>, nu: f64) -> Self {
		println!("making a rust model");
		ScaledTModel {
			// skipped in slides!
		}
	}

	#[getter]
	fn get_mu(&self) -> PyResult<Vec<f64>> {
		Ok(self.result_mu.clone())
	}

	#[getter]
	fn get_sigma2(&self) -> PyResult<Vec<f64>> {
		Ok(self.result_sigma2.clone())
	}

	fn run(&mut self, burn_in: usize,
			sample_size: usize) -> PyResult<()> {
		todo!()
	}
}
	\end{minted}
\end{frame}

\begin{frame}[fragile]{Folder Structure}
\begin{minted}{text}
great_model
│   Cargo.lock                  <---- Rust related
│   Cargo.toml                  <---- Rust related
│   MANIFEST.in                 <---- Some Rust changes
│   pyproject.toml
│   requirements.txt
│   setup.py                    <---- Some Rust changes
│
├───great_model
│   ├───numpy_great_model
│   │       scaled_t_model.py
│   │       __init__.py
│   │
│   └───python_great_model
│           scaled_t_model.py
│           __init__.py
│
└───src
    lib.rs                      <---- Rust related (source code)
\end{minted}
\end{frame}

\begin{frame}[fragile]{Cargo.toml}
\begin{minted}[fontsize=\scriptsize]{toml}
[package]
name = "great_model"
version = "1.0.0"
edition = "2018"

# See more keys and their definitions at
# https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
name = "great_model"
# "cdylib" is necessary to produce a shared
# library for Python to import from.
#
# Downstream Rust code (including code in `bin/`, `examples/`,
# and `tests/`) will not be able the code unless the "rlib" or
# "lib" crate type is also included, e.g.:
# crate-type = ["cdylib", "rlib"]
crate-type = ["cdylib"]

[dependencies]
rand = "0.8.4"
rand_distr = "0.4.1"
rand_xoshiro = "0.6.0"

[dependencies.pyo3]
version = "0.14.1"
features = ["extension-module"]
\end{minted}
\end{frame}

\begin{frame}[fragile]{MANIFEST and pyproject}
A MANIFEST.in file consists of commands, one per line, instructing setuptools to add or remove some set of files from the distribute package .
\begin{minted}[fontsize=\scriptsize]{ini}
include pyproject.toml Cargo.toml
recursive-include src *
\end{minted}

pyproject.toml specifies the minimum build system for python (basically - make setup.py work)
\begin{minted}[fontsize=\scriptsize]{toml}
[build-system]
requires = [
	"setuptools>=42",
	"wheel",
	"setuptools-rust"
]
build-backend = "setuptools.build_meta"
\end{minted}
\end{frame}

\begin{frame}[fragile]{setup.py}
\begin{minted}[fontsize=\small, linenos]{python}
import setuptools
from setuptools_rust import Binding, RustExtension

setuptools.setup(
	name="great-model",
	version="1.0.0",
	author="Metodi Nikolov",
	author_email="metodi.nikolov@gmail.com",
	classifiers=[
		"Programming Language :: Python :: 3",
		"License :: OSI Approved :: MIT License",
		"Operating System :: OS Independent",
	],
	rust_extensions=[RustExtension("great_model.rust_great_model",
				binding=Binding.PyO3)],
	zip_safe=False,
	packages=setuptools.find_packages(),
	python_requires=">=3.8",
)
\end{minted}
Lines 2, 14-16 are need for the rust bindings, the rest are standard python package.
\end{frame}

\begin{frame}[fragile]{Implementing the model}
\begin{minted}[fontsize=\small]{rust}
fn run(&mut self, burn_in: usize, sample_size: usize) -> PyResult<()> {
	let mut rng = Xoshiro256Plus::seed_from_u64(0);
	for _ in 0..burn_in {
		self.update_extended_vars(&mut rng);
		self.update_alpha2(&mut rng);
		self.update_mu(&mut rng);
		self.update_tau2(&mut rng);
	}

	self.result_mu.resize(sample_size, 0.0);
	self.result_sigma2.resize(sample_size, 0.0);

	for i in 0..sample_size {
		self.update_extended_vars(&mut rng);
		self.update_alpha2(&mut rng);
		self.update_mu(&mut rng);
		self.update_tau2(&mut rng);
		self.result_mu[i] = self.mu;
		self.result_sigma2[i] = self.alpha2 * self.tau2;
	}
	Ok(())
}
\end{minted}
\end{frame}

\begin{frame}[fragile]{Implementing the model}
\begin{minted}[fontsize=\small]{rust}
fn update_mu<R>(&mut self, rng: &mut R)
	where
		R: Rng,
{
	let mut tmp: f64;
	let mut variance = 0.0;
	let mut expected_value = 0.0;
	for (datum, ext_var) in self.data.iter().
			zip(self.extended_vars.iter()) {
		tmp = 1.0 / ext_var;
		variance += tmp;
		expected_value += datum * tmp;
	}
	variance /= self.alpha2;
	expected_value /= self.alpha2;
	variance = 1.0 / variance;
	expected_value = expected_value * variance;

	self.mu = expected_value + variance.sqrt() *
			rng.sample::<f64, _>(StandardNormal);
}
\end{minted}
\end{frame}

\begin{frame}[fragile]{Implementing the model}
\begin{minted}[fontsize=\small]{rust}
fn update_tau2<R>(&mut self, rng: &mut R)
	where
		R: Rng,
{
	let x: f64 = self.extended_vars.iter().map(|x| 1.0 / x).sum();
	let scale = 2.0 / (self.nu * x);
	let gamma = Gamma::new(
		(self.data_size as f64) * self.nu / 2.0,
		scale,
		).expect(&format!(
			"Failed at creation of Gamma, shape:{:}, scale: {:}",
			(self.data_size as f64) * self.nu / 2.0,
			2.0 / (self.nu * x)
		),
	);
	self.tau2 = gamma.sample(rng);
}
\end{minted}
\end{frame}

\begin{frame}[fragile]{Implementing the model}
\begin{minted}[fontsize=\small]{rust}
fn update_alpha2<R>(&mut self, rng: &mut R)
	where
		R: Rng,
{
	let mu = self.mu;
	let mut x = self
		.data
		.iter()
		.zip(self.extended_vars.iter())
		.map(|(datum, ext_var)| (datum - mu) * (datum - mu) / ext_var)
		.sum();
	x /= self.data_size as f64;
	self.alpha2 = sample_scaled_inv_chi_square(rng, self.data_size as _, x);
}
\end{minted}
\end{frame}

\begin{frame}[fragile]{Implementing the model}
\begin{minted}[fontsize=\small]{rust}
fn update_extended_vars<R>(&mut self, rng: &mut R)
	where
		R: Rng,
{
	let mut x: f64;
	let mu = self.mu;
	let alpha2 = self.alpha2;
	let tau2 = self.tau2;
	let nu = self.nu + 1.0;

	let nutau2 = self.nu * tau2;
	let chi = ChiSquared::new(nu).expect(
					"Failed at creation of ChiSquared");
	for i in 0..self.data_size {
		let datum = self.data[i];
		x = (datum - mu) * (datum - mu) * alpha2;
		self.extended_vars[i] = (nutau2 + x) / chi.sample(rng);
	}
}
\end{minted}
\end{frame}

\begin{frame}[fragile]{Rust implementation}
\begin{minted}[fontsize=\scriptsize]{python}
from great_model.rust_great_model import ScaledTModel as RustModel
import numpy as np
from timeit import timeit

nu = 6
mu = -3.14
sigma2 = 30
data_size = 500
z = np.random.randn(data_size)
x = np.random.chisquare(nu, data_size)

t_data = mu + z * np.sqrt(sigma2 * nu / x)

r_model = RustModel(t_data, nu)

exec_time = timeit('r_model.run(2000, 2000)',
	globals=globals(), number = 10)
print(f"Average run time of Rust model: {exec_time * 1000 / 10:3.5f} ms")
Average run time of Rust model: 113.34160 ms
\end{minted}
\end{frame}

\section{Next Steps}
\begin{frame}{Leaving you with..}
\begin{itemize}
	\item Language \texttt{\url{https://www.rust-lang.org/}}
	\item The Book \texttt{\url{https://doc.rust-lang.org/stable/book/}}
	\item Good introduction \texttt{\url{https://tourofrust.com/}}
	\item Reference (work in progress) \texttt{\url{https://doc.rust-lang.org/stable/reference/}}
	\item Reddit \texttt{\url{https://www.reddit.com/r/rust/}}

	\item \texttt{\url{https://github.com/MetodiNikolov/SummerSchool2021}}
\end{itemize}
\end{frame}
%\begin{frame}[allowframebreaks]
%\begin{thebibliography}{9}
%	\setbeamertemplate{bibliography item}[triangle]
%	\bibitem{gelman}
%	Gelman, A.; Carlin, J. B.; Stern, H. S. \& Rubin, D. B. (2014), \emph{Bayesian Data Analysis}, Chapman and Hall/CRC
%\end{thebibliography}
%\end{frame}

\begin{frame}{Thank you!}
\huge Thank you for the attention!
\end{frame}
\end{document}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Beamer Presentation
% LaTeX Template
% Version 1.0 (10/11/12)
%
% This template has been downloaded from:
% http://www.LaTeXTemplates.com
%
% License:
% CC BY-NC-SA 3.0 (http://creativecommons.org/licenses/by-nc-sa/3.0/)
%
% Modified by Jeremie Gillet in March 2017 to make an OIST template
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%----------------------------------------------------------------------------------------
%	PACKAGES AND THEMES
%----------------------------------------------------------------------------------------
\documentclass[8pt]{beamer}

\usepackage{graphicx} % Allows to include images
\usepackage{booktabs} % Allows the use of \toprule, \midrule and \bottomrule in tables

\mode<presentation> {

\usetheme{default}
\definecolor{OISTcolor}{rgb}{0.65,0.16,0.16}

%\usecolortheme[named=OISTcolor]{structure} % Use this line for OIST colors
\usecolortheme[named=black]{structure} % Black titles and such

\setbeamertemplate{itemize item}{\color{black}$\bullet$} % Comment this line for default bullet points (colored triangles)

\usepackage{helvet} % Helvetica Font
\renewcommand{\familydefault}{\sfdefault}

\setbeamertemplate{navigation symbols}{} % No navigation symbols
\setbeamertemplate{footline} % Only page number at the bottom
 {\begin{minipage}{125mm} \vspace{-3 mm} \hfill \insertframenumber \end{minipage}}
 }

\newcommand{\norm}[1]{\left\lVert#1\right\rVert}

%----------------------------------------------------------------------------------------
%	TITLE PAGE
%----------------------------------------------------------------------------------------

\title[Short title]{\color{black} Eigendecomposition for Matrices of Special Forms}
\subtitle{ \color{black}
01.07.2021
}

\author{Vsevolod Nikulin} % Your name
\date{} % Date, leave empty, use subtitle instead

\begin{document}

\setbeamertemplate{background}{\includegraphics[width=\paperwidth]{title.png}} % Adding the background logo for the title page

\begin{frame}[plain]
\vspace*{1.55cm} % Use this spacing if author field is empty
%\vspace*{5mm}  % Use this spacing if author field is used
\titlepage % Print the title page as the first slide
\end{frame}

\setbeamertemplate{background}{\includegraphics[width=\paperwidth, trim=0 0 0 -700 ]{footer.png}} % Adding the background logo for the rest of the slides

\begin{frame}
\frametitle{Overview} % Table of contents slide, comment this block out to remove it

\begin{itemize}
    \item Symmetric Matrices and Their Properties
    \item Symmetric Positive (Semi-)Definite Matrices and Their Properties
    \item Gram Decomposition
    \item Another Useful Property
\end{itemize}

\end{frame}

%----------------------------------------------------------------------------------------
%	PRESENTATION SLIDES
%----------------------------------------------------------------------------------------

\subsection{Subsection Example} % A subsection can be created just before a set of slides with a common theme to further break down your presentation into chunks

\begin{frame}
\frametitle{Symmetric Matrix}

\begin{block}{Definition}

$M$ Symmetric $\iff M^T = M$
\end{block}

\begin{block}{Properties}
\begin{itemize}
    \item All eigenvalues are real
    \item Eigenvectors form an orthogonal basis
\end{itemize}
\end{block}

\end{frame}

%------------------------------------------------

\begin{frame}
\frametitle{Eigenvalues are real}

\begin{block}{Notation: Conjugate Transpose}
$M^* = \overline{M^T}$
\end{block}

\begin{block}{Properties of symmetric $M$}
If $M$ is symmetric and real, then $M^* = M$. In particular, $(\mathbf{x}^* M \mathbf{x})^* = \mathbf{x}^* M^* \mathbf{x} = \mathbf{x}^* M \mathbf{x}$.

\begin{align*}
 \forall \mathbf{x} \in \mathbb{C}^n : \mathbf{x}^* M \mathbf{x} \in \mathbb{R}
\end{align*}

For any eigenvalue $\lambda$ and eigenvector $\mathbf{v}$ we have

\begin{align*}
    M \mathbf{v} &= \lambda \mathbf{v} \\
    \mathbf{v}^* M \mathbf{v} &= \lambda \mathbf{v}^* \mathbf{v} \implies \lambda = \overline{\lambda}
\end{align*}

Moreover

\begin{align*}
    M \mathbf{v} &= \lambda \mathbf{v} \\
    M \overline{\mathbf{v}} &= \lambda \overline{\mathbf{v}} \\
    M (\mathbf{v} + \overline{\mathbf{v}}) &= \lambda (\mathbf{v} + \overline{\mathbf{v}})
\end{align*}

Hence, for a real eigenvalue it is always possible to find a real eigenvector.

\end{block}

\end{frame}

%------------------------------------------------

\begin{frame}
\frametitle{Eigenvectors form an orthogonal basis}

Proof that any pair of linearly independent eigenvectors $\mathbf{v}_1$ and $\mathbf{v}_2$ corresponding to eigenvalues $\lambda_1$ and $\lambda_2$ are orthogonal:

\begin{block}{Case 1: $\lambda_1$ and $\lambda_2$ are distinct}
\begin{align*}
    M \mathbf{v}_1 &= \lambda_1 \mathbf{v}_1 \\
    \mathbf{v}_2^T M \mathbf{v}_1 &=  \lambda_1 \mathbf{v}_2^T \mathbf{v}_1 \\
    \mathbf{v}_2^T M^T \mathbf{v}_1 &= \lambda_1 \mathbf{v}_2^T \mathbf{v}_1 \\
    (M \mathbf{v}_2)^T \mathbf{v}_1 &= \lambda_1 \mathbf{v}_2^T \mathbf{v}_1 \\
    \lambda_2 \mathbf{v}_2^T \mathbf{v}_1 &= \lambda_1 \mathbf{v}_2^T \mathbf{v}_1 \implies \mathbf{v}_2^T \mathbf{v}_1 = 0
\end{align*}
\end{block}

\begin{block}{Case 2: $\lambda_1 = \lambda_2 = \lambda$}
\begin{align*}
    M \mathbf{v}_1 &= \lambda \mathbf{v}_1 \\
    M \mathbf{v}_2 &= \lambda \mathbf{v}_2 \\
    M (a \mathbf{v}_1 + b \mathbf{v}_2) &= \lambda (a \mathbf{v}_1 + b \mathbf{v}_2 )
\end{align*}

The entire linear subspace spanned by $\mathbf{v}_1$ and $\mathbf{v}_2$ consists of eigenvectors. Of course it is possible to find two orthogonal vectors.
\end{block}

\end{frame}

\begin{frame}
\frametitle{Eigendecomposition of Symmetric Matrix}

Eigendecomposition of $M$ is

\begin{align*}
    M = S D S^{-1}
\end{align*}

We can find orthogonal unit eigenvectors, hence $S^{-1} = S^T$:

\begin{align*}
    S^T S = \begin{pmatrix}
    \mathbf{v}_1 \\
    \mathbf{v}_2 \\
    \dots \\
    \mathbf{v}_n
    \end{pmatrix} (\mathbf{v}_1, \mathbf{v}_2, \dots, \mathbf{v}_n) = \begin{pmatrix}
    1 & 0 & \dots & 0 \\
    0 & 1 & \dots & 0 \\
      &   & \ddots &  \\
    0 & 0 & \dots & 1
    \end{pmatrix}
\end{align*}

Therefore eigendecomposition of symmetric $M$ has especially convenient form:

\begin{align*}
    M = S D S^T
\end{align*}

\end{frame}

%------------------------------------------------

\begin{frame}
\frametitle{Positive (Semi-)Definite Matrices}

\begin{block}{Definition}
$M$ Positive Semi-Definite $\iff \forall \mathbf{x} \in \mathbb{R}^n : \mathbf{x}^T M \mathbf{x} \geq 0$

$M$ Positive Definite $\iff \forall \mathbf{x} \in \mathbb{R}^n \setminus \{\mathbf{0}\} : \mathbf{x}^T M \mathbf{x} > 0$
\end{block}

\begin{block}{Properties of symmetric positive (semi-)definite matrices}
\begin{itemize}
    \item All eigenvalues are real and (non-negative) positive
    \item Eigenvectors form an orthogonal basis
    \item When $M$ is real, it accepts following decomposition: $M = B^T B$
    \item For any matrix $B$ the matrix $B^T B$ is symmetric positive semi-definite
\end{itemize}
\end{block}
\end{frame}

%------------------------------------------------

\begin{frame}
\frametitle{Eigenvalues are (Non-Negative) Positive}

Remember, eigenvalues and eigenvectors are real

\begin{align*}
    M \mathbf{v} &= \lambda \mathbf{v} \\
    \mathbf{v}^T M \mathbf{v} &= \lambda \mathbf{v}^T \mathbf{v}
\end{align*}

Since $\mathbf{v}^T M \mathbf{v} \geq 0$ and $\mathbf{v}^T \mathbf{v} \geq 0$, we have $\lambda \geq 0$.

\end{frame}

%------------------------------------------------

\begin{frame}
\frametitle{Gram Decomposition}

For symmetric positive (semi-)definite matrix $M$ we can write

\begin{align*}
    M = S D S^T = S \sqrt{D} \sqrt{D} S^T = \sqrt{D} S (\sqrt{D} S)^T = B^T B
\end{align*}

Where $\sqrt{D}$ is element-wise square root of the matrix $D$.

Also for any matrix $B$ we know that matrix $B^T B$ is symmetric:

\begin{align*}
    (B^T B)^T = B^T (B^T)^T = B^T B
\end{align*}

and positive semi-definite:

\begin{align*}
    \mathbf{x}^T B^T B \mathbf{x} = (B \mathbf{x})^T B \mathbf{x} \geq 0
\end{align*}

Notice, $B$ doesn't need to be square!

\end{frame}

\begin{frame}{Useful Property}

Find a unit vector $\mathbf{x}$ (s.t. $\norm{\mathbf{x}}^2 = 1$) which maximizes $\mathbf{x}^T M \mathbf{x}$:

\begin{align*}
    \mathbf{x}^T M \mathbf{x} = \mathbf{x}^T S D S^T \mathbf{x} = \mathbf{u}^T D \mathbf{u} = \lambda_1 u_1^2 + \lambda_2 u_2^2 + \dots + \lambda_n u_n^2
\end{align*}

Where $\mathbf{u} = S^T \mathbf{x}$. Notice that $S$ is orthogonal matrix, hence if $\mathbf{x}$ is an arbitrary unit vector, then $\mathbf{u}$ is also arbitrary unit vector.

Therefore $\mathbf{u}^T D \mathbf{u}$ is an affine combination of eigenvalues. Assuming $\lambda_1$ is the largest eigenvalue, the expression is maximized with $\mathbf{u} = (1, 0, 0, ..., 0)$. Hence

\begin{align*}
    \mathbf{x} = (S^T)^{-1} \mathbf{u} = S \mathbf{u} = (\mathbf{v}_1, \mathbf{v}_2, \dots, \mathbf{v}_n) \begin{pmatrix}
    1 \\
    0 \\
    \dots \\
    0
    \end{pmatrix} = \mathbf{v}_1
\end{align*}

The answer is the eigenvector which corresponds to the largest eigenvalue.

\end{frame}

\begin{frame}
\Huge{\centerline{The End}}
\end{frame}

%----------------------------------------------------------------------------------------

\end{document}