\documentclass{memoir}
\usepackage{notestemplate}

% \begin{figure}[ht]
%     \centering
%     \incfig{riemmans-theorem}
%     \caption{Riemmans theorem}
%     \label{fig:riemmans-theorem}
% \end{figure}

\begin{document}

\begin{defn}[Holomorphic] % Testing
\label{defn:Holomorphic}
	Let \(\Omega\subset \C\) be open. A complex-valued function \(f:\Omega\to \C\) is \textbf{holomorphic} (or \textbf{regular}, \textbf{complex differentiable}) if for every \(z\in \Omega\), the limit exists:
	\begin{align*}
		\lim_{h \to 0} \frac{f(z+h)-f(z)}{h} := f'(z)
	\end{align*}
	\(f'\) is called the \textbf{complex derivative} of \(f\).
\end{defn}
Note that \(h\) is a non-zero complex number in \(\Omega\). Hence the derivative has to exist and be equal for any possible direction that \(h\) may approach zero.\\

\begin{anki}
TARGET DECK
Complex Qual::Complex Analysis
START
MathJaxCloze
Text: Let \(\Omega\subset \C\) be open. A complex-valued function \(f:\Omega\to \C\) is **holomorphic** (or **regular**, **complex differentiable**) if for every \(z\in \Omega\), the limit exists:
 {{c1::\(\begin{align*}
         	\lim_{h \to 0} \frac{f(z+h)-f(z)}{h} := f'(z)
         \end{align*}\)}}
	\(f'\) is called the **complex derivative** of \(f\).
Extra: Note that \(h\) is a non-zero complex number in \(\Omega\). Hence the derivative has to exist and be equal for any possible direction that \(h\) may approach zero.
Tags: analysis complex_analysis complex_analyticity defn
<!--ID: 1624408998120-->
END
\end{anki}

\begin{exmp}[Holomorphic and non-holomorphic functions]
	Any polynomial \(p \in \C[z]\) defined by
	\begin{align*}
		p(z) = a_0 + a_1z + \ldots + a_n z^{n}
	\end{align*}
	is holomorphic in the entire complex plane with
	\begin{align*}
		p'(z) = a_1 + \ldots + na_n z^{n-1}.
	\end{align*}
	However, \(f(z) = 1 / z\) is only holomorphic on open sets that do not contain the origin.\\

	For an example of a function that is never holomorphic, consider the involuntary transformation
	\begin{align*}
		f(z) = \overline{z}.
	\end{align*}
	One can see that
	\begin{align*}
		\frac{f(z_0+h) - f(z_0)}{h} = \frac{\overline{h}}{h}
	\end{align*}
	which has no limit as \(h\to 0\), as if \(h\) approaches zero on the real axis, then \(\frac{\overline{h}}{h} = 1\), and if it approaches zero on the imaginary axis, then \(\frac{\overline{h}}{h}= -1\).
\end{exmp}

It is useful to review the definition of real differentiation in \(\R^2\). At first, it seems there should be no reason to view complex and real differentiation differently, but we will start to see some subtle and important differences soon.
\begin{defn}[Real Differentiation]
	Let \(\Omega\subset \R^2\) be open. Let \(F:\Omega\to \R^2\). Then \(F\) is real-differentiable if there exists a linear transformation \(J:\R^2\to \R^2\) such that, for every \(z \in \Omega\)
	\begin{align*}
		\lim_{\left| h \right|  \to 0} \frac{\left| F(z+h)-F(z)-J_F(h) \right| }{\left| h \right| } = 0
	\end{align*}
	where \(h \in \R^2\). \(J_F\) is called the Jacobian and is exactly the \(2\times 2\) real matrix of partial derivatives
\begin{align*}
	J = J_F(x,y) = \begin{pmatrix} \sfrac{\partial u}{\partial x} & \sfrac{\partial u}{\partial y} \\ \sfrac{\partial v}{\partial x} & \sfrac{\partial v}{\partial y}  \end{pmatrix}
\end{align*}
\end{defn}
When \(F\) is a complex function, there is a special relation between the entries of the Jacobian, if it is holomorphic.

\begin{prop}[Cauchy-Riemann Equations]
	Let \(f\) be a complex function with \(f = u + iv\) for \(u,v\) real-valued functions. If \(f\) is holomorphic, then \(f\) satisfies the \textbf{Cauchy-Riemann equations}:
\begin{align*}
	\frac{\partial f}{\partial x} = \frac{1}{i}\frac{\partial f}{\partial y} &\implies \\
	\frac{\partial u}{\partial x} &= \frac{\partial v}{\partial y} \quad \frac{\partial u}{\partial y} = -\frac{\partial v}{\partial x}
\end{align*}
where \((x,y)\) is a complex variable.
\end{prop}

\begin{anki}
START
MathJaxCloze
Text: Let \(f\) be a complex function with \(f = u + iv\) for \(u,v\) real-valued functions. If \(f\) is holomorphic, then \(f\) satisfies the **Cauchy-Riemann equations**:
 {{c1::\(\begin{align*}
         	\frac{\partial f}{\partial x} = \frac{1}{i}\frac{\partial f}{\partial y} \implies \\
         	\frac{\partial u}{\partial x} = \frac{\partial v}{\partial y} \quad \frac{\partial u}{\partial y} = -\frac{\partial v}{\partial x}
         \end{align*}\)}}
where \((x,y)\) is a complex variable.
Extra: The reverse direction holds: \(f\) is complex-differentiable iff \(f\) is real-differentiable and satisfies the Cauchy-Riemann equation.
Tags: analysis complex_analysis complex_analyticity
<!--ID: 1624408998160-->
END
\end{anki}

\begin{proof}[Construction of Cauchy-Riemann Equations]
	Recall that any complex-valued function \(f\) can be parametrized by some mapping
	\begin{align*}
		f = F(x,y) = (u(x,y), v(x,y))
	\end{align*}
	where \(x,y\) represent the real and imaginary coordinate respectively, and \(u,v\) are real-valued functions. If \(F\) is real-differentiable, then the partial derivatives of \(u,v\) exist and hence
	\begin{align*}
		J_F(x,y) = \begin{pmatrix} \sfrac{\partial u}{\partial x} & \sfrac{\partial u}{\partial y} \\ \sfrac{\partial v}{\partial x} & \sfrac{\partial v}{\partial y}  \end{pmatrix}
	\end{align*}
	satisfies the necessary properties as \(h\to 0\). However, there is an implicit relation imposed, as we utilize the parametrization \(h = (h_1,h_2)\). Observe that we can treat \(x\) or \(y\) as fixed when approaching from the imaginary or real axes respectively, and get
	\begin{align*}
		f'(z) &= \lim_{h_1 \to 0} \frac{f(x+h_1,y) - f(x,y)}{h_1} = \frac{\partial f}{\partial x} (z)\\
		f'(z) &= \lim_{h_2 \to 0} \frac{f(x,y+h) - f(x,y)}{i h_2} = \frac{1}{i} \frac{\partial f}{\partial y} (z)
	\end{align*}
	Hence, if \(f\) is holomorphic, these limits must be equal and thus
	\begin{align*}
		\frac{\partial f}{\partial x} = \frac{1}{i} \frac{\partial f}{\partial y}
	\end{align*}
	Substituting \(f = u + iv\), we get the relations
	\begin{align*}
		\frac{\partial u}{\partial x} = \frac{\partial v}{\partial y} \quad \frac{\partial u}{\partial y} = - \frac{\partial v}{\partial x}
	\end{align*}
\end{proof}

\begin{thm}
	Let \(\Omega\subset \C\) be open. Let \(f:\Omega\to \C\). Express \(z = x+yi\) and \(f = u+vi\) in the usual way. Then \(f\) is complex-differentiable if and only if \(f\) is real-differentiable and the Cauchy-Riemann equations are satisfied:
	\begin{align*}
		\frac{\partial u}{\partial x} = \frac{\partial v}{\partial y} \quad \frac{\partial u}{\partial y} = -\frac{\partial v}{\partial x}
	\end{align*}
\end{thm}
This follows directly from the work above.

\begin{prop}[Properties of Complex Differentiation]\label{prop:properties_of_complex_differentiation}
	Let \(f,g:\Omega \to \C\) be holomorphic complex-valued functions. Then
	\begin{align*}
		(f+g)' &= f'+g'\\
		(fg)' &= f'g + fg'\\
		\left( \frac{f}{g} \right)' &= \frac{f'g-fg'}{g^2} \text{ at all \(g(z)\neq 0\)}\\
		(f \circ g)' &= (f'\circ g)\cdot g' \text{ at all \(g(z) \in \Omega\)}
	\end{align*}
	and hence all of these compositions are holomorphic functions.
\end{prop}

\begin{hw}
	Prove \ref{prop:properties_of_complex_differentiation}.
\end{hw}

\subsection{Complex Differential Forms}
\label{sub:complex_differential_forms}

When first encountering the complex plane and complex functions, it is tempting to "view" these structures as a variant on \(\R^2\). While this interpretation is not wrong, it can be restrictive at times. While it is true that a complex function is a parametrization \(f = (u,v)\) where each component represents the real and imaginary coordinate, the underlying relation between the real and imaginary coordinate can be hidden.\\

Thus, we encourage the reader to view complex functions \(f:\C\to \C\) as mappings \(f:z\mapsto f(z)\). This interpretation comes in handy when working with differential forms on \(\C\). Let \(f(z) = f((x,y))\) be given. Then the differential \(df\) can be given by
\begin{align*}
	df = \frac{\partial f}{\partial x} \,d x + \frac{\partial f}{\partial y} \,d y.
\end{align*}
This form is perfectly valid, but can be clunky depending on how \(f\) is defined. Instead, let \(z = (x,y)\). Then we have a relation given by
\begin{align*}
	z &= (x,y) &\quad x &= (\sfrac{1}{2},0)(z+\overline{z})\\
	\overline{z}&=(x,-y) &\quad y &= (0,\sfrac{1}{2})(z-\overline{z})
\end{align*}

These identities carry over to the differentials \(dx, \,d y\) so that
\begin{align*}
	dz &= (dx,dy) & \quad dx &= (\sfrac{1}{2},0)(dz + d\overline{z}) \\
	d \overline{z} &= (dx,-dy) &\quad \,d y &= (0,\sfrac{1}{2})(dz - d \overline{z})
\end{align*}
This change of variable offers a few distinct advantages, but first we point out its limitations. One convenience offered by \(dx,\,d y\) is that they are independent of one another, unlike \(z\) and \(\overline{z}\). We cannot treat \(dz,\,d \overline{z}\) as independent variables-- however, we do have a form of independence:
\begin{prop}
	Let \(g,h\) be complex-valued functions. Then
	\begin{align*}
		g \,d z + h \,d \overline{z} = 0 \iff g= h = 0.
	\end{align*}
\end{prop}

This differential form is not particularly useful if we cannot define the differential \(df\) in the form
\begin{align*}
	df = \frac{\partial f}{\partial z} \,d z + \frac{\partial f}{\partial \overline{z}} \,d \overline{z}.
\end{align*}
We can already obtain
\begin{align*}
	df &= \frac{\partial f}{\partial x} \,d x + \frac{\partial f}{\partial y} \,d y\\
	   &= \frac{\partial f}{\partial x} \left( (\sfrac{1}{2},0)(dz + d \overline{z} ) \right) + \frac{\partial f}{\partial y} \left( (0,\sfrac{1}{2})(dz - d \overline{z} \right) \\
	   &= \frac{1}{2}\left( \frac{\partial f}{\partial x} , - \frac{\partial f}{\partial y}  \right) \,d z + \frac{1}{2} \left( \frac{\partial f}{\partial x} , \frac{\partial f}{\partial y}  \right) \,d \overline{z}.
\end{align*}
This makes it clear what a natural definition for \(\frac{\partial }{\partial z} \) and \(\frac{\partial }{\partial \overline{z}} \) should look like. With this, we formally define what we have just discussed:

\begin{defn}[Complex Differential 1-form]
	Let \((x,y)\) be complex variables with corresponding differentials \(dx , \,d y\) and partial derivatives \(\frac{\partial }{\partial x} , \frac{\partial }{\partial y} \). Then taking \(z = (x,y)\), we define the \textbf{complex differential 1-form} by
	\begin{align*}
		dz = (dx, dy)\\
		d \overline{z} = (dx,-dy)
	\end{align*}
	so that
	\begin{align*}
		dx = (\sfrac{1}{2},0) (dz + d \overline{z})\\
		dy = (0, \sfrac{1}{2}) (dz - d \overline{z})
	\end{align*}
	is satisfied. Furthermore, we define the **complex differential operators** by
	\begin{align*}
		\frac{\partial }{\partial z} &= \frac{1}{2}\left( \frac{\partial }{\partial x} , \frac{\partial }{\partial y}  \right)\\
		\frac{\partial }{\partial \overline{z}} &= \frac{1}{2} \left( \frac{\partial }{\partial x} , - \frac{\partial }{\partial y}  \right)
	\end{align*}
	so that
	\begin{align*}
		df = \frac{\partial f}{\partial z} \,d z + \frac{\partial f}{\partial \overline{z}} \,d \overline{z}
	\end{align*}
	is satisfied.
\end{defn}

\begin{anki}
START
MathJaxCloze
Text: Let \((x,y)\) be complex variables with corresponding differentials \(dx , \,d y\) and partial derivatives \(\frac{\partial }{\partial x} , \frac{\partial }{\partial y} \). Then taking \(z = (x,y)\), we define the **complex differential 1-form** by
\(\begin{align*}
  	dz = (dx, dy)\\
  	d \overline{z} = (dx,-dy)
  \end{align*}\)
so that
{{c1::\(\begin{align*}
      	dx = (\sfrac{1}{2},0) (dz + d \overline{z})\\
      	dy = (0, \sfrac{1}{2}) (dz - d \overline{z})
        \end{align*}\)}}
is satisfied. Furthermore, we define the \textbf{complex differential operators} by
{{c2::\(\begin{align*}
        	\frac{\partial }{\partial z} &= \frac{1}{2}\left( \frac{\partial }{\partial x} , \frac{\partial }{\partial y}  \right)\\
        	\frac{\partial }{\partial \overline{z}} &= \frac{1}{2} \left( \frac{\partial }{\partial x} , - \frac{\partial }{\partial y}  \right)
        \end{align*}\)}}
so that
\(\begin{align*}
  	df = \frac{\partial f}{\partial z} \,d z + \frac{\partial f}{\partial \overline{z}} \,d \overline{z}
  \end{align*}\)
is satisfied.
Extra: One convenience offered by \(dx,\,d y\) is that they are independent of one another, unlike \(z\) and \(\overline{z}\). We cannot treat \(dz,\,d \overline{z}\) as independent variables-- however, we do have a form of independence. If \(g,h\) are complex functions, then:
\(\begin{align*}
  	g \,d z + h \,d \overline{z} = 0 \iff g= h = 0.
  \end{align*}\)
Tags: analysis complex_analysis complex_analyticity defn
<!--ID: 1626483183627-->
END
\end{anki}

\begin{exmp}
	What is the derivative of \(f(z) = z^2 \)?
\end{exmp}

\begin{prop}
	A complex-valued function \(f\) is holomorphic if and only if
	\begin{align*}
		\frac{\partial f}{\partial \overline{z}} = 0.
	\end{align*}
\end{prop}
This follows directly from applying \(\frac{\partial }{\partial \overline{z}} \) to \(f = (u,v)\). We encourage the reader to compute this by hand as a short exercise if it is not immediately apparent.\\

\begin{anki}
START
MathJaxCloze
Text: A complex-valued function \(f\) is holomorphic if and only if
 {{c1::\(\begin{align*}
        	\frac{\partial f}{\partial \overline{z}} = 0.
        \end{align*}\)::complex differential operator}}
Tags: analysis complex_analysis complex_analyticity defn
<!--ID: 1626483183638-->
END
\end{anki}

One should also verify that \(\frac{\partial }{\partial z} \) and \(\frac{\partial }{\partial \overline{z}} \) commute as one expects partial derivatives to commute from real analysis. Furthermore, they satisfy the product rule and chain rule.\\

We conclude the discussion on the complex differential with one last identity of note. We will use this tool throughout, although we will not see the full scope of the complex differential operator until we discuss harmonic functions.
\begin{prop}
If \(f = (u,v)\), then we can express the complex derivative by
\begin{align*}
	f'(z) = 2 \frac{\partial u}{\partial z} = \frac{\partial u}{\partial x} - i \frac{\partial u}{\partial y} .
\end{align*}
\end{prop}

% Info on potential functions??

\subsection{Analytic Continuity}
\label{sub:analytic_continuity}

We briefly mentioned that the set of zeroes of a non-constant holomorphic function is discrete. This property is a remarkably strong statement on holomorphic functions. First, we state it a bit more formally.

\begin{thm}[Discreteness of Holomorphic Zeroes]
	Let \(\Omega \subset \C\) be a connected open set. If \(f:\Omega \to \C\) is holomorphic on \(\Omega \) and non-constant, then \(U = f^{-1}(\left\{ 0 \right\}\subset \Omega  )\) is discrete.\\

	In particular, if \(f,g\) are holomorphic on \(\Omega \), and there exists \(U\subset \Omega \) non-discrete so that \(f(z)=g(z)\) for \(z \in U\), then \(f(z)=g(z)\) for \(z \in \Omega \).
\end{thm}

\begin{proof}
	The second statement follows from the first by observing that \(f-g \) is holomorphic and hence must have a discrete set of zeroes. Hence, if \(f-g=0\) on a non-discrete set, \(f-g\) must be constant.\\

	We will prove the first part once we introduce the notion of locally constant.
\end{proof}

\begin{anki}
START
MathJaxCloze
Text: Let \(\Omega \subset \C\) be a connected open set. If \(f\) is holomorphic on \(\Omega \) and non-constant, then the set of zeroes of \(f\) on \(\Omega \) is {{c1::discrete}}.

	In particular, if \(f,g\) are holomorphic on \(\Omega \), and there exists \(U\subset \Omega \) {{c1::non-discrete}} so that \(f(z)=g(z)\) for \(z \in U\), then {{c1::\(f(z)=g(z)\) for \(z \in \Omega \)}}.
Tags: analysis complex_analysis complex_analyticity
<!--ID: 1625191420102-->
END
\end{anki}

The theorem above is so powerful because it gives us a uniqueness of holomorphic functions.

\begin{defn}[Analytic Continuation]
	Let \(f\) be a holomorphic function on an open set \(U\) with \(U\subset \Omega \subset \C \) for some \(\Omega \) open. Suppose \(g\) is a holomorphic function on \(\Omega \) with \(f(z)=g(z)\) for \(z \in U\). Then \(g\) is the \textbf{analytic continuation} of \(f\) to \(\Omega \).\\

	Instead, suppose there exists an open set \(V \subset \C\), \(U,V\) connected, with \(U\cap V \neq \emptyset\). Then if \(g\) is holomorphic on \(V\) and equal to \(f\) on \(U\cap V\), then we also say that \(g\) is the analytic continuation of \(f\) to \(V\).
\end{defn}
In general, there are many ways to extend \(f\) depending on the structure of our sets by ensuring it agrees on non-isolated sets. We may refer to any of these extensions as analytic continuations. The theorem above guarantees that these extensions are unique.

\begin{anki}
START
MathJaxCloze
Text: Let \(f\) be a holomorphic function on an open set \(U\) with \(U\subset \Omega \subset \C \) for some \(\Omega \) open. Suppose \(g\) is {{c1::a holomorphic function}} on \(\Omega \) with {{c1::\(f(z)=g(z)\)}} for \(z \in U\). Then \(g\) is the **analytic continuation** of \(f\) to \(\Omega \).
Extra: Another form of analytic continuity: suppose there exists an open set \(V \subset \C\), \(U,V\) connected, with \(U\cap V \neq \emptyset\). Then if \(g\) is holomorphic on \(V\) and equal to \(f\) on \(U\cap V\), then we also say that \(g\) is the analytic continuation of \(f\) to \(V\).
Tags: analysis complex_analysis complex_analyticity defn
<!--ID: 1625191420112-->
END
\end{anki}

\subsection{Conformality of Holomorphic Functions}
\label{sub:conformality_of_holomorphic_functions}

Holomorphic functions play an important role with regard to curves.\\

We will ask that curves in \(\C\) are differentiable (and not, say, holomorphic). This is because we cannot construct a concept of holomorphicity that makes sense with complex curves at the moment (why?).\\

Hence, we merely say that a curve \(\gamma \) is differentiable provided its components are differentiable. That is, if \(\gamma = (x,y)\) for real-valued curves \(x,y\), then \(\gamma \) is holomorphic if and only if \(x,y\) are differentiable. Differentiable curves get a special name.

\begin{defn}[Smooth]
	Let \(\gamma =(x,y)\) be a curve in \(\C\), where \(x,y\) are real-valued curves. Then \(\gamma \) is \textbf{smooth} if it is component-wise \(C^{1}\)-- that is, \(x,y \in C^{1}\), and define
	\begin{align*}
		\gamma '(t) = (x'(t),y'(t)).
	\end{align*}
	Furthermore, we require that \(\gamma'(t) \neq 0\) for any time \(t\).
\end{defn}
A smooth curve is \textbf{closed} if \(\gamma(t_0) = \gamma (t_1)\), and \textbf{simple} if \(\gamma(t) \neq \gamma(s)\) for \(t\neq s\), where \(t,s\) are not both endpoints.

\begin{defn}[Tangent Vectors]
	Let \(\gamma ,\eta \) be smooth curves passing through a point \(z_0 \in \C\), that is:
	\begin{align*}
		\gamma (\tau_1) = \eta (\tau_2) = z_0
	\end{align*}
	for some \(\tau_1,\tau_2 \in \R\). Then \(\gamma '(\tau_1)\) is the \textbf{tangent vector of \(\gamma \) at \(z_0\)}.\\

	The \textbf{angle between \(\gamma ,\eta \)} is defined to be the angle between \(\gamma'(\tau_1)\) and \(\eta'(\tau_2)\), that is
	\begin{align*}
		\theta_{z_0} (\gamma ,\eta ) = \theta (\gamma'(\tau_1), \eta'(\tau_2))
	\end{align*}
\end{defn}

\begin{prop}[Preservation of Angles]
	Let \(\gamma ,\eta \) be smooth curves passing through a point \(z_0 \in \Omega\subset \C\), and let \(f:\Omega \to \C\) be holomorphic. Then
	\begin{align*}
		\frac{\partial }{\partial t} f(\gamma (t)) = f'(\gamma (t)) \gamma '(t).
	\end{align*}
	and
	\begin{align*}
		\theta_{z_0}(\gamma,\eta ) = \theta_{f(z_0)}(f\circ \gamma , f\circ \eta ).
	\end{align*}
\end{prop}
In other words, holomorphic functions preserve the angles between curves.\\

Any isomorphism between metric spaces with curves that satisfies
\begin{align*}
	\theta_{z_0}(\gamma ,\eta ) = \theta_{f(z_0)}(f\circ \gamma , f\circ \eta )
\end{align*}
is called \textbf{conformal}. Hence, the proposition above states that all holomorphic isomorphisms are conformal.

\begin{anki}
START
MathJaxCloze
Text: Any isomorphism between metric spaces with curves that satisfies for every \(z_0\) in the metric space and \(\gamma ,\eta \) curves within the space:
 {{c1::\(\begin{align*}
        	\theta_{z_0}(\gamma ,\eta ) = \theta_{f(z_0)}(f\circ \gamma , f\circ \eta )
        \end{align*}\)}}
is called \textbf{conformal}.
Tags: analysis complex_analysis defn
<!--ID: 1624675761922-->
END
\end{anki}

\begin{anki}
START
MathJaxCloze
Text: Holomorphic isomorphisms in \(\C\) are {{c1::conformal}} maps.
Tags:
<!--ID: 1624675761966-->
END
\end{anki}

\begin{proof}
	The derivative of the composition follows from the rule of complex differentiation on compositions. For the second part, let \(f'(z_0) = \alpha \). Then
	\begin{align*}
		\langle \alpha z, \alpha w \rangle = \textrm{Re}(\alpha z \overline{\alpha } \overline{w}) = \alpha \overline{\alpha } \textrm{Re}(z \overline{w}) = \left| \alpha  \right|^2 \langle z,w \rangle .
	\end{align*}
	Hence
	\begin{align*}
		\langle (f\circ \gamma)' , (f\circ \eta)'  \rangle = \langle \alpha \gamma' , \alpha \eta'  \rangle \\
		\left| (f\circ \gamma)'  \right| = \left| \alpha  \right|\left| \gamma ' \right|
	\end{align*}
	which implies that
	\begin{align*}
		\theta ( (f\circ \gamma)' , (f \circ \eta )') = \theta (\alpha \gamma , \alpha \eta )
	\end{align*}
	One can check that scalar multiplication of complex vectors does not change the angle between complex vectors, and hence it holds that \(f\) is conformal.
\end{proof}
The reverse is false in general.\\

This gives an interesting new light to holomorphic functions. We can instead treat functions that are holomorphic on \(\C\) as isomorphisms of \(\C\). Hence we can view functions as holomorphic transformations of the complex plane. This equivalence allows us to infer a lot of information of geometric transformations of the complex plane.\\

Furthermore, one can show that \(\overline{f}\) is \textbf{indirectly conformal}-- that is, angles are preserved but reversed in direction. In general, holomorphic transformations scale continuously the area of sets. That is, let \(E\subset \C\) be a measurable set. Then
\begin{align*}
	A(E) &= \int_{E} 1 \,d \mu \\
	     &\implies A(f(E)) = \int_E \left| f' \right| \,d \mu .
\end{align*}
This holds because in general for any real-differentiable isomorphism \(f = u+iv\)
\begin{align*}
	A(f(E)) = \int_E \left| u_x v_y - u_y v_x \right| \,d x \,d y
\end{align*}
When \(f\) is conformal, we have \(u_xv_y - u_yv_x = \left| f'(z) \right|^2\) and hence the statement holds.

\begin{anki}
START
MathJaxCloze
Text: One can show that \(\overline{f}\) is **indirectly conformal**-- that is, {{c1::angles are preserved but reversed in direction}}.

Holomorphic transformations {{c2::scale continuously the area of sets}} . That is, let \(E\subset \C\) be a measurable set. Then
 {{c2::\(\begin{align*}
        	A(E) &= \int_{E} 1 \,d \mu \\
        	     &\implies A(f(E)) = \int_E \left| f' \right| \,d \mu .
        \end{align*}\)}}

Extra: In general, for any real-differentiable isomorphism \(f = u+iv\)
\(\begin{align*}
  	A(f(E)) = \int_E \left| u_x v_y - u_y v_x \right| \,d x \,d y
  \end{align*}\)
When \(f\) is conformal, we have \(u_xv_y - u_yv_x = \left| f'(z) \right|^2\) and hence the statement holds.
Tags: analysis complex_analysis defn complex_analyticity
<!--ID: 1624675762007-->
END
\end{anki}

\end{document}


% Copyright 2018 Melvin Eloy Irizarry-Gelpí
\chapter{Nilplex Numbers}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
An exo-1 real number has the form
\begin{equation}
    a_{0} + a_{1} W
\end{equation}
These follow from a parabolic Cayley-Dickson construct on the reals.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Arithmetic Operations}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
...
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Multiplication}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
...
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Conjugate Operations}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
...
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Asterisk Conjugation}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
...
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Quadrance}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
...
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Cloak Conjugation}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
...
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Dagger Conjugation}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
...
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Hodge Star}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
...
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Differential Operators}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
...


%TODOS FOR THIS LAB
%1.  Maybe merge mst and ImgSegMST
% Note: Prim's section has been taken out since it was covered in class, content is commented out
% Kruskal's section also contains a short comparison of Kruskal's and Prim's

\lab{Kruskal's Algorithm}{Kruskal's Algorithm}

\label{lab:Kruskal}

\objective{Find a minimum spanning tree for a connected, weighted graph using Kruskal's Algorithm}

\section*{Weighted Graphs and Spanning trees}

In this lab we will focus on graphs that are \emph{connected, undirected}, and \emph{weighted}. Recall that a graph is represented as a set of nodes combined with a set of edges that connect the nodes. A \emph{connected graph} is a graph where there is a path between each pair of nodes. If the directions of these edges are specified, we have a \emph{directed graph}, and if all of the edges are bidirectional, we have an \emph{undirected graph}.

\begin{figure}[h]
\begin{tikzpicture}[node distance= 1.5cm, thick, main
	node/.style={circle, draw, minimum size = .75cm}]

\node[main node](B)[]{B};
\node[main node](C)[right of=B]{C};
\node[main node](F)[above of=B]{F};
\node[main node](E)[right of=F]{E};
\node[draw=none, node distance=.75cm](dummy)[above of= B]{};
\node[main node, node distance=1cm](A)[left of=dummy]{A};
\node[main node, node distance=2.5cm](D)[right of=dummy]{D};

\foreach \s/\t in {A/B, B/F, F/C, B/C, F/E, E/D, C/D, E/C, A/F}{\path[draw] (\s) edge (\t);}

\end{tikzpicture}
\caption{An example of a connected, undirected graph}
\label{mst:graph1}
\end{figure}

A \emph{weighted graph} is a graph where each edge has a value associated with it.
Usually these values represent some sort of cost or distance. For example, if we had a graph representing cities in the U.S., the weights between nodes (cities) would be the distance between the two cities. We represent the graph in the figure above as an adjacency matrix. Note that since the graph is undirected, the matrix is symmetric.

\[
\bordermatrix{\hspace{.4cm}&A&B&C&D&E&F\cr
A&0 & 1 & 0 & 0 & 0 & 1\cr
B&1 & 0 & 1 & 0 & 0 & 1\cr
C&0 & 1 & 0 & 1 & 1 & 1\cr
D&0 & 0 & 1 & 0 & 1 & 0\cr
E&0 & 0 & 1 & 1 & 0 & 1\cr
F&1 & 1 & 1 & 0 & 1 & 0\cr}
\]

Now consider the graph in Figure \ref{mst:graph4}.  This graph is the same as the graph in Figure \ref{mst:graph1}, except now there is a weight attached to each edge.  The adjacency matrix for this graph is
\[
\bordermatrix{\hspace{.4cm}&A&B&C&D&E&F\cr
A&0 & 3 & 0 & 0 & 0 & 6\cr
B&3 & 0 & 5 & 0 & 0 & 4\cr
C&0 & 5 & 0 & 1 & 1 & 5\cr
D&0 & 0 & 1 & 0 & 2 & 0\cr
E&0 & 0 & 1 & 2 & 0 & 4\cr
F&6 & 4 & 5 & 0 & 4 & 0\cr}
\]

We can also represent weighted graphs as adjacency lists. When we make the adjacency list of a directed, unweighted graph, we can make a dictionary with each node as a key and a list of its neighbors as the corresponding value. We can also make a list of the pairs of nodes corresponding to each edge (we will need two pairs to represent each edge in an undirected graph). For a weighted graph, we add a third value representing the weight of that edge.
Such a list for our undirected, weighted graph would look like the following:

\begin{lstlisting}
[('A', 'F', 6), ('A', 'B', 3), ('B', 'A', 3), ('B', 'C', 5), ('B', 'F', 4),
 ('C', 'B', 5), ('C', 'D', 1), ('C', 'E', 1), ('C', 'F', 5), ('D', 'C', 1),
 ('D', 'E', 2), ('E', 'C', 1), ('E', 'D', 2), ('E', 'F', 4), ('F', 'A', 6),
 ('F', 'B', 4), ('F', 'C', 5), ('F', 'E', 4)]
\end{lstlisting}

A \emph{spanning tree} of a connected, undirected graph $G$ is an undirected graph that contains all the nodes of $G$, a subset of the edges, and no cycles.
A cycle, for undirected graphs, is a path where you start and end on the same node without crossing any edge more than once.
The red in Figure \ref{mst:graph2} is an example of a cycle in an undirected graph.

\begin{figure}[H]
\begin{tikzpicture}[node distance= 1.5cm, thick, main
	node/.style={circle, draw, minimum size = .75cm}]

\node[main node](B)[]{B};
\node[main node](C)[right of=B]{C};
\node[main node](F)[above of=B]{F};
\node[main node](E)[right of=F]{E};
\node[draw=none, node distance=.75cm](dummy)[above of= B]{};
\node[main node, node distance=1cm](A)[left of=dummy]{A};
\node[main node, node distance=2.5cm](D)[right of=dummy]{D};

\foreach \s/\t in {A/B, A/F, F/C, B/C}{\path[draw, red](\s) edge (\t);}
\foreach \s/\t in {E/C, C/D}{\path[draw](\s)edge(\t);}

\end{tikzpicture}
\caption{A cycle in an undirected graph.}
\label{mst:graph2}
\end{figure}

The minimum spanning tree (MST) of a weighted, undirected graph is a spanning tree where the total weight is less than or equal to the total weight of every other spanning tree.
Kruskal's Algorithm is a method that finds the minimum spanning tree of a weighted, undirected graph.
Figure \ref{mst:graph3} shows a spanning tree of the graph shown in Figure \ref{mst:graph1}.
Figure \ref{mst:graph5} shows a minimum spanning tree of the graph shown in Figure \ref{mst:graph4}.

\begin{figure}[H]
\begin{tikzpicture}[node distance= 1.5cm, thick, main
	node/.style={circle, draw, minimum size = .75cm}]

\node[main node](B)[]{B};
\node[main node](C)[right of=B]{C};
\node[main node](F)[above of=B]{F};
\node[main node](E)[right of=F]{E};
\node[draw=none, node distance=.75cm](dummy)[above of= B]{};
\node[main node, node distance=1cm](A)[left of=dummy]{A};
\node[main node, node distance=2.5cm](D)[right of=dummy]{D};

\foreach \s/\t in {A/B, B/C, F/E, E/C, C/D}{\path[draw](\s)edge(\t);}
\end{tikzpicture}
\caption{A spanning tree with no cycles for the graph in Figure \ref{mst:graph1}.}
\label{mst:graph3}
\end{figure}

\begin{figure}[H]
\begin{tikzpicture}[node distance= 1.5cm, thick, main
	node/.style={circle, draw, minimum size = .75cm}]

\node[main node](B)[]{B};
\node[main node](C)[right of=B]{C};
\node[main node](F)[above of=B]{F};
\node[main node](E)[right of=F]{E};
\node[draw=none, node distance=.75cm](dummy)[above of= B]{};
\node[main node, node distance=1cm](A)[left of=dummy]{A};
\node[main node, node distance=2.5cm](D)[right of=dummy]{D};

\node[draw=none]at (-.6,.2)(3){3};
\node[draw=none]at (-.2,.75)(4){4};
\node[draw=none]at (.75,1.7)(4_2){4};
\node[draw=none]at (1.7,.75)(1){1};
\node[draw=none]at (2.1,.2)(1_2){1};
\node[draw=none]at (-.6,1.3)(6){6};
\node[draw=none]at (.75, -.2)(5){5};
\node[draw=none]at (2.1,1.3)(2){2};
\node[draw=none]at (.6,.6)(five){5};

\foreach \s/\t in {A/B, B/F, F/C, B/C, F/E, E/D, C/D, E/C, A/F, E/D}{\path[draw] (\s) edge (\t);}

\end{tikzpicture}
\caption{A weighted, undirected graph}
\label{mst:graph4}
\end{figure}

\begin{figure}[H]
\begin{tikzpicture}[node distance= 1.5cm, thick, main
	node/.style={circle, draw, minimum size = .75cm}]

\node[main node](B)[]{B};
\node[main node](C)[right of=B]{C};
\node[main node](F)[above of=B]{F};
\node[main node](E)[right of=F]{E};
\node[draw=none, node distance=.75cm](dummy)[above of= B]{};
\node[main node, node distance=1cm](A)[left of=dummy]{A};
\node[main node, node distance=2.5cm](D)[right of=dummy]{D};

\foreach \s/\t in {A/B, B/F, F/E, E/C, C/D}{\path[draw](\s)edge(\t);}
\node[draw=none]at (-.6,.2)(3){3};
\node[draw=none]at (-.2,.75)(4){4};
\node[draw=none]at (.75,1.7)(4_2){4};
\node[draw=none]at (1.7,.75)(1){1};
\node[draw=none]at (2.1,.2)(1_2){1};

\end{tikzpicture}
\caption{The MST of the graph in Figure \ref{mst:graph4}.}
\label{mst:graph5}
\end{figure}

\section*{Kruskal's algorithm}

Given a connected, weighted graph G with $n$ nodes, Kruskal's algorithm finds a minimum spanning tree. It is similar to Prim's algorithm, which also finds a minimum spanning tree of a connected, weighted graph. While Prim's algorithm is much faster for dense graphs since it avoids sorting the edges, it is much slower than Kruskal's for sparse graphs. Note that although we have not explicitly required that the graph be undirected, the fact that we are finding a minimum spanning tree means that the graph must be undirected.

Kruskal's algorithm first sorts the edges from smallest to largest, then starting with the smallest, the algorithm adds edges to the tree as long as the addition of each new edge does not create a cycle.
When $n-1$ edges have been added, the algorithm stops.

In order to avoid creating cycles while building the tree, it is necessary to keep track of which portions of the tree currently lie in connected groups.
This can be done by creating a dictionary where, when the algorithm starts, each node points to itself as the root of its own tree.
As we iterate over the edges, we compare the roots of the nodes connected by the edge. If they are distinct, then the nodes are in separate trees, so adding this edge will not create a cycle. When we add an edge, we update the root of one of the nodes connected by it so we can track which nodes are already connected by our growing MST.
We apply Kruskal's algorithm to the graph in Figure \ref{mst:graph4}. We are given a list of edges. Note that since the graph is undirected, we only have one entry for each edge instead of including both \li{(A, B, 2)} and \li{(B, A, 2)} for an edge from \li{A} to \li{B} with weight 2. Before beginning, we initialize what will become our MST as an empty list, initialize a dictionary \li{\{A:A, B:B, C:C, D:D, E:E, F:F\}} where each node points to itself, and sort the edges by weight to get the list \li{[(C, D, 1), (C, E, 1), (D, E, 2), (A, B, 3), (B, F, 4), (E, F, 4), (B, C, 5), (C, F, 5), (A, F, 6)]}. Since there are six nodes in the graph, we will continue until we have 5 edges in the tree.

\vspace{.25cm}

\begin{minipage}{0.35\textwidth}
\begin{tikzpicture}[node distance= 1.5cm, thick, main
	node/.style={circle, draw, minimum size = .75cm}]

\node[main node](B)[]{B};
\node[main node](C)[right of=B]{C};
\node[main node](F)[above of=B]{F};
\node[main node](E)[right of=F]{E};
\node[draw=none, node distance=.75cm](dummy)[above of= B]{};
\node[main node, node distance=1cm](A)[left of=dummy]{A};
\node[main node, node distance=2.5cm](D)[right of=dummy]{D};

\foreach \s/\t in {C/D}{\path[draw](\s)edge(\t);}
%\node[draw=none]at (1.7,.75)(1){1};
\node[draw=none]at (2.1,.2)(1_2){1};

\end{tikzpicture}
\end{minipage}\hfill
\begin{minipage}{0.55\textwidth}
We begin iterating through the edges to build the tree.
The first edge in the list is \li{(C,D,1)}.
The root for \li{C} is \li{C} and the root for \li{D} is \li{D}. Since their roots are distinct, they are in separate trees, so we add this edge to the tree. The tree becomes \li{[(C, D, 1)]}.
We then change the root node of \li{D} to \li{C}.
The dictionary of root nodes is now \li{\{A:A, B:B, C:C, D:C, E:E, F:F\}}.
\end{minipage}

\vspace{.25cm}

\begin{minipage}{0.35\textwidth}
\begin{tikzpicture}[node distance= 1.5cm, thick, main
	node/.style={circle, draw, minimum size = .75cm}]

\node[main node](B)[]{B};
\node[main node](C)[right of=B]{C};
\node[main node](F)[above of=B]{F};
\node[main node](E)[right of=F]{E};
\node[draw=none, node distance=.75cm](dummy)[above of= B]{};
\node[main node, node distance=1cm](A)[left of=dummy]{A};
\node[main node, node distance=2.5cm](D)[right of=dummy]{D};

\foreach \s/\t in {C/D, C/E}{\path[draw](\s)edge(\t);}
\node[draw=none]at (1.7,.75)(1){1};
\node[draw=none]at (2.1,.2)(1_2){1};

\end{tikzpicture}
\end{minipage}\hfill
\begin{minipage}{0.55\textwidth}
Now we process the next edge, \li{(C, E, 1)}.
The root node of \li{C} is \li{C}, and the root node of \li{E} is \li{E}, so adding this edge does not create a cycle.
We add this edge into the tree, so the tree is now \li{[(C, D, 1), (C, E, 1)]}.
Then we change the root of \li{E} to \li{C}, so the dictionary is \li{\{A:A, B:B, C:C, D:C, E:C, F:F\}}.
\end{minipage}

\vspace{.25cm}

The next edge is \li{(D, E, 2)}.
The root node of the tree containing \li{D} is \li{C} and the root node of the tree containing \li{E} is \li{C}, so these nodes are already connected, so we do not add this edge to the tree.

\vspace{.25cm}

\begin{minipage}{0.35\textwidth}
\begin{tikzpicture}[node distance= 1.5cm, thick, main
	node/.style={circle, draw, minimum size = .75cm}]

\node[main node](B)[]{B};
\node[main node](C)[right of=B]{C};
\node[main node](F)[above of=B]{F};
\node[main node](E)[right of=F]{E};
\node[draw=none, node distance=.75cm](dummy)[above of= B]{};
\node[main node, node distance=1cm](A)[left of=dummy]{A};
\node[main node, node distance=2.5cm](D)[right of=dummy]{D};

\foreach \s/\t in {A/B, E/C, C/D}{\path[draw](\s)edge(\t);}
\node[draw=none]at (-.6,.2)(3){3};
\node[draw=none]at (1.7,.75)(1){1};
\node[draw=none]at (2.1,.2)(1_2){1};

\end{tikzpicture}
\end{minipage}\hfill
\begin{minipage}{0.55\textwidth}
The next edge is \li{(A, B, 3)}.
The root node for \li{A} is \li{A}, and the root node for \li{B} is \li{B}, so we add the edge to the tree and change the root node of \li{B} to \li{A}.
The dictionary becomes \li{\{A:A, B:A, C:C, D:C, E:C, F:F\}}
\end{minipage}\hfill

\vspace{.25cm}

\begin{minipage}{0.35\textwidth}
\begin{tikzpicture}[node distance= 1.5cm, thick, main
	node/.style={circle, draw, minimum size = .75cm}]

\node[main node](B)[]{B};
\node[main node](C)[right of=B]{C};
\node[main node](F)[above of=B]{F};
\node[main node](E)[right of=F]{E};
\node[draw=none, node distance=.75cm](dummy)[above of= B]{};
\node[main node, node distance=1cm](A)[left of=dummy]{A};
\node[main node, node distance=2.5cm](D)[right of=dummy]{D};

\foreach \s/\t in {A/B, B/F, E/C, C/D}{\path[draw](\s)edge(\t);}
\node[draw=none]at (-.6,.2)(3){3};
\node[draw=none]at (-.2,.75)(4){4};
%\node[draw=none]at (.75,1.7)(4_2){4};
\node[draw=none]at (1.7,.75)(1){1};
\node[draw=none]at (2.1,.2)(1_2){1};

\end{tikzpicture}
\end{minipage}\hfill
\begin{minipage}{0.55\textwidth}
The next edge is \li{(B, F, 4)}.
The root node for \li{B} is \li{A} and the root node for \li{F} is \li{F}, so we add the edge to the tree and change the root node of \li{F} to \li{A}.
The dictionary becomes \li{\{A:A, B:A, C:C, D:C, E:C, F:A\}}
\end{minipage}\hfill

\vspace{.25cm}

\begin{minipage}{0.35\textwidth}
\begin{tikzpicture}[node distance= 1.5cm, thick, main
	node/.style={circle, draw, minimum size = .75cm}]

\node[main node](B)[]{B};
\node[main node](C)[right of=B]{C};
\node[main node](F)[above of=B]{F};
\node[main node](E)[right of=F]{E};
\node[draw=none, node distance=.75cm](dummy)[above of= B]{};
\node[main node, node distance=1cm](A)[left of=dummy]{A};
\node[main node, node distance=2.5cm](D)[right of=dummy]{D};

\foreach \s/\t in {A/B, B/F, F/E, E/C, C/D}{\path[draw](\s)edge(\t);}
\node[draw=none]at (-.6,.2)(3){3};
\node[draw=none]at (-.2,.75)(4){4};
\node[draw=none]at (.75,1.7)(4_2){4};
\node[draw=none]at (1.7,.75)(1){1};
\node[draw=none]at (2.1,.2)(1_2){1};

\end{tikzpicture}
\end{minipage}\hfill
\begin{minipage}{0.55\textwidth}
The next edge is \li{(E, F, 4)}.
The root node for \li{E} is \li{C} and the root node for \li{F} is \li{A}.
We add the edge to the tree and end the algorithm since there are now 5 edges in the tree.
(If we were to continue the algorithm, we would change the root node of \li{A} to \li{C}.)
\end{minipage}

\vspace{.25cm}

Notice how we updated the root of the root node to one of the nodes in the edge added.
We manage the root nodes in this manner in order to find the root node by tracing back through the dictionary until we find a node that points to itself.
For example, to find the root node of \li{F} we first need to get the value for \li{F} from the dictionary.  This is \li{A}.
Then we get the value for \li{A} from the dictionary which is \li{C}.
Since the value of \li{C} in the dictionary is itself, the \li{C} is the root node of the graph containing \li{F}.
It is necessary to trace through the dictionary in this manner each time because it allows us to avoid iterating over all of the nodes and updating their root values everytime.

Algorithm \ref{alg:kruskal} outlines the psuedocode for the algorithm as described above:
\begin{algorithm}
\begin{algorithmic}[1]
\Procedure{kruskal}{$edges$}
	\State $tree \gets \text{Empty list of edges for MST}$
	\State $nodes \gets \text{Dictionary that points each node towards its root, initially itself}$
	\State $remaining \gets \text{Set number of nodes to be processed to } n-1$
	\Function{track}{$node$} \Comment{Find the root of the given node}
		\State $temp \gets \text{Node whose root we are finding}$
		\While{$temp$ does not point to itself in the dictionary}
			\State Update $temp$ to be the node it currently points to in $nodes$
			\State \pseudoli{return} $temp$
		\EndWhile
	\EndFunction
	\For{$n_1, n_2, weight$ in sorted list of edges}
		\State $root \gets \text{Root node of } n_1$
		\State $remove \gets \text{Root node of } n_2$
		\If{$root$ is not $remove$}
			\State Add the edge to the tree
			\State Lower $remaining$ by 1
			\If{$remaining$ is 0}
				\State \pseudoli{return} $tree$
			\EndIf
			\State Change the value associated with $remove$ to $root$
		\EndIf
	\EndFor
\EndProcedure
\end{algorithmic}
\caption{Kruskal's algorithm for finding a MST}
\label{alg:kruskal}
\end{algorithm}

\begin{comment}
Previous description of the algorithm
\begin{itemize}

% Note: The comments in the solutions match the pseudocode.
% When making changes, please keep that in mind.

\item Initialize an empty list of edges for the minimum spanning tree.

\item Make a dictionary that points each node toward its root (not always directly to it).
Start with each node pointing to itself.

\item Initialize the number of nodes that still need to be processed to the number of nodes minus 1.

\item Define a helper function that, given a node, traces through the dictionary to find the root of its tree.
This can be done like this:

	\begin{itemize}

	\item Initialize a temporary variable to be the node for which we are finding the root.

	\item While the temporary node does not point to itself in the dictionary:

		\begin{itemize}

		\item Update the temporary node to be the node it currently points to in the dictionary.

		\end{itemize}

	\item Return the temporary node.

	\end{itemize}

\item Iterate over the edges by ascending weight.
Use a \li{for} loop for this and return the tree when it is big enough which breaks the loop for you.

	\begin{itemize}

	\item Trace through the dictionary to find the root node of each of the nodes in the edge you are processing.

	\item If the roots are not the same (i.e. if adding the edge doesn't form a cycle):

		\begin{itemize}

		\item Add the edge to the tree.

		\item Lower the number of edges remaining by one.

		\item If the number of edges remaining is 0, return the tree (which also breaks the loop).

		\item Update the root of the root of the second node in the edge to be the root of the first node in the edge.
			This lets us record that the two subtrees are now connected.

		\end{itemize}

	\end{itemize}

\end{itemize}
\end{comment}
Notice that if $remaining$ is 0, that means that the MST is as big as it needs to be and the for loop ends, and that updating the root of the second node in the edge is what allows us to check if two nodes are already connected.

You can iterate over a sorted copy of a list using the built in \li{sorted} function.
You can sort by the third value in each tuple using the \li{itemgetter} function that is part of the \li{operator} library included with Python.
For example:
\begin{lstlisting}
from operator import itemgetter

for n1, n2, weight in sorted(edges, key=itemgetter(2)):
    ...
\end{lstlisting}

\begin{problem}
Implement Kruskal's algorithm as in Algorithm \ref{alg:kruskal}
Test your algorithm on lists of weighted edges generated by the \li{randgraph} function below. Also use the data from MSTdata.npy to test your algorithm.
Use np.load("MSTdata.npy") to get it, and use the \li{formChanger} function below to put it in the right form.
\begin{lstlisting}
from scipy import linalg as la
import numpy as np

# n is the number of nodes in the graph
def randgraph(n):
    # Creates a sparse upper triangular matrix of ints between 1 and 50
    A = la.triu(np.random.randint(1,50,(n,n))*(np.random.rand(n,n)>.5))
    S = []
    # Iterate through (i,j) pairs in A; x is the value of (i,j)
    for index, x in np.ndenumerate(A):
        # If an edge exists
        if x != 0:
            # Append (i,j) as an edge with weight x
            S.append((str(index[0]), str(index[1]), x))

def formChanger(oldData):
    newData=[]
    for i in oldData: newData.append((i[0],i[1],int(i[2])))
    return newData
\end{lstlisting}
\end{problem}

\begin{comment}
\section*{Prim's algorithm}

Prim's is a similar algorithm for finding minimum spanning trees.
While it is much slower than Kruskal's algorithm for sparse graphs, it is much faster for dense graphs because Prim's algorithm avoids sorting the edges.

Again, consider the example shown in Figure 7.4.
We first initialize a dictionary with all the nodes as keys in order to track which nodes have not been processed.
At the beginning it will be \li{\{A:False, B:False, C:False, D:False, E:False, F:False\}}.
We then form the dictionary that maps each node to the edges that contain it.
Since we will already know one node of each edge while we use the dictionary, we only need to store the node that is not being looked up.
It should end up looking like \li{\{A:[(B, 3), (F, 6)], B:[(A, 3), (C, 5), (F, 4)], C:[(B, 5), (D, 1), (E, 1), (F, 5)], D:[(C, 1), (E, 2)], E:[(C, 1), (D, 2), (F, 4)], F:[(A, 6), (B, 4), (C, 5), (E, 4)]\}}.
We will also initialize an empty dictionary to track the shortest edges that run between nodes we have processed and nodes that we haven't.
As we iterated over the edges in our initialization step, we are also able to find the shortest edge.
In this case, it is \li{(D, C, 1)}.
Let's start with \li{(D, C, 1)} and initialize our tree as the list \li{[(D, C, 1)]}.
Next, we mark \li{D} and \li{C} as processed in the dictionary that tracks which nodes have been processed.
We now start to build our dictionary of nodes that are one edge away from our processed nodes.
In this case, after adding the shortest edges between processed and unprocessed nodes to the dictionary, the dictionary becomes \li{\{B:(C, B, 5), E:(C, E, 1), F:(C, F, 5)\}}.
Notice we did not include \li{E:(D, E, 2)} because there is a shorter edge to \li{E} from \li{C}.

Of the edges in the dictionary of edges that can be processed next, the shortest is \li{(C, E, 1)}, so we add that edge to the tree and mark \li{E} as processed.
With \li{E} being processed, we can now reach \li{F} at a cost of 4.
After making this change, the dictionary of edges to process becomes \li{\{B:(C, B, 5), E:(C, E, 1), F:(E, F, 4)\}}.
Since \li{E} no longer needs to be processed, we can remove it from consideration.
So this dictionary now becomes \li{\{B:(C, B, 5), F:(E, F, 4)\}}.

Of the edges to be processed next, \li{(E, F, 4)} is the shortest, so we add it to the tree and mark \li{F} as processed.
After performing the appropriate modifications to the dictionary of edges to be processed next, it becomes \li{\{B:(F, B, 4), A:(F, A, 6)\}}.

Of the edges to be processed next, \li{(F, B, 4)} is the shortest, so we add it to the tree and mark \li{B} as processed.
After performing the appropriate modifications to the dictionary of edges to be processed next, it becomes \li{\{A:(B, A, 3)\}}.

The only edge to be considered is \li{(B, A, 3)}, so we add it to the tree.
The tree is long enough that it it spans the nodes, so the algorithm is finished.

Here's pseudocode for a version of Prim's algorithm.
While it is not a perfectly optimized version, it is pretty good.

\begin{itemize}

% Note: The comments in the solutions match the pseudocode.
% When making changes, pleas keep that in mind.

\item Initialize a dictionary to track which nodes have been processed.

\item Initialize an empty dictionary of lists to track the edges containing each node.

\item Fill the edge list.
	Be sure to add each edge to the list corresponding to both of its nodes.

\item Get the first edge to add (The shortest edge from any given node is a good pick).

\item Mark the nodes in the first edge as processed.

\item Initialize the tree to be the list containing the first edge.

\item Initialize an empty dictionary that will be used to contain the edges that can be processed next.

\item Define a helper function to insert an edge into the dictionary (if that insertion is needed).
	This can be done as follows:

	\begin{itemize}

	\item Get the value of the node that is reached by the edge.

	\item If that node isn't in the dictionary, set its value to be the edge passed to the functions.

	\item If it is in the dictionary already, set its value to be the shorter of the edges being processed and the edges already in the dictionary.

	\end{itemize}

\item Use the helper function to insert the edges reached by the first two processed nodes into the dictionary of edges to be processed.

\item Until the tree contains enough edges to span all the nodes:

	\begin{itemize}

	\item Find the shortest edge in the dictionary of edges to be processed.

	\item Remove the shortest edge from the dictionary.

	\item Add it to the tree.

	\item Mark the node reached by the new edge as processed.

	\item Use the helper function to insert the edges reached by the newly processed node into the dictionary of edges to be processed.

	\end{itemize}

\item Return the completed tree.

\end{itemize}

\begin{problem}
Write a Python function that uses Prim's algorithm to find the minimum spanning tree of a graph.
Test your implementation with the same data as the previous problem.
Compare the speed of Prim's algorithm with the speed of Kruskal's algorithm.
Create a function which prints these two times.
\end{problem}
\end{comment}

\section*{NetworkX}

You have already used the NetworkX to find the shortest path between nodes in a graph. You can also use NetworkX to find the minimal spanning tree. Recall that NetworkX is used as follows:
\begin{lstlisting}
import networkx as nx

# Create an undirected graph G.
G = nx.Graph()
# Add the node x.
G.add_node(x)

# Add an edge with weight n from x to y.
# Remember that NetworkX will add nodes in an edge if they do not already exist and does not permit duplicate nodes
G.add_edge(x, y, weight=n)

# Add multiple nodes from a list at once
G.add_nodes_from(N)

# Return the minimal spanning tree using Kruskal's algorithm
nx.minimum_spanning_tree(G)
\end{lstlisting}

\begin{problem}
Use NetworkX to find the minimal spanning tree of the data in MSTdata.npy.
Compare the timing of your implementation with that of NetworkX.

\emph{Helpful Hint:} You should not use the output of your \li{formChanger} function to create your NetworkX graph. Instead, use a for loop to iterate over the original data and add an edge \li{i[0], i[2], weight=int(i[2])} for each element \li{i} .
\end{problem}

%Add specifications

\section*{Image Segmentation}

%Lab \ref{MSTImgSeg}

One application of Minimal Spanning Trees (MSTs) is image segmentation.
Kruskal's algorithm is especially good at this.
You can convert an image into a graph. Each pixel becomes a node and you define weights between the nodes. You then build the minimal spanning tree. If you take away the edge with the greatest weight you will get two forests (removing an edge from any graph with no cycles will create two forests). Then you can continue doing this to each forest to split up those forests. Each forest corresponds to a segment of the image.
Let $k$ be the number of divisions that is wanted and $n$ be the number of nodes.
Kruskal's algorithm is performed until $n-(k+1)$ edges are added, which is equivalent to taking out the $k$ edges with greatest weights.

There are many different ways to turn an image into a graph and weight the edges.
A simple, yet effective, version is to make every pixel a node and the edges are the difference in intensities in the four cardinal directions.

This means that there are less than $4n$ edges in the graph.
Other image segmentation algorithms have to use $n^2$ space.
This gives the MST algorithm a critical advantage over other image segmentation algorithms.

\begin{problem}
Write a function that takes a black and white .jpg image as input and outputs a list of the weighted edges.
Store the edges using the form \li{(node,node,weight)}. Use \li{scipy.ndimage.imread('filename.jpg')} to read in an RGB .jpg image. The output will be a three-dimensionsal Numpy array with the third dimension representing the red, green, and blue intensities of each pixel. In a black and white image, these will all be the same, so use the command \li{array[:,:,0]} to create a two-dimensional array with values set as the zeroth index of the corresponding list in the three dimensional array.

\emph{Helpful Hint:} Use the \li{ndenumerate()} command to easily iterate through the indices of the array. Keep in mind that since the array is bidirectional, you do not actually have to create four edges for every index.
\end{problem}

Our original Kruskal's algorithm returns a list of edges representing a MST. We modify this algorithm to take in an additional argument representing the number of divisions desired and return a dictionary with the nodes as the keys and their roots as the values (remember that the dictionary used in the original algorithm points \emph{towards} the root instead of pointing to the root itself). The number of distinct roots is the number of divisions, and the number of keys associated with each root gives the size of its tree. When we segment an image, the number of divisions often has to be higher than the actual number that is needed because sometimes one or two pixels form a division because the difference between them and the pixels around them is so great. You will have to adjust the number of divisions until the desired result is found.  See Figure \ref{mst:segmented}.

\begin{algorithm}
\begin{algorithmic}[1]
\Procedure{kruskal}{$edges$, $div$}
	\State $nodes \gets \text{Dictionary that points each node towards its root, initially itself}$
	\State $end \gets \text{Set number of nodes to be processed to } n-div$
	\Function{track}{$node$} \Comment{Find the root of the given node}
		\State $temp \gets \text{Node whose root we are finding}$
		\While{$temp$ does not point to itself in the dictionary}
			\State Update $temp$ to be the node it currently points to in $nodes$
			\State \pseudoli{return} $temp$
		\EndWhile
	\EndFunction
	\For{$n_1, n_2, weight$ in sorted list of edges}
		\State $root \gets \text{Root node of } n_1$
		\State $remove \gets \text{Root node of } n_2$
		\If{$root$ is not $remove$}
			\State Lower $end$ by 1
			\If{$end$ is 0}
				\State Change the value associated with $remove$ to $root$
				\State \pseudoli{return} dict with nodes as keys and their roots as values
			\EndIf
			\State Change the value associated with $remove$ to $root$
		\EndIf
	\EndFor
\EndProcedure
\end{algorithmic}
\caption{Modified Kruskal's algorithm for Image Segmentation}
\label{alg:modifiedkruskal}
\end{algorithm}

\begin{problem}
Convert the given image to a list of weighted edges using your previous solution. Implement the modified Kruskal's algorithm as described above and use it to segment the image, then graph the original image and the three largest divisions.

\emph{Helpful Hint:} Use the \li{Counter} class from \li{collections} to find the number of pixels (nodes) in each divisions, plot the images as subplots, and use \li{plt.imshow()} to view the images.
\end{problem}

\begin{comment}
\begin{problem}
Make a division of the image a different color.
\end{problem}
\end{comment}

\vfill
\begin{figure}[ht]
\begin{minipage}[b]{0.47\linewidth}
\centering
\includegraphics[width=\textwidth]{MSTseg1.jpg}
\end{minipage}
\hspace{0.5cm}
\begin{minipage}[b]{0.47\linewidth}
\centering
\includegraphics[width=\textwidth]{MSTseg2.jpg}
\end{minipage}
\begin{minipage}[b]{0.47\linewidth}
\centering
\includegraphics[width=\textwidth]{MSTseg3.jpg}
\end{minipage}
\hspace{0.5cm}
\begin{minipage}[b]{0.47\linewidth}
\centering
\includegraphics[width=\textwidth]{MSTseg4.jpg}
\end{minipage}
\caption{The original image is in the top left hand corner. The three largest segments are shown in the other corners. The original image was 498x498 and 50000 divisions were used.}
\label{mst:segmented}
\end{figure}
\vfill


\section{Part 3. Linear Structure Growth}

The file of the functions used for this exercise is:

\lstinputlisting{part_three.py}

The result of this function is shown in \ref{fig:lgf}:

\begin{figure}[h!]
  \centering
  \includegraphics[width=0.9\linewidth]{./plots/growth_factors.png}
  \caption{Linear Growth Factors for different cases.}
  \label{fig:lgf}
\end{figure}

As can be seen from the plot, the numerical solution is close the analytical solution, but not exact.
The Runge-Kutta 4th order method was chosen for its ease of implementation and relative accuracy.
One issue that I was not able to figure out was for the third case, the analytical and numerical solutions differ by
quite a bit. This is unexpected, since the other two cases, it does match fairly closely. Infact, the third case, the numerical
solution seems to converge on the first case for some reason. Quite possibly going to a 5th order Runge-Kutta could fix the issue,
but there was not time to implement it.

I did not have time to determine why this is the case and fix it.


\section{Numerical Results}
\label{sec:numerical_results}

In this section we present the numerical results of the online version of the policy gradient algorithms discussed in Section \ref{sec:basics_reinforcement_learning} for the asset allocation problem.

\subsection{Synthetic Asset}
To assess the different reinforcement learning methods in a controlled environment, the algorithms have been tested on a synthetic asset whose behavior presents some features that can be traded profitably. We simulated the log-price series $\{z_t\}$ for the risky asset as a random walk with autoregressive trend $\{\beta_t\}$. The two-parameter model is thus given by
\begin{equation}
	\begin{split}
		z_t &= z_{t-1} + \beta_{t-1} + \kappa \epsilon_t\\
		\beta_t &= \alpha \beta_{t-1} + \nu_t\\
	\end{split}
\end{equation}
We then define the synthetic price series as
\begin{equation}
	Z_t = \exp\left(\frac{z_t}{\max_t z_t - \min_t z_t}\right)
\end{equation}
This model is often taken as a benchmark test in the automated trading literature, see for instance \cite{moody1998performance}. In addition to presenting some exploitable patterns, the model is stationary and therefore the policy learned on the training set should generalize well on the test set, also known as backtest in the financial jargon. We would thus expect our learning algorithms to perform well on this test case.

\subsection{Experimental Setup}
All the algorithms were tested on the same price series of size $9000$, generated from the process above using $\alpha = 0.9$ and $\kappa = 3$. The learning process consisted of $500$ training epochs on the first $7000$ days of the series with a learning rate that decreased at each epoch according to a polynomial schedule. The trained agents were subsequently backtested on the final $2000$ days, during which the agents kept learning online in order to try to adapt to the changing environment. The results that we present are the average of $10$ independent experiments that used slightly different random initialization of the policy parameters.

\subsection{Convergence}
Let us first discuss the case with no transaction costs. Figure \ref{fig:single_synthetic_neutral_convergence} shows the learning curves three algorithms in terms of average daily reward, which is the quantity being maximized by the algorithms, the daily reward standard deviation and the annualized Sharpe ratio.
The NPGPE algorithm is an enhancement of the PGPE algorithm based on the natural gradient technique \cite{miyamae2010natural}. The first thing we observe is the ARAC algorithm seems not to be improving the trading strategy as the training epochs go by. The average reward obtained is close to zero and will be surely be negative once transaction costs are introduced. On the other hand, NPGPE slowly converges to a profitable strategy which is however suboptimal compared to the one found by PGPE, that is better in all three measures considered. It is interesting to notice that PGPE and NPGPE yield a learning curve for the Sharpe ratio very similar to the one for the average reward. Even if the algorithm is risk-neutral, it manages to improve a risk-senitive measure at the same time of the average reward. This might be simply a peculiarity of the very simple model assumed for the synthetic risky asset. Moreover, since the price process is stationary, the trading strategy learned on the training set generalizes well to the test set.
\begin{figure}[t!]
	\centering
	\includegraphics[height=6cm,width=1.0\textwidth]{Images/6_0_single_synthetic_neutral_convergence}
	\caption[Risk-neutral learning process for one synthetic risky asset]{Risk-neutral learning process for the asset allocation problem with one synthetic risky asset.}
	\label{fig:single_synthetic_neutral_convergence}
\end{figure}

\subsection{Performances}
Figure \ref{fig:single_synthetic_neutral_performance} compares the backtest performances of the three learned policies and a Buy and Hold strategy, which simply consists in investing all the available capital in the risky asset. Let us repeat that the solid lines are the averages of $10$ independent experiments, which allows us to determine the $95\%$ confidence intervals represented with the dashed lines. We clearly see that NPGPE and PGPE consistently outperform the market, realizing a total profit of $231.63\%$ and $314.34\%$ respectively against the $7.81\%$ profit of the Buy and Hold strategy over the same period. More statistics of the trading strategies are reported in Table \ref{tab:single_synthetic_neutral_performance}.
\begin{figure}[t]
	\centering
	\includegraphics[height=6cm,width=1.0\textwidth]{Images/6_1_single_synthetic_neutral_performance}
	\caption[Backtest performance with one synthetic risky asset]{Backtest performance of trained trading systems for the asset allocation problem with one synthetic risky asset.}
	\label{fig:single_synthetic_neutral_performance}
\end{figure}
\begin{table}[t!]
\centering
\begin{tabular}{@{}lllll@{}}
\toprule
 & \multicolumn{1}{c}{Buy and Hold} & \multicolumn{1}{c}{ARAC} & \multicolumn{1}{c}{NPGPE} & \multicolumn{1}{c}{PGPE} \\ \midrule
Total Return & 7.81\% & -0.86\% & 231.63\% & 314.34\% \\
Daily Sharpe & 0.27 & -0.02 & 4.13 & 4.95 \\
Monthly Sharpe & 0.19 & -0.07 & 2.90 & 3.26 \\
Yearly Sharpe & 0.23 & -0.10 & 1.55 & 1.76 \\
Max Drawdown & -22.35\% & -12.60\% & -3.72\% & -3.27\% \\
Avg Drawdown & -1.75\% & -1.81\% & -0.49\% & -0.43\% \\
Avg Up Month & 2.87\% & 1.14\% & 2.47\% & 2.74\% \\
Avg Down Month & -2.58\% & -1.10\% & -0.73\% & -0.67\% \\
Win Year \% & 40.00\% & 44.00\% & 98.00\% & 100.00\% \\
Win 12m \% & 56.36\% & 48.00\% & 100.00\% & 100.00\% \\
Reallocation Freq & 0.00\% & 50.01\% & 19.99\% & 15.43\% \\
Short Freq & 0.00\% & 50.13\% & 41.59\% & 44.25\% \\ \bottomrule
\end{tabular}
\caption[Backtest statistics for risk-neutral learning with one synthetic risky asset]{Backtest statistics of the risk-neutral trading strategies for the asset allocation problem with one synthetic risky asset.}
\label{tab:single_synthetic_neutral_performance}
\end{table}

\subsection{Impact of Transaction Costs}
In the algorithmic trading literature there are many examples of strategies based on the prediction of future returns based on more or less complex indicators \cite{kamijo1990stock}, \cite{saad1998comparative}, \cite{liang2011stock}. However, as pointed out in \cite{deng2016deep}, the performances of these methods quickly degrade when transaction costs for changing the portfolio composition or for shorting a security
are considered. Indeed, these methods simply invest based on the prediction of the future returns, without explicitly taking into account transaction costs. On the other hand, reinforcement learning algorithms should learn to avoid frequent reallocations or shorts thanks to the feedback mechanism between the learning agent and the system, thus generating better trading performances. In this section we analyze how the strategies learned by PGPE and by NPGPE change when gradually increasing the proportional transaction costs and the short-selling fees. Intuitively, we expect a progressive reduction of the frequency of reallocation and of shorting the risky asset.\\
Figure \ref{fig:impact_transaction_costs} shows the impact of proportional transaction costs on the trading strategies learned by PGPE and by NPGPE. As expected, the frequency of reallocation for both strategies quickly drops to zero as the transaction costs increase, converging to the profitable buy and hold strategy. It is peculiar that the reallocation frequency for the PGPE strategy initially drops more quickly than for the NPGPE strategy, but then slows down and even increases when $\delta_P = 20$ bps.
In summary, both algorithms are able to identify reallocation as the cause for lower rewards and to subsequently reduce the rate of reallocation, converging towards the simple yet profitable buy and hold strategy. Figure \ref{fig:impact_short_selling_fees} shows the impact of short-selling fees on the trading strategies learned by PGPE and NPGPE. Both algorithms behave as expected, displaying a progressive reduction of the frequency of short positions as the fees increase. For large values of short-selling fees, both strategies converge to the profitable buy and hold strategy, which completely avoids paying the fees. In particular, PGPE quickly replicates the buy and hold strategy. On the other hand, NPGPE is not able to exactly reproduce the buy and hold strategy but it seems to converge to it for very large values of the short-selling fee.
\begin{figure}[t!]
	\centering
	\includegraphics[height=6cm,width=1.0\textwidth]{Images/6_2_impact_transaction_costs}
	\caption[Impact of proportional transaction costs]{Impact of proportional transaction costs on the trading strategies learned by PGPE and NPGPE.}
	\label{fig:impact_transaction_costs}
\end{figure}

\begin{figure}[t!]
	\centering
	\includegraphics[height=6cm,width=1.0\textwidth]{Images/6_3_impact_short_selling_fees}
	\caption[Impact of short-selling fees]{Impact of short-selling fees on the trading strategies learned by PGPE and NPGPE.}
	\label{fig:impact_short_selling_fees}
\end{figure}