\documentclass[a4paper]{article}

%% Language and font encodings
\usepackage[english]{babel}
\usepackage[utf8x]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{parskip}

%% Sets page size and margins
\usepackage[a4paper,top=3cm,bottom=2cm,left=3cm,right=3cm,marginparwidth=1.75cm]{geometry}

%% Useful packages
\usepackage{amsmath}
\usepackage{graphicx}
\usepackage[colorinlistoftodos]{todonotes}
\usepackage[colorlinks=true, allcolors=blue]{hyperref}
\usepackage{tabu}
\usepackage{tikz}
\usepackage{subfig}

\title{DD2360 Final Project Report}
\author{Victor Ähdel, Tim Olsson, Alex Sundström, Konrad Magnusson}

\begin{document}
\maketitle

\section{Introduction}

In this project we aim to replicate the results in \emph{N-Body Simulation of the Formation of the Earth-Moon System} \cite{simulation_paper}.
The paper is trying to simulate the giant impact hypothesis, which claims that the creation of our earth and moon stems from the collision of two earth sized planets.
This theory originated from the fact that the earth and moon share a lot of isotopes, however the moon has a lot less iron.
The replication is implemented using CUDA and OpenGL.
Our work amounted in the open-sourced code at \url{https://github.com/timsl/agp-grus}.

\subsection{Scope}

Due to the limited time frame of the project, we restrict ourselves to shorter runs than in the original article.
As the original authors ran some simulations for 720 hours while using 131072 particles, it is infeasible for us to do the same.
Furthermore, we are not able to search the parameter space as extensively due to time constraints, so we might not necessarily end up with as good parameters as the original authors for the smaller number of particles.

\section{Methodology}

The implementation uses CUDA \cite{Cuda} for simulating the particles.
Rendering the simulation is achieved with OpenGL \cite{opengl}, using GLFW for the window management \cite{glfw}.

\subsection{Model}

We follow the model outlined in \cite{simulation_paper} but with a few modifications to enable completing the simulation in less time.
Their model is a normal N-body simulation, and all the particle interactions are summarized in `Table 2: Force function' in \cite{simulation_paper}.

\subsection{Initialization Of Planets}

The planets consist of two different types of particles: iron particles which form the inner core, and silicate particles which form an outer shell.
We begin by initializing the particles' positions by randomly sampling in spherical coordinates.
For the inner core we sample from a spherical source.
This is done by firstly uniformly sampling three numbers between 0 and 1, in equations 1-4 referred to as $\rho_1$, $\rho_2$, and $\rho_3$.
After that we calculate the particles' positions using the following equations:

\begin{equation}
x = rsin\theta cos\phi = R\rho^{1/3}_{1}(1-\mu^{2})^{1/2}cos(2\pi\rho_{3})
\end{equation}
\begin{equation}
y = rsin\theta sin\phi = R\rho^{1/3}_{1}(1-\mu^{2})^{1/2}sin(2\pi\rho_{3})
\end{equation}
\begin{equation}
z = rcos\theta = R\rho^{1/3}_{1}\mu
\end{equation}
\begin{equation}
\text{where:} \mu = (1-2\rho_2)
\end{equation}

The outer shell we distribute the particles according to a random shell distribution with radii between $R_1$ and $R_2$.
Similarly to the inner shell, we begin by uniformly sampling three numbers between 0 and 1, $\rho_1$, $\rho_2$, $\rho_3$ in equation 5-8.
We then calculate the positions using the following equations:

\begin{equation}
x = rsin\theta cos\phi = [R^3_1 + (R^3_2 - R^3_1)\rho_1)]^{1/3}(1 - \mu^2)^{1/2}cos(2\pi\rho_3)
\end{equation}
\begin{equation}
y = rsin\theta sin\phi = [R^3_1 + (R^3_2 - R^3_1)\rho_1)]^{1/3}(1 - \mu^2)^{1/2}sin(2\pi\rho_3)
\end{equation}
\begin{equation}
z = rcos\theta = [R^3_1 + (R^3_2 - R^3_1)\rho_1]^{1/3}\mu
\end{equation}
\begin{equation}
\text{where:} \mu = (1-2\rho_2)
\end{equation}

As the simulations start after the collision, the initial particle velocities of the two planets are opposite to each other.
The initial velocities of each particle has to take into account the impact and the rotational velocities as they were rotating around the Y axis.
The rotational velocity is computed by firstly calculating the distance to the center of mass, followed by calculating the angle and finally adding the rotational velocity.
The impact velocity is added to the x velocity as a factor of $\pm 3.2416 km/s$ depending on which planet the particle belongs to.

\begin{center}
$r = \sqrt{((x - \bar{x})^2 + (z - \bar{z})^2)}$ \\
$\theta = \arctan((z - \bar{z})/(x - \bar{x}))$ \\
$x_{velocity} = \pm 3.2416 + omega*r_xz*sin(theta)$ \\
$y_{velocity} = -omega*r_xz*cos(theta)$ \\
\end{center}

\subsection{CUDA}

The most significant part of the computation that needs to be done for the simulation is in the force calculations between the particles.
Generally in N-body simulations every particle affects each other particle with for example gravity.
This implies that the computational complexity is $O(n^2)$.
While there are ways of reducing the computations necessary, the original paper claims to not do any such optimizations, in order to keep a maximal amount of accuracy in the simulation.
By extension, we do not perform any such optimizations either, and so that computation is by far the biggest bottleneck in achieving a performant simulation.

We therefore use CUDA in order to leverage more power for the n-body force calculations.
Our algorithm is loosely based on the examples in the Nvidia Gems book chapter 31 \cite{nvidia_gems}.
We started out without looking at the book by just computing the forces necessary by running one kernel per particle, which implies that we need to iterate through every other particle in that kernel while grabbing its data from global memory.
That code happened to do pretty much the same things as in the book, aside from the shared memory usage which afterwards was rather easy to add on.
The change affected the performance only slightly though, probably due to how well modern GPGPU drivers cache things anyway when there is free shared memory to use.
Our code should therefore now do the same work as in the article, but it is not structured exactly the same.

In order to improve the performance of the code, we optimized the code by eliminating slow performing function calls with simpler ones.
The code bottlenecks were found using the profilers \verb|nvprof| and the NVIDIA Visual Profiler.
One necessary optimization was to eliminate all usages of \verb|pow()|, as that was seen to take a long time.
Normally such changes would seem to be a ``micro-optimization'', and you would prefer that the code remains as close to the mathematics as possible, but in this case it made too much of a difference.
It ended up approximately reducing the time needed for the n-body computations to a tenth of the original.

In addition, we also tried to reduce the amount of branching as much as possible by not having if-statements for the particle types as well as pre-computing common values.
The if-statements for the types can rather simply be replaced by indexing a property array with an enum that is based on the type of the particle.
We also compute all of the values that are necessary in all of the branches before branching anything, which will hopefully reduce cache issues related to branch misses, since those parts will always be done.
Furthermore, we do not do the if statements quite as in the original article, since that would incur more branches than necessary.
Instead, we branch in such a way that the common case where the particles are moving towards each other is not duplicated in different branches, and the logic was a bit simplified by multiplying with $KRP$ in all cases, but setting it to $1.0$ if it shouldn't be used.
By doing so we seemed to end up with a lot fewer branch-related performance issues.

\subsection{Camera}

In order to be able to move around the space and visualize the simulation from the best angle we needed a smooth and easily operated camera.
To that end, we implemented a camera that acts similar to how a spaceship might act, with controls like a first-person shooter.
We maintain three vectors at all times, a position vector and two direction vectors for forward and upwards.
For a rotation up or down we can take the cross product of the forward and upwards vector to recover a right-pointing vector, and rotate the forward and upwards vector about that axis.
Similarly, rotations left or right simply rotate the forward vector about the upwards vector.

\subsection{OpenGL}

To handle the visualization of the particles we used OpenGL~\cite{opengl}.
As a starting point the code skeleton from the GLFW version of the OpenGL lab was used.
To improve performance a sphere struct was created which handled the rendering.
Beyond that instanced rendering and face culling was also added.

\subsubsection{The Sphere Struct}
\label{sphere_struct}

The sphere struct holds its own vertex array object (VAO) which in turn has two vertex array buffers (VBO) already there from the \verb|GLUTSolidSphere| used in the labs and one additonal we created.
The first two of these buffers is used for storing the vertices and indices for rendering sphere and the third for the instanced rendering (see section \ref{instanced}).
To create the vertices and indicies we use the same code as in the OpenGL labs \verb|GLUTSolidSphere| function.
However since we only set up these values once and reuse them we save on performance.
When we close the application the struct will delete both the VBOs and the VAO.

\subsubsection{Instanced Rendering}
\label{instanced}

To render all the particles we need to provide the GPU with the spheres vertices and a model-view-projection matrix.
Doing this for every single particle does not scale very well since we need to make these OpenGL function calls on the CPU for every particle individually.
It would be better if all the relevant data was pushed to the GPU once and we issued a single call to render all the particles.
Instanced rendering does exactly that.

To achieve instanced rendering we use one large VBO which houses four floats and one unsigned integer for every particle.
The floats are the particles position in homogeneous coordinates and the integer the type of particle (used for deciding which color to render it with).
The type data (which is in the int) theoretically fits into just 2 bits (2 elements types, 2 planets), but we needed to align the data to a 32-bit boundary anyways.
An illustration of the structure of this VBO can be seen in Figure \ref{instanced_figure}.
By adding a stride and offset with \verb|glVertexAttribPointer| and setting \verb|glVertexAttribDivisor| to one OpenGL will know that this is a instanced buffer.

\begin{figure}[h]
\centering

\begin{tikzpicture}

\filldraw[fill=blue!40!white, draw=black] (0,0) rectangle (3,1) node[pos=.5] {4 Floats};
\filldraw[fill=blue!40!white, draw=black] (3,0) rectangle (4,1) node[pos=.5] {UInt};
\filldraw[fill=red!40!white, draw=black] (4,0) rectangle (7,1) node[pos=.5] {4 Floats};
\filldraw[fill=red!40!white, draw=black] (7,0) rectangle (8,1) node[pos=.5] {UInt};
\filldraw[fill=green!40!white, draw=black] (8,0) rectangle (11,1) node[pos=.5] {4 Floats};
\filldraw[fill=green!40!white, draw=black] (11,0) rectangle (12,1) node[pos=.5] {UInt};

\draw (12,1) -- (14,1);
\filldraw (12.5,0.5) circle (2pt);
\filldraw (13,0.5) circle (2pt);
\filldraw (13.5,0.5) circle (2pt);
\draw (12,0) -- (14,0);

\end{tikzpicture}

\caption{Illustration of how the data is packed in the VBO used for the instanced rendering.
The different colors indicate that the data belongs to a different instance of the spheres.
Note that this illustration only shows the data needed for three spheres, when in fact the actual VBO is much larger.}
\label{instanced_figure}

\end{figure}

When we then render the particles we first update this large VBO.
Then we compute a view-projection matrix which we send as a uniform to the OpenGL vertex shader.
When\\ \verb|glDrawElementsInstanced| is called OpenGL will draw the same vertices stored in the first VBO but will step through the third VBO to find the position and type of the particle.
In the vertex shader we have to define two new \emph{in} paramters with their own locations, one for a \verb|vec4| and one for a \verb|uint|.
The \verb|vec4| is used for calculating the particles position and the \verb|uint| is sent to the fragment shader as an \emph{out} parameter with the \emph{flat} prefix to make sure no interpolation in done (since it is an integer value).

Note that we issue more then one call on the CPU side for every render cycle because of the nature of the \verb|GLUTSolidSphere| code we based our rendering on.
The number of calls depends on how many ``\emph{stacks}'' the spheres have.
Even so the rendering is still very fast even as the number of particles start to scale to over 100,000.

\subsubsection{Face Culling}
Face culling is a technique where polygons are evaluated as facing towards or away from the camera. The way this is done is by comparing the order in which the vertices appear when projected onto the camera to the order the user specified. If the user defined the polygon in a clockwise manner and the face appears in a counter clockwise order, the face is turned away from the camera and can be assumed to not need rendering. This should drastically reduce the amount of polygons scheduled for rendering, resulting in a performance increase.

We turned on face culling by calling \verb|glEnable(GL_CULL_FACE)| and \verb|glCullFace(GL_BACK)| during the initialization of the program.
Turning the face culling on provided an approximate $32$ percent performance boost to the OpenGL rendering.

\subsection{Interop}

One bottleneck when programming GPUs is the transfer of memory between the CPU and the GPU.
If we only are interested in the simulation then all the memory can stay on the GPU.
However since we are also visualizing the particles in tandem with the simulation we have to move the new particle positions from the GPU to the CPU to prepare OpenGL to render them.
Then we again have to send this data to the GPU where OpenGL can access it.
With Interop we can let CUDA send the new positions to a OpenGL buffer directly, eliminating the intermediate transfer step.
This can be a quite good speedup especially as the number of particles, and as such the memory requirements, grow.

To achieve interoperability between OpenGL and CUDA we had to expose the Sphere structs (see \ref{sphere_struct}) VBO containing the positions and types to the CUDA kernel.
First a \verb|cudaGraphicsResource| had to be created.
To expose the VBO to this resource \verb|cudaGraphicsGLRegisterBuffer| was used, and then the resource was mapped with \verb|cudaGraphicsMapResources|.
Finally, a pointer to the VBO was fetched with \verb|cudaGraphicsResourceGetMappedPointer|.
After each update cycle this pointer was used to access the VBO and update the particles positions.
This was done using some pointer math and required that the data types in the VBO was aligned to a 32-bit boundary.

\section{Simulation Results}

\subsection{Creation of the moon}

Some promising results can be seen in figure \ref{fig:sim}. Here we are running the simulation with 32768 particles. In the top left image we have the simulation at the first time-step, at the initialization. In the top right image we are a few time steps later in the simulation, and we can see the first impact of the two planets. In (c), we observe the planets a bit later into the collision. In (d), several time steps later, we can see a planet, and something moonlike further away to the top-right of this image.

\begin{figure}[h]%
    \centering
     \subfloat[Initialization]{{\includegraphics[height=5cm, width=7cm]{1.png} }}%
     \qquad
    \subfloat[First impact]{{\includegraphics[height=5cm, width=7cm]{2.png} }}%
    \qquad
    \subfloat[After collision]{{\includegraphics[height=5cm, width=7cm]{3.png} }}%
    \qquad
    \subfloat[Planet and something moonlike]{{\includegraphics[height=5cm, width=7cm]{4.png} }}%
    \caption{Images from a simulation with 32768 particles. Each planets type of element has a different color.}%
    \label{fig:sim}%
\end{figure}

\subsection{Parameters}

The simulation was very sensitive to the time step parameter.
In the original report a timestep of $5.8117$ seconds was used \cite{simulation_paper}.
However with such a large step size the particles were more likely to just scatter away.
This is possibly because they then more often ended up penetrating both shells in a single update step, immediately being affected by large forces.
We had more success with a lower time step, which made more particle interactions start while they barely touched each other, which implies that the inner shells were less often penetrated as the first thing, and therefore the elastic forces were at play.
With the lower timestep, it also means that generally lower forces will be applied when particles start to collide, and the system stays more stable.

\section{Performance Results}
We used a computer with an i5-2500k CPU and an Nvidia GeForce GTX 960 GPU with 4GiB VRAM for the benchmarks.
As pretty much all the work is done on the GPU, the CPU will not be the bottleneck, and so it should not affect the measurements noticeably.
All the measurements here are averages of 64 update steps.

In table \ref{cudatime} the performance of the CUDA part is summarized.
It is there very visible that the time complexity is about $O(n^2)$, since each step down a row approximately quadruples the time.
We can also see that the optimal block size depends a bit on the choice of the number of particles.
For low number of particles, a block size of 256 might be optimal, while the more reasonably large simulations would like a block size of 1024.
We could not try out larger block sizes, as at that point the blocks run out of shared memory and the CUDA part stops working.
The standard deviations here are omitted for space since they scaled approximately the same as the time itself, and was consistently about a tenth of the time.
Most of the standard deviation appears to come from a few outliers, such as the first update step in each run which takes a significant higher amount of time (probably due to the GPU not having cached anything yet).
The same information is visible in figure \ref{cudatimeplot}, where the scaling is even more obvious.
Table \ref{nvprof} shows the relative time taken by the kernels for a run with 65536 particles, verifying that the force calculations take most of the time and the other kernels are negligible.

Table \ref{opengltime} summarizes the performance of the OpenGL part depending also on the number of particles.
There we can see that the time scales approximately linearly with the number of particles.

\begin{table}[h]
\center
\begin{tabu} to \textwidth {r|rrrrrrrr}
  Particles &   8 &  16 & 32 &  64 & 128 & 256 & 512 &1024 \\
\hline
 1024 &     574 &    478 &    454 &    443 &    439 &    438 &    447 &    508 \\
 2048 &    1552 &    926 &    788 &    760 &    744 &    737 &    743 &    843 \\
 4096 &    5124 &   2631 &   1697 &   1582 &   1514 &   1483 &   1456 &   1626 \\
 8192 &   19724 &   9951 &   5084 &   4359 &   3968 &   3811 &   3711 &   3655 \\
16384 &   77976 &  39116 &  19784 &  18670 &  17437 &  17000 &  14660 &  14350 \\
32768 &  311170 & 155934 &  78569 &  77015 &  70697 &  68759 &  58424 &  57163 \\
65536 & 1248198 & 626355 & 314103 & 281629 & 259492 & 252709 & 234937 & 231091 \\
\end{tabu}
\caption{Mean update time (CUDA part). Columns are the block size. Times are in microseconds.}
\label{cudatime}
\end{table}

\begin{figure}[h]
\center
\includegraphics[width=0.8\textwidth]{plot}
\caption{Plot of the mean update time (CUDA part), dependent on the number of particles and block size. Times are in microseconds. Both axes are in log 2.}
\label{cudatimeplot}
\end{figure}

\begin{table}[h]
\center
\begin{tabu} to \textwidth {l|rr}
  Kernel & Time & \%\\
\hline
\texttt{calculate\_forces} & 57541 & 99.85\%\\
\texttt{apply\_forces} & 52 & 0.09\%\\
\texttt{update\_gl} & 31 & 0.06\%\\
\end{tabu}
\caption{\texttt{nvprof} results for the kernels that run each update. Average times for a run with 65536 particles. Times are in microseconds.}
\label{nvprof}
\end{table}

\begin{table}[h]
\center
\begin{tabu} to \textwidth {r|rr}
Particles & Mean & Std.Dev. \\
\hline
  1024    &       428      &      428 \\
  2048    &       555      &      413 \\
  4096    &       833      &      556 \\
  8192    &      1274      &      681 \\
 16384    &      2280      &      805 \\
 32768    &      4108      &      894 \\
 65536    &      8155      &      912 \\
\end{tabu}
\caption{Display time (OpenGL part). Times are in microseconds.}
\label{opengltime}
\end{table}

\section{Discussion and Conclusion}

While we did not manage to recreate the moon in the exact manner as in the original article, we have succeeded in creating moon-like planets as a result of the collision.
Hence, we believe that the simulation method is very promising, and can certainly simulate this type of collision.

The usage of GPGPU methods for the simulation was certainly key to enable the program to perform efficiently enough for reasonably fast simulation and parameter searching.
The simulation could definitely not have been done if we could not make usage of our GPUs, as we would then need supercomputer-grade CPUs for the simulation to complete in a reasonable time frame.
Even though we still use the $O(n^2)$ the simulation runs quite fast, and we do not see many further possible optimizations while sticking to the all-pairs simulation.

It is as of yet unclear whether it was necessary to do the full $n^2$ particle computation, or if it might have been possible to use other optimizations while ending up with the same result.
It would be interesting to see if the simulation would still work well using hierarchical approaches with far-field approximations, that split the particles into groups and then approximate the forces against particles far away, instead of doing the all-pair version.

On the rendering side the most important optimization was the inclusion of instanced rendering.
For this specific application this provided enough of a boost that rendering a very large amount of particles became very easy.
Further optimizations are not very needed on our testing hardware since the larger bottleneck is in the simulation code.
However one thing that would improve the user experience would be to let the rendering and simulation be done on different threads.
This would allow the user to manipulate the camera in a smooth fashion even when the simulation would dip below real time.
To implement this in a proper manner triple buffering of the larger VBO mentioned in \ref{instanced} would be needed.

\section{Contribution of each member}
The team members all did a similar amount of work.
We most often used pair programming and mutually discussed the code while actually writing it on the computers with the most comfortable CUDA environment, so the git log is very inaccurate as to our work split.

\bibliographystyle{apalike}
\bibliography{sample}

\end{document}


\chapter{Proof Attempt}
\label{chap:chapter9}

\autoref{sec:AugmentedProgramApproach} contains details of the attempt made to prove the correctness of the algorithm - reason for the mentioned approach, claims made and reasons for its failure. \autoref{sec:WhyTheAlgorithmWorks} informally shows why the algorithm should work for the special case when the input program has no loops.

\section{Augmented Program Approach}
\label{sec:AugmentedProgramApproach}
Let $\mathcal{X}$ and $\mathcal{I}$ be the set of variables and instructions in the program respectively. Also, let $\mathcal{T}$ and $V$ be the set of terms and program points; and $\mathcal{D}(V, \mathcal{F})$ be the corresponding data flow framework. Let $\mathcal{W} \subseteq \mathcal{T}$ be the corresponding set of terms of length atmost two (in terms of number of operands).

The basic motive behind this approach was to prevent the disappearance of some equivalence classes in between the program due to reassignment to variables (see \autoref{sec:tc4} for an example). The classes disappear because there exists no expression in our working set $\mathcal{W}$ that belongs to that class however that class still contains expressions outside $\mathcal{W}$.

\subsection{Augmented Program}
\label{subsec:AugmentedProgram}

Every instruction in the original program is extended to a \textbf{bundle} of instructions - for each instruction $i \in \mathcal{I}$, add immediately after it dummy instructions of the form $x_i \gets x, \forall x \in \mathcal{X}$. This new program with dummy instructions is called the \textbf{augmented program} and the new variables introduced are called \textbf{shadow variables}.
\\
Let $\overline{\mathcal{X}}$, $\overline{\mathcal{I}}$, $\overline{\mathcal{T}}$ and $\overline{V}$ be the corresponding sets of variables, instructions, terms and program points respectively; and $\overline{\mathcal{D}}(\overline{V}, \overline{\mathcal{F}})$ be the corresponding data flow framework. Also $\overline{\mathcal{W}} \subseteq \overline{\mathcal{T}}$ be the corresponding set of terms restricted to length atmost two.

\subsection{Idea}
\label{subsec:Idea}
Let $\mathcal{L}$ and $\overline{\mathcal{L}}$ be the infinite lattices associated with the original and augmented programs respectively. These are same as $\overline{\mathcal{G}(\mathcal{T})}$ described in \autoref{sec:CongruenceRelation}, for the original and augmented programs.
\\
Given a partition $\mathcal{P}$, define
$$\Phi_W(\mathcal{P}) = \{A_i \cap W \mid A_i \in \mathcal{P} \ \mathrm{and} \ (A_i \cap W) \neq \phi\}$$
Let $\Phi_W$ be generalised so that when applied to set of partitions $\mathcal{S}$,
$$\Phi_W(\mathcal{S}) = \{\Phi_W(\mathcal{P}) \mid \mathcal{P} \in \mathcal{S}\}$$
It is clear that $\mathcal{L} = \Phi_{\mathcal{T}}(\overline{\mathcal{L}})$. Let $\mathcal{L}_{\mathcal{W}} = \Phi_{\mathcal{W}}(\mathcal{L})$ and $\overline{\mathcal{L}}_{\overline{\mathcal{W}}} = \Phi_{\overline{\mathcal{W}}}(\overline{\mathcal{L}})$ be the finite lattices associated with the original and augmented lattices respectively.
\\
Let $f_{\mathcal{D}}$ and $\overline{f}_{\overline{\mathcal{D}}}$ be be the composite transfer function associated $\mathcal{L}$ and $\overline{\mathcal{L}}$ respectively, as defined in \autoref{chap:chapter3}. The Hebrand congruence functions are given by
$$\mathcal{H}_{\mathcal{D}} = \bigwedge \{\top, f_{\mathcal{D}}(\top), f_{\mathcal{D}}^2(\top), ...\}\ \mathrm{and}\ \overline{\mathcal{H}}_{\overline{\mathcal{D}}} = \bigwedge \{\overline{\top}, \overline{f}_{\overline{\mathcal{D}}}(\overline{\top}), \overline{f}_{\overline{\mathcal{D}}}^2(\overline{\top}), ...\}$$
for the original and augmented lattice. Here, $\top$ and $\overline{\top}$ stands for top element in the product lattices corresponding to $\mathcal{L}$ and $\overline{\mathcal{L}}$ respectively.

\subsubsection{Observations}
\label{subsubsec:Observations}
\begin{itemize}
    \item $\Phi_{\mathcal{W}}(\mathcal{H}_{\mathcal{D}}) = \Phi_{\mathcal{W}}(\overline{\mathcal{H}}_{\overline{\mathcal{D}}})$
    \item $\Phi_{\mathcal{W}}(\Phi_{\overline{\mathcal{W}}}(\overline{\mathcal{H}}_{\overline{\mathcal{D}}})) = \Phi_{\mathcal{W}}(\mathcal{H}_{\mathcal{D}})$
\end{itemize}

\subsubsection{Claim}
\label{subsubsec:Claim}
$$\Phi_{\overline{W}}(\overline{\mathcal{H}}_{\overline{\mathcal{D}}}) =\text{ Maximum fix point of transfer function } \overline{f}_{\overline{\mathcal{W}}} \text{ on } \overline{\mathcal{L}}_{\overline{\mathcal{W}}}$$
The right hand side can computed efficiently using the algorithms in \autoref{chap:chapter4}, on the augmented program.

\subsection{Hypothesis}
\label{subsec:Hypothesis}
Following hypothesis was proposed which was supposed to be used later to prove the claim - suppose at program point $v \in V$ in the original program, variable $x \cong t$ (where $\mid t \mid\ \geq 2$) in our original infinite lattice $\mathcal{L}$, then at the output of the bundle corresponding to program point $v$ in the augmented program, there exists $t'$ in augmented finite lattice $\overline{\mathcal{L}}_{\overline{\mathcal{W}}}$ with $\mid t' \mid\ = 2$ which is equivalent to $x$ and consists only of constants and shadow variables.
\\
However, a counter example to the hypothesis was discovered while attempting the proof for the hypothesis. Consider test case in \autoref{sec:tc13} - at the confluence point (program point 6), in the original infinite lattice $x$ and $((y + z) + n)$ are equivalent; but in the augmented finite lattice no two length expression consisting of only shadow variables and constants that is equivalent to $x$.

\section{Why the Algorithm Works}
\label{sec:WhyTheAlgorithmWorks}
Instead of a general case, consider the ones in which the program has no loops. In such cases the control flow graph (CFG) is a directed acyclic graph (DAG). And if the algorithm processes CFG nodes in the topological order, it converges in the first iteration itself.

The \texttt{Parent} map captures the syntactic information present in the expressions in the form of an ordered tree. Each node in the tree is assigned a unique set identifier and represents some syntactically equivalent expressions. Suppose a node has set identifier $x$ and \texttt{Partitions[v][e]} is $x$ - it means that at program point $v$, expression $e$ has same syntactic value (across all program paths from the start) as represented by the node. A node captures this syntactic information in the form of its two ordered childrens and an operator - which is precisely the information stored the \texttt{Parent} map. Leaf nodes represents atomic values - a constant, non-deterministic or variable (variable in terms of different values along different execution paths) value. These properties implies that two expressions that are assigned the same set identifier at a program point are Herbrand equivalent at that point, which shows the correctness of the algorithm.

Now induction can be used to show that the algorithm actually maintains the properties mentioned in the last paragraph when it processes the nodes in the topological order.
\\
At the \texttt{START} point all the expressions in $\mathcal{W}$ are inequivalent to each other. And the algorithm also assigns different set identifiers to elements of $\mathcal{W}$. Also, for all $x_1 + x_2 \in (\mathcal{W} \setminus (\mathcal{C} \cup \mathcal{X}))$, \texttt{Parent[\{+, Partitions[START][$x_1$], Partitions[START][$x_2$]\}]} is assigned \texttt{Partitions[START][$x_1 + x_2$]}. So the properties hold at \texttt{START} point.

Now the properties will be shown to hold for program point $v$, assuming that they hold at all points which occur before $v$ in the topological order - in particular they hold for all $u \in \texttt{Predecessors[v]}$.
\begin{itemize}
    \item \textbf{$v$ is a transfer point}\\
    Suppose $v$ represents the assignment $x = e$ and $u$ is its predecessor. With respect to $u$, the only expressions changing values are the ones which contain $x$. So \texttt{Partitions[u]} is copied to \texttt{Partitions[v]} and $x$ is assigned the set identifier of $e$ because they now have equal values.\\
    Now consider all expressions of the form $a + b$ which contains $x$. If \texttt{Parent[\{+, Partitions[v][a], Partitions[v][b]\}]} is defined it means that there already exists a node that represents expressions syntactically equivalent to the value of $a + b$ at the current point. So \texttt{Partitions[v][a + b]} should be assigned the same set identifier. However, if no such node exists a new one needs to be created and is to be assigned to \texttt{Parent[\{+, Partitions[v][a], Partitions[v][b]\}]} as well as to \texttt{Partitions[v][a + b]} to maintain the properties. This is consistent with what the algorithm actually does.

    \item \textbf{$v$ is a confluence point}\\
    If $e \in \mathcal{W}$ has same set identifiers for all $u \in \texttt{Predecessors[v]}$, it means that it has same syntactic value at all its predecssors and hence even at the confluence point - so it must be assigned the same set identifier (as that of the predecessors) even at $v$ to maintain the properties.\\
    However, if $e \in \mathcal{W}$ has different identifiers at the predecessors then not all the values at the predecessor points are syntactically equivalent - for this case we require a new leaf node (because of variable values at predecessors). So we must find expressions which are equivalent to $e$ at all the predecessors - and assign a new set identifier (new leaf node) for them to maintain the properties.\\
    These both cases are consistent with the algorithm.
\end{itemize}


\chapter{Results}
\label{chap:cpv:results}

The difference in the raw asymmetries of the \pKK\ and \ppipi\ data defines
\dACP
\begin{equation*}
  \dACP = \ARaw(\pKK) - \ARaw(\ppipi).
\end{equation*}
The values of, and uncertainties on, \ARaw\ are measured by the weighted fits
described in \cref{chap:cpv:araw}.
In this section, the combinations of \ARaw\ are made within and across the
data-taking years (2011 and 2012) and magnet polarities (magnet up and down),
and the measured values of \ARaw\ and \dACP\ are reported.

\section{Combining measurements}
\label{chap:cpv:results:combination}

The values of \ARaw\ for a given decay mode and data-taking year and polarity
are measured in the fits.
Within a given year $\zeta$, $\zeta \in [2011, 2012]$, the average value of the
\ARaw\ for each mode is defined as the arithmetic mean of the two values of
\ARaw\ measured on the magnet up and magnet down data.
The average value of \dACP\ within a year is then defined as
\begin{equation}
  \dACP(\zeta) = \ARaw(\zeta, \pKK) - \ARaw(\zeta, \ppipi).
\end{equation}
Across both years, the values of \ARaw\ are computed as the weighted sum of the
per-year values, where the weights are the inverses of the squares of the
statistical uncertainties $\sigma$ on the measurements.
This quantity can be computed using the polarity-averaged \ARaw\ measurements,
and it can also be computed per polarity, for example to compute the average
magnet down result across 2011 and 2012.

The measured values of $\ARaw(\pKK)$, $\ARaw(\ppipi)$, and \dACP\ are given in
\cref{tab:cpv:results:asymmetries}, where the central values are blinded.
Plots of the three measurements for each data sub-sample are given in
\cref{fig:cpv:results:asymmetries}, where a \chisq\ fit of a constant function
to the measurements is also shown.
The values are compatible across years and magnet polarities.

The value of \dACP\ averaged across all magnet polarities and years is measured
to be
\begin{equation*}
  \dACP = \deltaACP.
  \label{eqn:cpv:results:dacp}
\end{equation*}
The central value is blinded.

\subsection{Unweighted asymmetries}

The results computed without the inclusion of the kinematic weights and phase
space efficiency corrections are given in
\cref{tab:cpv:results:asymmetries_unweighted}, where the central values are
blinded.
The average value of \dACP\ in these results is
\begin{equation*}
  \dACP = \deltaACPUnweighted.
\end{equation*}
Assuming the weighting does correctly equalise the kinematics, the small change
in central value from the weighted measurement indicates that the differences
between the modes before the weighting were small.
The \SI{8}{\percent} reduction in the statistical uncertainty is due to the
effective increase in the \ppipi\ sample size when unweighted, and illustrates
that the uncertainty on \dACP\ is dominated by the \pKK\ sample size.

\begin{table}
  \centering
  \caption{%
    Measured asymmetries, in percent, for each data sub-sample and combination
    of sub-samples.
    The computation of the combinations, ``2011 + 2012'' and ``Average'', is
    defined in \cref{chap:cpv:results:combination}.
    The central values of all measurements are blinded.
  }
  \label{tab:cpv:results:asymmetries}
  \input{tables/cpv/results/delta_acp.tex}
\end{table}

\begin{table}
  \centering
  \caption{%
    Measured asymmetries, in percent, for each data sub-sample and combination
    of sub-samples without the inclusion of the kinematic weights and phase
    space efficiency correction.
    The computation of the combinations, ``2011 + 2012'' and ``Average'', is
    defined in \cref{chap:cpv:results:combination}.
    The central values of all measurements are blinded.
  }
  \label{tab:cpv:results:asymmetries_unweighted}
  \input{tables/cpv/results/delta_acp-unweighted.tex}
\end{table}

\begin{figure}
  \begin{subfigure}[b]{0.5\textwidth}
    \includegraphics[width=\textwidth]{cpv/results/araw_pKK}
    \caption{$\ARaw(\pKK)$}
    \label{fig:cpv:results:asymmetries:pKK}
  \end{subfigure}
  \begin{subfigure}[b]{0.5\textwidth}
    \includegraphics[width=\textwidth]{cpv/results/araw_ppipi}
    \caption{$\ARaw(\ppipi)$}
    \label{fig:cpv:results:asymmetries:ppipi}
  \end{subfigure}

  \vspace{0.5cm}

  \begin{subfigure}[b]{\textwidth}
    \centering
    \includegraphics[width=0.5\textwidth]{cpv/results/dacp}
    \caption{\dACP}
    \label{fig:cpv:results:asymmetries:dacp}
  \end{subfigure}
  \caption{%
    Values of the asymmetries $\ARaw(\pKK)$
    (\subref*{fig:cpv:results:asymmetries:pKK}), $\ARaw(\ppipi)$
    (\subref*{fig:cpv:results:asymmetries:ppipi}), and \dACP\
    (\subref*{fig:cpv:results:asymmetries:dacp}), for the four data
    sub-samples.
    The central values of the measurements are blinded.
    For each asymmetry, a \chisq\ fit of a constant function to the four data
    points is also shown, along with the best fit value and uncertainty,
    \chisq\ per degree of freedom~(DOF), and $p$-value.
  }
  \label{fig:cpv:results:asymmetries}
\end{figure}


\chapter{Electromagnetism}

The important things:
\UnorderedList{
\item Magnetic field induced by an electric current.
\item Lorentz force on a charge moving in magnetic field.
}

\emph{Electric current} is a flow of electric charges.
The unit of current is \emph{ampere}.
One ampere is one coulomb per second.

\section{William Gilbert's research of magnets}

\section{Electrical objects}

\emph{Electric charge} is similar to mass.

\emph{Point charge} is similar to point mass.

A point charge exists in a \emph{medium}.
An example medium is vacuum.
A \emph{homogeneous medium} is a medium that is the same everywhere.
Every part of a homogeneous medium has the same property as every other part of the same medium.

An \emph{electron} has negative electric charge.
A \emph{proton} has positive electric charge.

The \emph{oil drop experiment} measures the charge of an electron.

\section{Coulomb's law of electrostatics}

Let there be two objects \(C_1\) and \(C_2\).
Let both of them exist in the same homogeneous medium.
Let \( k \) be a \emph{constant} that depends on the medium.

Let \( q_1 \) be the charge of \(C_1\).

Let \( q_2 \) be the charge of \(C_2\).

Let \( x_{12} \) be the position of \(C_2\) as seen from \(C_1\).
In other words, let \( x_{12} \) be the vector from \(C_1\) to \(C_2\).

Let \( F_2 \) be the force exerted by \(C_1\) on \(C_2\).

Let both \(C_1\) and \(C_2\) be \emph{stationary} (let their velocities be zero).

\emph{Coulomb's law} states that \( F_2 = k q_1 q_2 x_{12} / |x_{12}|^3 \),
and, by symmetry, \( F_1 = k q_2 q_1 x_{21} / |x_{21}|^3 = -F_2 \) because \( x_{12} = -x_{21} \).
This is the \emph{electrostatic force}.
Coulomb's law is similar to Newton's law of universal gravitation,
but Coulomb's can repel or attract, depending on the sign of the charges.
Newton's has only been found to attract because negative mass has not been found.

% https://en.wikipedia.org/wiki/Dielectric
A \emph{dielectric} is ...

% https://en.wikipedia.org/wiki/Force_between_magnets#Gilbert_Model
% https://en.wikipedia.org/wiki/Magnetic_dipole%E2%80%93dipole_interaction
% https://en.wikipedia.org/wiki/Magnetism#History
% https://en.wikipedia.org/wiki/Faraday%27s_law_of_induction

% Where does magnetism come from?
% Magnetic moment? Electric current? Spin magnetic moment?
% https://en.wikipedia.org/wiki/Magnetism#Sources_of_magnetism
% https://en.wikipedia.org/wiki/Magnetism#Quantum-mechanical_origin_of_magnetism

\emph{Faraday's law of induction}:
A changing magnetic field through a closed loop causes an electric current?

Force between magnets, Gilbert model, magnetic pole?

\section{Pieces of electromagnetism}

% https://en.wikipedia.org/wiki/Lorentz_force

In 1820, Hans Christian {\O}rsted found that electric current deflects magnetic needle.

Thomson: \(F = q v \times B\).

\emph{Lorentz force law}:
A particle of charge \(q\) moving with velocity \(v\)
in an electric field \(E\) and a magnetic field \(B\)
experiences a force \( F = q E + q v \times B \).
This force is called \emph{Lorentz force}.
("Lorentz force", Wikipedia)
The equation can be factored to \( F/q = E + v \times B \).
If \(E = 0\) and \(q > 0\), then the Lorentz force can be visualized as follows:
Use your right hand, point your thumb right (this is the direction of \(v\)),
your index finger forward (this is the direction of \(B\)),
and your middle finger up (this is the direction of \(F\)).

\emph{Biot-Savart law}:
A constant electric current causes a magnetic field that does not vary with time.
Right-hand rule.
Use your right hand.
Raise your thumb.
Curl the other four fingers.
The thumb is the direction of the current.
The other four fingers is the direction of the magnetic field lines.

\emph{Ampere's law}?

\emph{Gauss's law of magnetism}?

\section{Maxwell's equations}

\section{Heaviside's vector-calculus formulation}

\section{Electromagnetic radiation, electromagnetic wave}

\section{Lorentz invariance}

\section{Electricity, electrochemistry}

An \emph{electrochemical cell} has chemical reaction and voltage.
A \emph{battery} is a collection of electrochemical cells.

% https://en.wikipedia.org/wiki/Electricity
\emph{Electricity} is the set of physical phenomena associated with the presence of electric charge ("Electricity", Wikipedia, unhelpful?).

Why can't battery be more efficient?

Why can't solar cells be cheaper and more efficient?

% https://en.wikipedia.org/wiki/Solar_cell
% https://en.wikipedia.org/wiki/Photovoltaic_effect
The \emph{photovoltaic effect} is ...
A \emph{photovoltaic cell}, also called \emph{solar cell}, is ...

Energy storage: flywheel, battery, reserve hydroelectric reverse water pumping back upstream, thermal energy storage, etc.

\section{Units}

1 ampere is ...

1 farad is ...

1 tesla is ...

1 weber is ...

\section{Electric circuits}

\section{Resistance}

\section{Ohm's law}

\emph{Ohm's law}: \( V = IR \).

\section{Hertz's antenna experiment}

\section{Electromagnetic wave}

\section{Light is electromagnetic wave}

\section{Electromagnetic radiation}

\section{Magnetism}

Magnetism is caused by electron spin?%
\footnote{\url{https://en.wikipedia.org/wiki/Magnetism\#Sources_of_magnetism}}

Tesla is the unit of magnetic flux density (magnetic field strength).
1 tesla is 1 weber per \si{m^2}.
\enquote{A particle, carrying a charge of one coulomb, and moving perpendicularly through a magnetic field of one tesla,
at a speed of one metre per second, experiences a force with magnitude one newton, according to the Lorentz force law.}%
\footnote{\url{https://en.wikipedia.org/wiki/Tesla_(unit)\#Definition}}%
\footnote{\url{https://en.wikipedia.org/wiki/Orders_of_magnitude_(magnetic_field)}}


% -*- coding:utf-8 -*-
\documentclass[12pt]{article}
\usepackage[utf8]{inputenc}
\newenvironment{note}{\paragraph{NOTE:}}{}
\newenvironment{field}{\paragraph{field:}}{}
\newcommand*{\tags}[1]{\paragraph{tags: }#1}

\begin{document}

\begin{note}
    \tags{reciprocal}
    \begin{field}
    \[
        \cot \theta
    \]
    \begin{center}
    (reciprocal)
    \end{center}
    \end{field}
    \begin{field}
    \[
        \frac{1}{\tan \theta}
    \]
    \begin{center}
    (reciprocal)
    \end{center}
    \end{field}
\end{note}

\begin{note}
    \tags{reciprocal}
    \begin{field}
    \[
        \csc \theta
    \]
    \begin{center}
    (reciprocal)
    \end{center}
    \end{field}
    \begin{field}
    \[
        \frac{1}{\sin \theta}
    \]
    \begin{center}
    (reciprocal)
    \end{center}
    \end{field}
\end{note}

\begin{note}
    \tags{reciprocal}
    \begin{field}
    \[
        \sec \theta
    \]
    \begin{center}
    (reciprocal)
    \end{center}
    \end{field}
    \begin{field}
    \[
        \frac{1}{\cos \theta}
    \]
    \begin{center}
    (reciprocal)
    \end{center}
    \end{field}
\end{note}

\end{document}


\documentclass[a4paper,11pt]{article}

% Import packages
\usepackage[a4paper]{geometry}
\usepackage[utf8]{inputenc}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{graphicx}
\usepackage{scrextend}
\usepackage{listings}
\usepackage{color}
\usepackage{adjustbox}

\definecolor{dkgreen}{rgb}{0,0.6,0}
\definecolor{gray}{rgb}{0.5,0.5,0.5}
\definecolor{mauve}{rgb}{0.58,0,0.82}

\lstset{frame=tb,
  language=Java,
  aboveskip=3mm,
  belowskip=3mm,
  showstringspaces=false,
  columns=flexible,
  basicstyle={\small\ttfamily},
  numbers=none,
  numberstyle=\tiny\color{gray},
  keywordstyle=\color{blue},
  commentstyle=\color{dkgreen},
  stringstyle=\color{mauve},
  breaklines=true,
  breakatwhitespace=true,
  tabsize=3
}

\graphicspath{ {images/} }
\DeclareGraphicsExtensions{.pdf,.jpeg,.png,.jpg}

% Change enumerate environments you use letters
\renewcommand{\theenumi}{\alph{enumi}}

% Set title, author name and date
\title{Hashpipe Report}
\author{Simon Høiberg}
\date{\today}

\begin{document}

\maketitle

\section*{Abstract}
\begin{addmargin}[1em]{2em}
HashPipe.java is a symbol table implemented with a Hashpipe data structure.\\
HashPipe supports search and insertion in time proportional to $O(Log N)$ on\\ average.\\
\hspace{5mm}\\
HashPipe contains the following API:\\
\begin{verbatim}
public HashPipe()
public int size()
public void put(String key, Integer val)
public Integer get(String key)
public String floor(String key)
 \end{verbatim}
\end{addmargin}

\section*{Class design}
\begin{addmargin}[1em]{2em}
HashPipe uses a pointer-based data structure where each key-value pair is represented by a pipe.\\
\hspace{5mm}\\
Every pipe has a given height thus contains a pointer to the neighbour pipe(s).\\
On instantiation, a root-pipe is created which solely represents pointers and every key-value pair that is put will be represented as new pipes.\\
\hspace{5mm}\\
The height of the root-pipe will be fixed at 32, and every new pipe will have it's height calculated deterministically.\\
\newpage
Every pipe is based in the following structure
\begin{lstlisting}
class Pipe {
		String key;
		int value;
		int height;
		Pipe[] nextPipes;

		// Root pipe will be created with fixed height of 32
		public Pipe()

		// New pipe will be created given it's key-value pair
		public Pipe(String key, int value)

		public String getKey()

		public int getValue()

		public int getHeight()

		public void setNextPipe(Pipe pipe, int index)

		public Pipe getNextPipe(int index)
	}
\end{lstlisting}
The field \textbf{Pipe[] nextPipes} will represent the height of the pipe with \textit{height} amount of pointers to the neighbour pipe(s).\\
\hspace{5mm}\\
The \textbf{put()} method works by following the root-pipe's pointers searching from top down and recursivly rearranging the pointers such that the key-value pipes will be ordered by key ascending fra left to right.\\
\hspace{5mm}\\
The \textbf{get()} method works by recursivly following the root-pipe's pointers searching from top down until a key-match is found or the bottom of the pipe is reached.\\
The value of the pipe will be returned if key-match is found, null is returned otherwise.
\end{addmargin}
\newpage

\section*{Performence tests}
Following performence tests is done using CodeJudge\\
\hspace{5mm}\\

\textbf{TestsSmall}\\
\hspace{5mm}\\
\begin{adjustbox}{width=1\textwidth}
\tiny
\begin{tabular}{cccc}
\hline
\textit{Test} & \textit{Status} & \textit{CPU TIME} & \textit{WALL TIME} \\
\hline
Test01 & Succeeded & 0.32 s & 0.42 s \\
Test02 & Succeeded & 0.17 s & 0.21 s \\
Test03 & Succeeded & 0.13 s & 0.18 s \\
\hline
\end{tabular}
\end{adjustbox}

\hspace{5mm}\\
\hspace{5mm}\\

\textbf{TestsBest}\\
\hspace{5mm}\\
\begin{adjustbox}{width=1\textwidth}
\tiny
\begin{tabular}{cccc}
\hline
\textit{Test} & \textit{Status} & \textit{CPU TIME} & \textit{WALL TIME} \\
\hline
Test01 & Succeeded & 0.88 s & 0.93 s \\
Test02 & Runtime error & 2.78s s & 2.97 s \\
\hline
\end{tabular}
\end{adjustbox}

\hspace{5mm}\\
\hspace{5mm}\\

\textbf{TestsBest}\\
\hspace{5mm}\\
\begin{adjustbox}{width=1\textwidth}
\tiny
\begin{tabular}{cccc}
\hline
\textit{Test} & \textit{Status} & \textit{CPU TIME} & \textit{WALL TIME} \\
\hline
Test01 & Succeeded & 0.54 s & 0.59 s \\
Test02 & Succeeded & 1.12s s & 1.17 s \\
\hline
\end{tabular}
\end{adjustbox}

\end{document}


% Does this add anything new?  If so, be more specific about what this section contributes.

\section{Full derivation}
\subsection{Optimizing objective}
\label{appendix.ncall}

We want to choose $S_k^*$ that maximizes the objective:
\begin{align*}
  \ExpNCall{n}(S_k,\vec{q})
  = \mathbb{E}[R_k\geq n|s_1,\dots,s_k,\vec{q}]
\end{align*}

\noindent
By taking a greedy approach, we select $s_k^*$ given $S_{k-1}^*$:
\begin{align}
  s_k^* & = \argmax_{s_k} \mathbb{E}[R_k\geq n|S_{k-1}^*,s_k,\vec{q}] \nonumber\\
%
  & = \argmax_{s_k} P(R_k\geq n|S_{k-1}^*,s_k,\vec{q}) \label{note1}\\
%
  & = \argmax_{s_k} \!\sum_{T_k} \Bigl( P(t|\vec{q}) \,P(t_k|s_k) \Bigl( \prod_{i=1}^{k-1} P(t_i|s_i^*) \Bigr) \cdot P(R_k\geq n|T_k,S_{k-1}^*,s_k,\vec{q}) \Bigr) \label{note2}\\
%
  & = \argmax_{s_k} \!\sum_{T_k} P(t|\vec{q}) \,P(t_k|s_k) \Bigl( \prod_{i=1}^{k-1} P(t_i|s_i^*) \Bigr) \cdot \Bigl( \mbox{$\underbrace{P(r_k\!\geq\!0|R_{k-\!1}\!\geq\!n,t_k,t)}_{1}$} P(\!R_{k-\!1}\!\geq\!n|\TlessK) \nonumber \\[-1.5mm]
  & \hspace{55mm} + P(r_k=1|R_{k-1}\!=\!n\!-\!1,t_k,t) P(\!R_{k-\!1}\!=\!n\!-\!1|\TlessK) \Big) \label{note3}\\
%
  & = \argmax_{s_k} \Bigg( \sum_{\TlessK} \bigg[ \mbox{$\underbrace{ \!\sum_{t_k} \!\!P(t_k|s_k) }_{1}$} \bigg] P(t|\vec{q}) \Bigl( \prod_{i=1}^{k-1} P(t_i|s_i^*) \Bigr) P(R_{\!k-\!1}\geq\!n|\TlessK) + \nonumber \\[-1.5mm]
  & \hspace{20mm} \sum_{\TlessK} \bigg[ \sum_{t_k} P(t_k|s_k) P(r_k=1|t_k,t) \bigg] P(t|\vec{q}) \Bigl( \prod_{i=1}^{k-1} P(t_i|s_i^*) \Bigr) P(\!R_{k-\!1}\!=\!n\!-\!1|\TlessK) \Bigg) \nonumber\\
%
  & = \argmax_{s_k} \sum_{t} P(t|\vec{q}) P(t_k\!=\!t|s_k) \bigg[ \sum_{t_1, \dots, t_{k-1}}  P(R_{k-\!1}\!=\!n\!-\!1|\TlessK) \prod_{i=1}^{k-1} P(t_i|s_i^*) \bigg] \label{note4}\\
%
  & = \argmax_{s_k} \sum_{t} \!P(t|\vec{q}) P(t_k\!=\!t|s_k) P(R_{k-\!1}\!=\!n\!-\!1|S_{k-1}^*, t) \label{eq.ncall-repeat}
\end{align}

\noindent
Note: \\
~\eqref{note1} Since $( R_k \geq n )$ can only be zero or one (binary), the expected value is the probability of $( R_k \geq n )$. \\
~\eqref{note2} Marginalize out $T_k\!=\!\{t,t_1,\dots,t_k\}$. \\
~\eqref{note3} Split $( R_k \geq n )$ into two disjoint events $(r_k \! \geq \! 0, R_{k\!-\!1}\!\geq \!n)$, $(r_k\!=\!1, R_{k\!-\!1}\!=\!n\!-\!1)$, based on $R_{k-1}$. \\
~\eqref{note4} Drop the first line as it does not involve $s_k$ and has no influence in determining $s_k^*$. Note that $\sum_{t_k} \!\! P(t_k|s_k) P(r_k\!\!=\!\!1|t_k,t) = \sum_{t_k} \!\! P(t_k|s_k) \I[t_k\!=\!t] \! = \! P(t_k\!\!=\!\!t|s_k)$, where $t$ is implicitly conditioned and is not explicitly shown here. \\
~\eqref{eq.ncall-repeat} This objective is recursively defined. \\

By similar reasoning, the probability needed in~\eqref{eq.ncall-repeat} is recursively defined as
\begin{align*}
P(R_k=n|S_k,t)=
\begin{cases}
n \geq 1, k > 1:  &  \bigl( 1\!-\!P(t_k\!=\!t|s_k) \bigr) P(R_{k-1}\!=\!n|S_{k-1},t) \nonumber \\
  & \hspace{5mm} + P(t_k\!=\!t|s_k) P(R_{k-\!1}\!=\!n\!-\!1|S_{k-\!1},t) \\
%%
n = 0, k > 1:   & \bigl( 1\!-\!P(t_k\!=\!t|s_k) \bigr) P(R_{k-\!1}\!=\!0|S_{k-\!1},t) \\
%%
n = 1, k = 1:   & P(t_1\!=\!t|s_1) \\
n = 0, k = 1:   & 1 - P(t_1\!=\!t|s_1) \\
n > k:			& 0
\end{cases}
%       \bigl 1-P(t_1\!=\!t|s_1) \bigr) = \bigl 1-P(t_1\!=\!t|s_1) \bigr) \\
%  & \hspace{2mm} P(R_1\!=\!1|S_1,t) = P(t_1\!=\!t|s_1)
\end{align*}

For expected $n$-call@$k$ where $n \! \leq \! k/2$, by unrolling its recursive definition in \eqref{eq.ncall-repeat}, the explicit objective is
\begin{align}
  & s_k^* = \argmax_{s_k} \sum_t \Biggl( P(t|\vec{q}) \, P(t_k=t|s_k) \sum_{j_1, \dots, j_{n-\!1}} \hspace{-14mm} \prod_{\hspace{14.5mm} l \in \{j_1, \dots, j_{n-\!1}\}} \hspace{-14mm} P(t_l\!=\!t|s_l^*) \hspace{-13mm} \prod_{\substack{i=1 \\ \hspace{14mm} i \notin \{j_1, \dots, j_{n-\!1}\}}}^{k-1} \hspace{-13mm} \!\bigl( 1 - P(t_i\!=\!t|s_i^*) \bigr) \!\Biggr) \label{eq.ncall.alt-repeat}
\end{align}
where $j_1, \dots, j_{n-1} \in \{1,\ldots,k-1\}$ satisfy
that $j_i < j_{i+1}$ (\emph{i.e.},
an ordered permutation of $n-1$ result set indices). \\

Similarly, for expected $n$-call@$k$ where $n \! > \! k/2$, the explicit objective is
\begin{align}
  & s_k^* = \argmax_{s_k} \sum_t \Biggl( P(t|\vec{q}) \, P(t_k=t|s_k) \sum_{j_n, \dots, j_{k-\!1}} \hspace{-14mm} \prod_{\hspace{14.5mm} l \in \{j_n, \dots, j_{k-\!1}\}} \hspace{-14mm} \bigl(1 - P(t_l\!=\!t|s_l^*) \bigr) \hspace{-13mm} \prod_{\substack{i=1 \\ \hspace{14mm} i \notin \{j_n, \dots, j_{k-\!1}\}}}^{k-1} \hspace{-13mm} P(t_i\!=\!t|s_i^*) \!\Biggr) \label{eq.ncall.alt2}
\end{align}
where $j_n, \dots, j_{k-1} \in \{1,\ldots,k-1\}$ satisfy
that $j_i < j_{i+1}$ (i.e.,
an ordered permutation of $k-n$ result set indices).

% ===============================================================================
\subsection{Relation to MMR: expected n-call@k when $n>k/2$}
\label{appendix.2call}

Assuming that $\forall i \; P(t_i|s_i) \in \{0,1\}$ and $P(t|\vec{q}) \in \{0,1\}$. It is possible to write
\begin{align*}
  \hspace{-13mm} \prod_{\hspace{14.5mm} l \in \{j_n, \dots, j_{k-\!1}\}} \hspace{-14mm} \bigl( 1 - \!P(t_l\!=\!t|s_l^*) \bigr)
  = 1 - \Biggl( 1 - \hspace{-14mm} \prod_{\hspace{14.5mm} l \in \{j_n, \dots, j_{k-\!1}\}} \hspace{-13mm} \bigl( 1 - P(t_l\!=\!t|s_l^*) \bigr) \Biggr)
  = 1 - \Bigl( \max_{l \in \{j_n, \dots, j_{k-\!1}\}} P(t_l\!=\!t|s_l^*) \Bigr)
\end{align*}

This allows us to rewrite~\eqref{eq.ncall.alt2}
\begin{align}
 & s_k^* = \, \argmax_{s_k} \sum_t \Biggl( P(t|\vec{q}) P(t_k\!=\!t|s_k)  \sum_{\hspace{-1mm} j_n, \dots, j_{k-\!1}} \hspace{-13.5mm} \prod_{\substack{i=1 \\ \hspace{14mm} i \notin \{j_n, \dots, j_{k-\!1}\}}}^{k-1} \hspace{-13mm} P(t_i\!=\!t|s_i^*) \nonumber \\[-1.5mm]
 & \hspace{25mm} - \!P(t|\vec{q}) P(t_k\!=\!t|s_k) \sum_{j_n, \dots, j_{k-\!1}} \hspace{-14mm} \prod_{\substack{i=1 \\ \hspace{14mm} i \notin \{j_n, \dots, j_{k-\!1}\}}}^{k-1} \hspace{-13mm} P(t_i\!=\!t|s_i^*) \max_{l \in \{j_n, \dots, j_{k-\!1}\}} P(t_l\!=\!t|s_l^*) \Biggr) \label{eq.ncall.alt3}
\end{align}

Assuming $m$ relevant documents are already selected in the $k-1$ collection, then the top term (specifically $\prod_i$) is non-zero $\binom{m}{n-1}$ times.  For the
bottom term, it takes $n-1$ relevant documents to satisfy its
$\prod_i$, and one additional relevant document to satisfy the
$\max_l$ making it non-zero $\binom{m}{n}$ times.  Factoring out the
$\max$ element from the bottom and pushing the $\sum_t$ inwards (all legal
due to the $\{0,1\}$ subtopic probability assumption),~\eqref{eq.ncall.alt3} becomes
\begin{align}
 s_k^* & = \argmax_{s_k} \left[ \sum_t P(t|\vec{q}) P(t_k\!=\!t|s_k) \binom{m}{n-1} \right]
 - \left[ \sum_t P(t|\vec{q}) P(t_k\!=\!t|s_k) \binom{m}{n} \underbrace{\max_{s_i \in S_{k-1}^*} P(t_i\!=\!t|s_i)}_{1} \right] \nonumber\\
 & = \argmax_{s_k} \binom{m}{n-1} \underbrace{\sum_t P(t|\vec{q}) P(t_k\!=\!t|s_k)}_{\textrm{relevance}: \; \Sim_1(s_k,\vec{q})}
 - \binom{m}{n} \max_{s_i \in S_{k-1}^*} \underbrace{\sum_t P(t_i\!=\!t|s_i) \!P(t|\vec{q}) P(t_k\!=\!t|s_k)}_{\textrm{diversity}: \; \Sim_2(s_k,s_i,\vec{q})} \label{note9}\\
 & = \argmax_{s_k} \!\! \frac{n}{m\!+\!1} \Sim_1(s_k,\vec{q}) - \frac{m\!-\!n\!+\!1}{m+1} \max_{s_i \in S_{k-1}^*} \! \Sim_2(s_k,s_i,\vec{q}) \label{note10}
\end{align}

\noindent
Note: \\
~\eqref{note9} We can rearrange "$\sum_t P(t|\vec{q}) \max_{s_i} \cdots$" as "$\max_{s_i} \sum_t P(t|\vec{q}) \cdots$" since the $\sum_t P(t|\vec{q})$ 'selects' the only $t$ for which $P(t|\vec{q}) = 1$. \\
~\eqref{note10} Normalize by dividing the equation by $\binom{m}{n-1} + \binom{m}{n} = \binom{m+1}{n}$ (Pascal's rule).
The result is the same as the case where $n \leq k/2$. \\

The reason that we do not remove the max term in~\eqref{note9} is that this allows us to compare the objective with MMR directly. Also, leaving the max term suggests an approximate form for the case where the subtopic probabilities are non-deterministic (not strictly 0 or 1), and approaches~\eqref{note9} as the probabilities become more deterministic. \\

In practice, under the greedy approach of the expected n-call@k in selecting $S_k^*$, we expect that there are already $n$ relevant documents chosen in the set $S_{k-1}^* = \{s_1^*, \dots, s_{k-1}^*\}$ (where $n << k$). In expectation, $m = n$ and hence the optimizing objective can be thought to be
\begin{align}
 s_k^* = \argmax_{s_k} \!\! \frac{n}{n\!+\!1} \Sim_1(s_k,\vec{q}) - \frac{1}{n+1} \max_{s_i \in S_{k-1}^*} \! \Sim_2(s_k,s_i,\vec{q}) \label{eq.ncall.final}
\end{align}

From~\eqref{eq.ncall.final}, it is simple to see that the diversification level decreases with $n$.

% ===============================================================================


\documentclass[main.tex]{subfiles}
\begin{document}

\subsection{Conditions for stardom and brown dwarfs}

% \marginpar{Friday\\ 2019-12-06, \\ compiled \\ \today}
% \section*{Fri Dec 06 2019}

% Today we will discuss another possible \emph{caveat} for star formation: the case where the star collapses but does not ignite.

% After recombination the baryons' temperature decays more rapidly than the radiation's, so we get a temperature low enough to satisfy the instability criterion.

% The temperature stays low during the collapse: the thermal energy is used in order to break the bonds in \ce{H2} and ionize the hydrogen.

% Then we have a gas which is opaque to radiation: there is scattering, which means we lose energy through radiation very slowly.
% Then the Virial theorem is very close to being true.

% At the end of the process, even the mass does not matter anymore: we got \SI{2.6}{eV} as the temperature regardless of the mass. This is equivalent to around \SI{30e3}{K}.
% We must compare this to the ignition temperature: that is in the order of \SI{}{keV} (\SI{15e6}{K} is equivalent to around \SI{1.3}{keV}).

% After free-fall the radius is on the order of \SI{e10}{m} for a solar mass star, while the Sun's radius is smaller by two orders of magnitude.

At this point, the proto-star reaching a high enough temperature to fuse hydrogen is not a given: it may not happen.

In order to discuss the \emph{conditions for stardom} we need to account (albeit in an approximate way, as usual) for the fermionic nature of protons and electrons, which will give us a maximum density due to the Pauli exclusion principle: the particles will form a degenerate Fermi gas.
Depending on the mass of the star, this maximum density may be reached before the ignition temperature: when this is the case, a \textbf{brown dwarf} is formed.
% The way we will treat this today will be quite rough.

We estimate the minumum space a fermion can occupy with its De Broglie wavelength:
%
\begin{align}
  \lambda = \frac{h}{p} = \frac{2 \pi \hbar}{p}
\,,
\end{align}
%
where \(p\) is the momentum of the particle.
Since the temperature is still less than a \SI{}{keV}, both electrons and protons are nonrelativistic, so we can approximate \(E_{k} = p^2 /2m\), which will typically be of the order \(E_K \sim k_B T\).

% Objects which will not satisfy the conditions we talk about today become brown dwarves.

% The kinetic energy is of the order \(k_B T\), therefore
Then, the momentum and wavelength will be:
%
\begin{align}
  p \sim \sqrt{2 m k_B T} \implies \lambda \sim \frac{2 \pi \hbar}{\sqrt{m k_B T}}
\,.
\end{align}

We can see that \(\lambda \sim 1/\sqrt{m}\): this means that the wavelength is smaller (by a factor 40) for the protons than it is for the electrons, and they appear in equal numbers; therefore the first bound to be reached will be that of the degenerate electron gas, for this reason we will neglect protons now.

% and the critical density is defined by
The critical density will be reached when we have an electron for each \(\lambda^3\); however in order to ensure local charge neutrality we must have protons distributed in the same way, and their mass contribution to the density will be the largest:

\todo[inline]{I'd actually say, then, that we should write \(\rho _c = m_p / \lambda^3\)! }
%
\begin{align}
  \rho_c = \frac{\overline{m}}{\lambda^3}
  \sim \overline{m} \frac{(m_e k_B T)^{3/2}}{(2 \pi \hbar)^{3}}
\,.
\end{align}
% %
% where from the formula we found mk
% %
% \begin{align}
%   \lambda = \frac{2 \pi \hbar}{\sqrt{2 m_e k_B T}}
% \,,
% \end{align}
%
% which gives approximately
% %
% \begin{align}
%   \rho _c \sim \overline{m} \frac{(m_e k_B T)^{3/2}}{(2 \pi \hbar)^{3}}
% \,,
% \end{align}
%
% and from the virial theorem \(2 E_k + E _{\text{gr}}=0\), with
% %
% \begin{align}
%   E_k = \frac{3}{2} N k_B T = \frac{3}{2} \frac{M}{\overline{m}} k_B T
% \,,
% \end{align}
% %
% while
% %
% \begin{align}
%   E _{\text{gr}} = - \frac{G M^2}{R}
% \,,
% \end{align}
% %
% which means

As we have seen earlier, since the virial theorem applies the temperature of the proto-star is tied to its gravitational binding energy by
%
\begin{align}
  3 N k_B T = \frac{GM^2}{R} \implies k_B T = \frac{GM \overline{m}}{3  R}
\,.
\end{align}
% %
% and we can rewrite this as
% %
% \begin{align}
%   \frac{3 k_B T}{\overline{m}} = \frac{GM}{R}
% \,,
% \end{align}
% %

The mass can be expressed in terms of the average density as
\(M = \frac{4}{3} \pi \overline{\rho} R^3 \), so
%
\begin{align}
  \frac{1}{R} = \qty(\frac{4 \pi }{3} \frac{\overline{\rho}}{M})^{1/3}
\,,
\end{align}
%
which gives us the result
%
\begin{align}
  k_B T = \frac{GM \overline{m}}{3} \qty(\frac{4 \pi }{3} \frac{\overline{\rho}}{M})^{1/3}
\,.
\end{align}

If we substitute the critical density \(\rho _c\) for \(\overline{\rho}\) we will get the maximum possible temperature allowed at a given mass \(M\): after some manipulation we get (up to a small constant, which we neglect since the calculation is rough anyway):
%
\begin{align}
  k_B T &= \frac{GM \overline{m}}{3} \qty(\frac{4 \pi }{3 M})^{1/3} \frac{\overline{m}^{1/3}}{(2 \pi \hbar)} \qty(m_e k_B T)^{1/2} \\
  (k_B T)^2 &= \frac{G^2M^2 \overline{m}^2}{9}
  \qty(\frac{4 \pi }{3 M})^{2/3} \frac{\overline{m}^{2/3}}{(2 \pi \hbar)^2} m_e k_B T  \\
  k_B T &\approx \frac{G^2 \overline{m}^{8/3} M^{4/3} m_e}{(2 \pi \hbar)^2}
\,.
\end{align}

Inserting the ignition temperature of around \SI{1}{keV} we get \(M _{\text{min}} \approx M_{\odot}\), which is almost the right order of magnitude: more accurate models agree with the observational result of \(M _{\text{min}} \approx \num{.08} M_{\odot}\).
We have treated electron-degenerate matter in a very rough way, we will improve our estimate in a later section with a more accurate quantum-mechanical description.

\section{The Sun and other stars}

Let us start off with a list of the physical characteristics of the Sun: its mass is \(M_{\odot} \approx \SI{1.99e30}{kg}\), its radius is \(R_{\odot} \approx \SI{6.96e8}{m}\), its bolometric luminosity\footnote{This means: the total luminosity, integrated across all the electromagnetic spectrum.} is \(L_{\odot} = \SI{3.86e26}{W}\).

Its age is around \(t_{\odot} \approx \SI{4.55e9}{yr}\), which is comparable to the age of the Universe.

At its core, the density is \(\rho _c \approx \SI{1.48e5}{kg m^{-3}}\), the temperature is \(T_c = \SI{1.56e7}{K} \approx \SI{1.3}{keV}\), and the pressure is around \(P_c = \SI{2.29e16}{Pa}\).

The radiation emitted by the Sun approximately follows a blackbody curve, whose characteristic temperature is called the \emph{effective temperature}: it is around \(T_E \approx \SI{5780}{K} \approx \SI{.5}{eV}\).
% \todo[inline]{Definition?}

% What is the corresponding free fall time? It is much shorter than the age of the Sun: the Sun is not in free fall.
% \todo[inline]{What is the number?}

The power emitted by the Sun is quite small as a fraction of its total energy, so we can apply the virial theorem: one of its formulations we found is
%
\begin{align}
  \expval{P} = -\frac{1}{3} \frac{E _{\text{gr}}}{V}
\,,
\end{align}
%
where \(E _{\text{gr}} \approx - G M^2/R\) while \(V = 4 \pi R^3/3\): plugging the Sun's numbers we get
%
\begin{align}
  \expval{P}
  = \frac{G M_{\odot}^2}{4 \pi R_{\odot}^{4}}
  \approx \SI{e14}{Pa}
\,,
\end{align}
%
100 times less than the central pressure.
Similarly, the average density can be computed as \(\expval{\rho } = M _{\odot} / V \approx \SI{1.4e3}{kg/m^3}\), just slightly more than the density of water! This is also roughly 100 times less than the central value.

% The density of the Sun is actually very similar to the density of water.

% Was it correct to use nonrelativistic equations? (???)

By the ideal gas law (which does not precisely apply, but as we saw the Sun has a rather low density overall so it is a reasonable approximation) we can find the mean internal temperature of the Sun, \(T_I\), as:
%
\begin{align}
  \expval{P} = \frac{\expval{\rho}}{\overline{m}} k_B T_I
\,,
\end{align}
%
% where \(T_I\) is the mean internal temperature of the Sun.
where \(\overline{m}\), the average particle mass, is \(\overline{m} \approx 0.61 m_H\) instead of \(\num{.5} m_H\) when considering the proper composition of the Sun, which has a noticeable fraction of helium and heavier elements.

We get
%
\begin{align}
  k_B T_I
  =  \frac{G M_{\odot}^2}{4 \pi R_{\odot}^{4}}
   \qty( \frac{M_{\odot}}{4 \pi R_{\odot}^3 / 3})^{-1} \overline{m}
  = \frac{G M_{\odot} \overline{m}}{3 R_{\odot} } \approx \SI{.5}{keV} \approx \SI{5e6}{K}
\,.
\end{align}

Again, we see the relation \(x _{\text{central}} \ll x _{\text{mean}} \ll x _{\text{surface}}\), which holds for \(x = \) density, pressure, temperature.

% We have evidence that the Sun is a blackbody, we can write
The measured bolometric luminosity of the Sun is consistent with
%
\begin{align}
  L_{\odot} = 4 \pi R_{\odot}^2 \sigma T^{4}_{E}
\,,
\end{align}
%
where \(\sigma \) is Stefan's constant: \(\sigma \approx \SI{5.67e-8}{W m^{-2} K^{-4}}\).

Why does this hold with the comparatively low temperature \(T_E\) and not with the mean internal temperature \(T_I\)?
We will now see that this is because the interior of the Sun is optically thick (opaque), so any photon from the interior cannot simply be emitted, it will undergo many scatterings before doing so.

% In principle we could define another quantity:
% %
% \begin{align}
%   L_{\odot}^{\prime } = 4 \pi R_{\odot}^2 \sigma T_I^4
% \,,
% \end{align}
% %
% which does not fit the data. Why is this?

\subsection{Radiative diffusion}

% We must consider a photon which comes from the interior of the Sun and goes towards the outside: it will follow a random walk scattering many times.

% However, depending on the density of electrons in the outer regions (electron scattering dominates in the outside), the last scattering is in the outermost regions of the star.

% We need to deal with the Fourier equation.
% First of all, we need to write the Langevin equation: this is connected to the work by Einstein on Browinan motion.

% These are processes in which there is a ``random'' force (due to the fact that our description of the microscopic state is probabilistic), and possibly deterministic forces.

% \todo[inline]{What is the stuff about viscosity?}

The motion of the photon is Brownian, and the total displacement \(\vec{D}\) from production to emission will be written in terms of \(N\) short straight tracts,
%
\begin{align}
\vec{D} = \sum _{i=1}^{N} \vec{\ell}_i
\,.
\end{align}

The process is inherently stochastic, and we will need to describe it as such.
We need two equations in order to describe it: the Langevin and Fokker-Planck equations.

The \textbf{Langevin} equation gives us the derivative of the position of the particle in terms of a stochastic force \(\eta\):
%
\begin{align}
  \dot{\vec{D}}(t) = \vec{\eta} (t)
\,.
\end{align}

The requirements on \(\eta \) are that it should have zero mean: \(\expval{\vec{\eta}}(t) = 0\) and that it should satisfy \(\expval{\eta _i (t) \eta_j (t')} = 2 D \delta_{ij} \delta (t - t')\).
This means that it is spatially and temporally uncorrelated, making the process a Markovian one: it has ``no memory''.
The parameter \(D\) is called the \emph{diffusion constant}, its units are \SI{}{m^2 /s} (and it is not related to the displacement \(\vec{D}\)).s

% there is complete uncorrelation.
% This is the Markov property: the process has no memory.

Nontrivially (we will not discuss the details of the derivation) this gives us the \textbf{Fokker-Planck} formula:
%
\begin{align}
  \pdv{P}{t} = D \nabla^2 P
\,,
\end{align}
%
where \(P\), a function of position and time, quantifies the probability density of finding a photon there.

Mathematically speaking this is a \emph{parabolic differential equation}, which concretely means that we need to give it both initial conditions and boundary conditions.

% \todo[inline]{What is \(P\)?}

% In the There are three kinds of boundary conditions we can set:
% \begin{enumerate}
%   \item nothing: free boundary, allowing the solution can diverge;
%   \item a reflective boundary: particles ``bounce back'', in order to deal with this we use the images method, as in electromagnetism;
%   \item an absorbing boundary: particles disappear if they reach the boundary.
% \end{enumerate}
The kind of boundary condition we want for the study of the Sun is a so-called \emph{absorbing boundary}: physically, as a photon reaches the surface it is emitted, which from the inside looks like if the boundary ``absorbed it''.

% This is equivalent to the Fourier transport equation.

The solution to the Fokker-Planck equation, with an impulsive initial condition like \(P(x, t=0) = \delta^{(3)} (x)\) is a Gaussian with variance \(\expval{x^2} =  2 D t\) and centered around zero:
%
\begin{align}
P(x, t) = \frac{1}{(4 \pi D t)^{3/2}} \exp(- \frac{x^2}{ 4 D t})
\,.
\end{align}

This holds for \(0 < \abs{\vec{x}} < R_{\odot}\), while for \(\abs{x} > R_{\odot}\) the particles have escaped.

Integrating the Gaussian within the stellar boundary at a time \(t\) yields the probability that any single photon emitted at the center of the Sun is still inside it after a time \(t\).
Roughly, this be the case with  \(\sigma = \sqrt{2 Dt } \lesssim R_{\odot} \).

% If \(\sigma = \sqrt{\expval{x^2}}\) becomes greater than the boundary then most of the particles have escaped.

Let us now consider the problem geometrically. The mean square value of the displacement will be given by
%
\begin{align}
  \expval{\vec{D}^2} = \sum _{i} \expval{\vec{\ell}_{i}^2}
  + 2\sum _{i<j} \expval{\vec{\ell}_i \cdot \vec{\ell}_j}
\,,
\end{align}
%
but if we have isotropy then the scalar products have mean zero, since they are averages of two lengths times a cosine.
% This might be unphysical since the steps are larger at the boundary than at the center\dots

Then we find that, in order for the photon to have reached the boundary of the star on average it will need to have undergone \(N\) scatterings: if we set \(\expval{\vec{D}^2} = R_{\odot}^2\) we get
%
\begin{align}
  \expval{\vec{D}^2} = N \ell^2 = R _{\odot}^2
\,,
\end{align}
%
so \(N = R _{\odot}^2 / \ell^2\), where \(\ell\) is the typical path travelled between scatterings.

The time it takes for a photon to cover a distance \(\ell\) is \(t= \ell/c\).
Then, the total time taken in the random walk is given by \(t_{RW} = Nt = R^2 _{\odot} \ell / (\ell^2 c)\), which means
%
\begin{align}
  t_{RW} = \frac{R _{\odot}^2}{c \ell}
\,,
\end{align}
%
while in direct flight the photon would only have taken \(t_0 = R _{\odot}/ c\): their ratio is
%
\begin{align}
  \frac{t_{RW}}{t_0 } = \frac{R _{\odot}}{ \ell}
\,.
\end{align}

\todo[inline]{The argument which follows is still unconvincing to me: the photons take \(\sim \SI{50}{kyr}\) to come out of the Sun, so this process will have stabilized in the Sun's \SI{5}{Gyr} lifetime!

Estimating the mean free path as \(\ell \sim 1/ (n \sigma _T)\) could work, it yields \(\sim \SI{1}{cm}\) with the mean density and \(\sim \SI{0.1}{mm}\) with the central density, so perhaps since in the low-\(\ell\) regions the photons stay for a longer time this can average out to \SI{1}{mm} when doing the calculation properly.}

If \(L' _{\odot}\) is the luminosity for the Sun calculated using the average internal temperature \(T_I\) instead of the effective temperature \(T_E\) we get
%
\begin{align}
  L _{\odot} = L _{\odot}^{\prime } \frac{\ell}{R _{\odot}}
\,,
\end{align}
%
which means
%
\begin{align}
  T_E = \qty(\frac{\ell}{R _{\odot}})^{1/4} T_I
\,,
\end{align}
%
so we can calculate \(\ell\) by knowing the other three parameters:
we get that the mean free path, averaged over the star, is \(\ell \approx \SI{1}{mm}\).
% This is actually an average of the mean free paths.

The total solar luminosity is then:
%
\begin{align}
  L_{\odot} = L'_{\odot} \frac{\ell}{R} = 4 \pi R _{\odot}^2 \sigma T_I^{4} \frac{\ell}{R}
\,,
\end{align}
%
and we know that \(k_B T_I = \frac{GM \overline{m}}{3 R_{\odot}}\): inserting this we find
%
\begin{align}
  L = 4 \pi R^2 \sigma  \qty(\frac{GM \overline{m}}{3 R k_B})^{4} \frac{\ell}{R}
  = \frac{(4 \pi )^2}{3^{5}} \frac{\sigma }{k_B^4} G^{4} \overline{m}^{4} \overline{\rho} \ell M^3
\,.
\end{align}

The most important part of this result, which is observationally verifiable, is \(L \propto M^{3}\).
% What is the typical lifespan of a star?
This allows us to estimate the lifespan of a star: the fraction of mass available to be turned into energy through fusion is a constant multiple of \(M\) (slighly less than \SI{1}{\percent}): therefore, we have \(\tau \propto M/L \propto M^{-2}\).
More massive stars die earlier.

The relation \(L \propto M^{\alpha } \) for \(\alpha = 3\) is quite close to the data globally, in specific regions we can have better estimates for the powerlaw index: the value \(\alpha = 3.5\) is more commonly used for Main Sequence stars (which we will discuss later).
% This matches the data pretty well for .

The lifetime always scales like \(\tau \propto M^{1 -\alpha }\), and we always have \(\alpha >1\), so the fact that more massive stars die earlier always holds.

We then expect that in each galaxy there can have been several ``generations'' of heavy stars, while the very lightest are still in their first generation. This can be observationally confirmed by looking at the abundances of elements, and comparing them with the expected production inside heavy stars.

\subsection{Thermonuclear fusion}

The reaction chain which produces Helium in stellar cores is the following:
%
\begin{subequations}
\begin{align}
  \ce{p + p} &\rightarrow \ce{d + e+ +} \nu_e  \\
  \ce{p + d} &\rightarrow \ce{^3He} + \gamma  \\
  \ce{^3He + ^3He} &\rightarrow \ce{^4He + p + p}
\,,
\end{align}
\end{subequations}
%
which involves the weak interaction (for the first process, whose lifetime is \(\tau \sim \SI{5e9}{yr}\)), EM interaction (for the second process: \(\tau \sim \SI{1}{s}\)) and strong interaction (for the third process: \(\tau \sim  \SI{3e5}{yr}\)).

The net balance is 4 protons in, one \ce{^{4}He} and some photons and neutrinos out, accounting for the \(\approx \SI{0.66}{\percent}\) mass difference.

We can then see that the weak-interaction part of the chain is the bottleneck.

The chain we had during primordial nucleosynthesis, on the other hand, did not need any weak-interaction processes:
%
\begin{subequations}
\begin{align}
  \ce{n + p} &\rightarrow \ce{d} + \gamma   \\
  \ce{d + d} &\rightarrow \ce{^3He + n}  \\
  \ce{^3He + d}  &\rightarrow \ce{^4He + p}
\,.
\end{align}
\end{subequations}

The issue is that all the free neutrons quickly decayed after primordial nucleosynthesis, and free deuterium is scarce: secondary production chains can then prevail.
% However, later there are no more free neutrons: this means that even if it is slower the first process is the only one which can happen.

% The net balance is 4 protons in, 1 \ce{^4 He} out.

\end{document}


\section{LLVM Reference}
\subsection*{Type}
i\{1-32\}: int; float, double, fp128: float; <type>*: pointers
\subsection*{Function}
define <type> @<f\_name>(<type> \%<name>, ...) \{\\
...instructions...\\
\}\\
call <type> @<f\_name>(<type0> <arg1>, ...)
\subsection*{Labels}
<label>:\\
...instructions...\\
br label \%<label>\\
br i1 <cond>, label <true>, label <false>
\subsection*{Comparisons}
\{i,f\}cmp <policy> <type> <arg1>, <arg2>; i-policies: eq, neq, (u,s)gt, (u,s)lt, (u,s)le, (u,s)ge [u=unsigned, s=signed]; f-policies: oeq,ogt,ege,olt,ole,one,ord,ueq,ugt etc[o=ordered,u=unordered]
\subsection*{Phi}
phi <type> [<val0>, <label0>], ...: based on predecessor block
\subsection*{Arithmetic}
<op> <type> <arg1>, <arg2>: \{f\}add, \{f\}sub, \{f\}mul, \{u,s,f\}div, and, or, xor;\{f,s,u\}rem, ashl, lshr, ashr
\subsection*{Load/Store}
alloca <type>: allocate space on the stack, ret=ptr; store <val\_type> <val>, <ptr\_type> <ptr>, ret=void; load <val\_type>,<ptr\_type> <ptr>, ret=val
\subsection*{Conversion/Cast}
\{trunc, zext, sext, fptrunc, fpext\} <in\_type> <in> to <out\_type>: ret=out
\subsection*{Arrays}
type = [<size> $\times$ <type>]; alloca; getelementptr <arr\_elem\_type>, <arr\_type\_ptr>
<ptr\_to\_array>, <idx\_type> 0, <idx\_type> <idx> (arrptr[0][idx] == arr[idx])
\subsection*{Strictly dominates \& dominance frontier}


%!TEX root = ../../dissertation.tex

\section{Tables and Figures}

\begin{table}[tph]
  \caption{Accuracy and speed of value iterative methods}
  \label{clmm:Table1}\vspace{-0.3cm}
  \par
  \begin{center}
  \begin{threeparttable}
{\footnotesize
  \begin{tabular}{c|cc|ccc}
    \hline \hline
    Degree & $L_1$ & $L_\infty$ & Julia CPU (s) & Matlab CPU (s) & Python CPU (s) \\ \hline
    \multicolumn{6}{c}{} \\
    \multicolumn{6}{c}{Conventional VFI (VFI)} \\ \hline
    2nd &  -3.83 & -2.76 & 2.06 & 74.02 & 11.20 \\
    3rd &  -4.97 & -3.32 & 1.79 & 49.87 & 6.83 \\
    4th &  -6.06 & -4.03 & 1.88 & 43.08 & 6.06 \\
    5th &  -7.00 & -4.70 & 3.28 & 32.48 & 4.61 \\ \hline
    \multicolumn{6}{c}{} \\
    \multicolumn{6}{c}{Envelope condition method (ECM)} \\ \hline
    2nd & -3.83 & -2.76 & 0.56 & 0.38 & 0.34 \\
    3rd & -4.97 & -3.32 & 0.35 & 0.21 & 0.24 \\
    4th & -6.06 & -4.03 & 0.57 & 0.22 & 0.27 \\
    5th & -7.00 & -4.70 & 0.63 & 0.11 & 0.15 \\ \hline
    \multicolumn{6}{c}{} \\
    \multicolumn{6}{c}{Endogenous grid method (EGM)} \\ \hline
    2nd & -3.81 & -2.76 & 1.03 & 59.89 & 4.11 \\
    3rd & -4.95 & -3.34 & 0.76 & 46.19 & 2.82 \\
    4th & -6.06 & -4.05 & 0.91 & 34.89 & 2.51 \\
    5th & -7.04 & -4.73 & 0.99 & 27.05 & 1.89 \\ \hline
  \end{tabular}%
  \begin{tablenotes}
    \item[a] $L_1$ and $L_\infty$ are, respectively, the average and maximum of
    absolute residuals across optimality conditions and test points (in $\log
    10$) units on a stochastic simulation of 10,000 observations. CPU is the
    time necessary for computing a solution (in seconds)
  \end{tablenotes}
}  % End footnote size
  \end{threeparttable}
  \end{center}
  \par
\end{table}

\begin{table}[tph]
  \caption{Accuracy and speed of policy iterative methods}
  \label{clmm:Table2}\vspace{-0.3cm}
  \par
  \begin{center}
  \begin{threeparttable}
{\footnotesize
  \begin{tabular}{c|cc|ccc}
    \hline \hline
    Degree & $L_1$ & $L_\infty$ & Julia CPU (s) & Matlab CPU (s) & Python CPU (s) \\ \hline
    \multicolumn{6}{c}{} \\
    \multicolumn{6}{c}{Conventional PI} \\ \hline
    2nd & -3.81 & -2.76 & 0.37 & 47.13 & 5.66 \\
    3rd & -4.95 & -3.34 & 1.58 & 39.30 & 5.07 \\
    4th & -6.06 & -4.05 & 2.06 & 41.83 & 5.75 \\
    5th & -7.04 & -4.73 & 3.28 & 32.54 & 4.44 \\ \hline
    \multicolumn{6}{c}{} \\
    \multicolumn{6}{c}{Envelope condition method iterrating on policy functions
    (ECM-PI)} \\ \hline
    2nd & -3.81 & -2.76 & 0.32 & 0.38 & 0.42 \\
    3rd & -4.95 & -3.34 & 0.37 & 0.15 & 0.34 \\
    4th & -6.06 & -4.05 & 0.55 & 0.24 & 0.41 \\
    5th & -7.04 & -4.73 & 0.64 & 0.11 & 0.27 \\ \hline
    \multicolumn{6}{c}{} \\
    \multicolumn{6}{c}{Envelope condition method iterating on derivative of
    value function (ECM-DVF)} \\ \hline
    2nd & -3.81 & -2.76 & 0.74 & 0.68 & 0.61 \\
    3rd & -4.95 & -3.34 & 1.12 & 0.66 & 0.65 \\
    4th & -6.06 & -4.05 & 1.62 & 0.69 & 0.75 \\
    5th & -7.04 & -4.73 & 4.05 & 0.73 & 0.81 \\ \hline
    \multicolumn{6}{c}{} \\
    \multicolumn{6}{c}{Euler equation method} \\ \hline
    2nd & -3.81 & -2.76 & 0.40 & 0.46 & 0.38 \\
    3rd & -4.95 & -3.34 & 0.37 & 0.28 & 0.27 \\
    4th & -6.06 & -4.05 & 0.53 & 0.24 & 0.25 \\
    5th & -7.04 & -4.73 & 0.77 & 0.11 & 0.12 \\ \hline
    \end{tabular}
  \begin{tablenotes}
    \item[a] $L_1$ and $L_\infty$ are, respectively, the average and maximum of
    absolute residuals across optimality conditions and test points (in $\log
    10$) units on a stochastic simulation of 10,000 observations. CPU is the
    time necessary for computing a solution (in seconds)
  \end{tablenotes}
}  % End footnote size
  \end{threeparttable}
  \end{center}
  \par
\end{table}

\begin{table}[tph]
  \caption{Accuracy and speed of a projection method for solving new Keynesian model}
  \label{clmm:Table3}\vspace{-0.3cm}
  \par
  \begin{center}
    \begin{threeparttable}
      {
      \footnotesize
        \begin{tabular}{c|cc|ccc}
          \hline \hline
          Degree & $L_1$ & $L_\infty$ & Julia CPU (s) & Python CPU (s) & Matlab CPU (s) \\ \hline
          \multicolumn{6}{c}{} \\
          \multicolumn{6}{c}{Inflation target $\pi_*=1.0598$} \\ \hline
          1st    & -3.41 &  -1.94 &           0.74 &            0.96 &            0.79 \\
          2nd    & -4.71 &  -3.13 &           3.28 &            2.24 &            2.65 \\
          3rd    & -6.07 &  -4.25 &          14.30 &            9.18 &            7.49 \\
          4th    & -6.73 &  -4.65 &          54.84 &           94.26 &           55.57 \\
          5th    & -7.00 &  -5.47 &         902.95 &         1879.04 &         1120.17 \\  \hline
          \multicolumn{6}{c}{} \\
          \multicolumn{6}{c}{Inflation target $\pi_*=1$} \\ \hline
          1st    & -3.12 &  -1.73 &           0.39 &            0.50 &            0.47 \\
          2nd    & -4.40 &  -2.77 &           1.45 &            0.98 &            1.09 \\
          3rd    & -5.71 &  -3.54 &           6.06 &            3.81 &            3.08 \\
          4th    & -6.82 &  -4.89 &          23.62 &           38.44 &           22.45 \\
          5th    & -7.01 &  -5.12 &         375.57 &          798.46 &          461.46 \\\\ \hline
          \multicolumn{6}{c}{} \\
          \multicolumn{6}{c}{Inflation target $\pi_*=1$ with ZLB} \\ \hline
          1st    & -3.12 &  -1.73 &           0.41 &            0.45 &            0.50 \\
          2nd    & -4.40 &  -2.16 &           1.45 &            0.87 &            1.06 \\
          3rd    & -5.60 &  -2.15 &           5.86 &            3.70 &            2.95 \\
          4th    & -6.17 &  -2.15 &          23.87 &           39.73 &           22.98 \\
          5th    & -6.20 &  -2.15 &         347.89 &          822.97 &          455.39 \\ \hline
        \end{tabular}
        \begin{tablenotes}
          \item[a] $L_1$ and $L_\infty$ are, respectively, the average and maximum of
          absolute residuals across optimality conditions and test points (in $\log
          10$) units on a stochastic simulation of 10,000 observations. CPU is the time
          necessary for computing a solution (in seconds)
        \end{tablenotes}
      }
    \end{threeparttable}
  \end{center}
\end{table}

\begin{figure}
  \includegraphics[width=\textwidth]{images/CLMM/Figure1-eps-converted-to.pdf}
  \caption{Stochastic-simulation grid and epsilon-distinguishable set grid. }
  \label{fig:eps_dist_grid}
\end{figure}

\begin{figure}
  \includegraphics[width=\textwidth]{images/CLMM/Figure2-eps-converted-to.pdf}
  \caption{Uniformly-spaced random grid and quasi-Monte Carlo grid.}
  \label{fig:rand_sobol_grid}
\end{figure}


\section{Discussion}

Perhaps the most striking result is that only ten topics of five hundred total can be considered strictly overlapping.
That is, there is only two percent overlap.
An additional twenty four topics (for a total of thirty four) can be considered ``weakly overlapping'' by relaxing the $\theta$ constraint to only one $D_j$ rather than all.
However, this still only gives a Jaccard similarity coefficient of 0.68.
There are several ways to interpret this.

The most direct reading of the data indicates, simply, that universities are not teaching to what the workforce expects.
Of the five hundred extracted topics, some are expressed by curricular data, some are expressed by career data, but the degree of overlap is low.
The low Jaccard index of the two sets indicates a fairly significant dissimilarity.

However, perhaps the most probable interpretation is that the number of extracted topics was simply significantly too low.
Considering that almost fifty thousand documents were modeled across the two corpora, and considering that any given document can express many different topics, five hundred topics is simplty too low a number.
Increasing that count to several hundred thousand would most likely garner significantly higher levels of overlap.
The LDA process is storage and memory bound.
Increasing the number of topics significantly beyond five hundred would require significant computational resources.

One future extension to this work is the systematic analysis of the hyper parameters.
Specifically: the number of inferred topics ($k$), relevance ($\rho$), and intersection ($\theta$).
The author hypothesizes that an optimal maximum Jaccard index can be obtained most directly by increasing $k$ beyond five hundred.