commit 21b03f3ad07ee7cc7ea187a0076dff35d885aa20
parent 85dc0e2402254ea37a14d03822f174e95d757092
Author: Andrew Laack <andrew@laack.co>
Date: Sat, 7 Feb 2026 17:33:08 -0600
Pruning
Diffstat:
29 files changed, 0 insertions(+), 2343 deletions(-)
diff --git a/latex/DeepLearning-Goodfellow/DeepLearning.tex b/latex/DeepLearning-Goodfellow/DeepLearning.tex
@@ -1,655 +0,0 @@
-\documentclass[12pt, letterpaper]{article}
-\usepackage{xcolor}
-
-
-\usepackage{enumitem}
-\usepackage{graphicx}
-\usepackage{listings}
-\usepackage{caption}
-\usepackage{tcolorbox}
-\usepackage{datetime}
-\usepackage{amsfonts}
-\usepackage{amsmath}
-\usepackage{geometry}
-\geometry{verbose,tmargin=1in,bmargin=1in,lmargin=1in,rmargin=1in}
-\usepackage{amssymb,enumerate}
-\usepackage{amsthm,stmaryrd}
-\usepackage[all]{xy}
-
-\newenvironment{definition}{
- \begin{quote}
- \textbf{Definition:}
- }{
- \end{quote}
-}
-
-
-\newenvironment{explanation}{
- \begin{quote}
- \textbf{Explanation:}
- }{
- \end{quote}
-}
-
-\newenvironment{example}{
- \begin{quote}
- \textbf{Example:}
- }{
- \end{quote}
-}
-
-\lstnewenvironment{code}{
- \hspace{.45cm}\textbf{Code:}
- \lstset{
- basicstyle=\ttfamily,
- columns=fullflexible,
- breaklines=true
- }
-}{
-}
-
-
-\begin{document}
-
-\noindent{\large \textbf{Deep Learning by Ian Goodfellow}}
-
-\noindent Notes by Andrew Laack
-
-\tableofcontents
-
-\section{Linear Algebra}
-
-
-\subsection{Broadcasting}
-
-\begin{definition}
-Broadcasting is the process of iteratively applying a lower dimensional operation on higher dimensionalt structures.
-\end{definition}
-
-\begin{explanation}
-
-Assume \[ C = A + b\]
-
-and \[ C,A \in \mathbb{R}^{m,n}, b \in \mathbb{R}^n. \]
-
-With this, we see we are adding an $n$ dimentional vector to an $m \times n$ matrix. For this to be well defined, we know the $n$ indicies must relate to each other. In the case of the matrix, we have $n$ columns and thus we add each $b_i$ to $A_{:,i}$.
-
-\end{explanation}
-
-\begin{example}
-
-Assume
-
-\begin{align*}
- A = \begin{bmatrix}
- 3 & 4 & 1 \\
- 5 & 7 & 8
- \end{bmatrix},
- b = \begin{bmatrix} 1 & 2 & 3 \end{bmatrix}^\top
-\end{align*}
-
-Compute $C = A + b$
-
-\begin{align*}
-&= \begin{bmatrix}
- 3 & 4 & 1 \\
- 5 & 7 & 8
- \end{bmatrix} + \begin{bmatrix}1 & 2 & 3\end{bmatrix}\\
-&= \begin{bmatrix}
- 4 & 6 & 4 \\
- 6 & 9 & 11
-\end{bmatrix}
-\end{align*}
-
-\end{example}
-
-\begin{code}
- import numpy as np
-
- B = np.array([[6,2,8], [2,9,8]])
- a = [2, 1, 2]
- D = np.empty((len(B), len(B[0])))
-
- for i in range(len(B)):
- for j in range(len(B[i])):
- D[i][j] = B[i][j] + a[j]
-
- # Alternatively
- D = B + a
-
-\end{code}
-
-\subsection{Matrix Multiplication}
-
-\begin{definition}
- The product of A and B, C, is defined as \[C_{i,j} = A_{i,:}^\top \cdot B_{:,j}.\]
-\end{definition}
-
-\begin{explanation}
- If $C = AB$ then the index $i,j$ is the dot product between the transpose of the $i$'th row vector of A and the $j$'th column vector of B. The row vector must be transposed, or vice versa, as dot products are defined for like vectors.
-
- Additionally, we note that the number of \textbf{columns} of A must be equal to the number of \textbf{rows} in B. The result will be a matrix that has as many rows as A and as many columns as B.
-
- \textbf{Properties:} Matrix multiplication is distributive and associative, but not commutative. Transposition also has an interesting property.
- \begin{align*}
- A(B + C) &= AB + AC\\
- A(BC) &= (AB)C \\
- AB &\not\equiv BA \\
- (AB)^\top &= B^\top A^\top
- \end{align*}
-\end{explanation}
-
-\begin{example}
- Compute $C = A \cdot B$
- \begin{align*}
- A = \begin{bmatrix}
- 4 & 3 & 4 \\
- 1 & 1 & 5 \\
- 2 & 3 & 6
- \end{bmatrix},
- B = \begin{bmatrix}
- 3 & 1 & 7 \\
- 1 & 2 & 1 \\
- 2 & 4 & 2
- \end{bmatrix}
- \end{align*}
-
- \begin{align*}
- C &= AB \\
- &= \begin{bmatrix}
- 4 & 3 & 4 \\
- 1 & 1 & 5 \\
- 2 & 3 & 6 \\
- \end{bmatrix}
- \cdot
- \begin{bmatrix}
- 4 & 3 & 4 \\
- 1 & 1 & 5 \\
- 2 & 3 & 6 \\
- \end{bmatrix} \\
- & =
- \begin{bmatrix}
- 23 & 26 & 39 \\
- 14 & 23 & 18 \\
- 21 & 32 & 29 \\
- \end{bmatrix} \\
- \end{align*}
-
-\end{example}
-
- \begin{code}
- import numpy as np
-
- A = np.array([[4,3,4],[1,1,5],[2,3,6]])
- B = np.array([[3,1,7],[1,2,1],[2,4,2]])
- C = A @ B # matrix multiplication
- C = A.__matmul__(B) # more explicit
-
- def matMul(A, B):
- C = np.empty((len(A), len(B[0])))
- for i in range(0, len(A)):
- for j in range(0, len(B[0])):
- C[i][j] = A[i].dot(B[:,j])
- return C
-
- C = matMul(A,B)
- \end{code}
-
-\subsection{Inverse Matrices}
-
-\begin{definition}
- The inverse matrix of $A$ is $A^{-1}$ such that $A^{-1}A = AA^{-1} = I_n$.
-\end{definition}
-
-\begin{explanation}
-The inverse of a matrix is the matrix whose product is the identity matrix. If both the left and right inverses exist, the matrix $A$ is considered invertible. If $A$ only does not have the same left and right inverses, it is not invertible. For a matrix to be invertible $\text{rank}(A) = n$ and $A \in R^{n \times n}$. Non-square matrices may have inverses, if they have full column or row rank, but such inverses are not two-sided or unique.
-
-\end{explanation}
-
-\subsubsection{Finding Inverse Matrices (Gauss-Jordan)}
-
-\begin{explanation}
- We can solve for the inverse of a matrix using a variant of Gaussian elimination called Gauss-Jordan elimination. We start by constructing an augmented matrix of the form
-
- \begin{align*}
- \begin{bmatrix}
- A & | & I_n
- \end{bmatrix}.
- \end{align*}
-
- We then perform elementary row operations on the matrix until we have
-
- \begin{align*}
- \begin{bmatrix}
- I_n & | & A^{-1}
- \end{bmatrix}.
- \end{align*}
-
- In essence, we convert $A$ into the identity matrix, and the same row operations applied to $I_n$ produces $A^{-1}$.
-
-\end{explanation}
-
-\begin{example}
- Invert the matrix
- \begin{align*}
- A :=
- \begin{bmatrix}
- 2 & 8 \\
- 1 & 3
- \end{bmatrix}
- \end{align*}
-
- Clearly, the matrix is linearly independent and square thus invertible. We thus perform the following steps:
-
- \begin{align*}
- &\begin{bmatrix}
- 2 & 8 & | & 1 & 0 & \\
- 1 & 3 & | & 0 & 1 & \\
- \end{bmatrix} \\
- = &
- \begin{bmatrix}
- 1 & 5 & | & 1 & -1 & \\
- 1 & 3 & | & 0 & 1 & \\
- \end{bmatrix} \\
- = &
- \begin{bmatrix}
- 1 & 5 & | & 1 & -1 & \\
- 0 & -2 & | & -1 & 2 & \\
- \end{bmatrix} \\
- = &
- \begin{bmatrix}
- 1 & 0 & | & -1.5 & 4 & \\
- 0 & 1 & | & .5 & -1 & \\
- \end{bmatrix} \\
- \end{align*}
-
- As such, we have
-
- \begin{align*}
- A^{-1} = &
- \begin{bmatrix}
- & -1.5 & 4 & \\
- & .5 & -1 & \\
- \end{bmatrix} \\
- \end{align*}
-
-\end{example}
-
-\subsubsection{Solving a System of Linear Equations With Inverse Matrices}
-
-\begin{explanation}
- To find the solution to the system of equations
-
- \begin{align*}
- Ax &= b
- \end{align*}
-
- where
-
- \begin{align*}
- A \in \mathbb{R}^{n,n}, \text{ rank } (A) = n, x,b \in \mathbb{R}^n
- \end{align*}
-
- We first note that since the rank of $A$ is $n$, and $A \in \mathbb{R}^{n,n}$, $A$ is invertible. We use this information as follows:
-
- \begin{align*}
- Ax &= b \\
- A^{-1}Ax &= A^{-1}b\\
- I_nx &= A^{-1}b \\
- x &= A^{-1}b
- \end{align*}
-
- The vector $b$ is known, and we are trying to solve for $x$. Given this, we can use our procedure for finding $A^{-1}$ to solve the system of equations for $x$.
-
-\end{explanation}
-
-\begin{example}
- example
-\end{example}
-
-\begin{code}
- import numpy as np
-
- A = np.array([[10, 2, 3], [1, 4, 1], [9, 1, 3]])
- b = np.array([10, 2, 3])
- A_inv = np.linalg.inv(A)
- result = A_inv @ b
- print(result)
-\end{code}
-
-\subsection{Norm}
-
-\begin{definition}
- A norm is a function $f : X \to \mathbb{R}$, where $X$ is a vector space, such that
-
- \begin{align*}
- f(x + y) &\leq f(x) + f(y), &&\text{for all } x, y \in X \quad \text{(Triangle Inequality)} \\
- f(ax) &= |a| \cdot f(x), &&\text{for all } a \in \mathbb{R}, x \in X \quad \text{(Absolute Homogeneity)} \\
- f(x) = 0 &\implies x = 0, &&\text{for all } x \in X \quad \text{(Positive Definiteness)}
- \end{align*}
-\end{definition}
-
-\begin{explanation}
-
- While a norm has a formal definition, we are often concerned with the Frobenius and $L_p$ for $p \in \mathbb{N} \cup \{\infty\}$ norms in machine learning.
-
- The $L_2$ norm is simply the euclidean distance between $\vec{0}$ and $x$. This function can be stated as
-
- \begin{align*}
- L_2(x) &= \sqrt{\sum_{i=1}^{n} x_i^2}
- \end{align*}
-
- More generally, the $L_p$ norm is defined as:
-
- \begin{align*}
- L_p(x) &= \left( \sum_{i=1}^{n} |x_i|^p \right)^{1/p}
- \end{align*}
-
- It is important to point out that the $L_0$ norm is not a true norm. It does not have the absolute homogeneity property, but the metric is nevertheless useful for counting the number of non-zero coordinates in a vector. We also note the $L_\infty$ norm is defined as \[ ||x||_\infty = \max_{i} (x_i).\]
-
-The Frobenius norm is used on matrices and is a generalization of the $L_2$ norm. It can be stated as follows:
-
- \begin{align*}
- \|X\|_F = \left( \sum_{i=1}^{n} \sum_{j=1}^{n} x_{i,j}^2 \right)^{1/2}
- \end{align*}
-\end{explanation}
-
-\begin{code}
- x = [1, 3, 5]
- p = 2
-
- sum = 0
- for i in x:
- sum += i**p
-
- res = sum ** (1/p)
-\end{code}
-
-
-\subsection{Orthogonal Matrix}
-
-\begin{definition}
- definition
-\end{definition}
-
-\begin{explanation}
- explain
-\end{explanation}
-
-\begin{example}
- example
-\end{example}
-
-\subsection{LU Decomposition}
-
-\begin{definition}
- definition
-\end{definition}
-
-\begin{explanation}
- explain
-\end{explanation}
-
-\begin{example}
- example
-\end{example}
-
-\subsection{Determinant}
-
-\begin{definition}
- The determinant of a matrix
-\end{definition}
-
-\begin{explanation}
- Conceptually, the determinant of a matrix is the signed $n$-dimensional volume of the image of the unit $n$-cube under the linear transformation defined by the matrix. Given this, we see if det$(A) = 0$, $A$ is singular.
-
- To solve for the determinant, we can use Gaussian elimination, cofactor expansion, or a handful of other approaches. For simplicity, I will use Gaussian elimination in my example, and we note the product of the diagonal entries of the upper triangular matrix are the determinant of the matrix.
-\end{explanation}
-
-\begin{example}
- Compute the determinant of
- \begin{align*}
- A :=
- \begin{bmatrix}
- 10 & 4 & 2 & 1 \\
- 8 & 3 & 1 & 2 \\
- 2 & 6 & 7 & 5 \\
- 5 & 1 & 1 & 3 \\
- \end{bmatrix}.
- \end{align*}
-
- Perform LU decomposition, find we don't need any row swaps, and
-
- \begin{align*}
- U
- \approx
- \begin{bmatrix}
- 10 & 4& 2& 1 \\
- 0 & 5.2& 6.6 & 4.8 \\
- 0 & 0. & 1.26923077 & 3.42307692 \\
- 0 & 0. & 0. & 2.31818182 \\
- \end{bmatrix}.
- \end{align*}
-
- (Note: if we have an even number of row swaps, the determinant is positive. If we have an odd number, it is negative.)
-
- Multiply the pivots together to find det$(A) = 153$.
-
-
-\end{example}
-
-\begin{code}
- import numpy as np
- import scipy.linalg
-
- A = np.array([[10,4,2,1],[8,3,1,2],[2,6,7,5],[5,1,1,3]])
-
- upper = scipy.linalg.lu(A)[2]
-
- det = 1
- for i in range(0,len(upper)):
- det *= upper[i][i]
-
-\end{code}
-
-\subsection{Eigen Vectors}
-
-\begin{definition}
- An eigenvector of $A$ is a vector $v$ such that $Av = \lambda v$ where $\lambda$ is a scalar.
-\end{definition}
-
-\begin{explanation}
- An eigenvector is a vector that is only scaled by some scalar when multiplied by the matrix it is an eigenvector of. The associated scalar ($\lambda$) is called the eigenvalue of $v$.
-
-\end{explanation}
-
-\subsubsection{Eigen Decomposition}
-
-\begin{definition}
- The eigen decomposition of the matrix $A$ is $V\Lambda V^{-1}$ where $V$ is the matrix of eigenvectors and $\Lambda$ is the diagonal matrix of eigenvalues.
-\end{definition}
-
-\begin{explanation}
-
-The eigen decomposition is important as it allows us to decompose specific matrices into simpler ones with nicer properties. Particularly, diagonal matrices are easy to take to powers when compared with their non-diagonal counterparts.
-
-\textbf{Solving:}
-\begin{align*}
- Av &= \lambda I_n v \\
- Av - \lambda I_n v &= \vec{0} \\
- (A - \lambda I_n)v &= \vec{0} \\
-\end{align*}
-
-Given this, we need to find a matrix $A - \lambda I_n$ that takes $v$ to the zero vector. Trivially, this is true when $v = \vec{0}$, but we are not interested in that. We know that det$(A) = 0$ means dimensionallity is being reduced and this must be true for $v$ to go to $\vec{0}$ when $v \neq \vec{0}$. Thus we have:
-
- \begin{align*}
- \text{det}(A - \lambda I_n) = 0
- \end{align*}
-
-Shown above is referred to as the characteristic polynomial. This can be stated in matrix form as
-
- \begin{align*}
- \text{det} (\begin{bmatrix}
- a_{1,1} - \lambda & a_{1,2} & \hdots & a_{1,n}\\
- a_{2,1} & a_{2,2} - \lambda & \hdots & a_{2,n}\\
- \vdots & \vdots & \ddots & \vdots\\
- a_{n,1} & a_{n,2} & \hdots & a_{n,n} - \lambda\\
- \end{bmatrix}) = 0.
- \end{align*}
-
-We solve this by computing the eigenvalues that make the equality true. This is done using basic algebra on the equation for the determinant of the above matrix. With the resulting eigenvalues, we plug in each $\lambda_i \in \Lambda$ into the equation $A - \lambda_i I_n$. We know this matrix is singular as it has a non-trivial null space, because it has a determinant of $0$. Define $B = A - \lambda_i I_n$. We can state the equation as
-
-\begin{align*}
- Bv = \vec{0}
-\end{align*}
-
- We solve this by computing the nullspace of $B$. This is done by solving the system of equations. Once done for each eigenvalue, we have each eigenvector. These eigenvectors define $V$ and thus the final part is computing $V^{-1}$. I refer back to the section on computing inverses of matrices for the derivation of $V^{-1}$. Once done, we can state the eigen decomposition as
-
-\begin{align*}
- A = V \Lambda V^{-1}.
-\end{align*}
-
-\end{explanation}
-
-\begin{example}
- Compute the eigen decomposition for
-\begin{align*}
- A =
- \begin{bmatrix}
- 1 & 8 \\
- 2 & 3 \\
- \end{bmatrix}.
-\end{align*}
-
-Find the eigenvalues:
-
-\[
-\det\left(\begin{bmatrix} 1 - \lambda & 8 \\ 2 & 3 - \lambda \end{bmatrix}\right) = 0
-\]
-
-\[
-(1 - \lambda)(3 - \lambda) - (8)(2) = 0
-\]
-
-\[
-3 - \lambda - 3\lambda + \lambda^2 - 16 = 0
-\]
-
-\[
-\lambda^2 - 4\lambda - 13 = 0
-\]
-
-\[
-\lambda = 2 \pm \sqrt{17}
-\]
-
-Now, for \(\lambda_1 = 2 + \sqrt{17}\):
-
-\[
-A - \lambda_1 I =
-\begin{bmatrix}
-1 - (2 + \sqrt{17}) & 8 \\
-2 & 3 - (2 + \sqrt{17})
-\end{bmatrix}
-=
-\begin{bmatrix}
--1 - \sqrt{17} & 8 \\
-2 & 1 - \sqrt{17}
-\end{bmatrix}
-\]
-
-Solve for the null space:
-
-\[
-\begin{bmatrix}
--1 - \sqrt{17} & 8 \\
-2 & 1 - \sqrt{17}
-\end{bmatrix}
-\begin{bmatrix}
-x \\
-y
-\end{bmatrix}
-=
-\begin{bmatrix}
-0 \\
-0
-\end{bmatrix}
-\]
-
-From the first row:
-
-\[
-(-1 - \sqrt{17})x + 8y = 0
-\Rightarrow (1 + \sqrt{17})x = 8y
-\Rightarrow x = \frac{8y}{1 + \sqrt{17}}
-\]
-
-So one eigenvector is:
-
-\[
-v_1 = \begin{bmatrix} \frac{8}{1 + \sqrt{17}} \\ 1 \end{bmatrix}
-\]
-
-Do the same for \(\lambda_2 = 2 - \sqrt{17}\):
-
-\[
-v_2 = \begin{bmatrix} \frac{8}{1 - \sqrt{17}} \\ 1 \end{bmatrix}
-\]
-
-Construct matrix \(V\) of eigenvectors:
-
-\[
-V = \begin{bmatrix}
-\frac{8}{1 + \sqrt{17}} & \frac{8}{1 - \sqrt{17}} \\
-1 & 1
-\end{bmatrix}
-\]
-
-Diagonal matrix \(D\) of eigenvalues:
-
-\[
-D = \begin{bmatrix}
-2 + \sqrt{17} & 0 \\
-0 & 2 - \sqrt{17}
-\end{bmatrix}
-\]
-
-We then have the eigen decomposition:
-
-\[
-A = V D V^{-1}
-\]
-
-Now compute \(V^{-1}\) based on the prior section's description for matrix inversion to find:
-
-\[
-V^{-1} = \frac{1}{\sqrt{17}}
-\begin{bmatrix}
-1 & -\frac{8}{1 - \sqrt{17}} \\
--1 & \frac{8}{1 + \sqrt{17}}
-\end{bmatrix}
-\]
-
-Thus we have:
-
-\[
-A =
-\begin{bmatrix}
-\frac{8}{1 + \sqrt{17}} & \frac{8}{1 - \sqrt{17}} \\
-1 & 1
-\end{bmatrix}
-\begin{bmatrix}
-2 + \sqrt{17} & 0 \\
-0 & 2 - \sqrt{17}
-\end{bmatrix}
-\frac{1}{\sqrt{17}}
-\begin{bmatrix}
-1 & -\frac{8}{1 - \sqrt{17}} \\
--1 & \frac{8}{1 + \sqrt{17}}
-\end{bmatrix}
-\]
-
-
-\end{example}
-
-\end{document}
diff --git a/latex/designing/DesigningDataIntensiveApplications.tex b/latex/designing/DesigningDataIntensiveApplications.tex
@@ -1,198 +0,0 @@
-\documentclass[12pt, letterpaper]{article}
-\usepackage{xcolor}
-
-\setlength{\parindent}{0pt}
-\setlength{\parskip}{.5em}
-
-\usepackage{enumitem}
-\usepackage{graphicx}
-\usepackage{listings}
-\usepackage{caption}
-\usepackage{tcolorbox}
-\usepackage{datetime}
-\usepackage{amsfonts}
-\usepackage{amsmath}
-\usepackage{geometry}
-\geometry{verbose,tmargin=1in,bmargin=1in,lmargin=1in,rmargin=1in}
-\usepackage{amssymb,enumerate}
-\usepackage{amsthm,stmaryrd}
-\usepackage[all]{xy}
-
-\newenvironment{definition}{
- \begin{quote}
- \textbf{Definition:}
- }{
- \end{quote}
-}
-
-
-\newenvironment{explanation}{
- \begin{quote}
- \textbf{Explanation:}
- }{
- \end{quote}
-}
-
-\newenvironment{example}{
- \begin{quote}
- \textbf{Example:}
- }{
- \end{quote}
-}
-
-\lstnewenvironment{code}{
- \textbf{Code:}
- \lstset{
- basicstyle=\ttfamily,
- columns=fullflexible,
- breaklines=true
- }
-}{
-}
-
-
-\begin{document}
-
-\noindent{\large \textbf{Designing Data-Intensive Applications by Martin Kleppmann}}
-
-\noindent Notes by Andrew Laack
-
-\tableofcontents
-
-\section{Reliable, Scalable, and Maintainable Applications}
-
-Our goal when architecting data systems is to ensure they are reliable, scalable, and maintainable.
-
-\subsection{Reliability}
-
-The system should work correctly even in cases of \textit{adversity}. These adversities include hardware, software, and human errors. Oftentimes we refer to this as the system being fault-tolerant (tolerant to certain types of faults) or resilient.
-
-An important distinction is that of fault vs. failure. A fault is when a component fails to achieve their specification while a failure is the system as a whole failing to provide the expected service. By these definitions, we try to decrease the likelihood that faults result in failures.
-
-\subsection{Scalability}
-
-As the needs of the system grow, the demands should be dealt with in a reasonable way. When discussing scalability, we are primarily concerned with load parameters. This is a blanket term that can describe ingress, egress, request counts, etc..
-
-When discussing scalability, it is important to consider response times (roundabout times). In particular, the median, p95, p99, and p999 are quite important. These upper percentiles are referred to as tail latencies. An extension of this are tail latency amplifications, which is where multiple requests are made to a service which increases the likelihood of causing a tail latent event.
-
-Head-of-line blocking is where queueing delays, caused by a few slow requests in the front, cause a pile up of requests in the queue. This is part of the reason why it is important to track response times on the side of the client instead of based on processing time.
-
-\subsection{Maintainability}
-
-Disparate individuals should be able to work with the system with minimal hassle.
-
-\section{Data Models and Query Languages}
-
-\subsection{Relational vs. Document Model}
-
-Relational databases have relations (tables) that can be joined together when querying. While these joins exist in \textit{some} document databases, they are often quite slow and outside the intended use case for the database. To combat this limitation, we often run multiple queries against document databases cases where there are \textit{document references} (when we don't want denormalized data).
-
-Often it is simpler to use the document model when our data is structured in a tree like form that has lots of one-to-many relationships. This removes the need for \textit{shredding}, the process of mapping a document structure to a relational structure.
-
-\subsection{Data Locality}
-
-Data locality refers to the location data is stored on disk. In document databases, documents are often stored in contiguous memory as some form of encoded string. This storage locality allows for faster lookups because data is stored near each other, which is more efficient on spinning disks.
-
-Despite this improvement in data locality, we often need to load entire documents to look for information in them which can sometimes render this improvement moot when the document is large. Beyond this, rewriting documents often requires moving them when the size of the encoded string changes which is an expensive procedure.
-
-This can limit the applicability of document databases. Additionally, there are approaches, like Google's Spanner database, that attempt to achieve data locality without requiring a schemaless approach. This is done by interleaving (nesting) rows within a parent table. Oracle also allows this with \textit{multi-table index cluster tables}.
-
-Similarly, \textit{column-family} databases (like Cassandra) achieve good data locality as well.
-
-\subsection{Declarative vs. Imperative}
-
-Imperative languages state the steps needed to perform a task. Declarative languages declare the result that is expected. Based on this, we see SQL is a declarative language because we declare the data we want, and then the database's query optimizer determines how best to do that. This adds complexity and provides value for the \textit{EXPLAIN} keyword, used to introspect a query.
-
-Additionally, given the necessity of execution order for imperative languages, it can be easier to parallelize execution when using a declarative style.
-
-\subsection{MapReduce}
-
-MapReduce is a model for the bulk processing of large amounts of data across distributed systems. The model was popularized by Google and is implemented, to varying degrees, in some NoSQL datastores like MongoDB and CouchDB.
-
-MapReduce allows the definition of the functions map and reduce. Map defines the key and value to emit from each document, and reduce is called for each grouping of keys returned from map.
-
-This is exceptionally useful for big datasets because map can be parallelized (locally ran on each system), the results can be shuffled together based on keys, and then reduced to outputs.
-
-\vspace{.25cm}
-
-\noindent\begin{code}
-
-db.observations.mapReduce(
- function map() {
- var year = this.observationTimestamp.getFullYear();
- var month = this.observationTimestamp.getMonth() + 1;
- emit(year + "-" + month, this.numAnimals);
- },
- function reduce(key, values) {
- return Array.sum(values);
- },
- {
- query: { family: "Sharks" },
- out: "monthlySharkReport"
- }
-);
-
-\end{code}
-
-The map and reduce functions must also be \textit{pure} functions, functions that don't have any side effects and always have the same output for the same inputs.
-
-Additionally, given the low-level nature of map reduce, it is possible to create SQL implementations that are use a pipeline of map reduce steps.
-
-
-\subsection{Aggregation Pipeline}
-
-Some more recent versions of MongoDB support the aggregation pipeline query language which is similar to SQL, but built with documents in mind. This allows a declarative, query optimizer based approach, to be used with document datastores.
-
-\begin{verbatim}
-db.observations.aggregate([
- { $match: { family: "Sharks" } },
- { $group: {
- _id: {
- year: { $year: "$observationTimestamp" },
- month: { $month: "$observationTimestamp" }
- },
- totalAnimals: { $sum: "$numAnimals" }
- } }
-])
-\end{verbatim}
-
-\subsection{Graph-Like Data Models}
-
-Graph models are often useful when there are lots of many-to-many relationships, as is the case with a social network, a road network, or a graph of the web. Despite the homogeneity of data in each of these situations, it needn't be so. In the case of Facebook, they may have a single graph where vertices could represent friends, events, comments, and everything else that relates individuals to each other.
-
-\subsubsection{Property Graph Model}
-
-The property graph model, as implemented by Neo4j, Titan, and InfiniteGraph, each vertex contains and identifier, a set of outgoing edges, a set of incoming edges, and a collection of key-value pairs (properties). Each edge has a unique identifier, a tail vertex (where it starts), a head vertex (where it ends), a label to describe the relationship, and a collection of properties (key-value pairs).
-
-As we see, this is a directed graph and each object (edges and vertices) contains its own collection of properties and identifier. Conceptually, this can be implemented by a SQL database where we have a table for vertices and a table for edges, each of which contains respective columns for attributes of said records, presuming we have a json datatype, which is supported in PostgreSQL.
-
-\subsubsection{Triple-Store Model}
-
-The triple-store model, as implemented by Datomic, AllegroGraph, and others,
-
-\section{Storage and Retrieval}
-
-\subsection{Compaction}
-
-Compaction is an approach often used by log-based DBs to condense the information contained in logs without losing any information by removing stale writes/updates.
-
-\subsection{Hash Indexing}
-
-A simple hash indexing key-value store, implemented with logging and in memory keys, using compaction, is the data storage approach used by Riak. This approach allows fast seeks, but can have costly startups as the in memory hashtable must be rebuilt (unless it is written to disk which Riak does).
-
-\section{SSTables}
-
-Sorted String Tables (SSTables) are logs that require sequential keys be sorted.
-
-\section{Encoding and Evolution}
-\section{Replication}
-\section{Partitioning}
-\section{Transactions}
-\section{The Trouble with Distributed Systems}
-\section{Consistency and Consensus}
-\section{Batch Processing}
-\section{Stream Processing}
-\section{The Future of Data Systems}
-
-
-\end{document}
diff --git a/latex/fluent-python/FluentPython.tex b/latex/fluent-python/FluentPython.tex
@@ -1,89 +0,0 @@
-\documentclass[12pt, letterpaper]{article}
-\usepackage{xcolor}
-
-\setlength{\parindent}{0pt}
-\setlength{\parskip}{.5em}
-
-\usepackage{enumitem}
-\usepackage{graphicx}
-\usepackage{listings}
-\usepackage{caption}
-\usepackage{tcolorbox}
-\usepackage{datetime}
-\usepackage{amsfonts}
-\usepackage{amsmath}
-\usepackage{geometry}
-\geometry{verbose,tmargin=1in,bmargin=1in,lmargin=1in,rmargin=1in}
-\usepackage{amssymb}
-\usepackage{amsthm,stmaryrd}
-\usepackage[all]{xy}
-
-\newenvironment{definition}{
- \begin{quote}
- \textbf{Definition:}
- }{
- \end{quote}
-}
-
-
-\newenvironment{explanation}{
- \begin{quote}
- \textbf{Explanation:}
- }{
- \end{quote}
-}
-
-\newenvironment{example}{
- \begin{quote}
- \textbf{Example:}
- }{
- \end{quote}
-}
-
-\lstnewenvironment{code}{
- \textbf{Code:}
- \lstset{
- basicstyle=\ttfamily,
- columns=fullflexible,
- breaklines=true
- }
-}{
-}
-
-
-\begin{document}
-
-\noindent{\large \textbf{Fluent Python}}
-
-\noindent Notes by Andrew Laack
-
-\tableofcontents
-
-\section{Python Data Model}
-
-\subsection{Special Methods}
-
-Special methods are methods that take a general input object. These are things like \textbf{len()} and \textbf{str()}. When defining these special methods, we define them with method names that start and end with double underscores.
-
-We implement these special methods when we want objects to support fundamental constructs. These include:
-
-\begin{enumerate}
- \item Collections
- \item Attribute Access
- \item Iteration (and async)
- \item Operator Overloading
- \item Function and Method Invocation
- \item String Representation and Formatting
- \item Asynchronous With \textbf{await}
- \item Object Creation/Destruction
- \item Managed Contexts Using \textbf{with} or \textbf{async with}
-\end{enumerate}
-
-These are also referred to as \textbf{magic methods}.
-
-
-\subsection{Named Tuples}
-
-To use named tuples we import \textbf{collections} and use \textbf{collections.namedtuple()}. Named tuples are a common approach for creating a struct analog in cases where there isn't a need to define associated functions. These are key-value pairs where keys are hashed, and, unlike with dictionaries, we can use indexes on them. A limitation of named tuples is they are immutable, but there is an update analog called \textbf{\_replace} which deletes a record and creates a new one.
-
-\end{document}
diff --git a/latex/fluent-python/python-code/doubly-linked-list.py b/latex/fluent-python/python-code/doubly-linked-list.py
@@ -1,56 +0,0 @@
-class DoublyLinkedList:
- class Node:
- def __init__(self, val, left=None, right=None):
- self.val = val
- self.left = left
- self.right = right
-
- def __init__(self, ls):
-
- cp_ls = ls.copy()
-
- for index, ele in enumerate(cp_ls):
-
- cp_ls[index] = self.Node(ele)
-
- if index != 0:
- cp_ls[index].left = cp_ls[index - 1]
-
- for index, ele in enumerate(cp_ls):
- if index != len(cp_ls) - 1:
- ele.right = cp_ls[index + 1]
-
- self.head = cp_ls[0]
- self.tail = cp_ls[-1]
- self.length = len(ls)
-
- def __getitem__(self, position):
-
- while position < 0:
- position += len(self)
-
- if position > self.length // 2:
- current = self.tail
- for _ in range(0, position - self.length):
- current = current.left
- return current.val
- else:
- current = self.head
- for _ in range(0, position):
- current = current.right
- return current.val
-
- def __len__(self):
- return self.length
-
-
-
-if __name__ == "__main__":
- nums = [10, 487, 123908, 7120398]
- ls = DoublyLinkedList(nums)
-
- for i in range(0, len(ls)):
- print(ls[i])
-
- print(ls[-1])
- print(ls[-2])
diff --git a/latex/leetcode/Leetcode.tex b/latex/leetcode/Leetcode.tex
@@ -1,143 +0,0 @@
-\documentclass[12pt, letterpaper]{article}
-\usepackage{xcolor}
-
-
-\usepackage{enumitem}
-\usepackage{graphicx}
-\usepackage{listings}
-\usepackage{caption}
-\usepackage{tcolorbox}
-\usepackage{datetime}
-\usepackage{amsfonts}
-\usepackage{amsmath}
-\usepackage{geometry}
-\geometry{verbose,tmargin=1in,bmargin=1in,lmargin=1in,rmargin=1in}
-\usepackage{amssymb,enumerate}
-\usepackage{amsthm,stmaryrd}
-\usepackage[all]{xy}
-
-\newenvironment{definition}{
- \begin{quote}
- \textbf{Definition:}
- }{
- \end{quote}
-}
-
-
-\newenvironment{explanation}{
- \begin{quote}
- \textbf{Explanation:}
- }{
- \end{quote}
-}
-
-\newenvironment{example}{
- \begin{quote}
- \textbf{Example:}
- }{
- \end{quote}
-}
-
-\lstnewenvironment{code}{
- \textbf{Code:}
- \lstset{
- basicstyle=\ttfamily,
- columns=fullflexible,
- breaklines=true
- }
-}{
-}
-
-
-\begin{document}
-
-\noindent{\large \textbf{Leetcode}}
-
-\noindent Notes by Andrew Laack
-
-\tableofcontents
-
-
-\section{Merge k Sorted Lists}
-
-\textbf{Problem:}
-
-\noindent You are given an array of k linked-lists lists, each linked-list is sorted in ascending order. Merge all the linked-lists into one sorted linked-list and return it.
-
-\vspace{.25cm}
-
-\noindent\textbf{Explanation:}
-
-\noindent We first find the lowest value that starts a list. This node will be the head of our list. From here, we iterate through each of the lists at each step selecting the lowest value and making it the next node in the list. Once all items have been added to the list, we return the head. There are quite a few edge cases to consider related to data nullity and how to handle empty lists, but that's the extent of the complication.
-
-\vspace{.25cm}
-
-\noindent\begin{code}
-# Definition for singly-linked list.
-# class ListNode:
-# def __init__(self, val=0, next=None):
-# self.val = val
-# self.next = next
-
-class Solution:
- def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
-
- if len(lists) == 0:
- return None
-
- lowest = 10**4 # upper bound
- head = lists[0]
- headList = 0
-
- for i in range(0,len(lists)):
- if lists[i] is not None and lists[i].val < lowest:
- head = lists[i]
- lowest = lists[i].val
- headList = i
-
- if lists[headList] is not None:
- lists[headList] = lists[headList].next
-
-
- i = 0
- while i < len(lists):
- if lists[i] is None:
- lists.pop(i)
- else:
- i += 1
-
-
- if len(lists) == 0:
- return head
-
- done = False
- current = head
-
- while not done:
- lowest = 10**4 # upper bound
- listNum = 0
-
- for i in range(0, len(lists)):
- if lists[i].val < lowest:
- lowest = lists[i].val
- listNum = i
-
- current.next = lists[listNum]
- lists[listNum] = lists[listNum].next
- current = current.next
- if lists[listNum] is None:
- lists.pop(listNum)
- if len(lists) == 0:
- done = True
-
-
- return head
-\end{code}
-
-\section{Section}
-
-\begin{code}
- code
-\end{code}
-
-\end{document}
diff --git a/latex/leetcode/c++/a.out b/latex/leetcode/c++/a.out
Binary files differ.
diff --git a/latex/leetcode/c++/puzzle.txt b/latex/leetcode/c++/puzzle.txt
@@ -1,9 +0,0 @@
-.........
-.........
-.........
-.........
-..1......
-......2..
-.........
-.........
-.........
diff --git a/latex/leetcode/c++/reverseVowels.cpp b/latex/leetcode/c++/reverseVowels.cpp
@@ -1,51 +0,0 @@
-#include <string>
-#include <unordered_set>
-
-class Solution {
-public:
- std::string reverseVowels(std::string s) {
-
- std::unordered_set<char> set = {'a', 'e', 'i', 'o', 'u'};
-
-
- int left = 0;
- int right = s.length();
-
- while(right > left){
-
- auto itl = set.find(tolower(s[left]));
- auto itr = set.find(tolower(s[right]));
-
- bool leftFound = false;
- bool rightFound = false;
- if(itl != set.end()){
- leftFound = true;
- }
- if(itr != set.end()){
- rightFound = true;
- }
-
- if(leftFound && rightFound){
- char temp = s[left];
- s[left] = s[right];
- s[right] = temp;
- left += 1;
- right -= 1;
- }
-
- if(!leftFound){
- left += 1;
- }
- if(!rightFound){
- right -= 1;
- }
-
- }
-
- return s;
- }
-};
-
-int main(){
- Solution sln;
-}
diff --git a/latex/leetcode/c++/sudoku.cpp b/latex/leetcode/c++/sudoku.cpp
@@ -1,126 +0,0 @@
-#include <bits/stdc++.h>
-using namespace std;
-
-class Solution {
-public:
- void solveSudoku(vector<vector<char>>& board) {
- recurse(board, 0, 0);
- return;
- }
-
- bool recurse(std::vector<std::vector<char>>& board, int xPos, int yPos) {
- if (yPos == 9) {
- return true;
- }
-
- int newX = (xPos + 1) % 9;
- int newY = yPos;
- if (newX < xPos) {
- newY = yPos + 1;
- }
-
- if (board[xPos][yPos] != '.') {
- return recurse(board, newX, newY);
- } else {
- for (int i = 1; i < 10; ++i) {
- board[xPos][yPos] = '0' + i;
- // only move forward with valid choices.
- if (!isValid(board, xPos, yPos)) {
- continue;
- }
- if (recurse(board, newX, newY)) {
- return true;
- }
- }
- // failed
- board[xPos][yPos] = '.';
- }
-
- return false;
- }
-
- bool isValid(std::vector<std::vector<char>>& board, int posX, int posY) {
- auto brd = board;
- char current = brd[posX][posY];
-
- // Check column
- for (int i = 0; i < 9; ++i) {
- if (current == brd[i][posY] && i != posX) {
- return false;
- }
- }
-
- // Check row
- for (int i = 0; i < 9; ++i) {
- if (current == brd[posX][i] && i != posY) {
- return false;
- }
- }
-
- // Check 3x3 sub-grid
- int x = (posX / 3) * 3;
- int y = (posY / 3) * 3;
- for (int rw = 0; rw < 3; ++rw) {
- for (int cl = 0; cl < 3; ++cl) {
- if (current == brd[x + cl][y + rw] && (x + cl != posX || y + rw != posY)) {
- return false;
- }
- }
- }
-
- return true;
- }
-};
-
-int main() {
- ios::sync_with_stdio(false);
- cin.tie(nullptr);
-
- // Read a 9x9 Sudoku board from standard input.
- // Expect 9 lines, each containing exactly 9 characters:
- // digits '1'–'9' for filled cells and '.' for empty cells.
- vector<vector<char>> board(9, vector<char>(9));
- string line;
- for (int i = 0; i < 9; ++i) {
- if (!getline(cin, line)) {
- cerr << "Insufficient input: expected 9 lines, got fewer.\n";
- return 1;
- }
- // Remove any spaces in the line (in case input uses spaces)
- string filtered;
- for (char c : line) {
- if (c != ' ' && c != '\t') {
- filtered.push_back(c);
- }
- }
- if ((int)filtered.size() != 9) {
- cerr << "Invalid input on line " << i + 1 << ": expected 9 non-space characters.\n";
- return 1;
- }
- for (int j = 0; j < 9; ++j) {
- char c = filtered[j];
- if ((c >= '1' && c <= '9') || c == '.') {
- board[i][j] = c;
- } else {
- cerr << "Invalid character '" << c << "' on line " << i + 1
- << ". Use digits '1'-'9' or '.'.\n";
- return 1;
- }
- }
- }
-
- Solution solver;
- solver.solveSudoku(board);
-
- // Output the solved board: 9 lines of 9 characters each
- for (int i = 0; i < 9; ++i) {
- for (int j = 0; j < 9; ++j) {
- cout << board[i][j];
- }
- cout << "\n";
- }
-
- return 0;
-}
-
-
diff --git a/latex/node/node.tex b/latex/node/node.tex
@@ -1,174 +0,0 @@
-\documentclass[12pt, letterpaper]{article}
-\usepackage{xcolor}
-
-
-\setlength{\parindent}{0pt}
-\setlength{\parskip}{.5em}
-
-\usepackage{xcolor}
-\definecolor{lightgray}{gray}{0.95}
-\usepackage{listings}
-\usepackage{enumitem}
-\usepackage{graphicx}
-\usepackage{listings}
-\usepackage{caption}
-\usepackage{tcolorbox}
-\usepackage{datetime}
-\usepackage{amsfonts}
-\usepackage{amsmath}
-\usepackage{geometry}
-\geometry{verbose,tmargin=1in,bmargin=1in,lmargin=1in,rmargin=1in}
-\usepackage{amssymb,enumerate}
-\usepackage{amsthm,stmaryrd}
-\usepackage[all]{xy}
-
-\usepackage{tcolorbox} % for padding
-
-\newenvironment{definition}{
- \begin{quote}
- \textbf{Definition:}
- }{
- \end{quote}
-}
-
-
-\newenvironment{explanation}{
- \begin{quote}
- \textbf{Explanation:}
- }{
- \end{quote}
-}
-
-\newenvironment{example}{
- \begin{quote}
- \textbf{Example:}
- }{
- \end{quote}
-}
-
-\lstnewenvironment{code}{
- \lstset{
- basicstyle=\ttfamily,
- columns=fullflexible,
- breaklines=true,
- backgroundcolor=\color{lightgray},
- frame=single,
- framerule=0pt,
- rulecolor=\color{lightgray}
- }
-}{}
-
-
-\begin{document}
-
-\noindent{\large \textbf{Node.js Design Patterns by Mario Casciaro}}
-
-\noindent Notes by Andrew Laack
-
-\tableofcontents
-
-\section{Node.js Platform}
-
-\subsection{Multiplexer}
-
-A multiplexer is a process that interlaces signals together.
-
-\subsection{Demultiplexer}
-
-A demultiplexer is a process that de-interlaces signals from each other.
-
-\subsection{Reactor}
-
-Given that I/O is often slow, it is preferable to have non-blocking I/O calls. However, there is overhead associated with having lots of threads thus spawning threads for each non-blocking call can also be suboptimal. To overcome this, NodeJS uses the reactor pattern.
-
-The reactor pattern first accepts an I/O operation and handler from the application and dispatches it to the event demultiplexer. The handlers are callbacks and when the operation receives an event, the event is sent to the event queue. Once here, events are handled in series via the event loop where the callback is executed. Shown below is a simple implementation of this concept:
-
-\begin{code}
-watchedList.add(socketA, FOR_READ)
-watchedList.add(fileB, FOR_READ)
-while (events = demultiplexer.watch(watchedList)) {
- // event loop
- for (event of events) {
- // This read will never block and will always return data
- data = event.resource.read()
- if (data === RESOURCE_CLOSED) {
- // the resource was closed, remove it from the watched list
- demultiplexer.unwatch(event.resource)
- } else {
- // some actual data was received, process it
- consumeData(data)
- }
- }
-}
-\end{code}
-
-\subsection{Composition of NodeJS}
-
-\subsubsection{Libuv}
-
-Libuv is the implementation of the reactor pattern that works across operating systems, used by NodeJS.
-
-\subsubsection{V8}
-
-This is the JS engine developed by Google for Chrome that runs on the server side.
-
-\subsubsection{Core JS APIs}
-
-The core JS APIs are the APIs that implement the core (high-level) functionality of NodeJS.
-
-\subsubsection{Bindings}
-
-The binding layer exposes libuv and other JS functionality.
-
-\subsection{Polyfill / Transpiler}
-
-A polyfill is code (often JS) that allows the use of newer features in older runtimes. This is a common practice in browsers to ensure older browsers can still view modern content.
-
-A transpiler fits a similar purpose where it converts one source to another source (aka source-to-source compiler).
-
-
-\subsection{Modules}
-
-Modules are the cornerstone of NodeJS as NodeJS is intended to be minimal. Similarly, the philosophy of modules is similar, they are supposed to be small with a minimal number of features.
-
-\subsubsection{Revealing Module Pattern}
-
-This is the JS pattern of revealing functionallity of a module as needed instead of scoping everything to global.
-
-\subsubsection{CommonJS (CJS)}
-
-CommonJS is the classic NodeJS module system. This differs from web based module systems because a browser must be able to access all modules using http whereas NodeJS has access the to filesystem.
-
-\subsubsection{ECMAScript (ES/ESM)}
-
-ECMAScript is the other NodeJS module system. In the modern era, this is what people are using moving forwards.
-
-\subsubsection{crypto}
-
-The crypto module is provides standard implementations of encryption and hashing via OpenSSL.
-
-\subsubsection{http}
-
-The http module is used to create an http server.
-
-\subsubsection{https}
-
-The https module is used to create an https server.
-
-\subsubsection{net}
-
-The net module is used to write to TCP sockets.
-
-\subsubsection{dgram}
-
-The dgram module is used to write to UDP sockets.
-
-\subsubsection{fs}
-
-The fs module is used to access the underlying filesystem.
-
-\subsubsection{express}
-
-The express module is a web framework for NodeJS. This serves as a way to make the NodeJS runtime environment into a web server.
-
-\end{document}
diff --git a/latex/pytorch/PyTorch.tex b/latex/pytorch/PyTorch.tex
@@ -1,136 +0,0 @@
-\documentclass[12pt, letterpaper]{article}
-\usepackage{xcolor}
-
-\setlength{\parindent}{0pt}
-\setlength{\parskip}{.5em}
-
-\usepackage{enumitem}
-\usepackage{graphicx}
-\usepackage{listings}
-\usepackage{caption}
-\usepackage{tcolorbox}
-\usepackage{datetime}
-\usepackage{amsfonts}
-\usepackage{amsmath}
-\usepackage{geometry}
-\geometry{verbose,tmargin=1in,bmargin=1in,lmargin=1in,rmargin=1in}
-\usepackage{amssymb,enumerate}
-\usepackage{amsthm,stmaryrd}
-\usepackage[all]{xy}
-
-\newenvironment{definition}{
- \begin{quote}
- \textbf{Definition:}
- }{
- \end{quote}
-}
-
-
-\newenvironment{explanation}{
- \begin{quote}
- \textbf{Explanation:}
- }{
- \end{quote}
-}
-
-\newenvironment{example}{
- \begin{quote}
- \textbf{Example:}
- }{
- \end{quote}
-}
-
-\lstnewenvironment{code}{
- \hspace{.45cm}\textbf{Code:}
- \lstset{
- basicstyle=\ttfamily,
- columns=fullflexible,
- breaklines=true
- }
-}{
-}
-
-
-\begin{document}
-
-\noindent{\large \textbf{Deep Learning with PyTorch by Eli Stevens}}
-
-\noindent Notes by Andrew Laack
-
-\tableofcontents
-
-\section{Introducing Deep Learning and PyTorch}
-
-\subsection{PyTorch}
-
-PyTorch is a deep learning library, but more generally, is an optimization library.
-
-\subsection{torch.nn}
-
-torch.nn provides common functionality for neural network layers and architecture. Some common functionality are activation functions, conv. layers, loss functions, and connected layers.
-
-\subsection{torch.Tensor}
-
-torch.Tensor is a multidimensional array class that provides tensors for use with PyTorch's optimization functionallity.
-
-\subsection{torch.optim}
-
-In our training loop, PyTorch has an autograd engine to compute gradients quickly, but it does not supply a way to update the weights and biases of our model. torch.optim provides these optimizers to update the weights of our models.
-
-\subsection{Dataset (torch.utils.data)}
-
-The Dataset class is used to store data in a PyTorch compliant way.
-
-\subsection{DataLoader (torch.utils.data)}
-
-DataLoader wraps our dataset, facilitating batching and other fast operations.
-
-\subsection{Distributed Training}
-
-To facilitate distributed training PyTorch provides torch.nn.parallel.Distributed-DataParallel and torch.distributed to use additional hardware.
-
-\subsection{TorchScript}
-
-TorchScript is a way to compile a model ahead of time into a set of instructions that can be ran without a Python runtime.
-
-\subsection{Modules}
-
-Modules are the building blocks for NN architectures in PyTorch, other libraries often call modules \textit{layers}.
-
-\section{Datasets}
-
-\subsection{torchvision.transforms}
-
-torchvision.transforms allows us to define pipelines to do basic preprocessing.
-
-\subsection{ImageNet}
-
-ImageNet is a dataset of over 14 million labeled images, maintained by Standford University. Each of the images are labeled with with words from the WordNet dataset which is an English word dataset.
-
-The ImageNet Large Scale Visual Recognition Challenge (ILSVRC) is a varying competition, held each year, to test models on different tasks related to the dataset. The image classification task consist of taking an input image and giving 5 labels out of 1,000 total labels, ranked by confidence, to describe the image. The training set for ILSVRC is 1.2 million images labeled with one of 1,000 nouns.
-
-\section{Pretrained Networks}
-
-\subsection{torchvision.models}
-
-torchvision.models provides a bunch of pretrained vision models. The capitalized options are classes, and the lower case options are functions that return objects of the specified architecture. When we create objects using the functions, we can also specify if we want \texttt{pretrained=True} (the default is \texttt{False}).
-
-\subsection{AlexNet}
-
-AlexNet won ILSVRC in 2012. It is a CNN for image based classification.
-
-\subsection{ResNet}
-
-ResNet was the first mainstream residual network, achieving stable training at depths that were previously extremely difficult. The ResNet network was trained on the ImageNet dataset with 1.2 million images and 1,000 categories.
-
-\section{Architectures}
-
-\subsection{GAN}
-
-GANs (generative adversarial networks) are networks that play the \textit{GAN game}, where a generator network tries to create images to trick a discriminator into thinking it is a real image, and the discriminator network tries to predict which images are real and which come from the other network.
-
-\subsection{CycleGAN}
-
-
-
-\end{document}
diff --git a/pytorch/ch2/pretrained-image-classifiers.ipynb b/pytorch/ch2/pretrained-image-classifiers.ipynb
@@ -1,159 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": 8,
- "id": "1452c9e5-2ed1-4318-920a-6513ba106493",
- "metadata": {},
- "outputs": [],
- "source": [
- "from torchvision import models\n",
- "from torchvision import transforms\n",
- "\n",
- "resnet = models.resnet101(pretrained=True)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "id": "1df38383-5c33-4887-ae4d-126feb4ae8d8",
- "metadata": {},
- "outputs": [],
- "source": [
- "preprocess = transforms.Compose([\n",
- " transforms.Resize(256),\n",
- " transforms.CenterCrop(224),\n",
- " transforms.ToTensor(),\n",
- " transforms.Normalize(\n",
- " mean = [.485, .456, .406],\n",
- " std = [.229, .224, .225]\n",
- " )\n",
- "])"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "id": "162d49a9-1c26-4da6-9fe7-83673d9f381f",
- "metadata": {},
- "outputs": [],
- "source": [
- "from PIL import Image\n",
- "\n",
- "img = Image.open('../data/p1ch2/dog.jpeg')"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "id": "91509f42-efb0-4cd1-86ef-607e0ba3f514",
- "metadata": {},
- "outputs": [],
- "source": [
- "import torch\n",
- "\n",
- "dog_img_tensor = preprocess(img)\n",
- "batch_tensor = torch.unsqueeze(dog_img_tensor, 0)\n",
- "\n",
- "# put network into eval mode (always do this before inference)\n",
- "\n",
- "resnet.eval()\n",
- "out = resnet(batch_tensor)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "id": "ba143165-f758-4ed5-b834-7d55e314acd6",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "207, golden_retriever\n"
- ]
- }
- ],
- "source": [
- "\n",
- "_, most_likely = torch.max(out, 1)\n",
- "\n",
- "with open('../data/p1ch2/imagenet_classes.txt') as f:\n",
- " labels = [line.strip() for line in f.readlines()]\n",
- " print(labels[most_likely])"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
- "id": "f0fc8fc5-bdfe-463f-897c-247c4dd73845",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "tensor([97.6346], grad_fn=<IndexBackward0>)"
- ]
- },
- "execution_count": 6,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "\n",
- "proba = torch.nn.functional.softmax(out, dim=1)[0] * 100\n",
- "proba[most_likely]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "id": "298c308d-ff8e-4316-84c0-7af7c01a3538",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "[('207, golden_retriever', 97.63463592529297),\n",
- " ('208, Labrador_retriever', 1.6066557168960571),\n",
- " ('852, tennis_ball', 0.30485954880714417),\n",
- " ('222, kuvasz', 0.06295711547136307),\n",
- " ('205, flat-coated_retriever', 0.05671220272779465)]"
- ]
- },
- "execution_count": 7,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "\n",
- "_, indices = torch.sort(out, descending=True)\n",
- "[(labels[idx], proba[idx].item()) for idx in indices[0][:5]]"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "myenv",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.11.5"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/pytorch/ch2/tensor-multiplication.ipynb b/pytorch/ch2/tensor-multiplication.ipynb
@@ -1,40 +0,0 @@
-{
- "cells":[{
- "metadata":{
- },
- "outputs":[{
- "data":{
- "text/plain":["tensor([[ 2, 2, 1],\n"," [ 4, 9, 5],\n"," [ 4, 6, 10]])"]
- },
- "output_type":"execute_result",
- "execution_count":24,
- "metadata":{
- }
- }],
- "id":"4c9b6198",
- "cell_type":"code",
- "execution_count":24,
- "source":["import torch\n","\n","t1 = torch.tensor(data=[[2,2,1], [2, 3, 1], [1, 3, 5]])\n","t2 = torch.tensor(data=[[1,1,1], [2, 3, 5], [4, 2, 2]])\n","\n","torch.mul(t1, t2)"]
- }],
- "metadata":{
- "kernelspec":{
- "name":"python3",
- "display_name":"myenv",
- "language":"python"
- },
- "language_info":{
- "codemirror_mode":{
- "version":3,
- "name":"ipython"
- },
- "file_extension":".py",
- "pygments_lexer":"ipython3",
- "version":"3.11.5",
- "name":"python",
- "nbconvert_exporter":"python",
- "mimetype":"text/x-python"
- }
- },
- "nbformat":4,
- "nbformat_minor":5
-}-
\ No newline at end of file
diff --git a/work/deep-learning/Broadcasting.py b/work/deep-learning/Broadcasting.py
@@ -1,56 +0,0 @@
-# How is it we broadcast a vector to a matrix?
-
-# We first consider the vector to be a row vector.
-# This assumption seems kinda stupid, but alright then.
-
-# assume $a \in R^n$.
-
-# assume $B \in R^{m,n}$.
-
-# By this assumption, B has the same number of columns as a has coordinates.
-# This makes it easy to broadcast across the rows of the matrix. Observe the notion:
-
-# B := [6 2 8]
-# [2 9 8]
-
-# Since $B \in R^{m,n}$, we see $m = 2$ and $n = 3$.
-# Since $n = 3, a \in R^3$.
-
-# a := [2, 1, 2]
-# We a has the same coordinates as $B_{:,i}$, this makes it prime for broadcasting.
-# NOTE: $B_{:,i}$ is the slice (column) where the second index of the entry must be i.
-
-# Let's do this in math!!!
-
-import numpy as np
-
-B = np.array([[6,2,8], [2,9,8]])
-a = [2, 1, 2]
-
-print("B:")
-print()
-print(str(B))
-print()
-print("a:")
-print()
-print(str(a))
-print()
-
-# this does it exactly how we thought it would!!!
-# BUT.... that's kinda boring to just do, so let's do it ourselves!
-
-D = B + a
-
-print()
-print(D)
-print()
-
-#########
-
-D = np.empty((len(B), len(B[0]))) # Create empty array of same size as B (n x m)
-
-for i in range(len(B)):
- for j in range(len(B[i])):
- D[i][j] = B[i][j] + a[j]
-
-print(D)
diff --git a/work/deep-learning/PolarCoordinatesConversion.py b/work/deep-learning/PolarCoordinatesConversion.py
@@ -1,24 +0,0 @@
-# convert from polar coordinates to cartesian and vice versa
-import math
-
-def polarToCart(r, theta):
- print("Polar Coordinates: \t" + str(r) + " " + str(theta))
- x = math.cos(theta) * r
- y = math.sin(theta) * r
- print("Cartesian Coordinates: \t" + str(x) + " " + str(y))
- return (x,y)
-
-def cartToPolar(x,y):
- print("Cartesian Coordinates: \t" + str(x) + " " + str(y))
- r = math.sqrt(x**2 + y**2)
- theta = math.asin(y/r)
- print("Polar Coordinates: \t" + str(r) + " " + str(theta))
-
-
-r = 2.3
-theta = 1.38
-print("POLAR TO CART:")
-x,y = polarToCart(r,theta)
-print()
-print("CART TO POLAR:")
-cartToPolar(x,y)
diff --git a/work/deep-learning/cov.py b/work/deep-learning/cov.py
@@ -1,31 +0,0 @@
-# Covarianc mat calc
-
-import numpy as np
-
-mat = np.array([
- [1, 3, 3, 1],
- [2, 6, 9, 2]
- ])
-
-
-print(np.cov(mat))
-means = []
-m = len(mat[0])
-
-for i in range(0, len(mat)):
- means.append(np.mean(mat[i]))
-
-
-res = np.zeros((len(mat), len(mat)))
-print(means)
-
-for x in range(0, len(mat)):
- for y in range(0, len(mat)):
- m = len(mat[x]) - 1
- m_inv = 1/m
- sum = 0
- for i in range(0, len(mat[x])):
- sum += (mat[x][i] - means[x]) * (mat[y][i] - means[y])
- res[x][y] = sum * m_inv
-
-print(res)
diff --git a/work/deep-learning/determinant.py b/work/deep-learning/determinant.py
@@ -1,14 +0,0 @@
-import numpy as np
-import scipy.linalg
-
-A = np.array([[10,4,2,1],[8,3,1,2],[2,6,7,5],[5,1,1,3]])
-
-upper = scipy.linalg.lu(A)[2]
-
-print(upper)
-
-det = 1
-for i in range(0,len(upper)):
- det *= upper[i][i]
-
-print(det)
diff --git a/work/deep-learning/gauss-jordan.py b/work/deep-learning/gauss-jordan.py
@@ -1,59 +0,0 @@
-# this solver is only for 2x2 matrices as a generalized solver is longer.
-# we assume A is invertible.
-
-import numpy as np
-
-A = np.array([[2.,8.],[1.,3.]])
-A = np.hstack([A, np.eye(2)])
-
-def switch(frm, to, A):
- res = A.copy()
- fr = res[frm].copy()
- res[frm] = res[to]
- res[to] = fr
- return res
-
-def addRows(frm, to, coeff, A):
- res = A.copy()
- fr = A[frm].copy()
- fr *= coeff
- res[to] += fr
- return res
-
-# get 1 in 0,0
-# ensure the first row has some value in [0,0], otherwise switch
-if A[0][0] == 0:
- switch(0,1,A)
-
-# get 1 in 0,0
-target = A[0][0] - 1
-otr = A[1][0]
-coeff = (target/otr) * -1
-A = addRows(1, 0, coeff, A)
-
-# get 1 in 1,1
-target = A[1][1] - 1
-otr = A[0][1]
-coeff = (target/otr) * -1
-A = addRows(0, 1, coeff, A)
-
-# get 0 in 0,1
-target = A[0][1]
-otr = A[1][1]
-coeff = (target/otr) * -1
-A = addRows(1, 0, coeff, A)
-
-
-# get 0 in 1,0
-target = A[1][0]
-otr = A[0][0]
-coeff = (target/otr) * -1
-A = addRows(0, 1, coeff, A)
-
-# ensure 0,0 is 1
-A[0] = A[0] / A[0][0]
-# ensure 1,1 is 1
-A[1] = A[1] / A[1][1]
-
-# this is the entire augmented matrix, but we only care about columns 3 and 4
-print(A)
diff --git a/work/deep-learning/matmul.py b/work/deep-learning/matmul.py
@@ -1,16 +0,0 @@
-import numpy as np
-
-A = np.array([[4,3,4],[1,1,5],[2,3,6]])
-B = np.array([[3,1,7],[1,2,1],[2,4,2]])
-C = A @ B # matrix multiplication
-C = A.__matmul__(B) # more explicit
-
-def matMul(A, B):
- C = np.empty((len(A), len(B[0])))
- for i in range(0, len(A)):
- for j in range(0, len(B[0])):
- C[i][j] = A[i].dot(B[:,j])
- return C
-
-C = matMul(A,B)
-print(C)
diff --git a/work/deep-learning/norm.py b/work/deep-learning/norm.py
@@ -1,9 +0,0 @@
-x = [10,8]
-p = 2
-
-sum = 0
-for i in x:
- sum += i**p
-
-res = sum ** (1/p)
-print(res)
diff --git a/work/deep-learning/norm.txt b/work/deep-learning/norm.txt
@@ -1,8 +0,0 @@
-consider L_1 norm:
-
-L_1(<1,3>) = 4
-L_1(<4,1>) = 5
-
-L_1(a+b) = 9
-
-
diff --git a/work/deep-learning/scratch.txt b/work/deep-learning/scratch.txt
@@ -1,53 +0,0 @@
-[1 8]
-[2 3]
-
-
-det ([1 - lambda 8]) = 0
- [2 3 - lambda]
-
-
-(1 - lam)(3 - lam) - (8)(2) = 0
-(3 - lam - 3lam + lam^2) - 16 = 0
-4lam + lam^2 - 13 = 0
-
-lam = 2 +- \sqrt(17)
-
-[1 - (2 + sqrt(17)) 8]
-[2 3 - (2 + sqrt(17))]
-
-[-1 - sqrt(17) 8 ]
-[2 1 - sqrt(17)]
-
-solve for nullspace.
-
-
-[-1 - sqrt(17) 8 ][x] = [0]
-[2 1 - sqrt(17)][y] [0]
-
-0 = (-1 - sqrt(17))x + 8y
-
-0 = -x - sqrt(17)x + 8y
-
-(1 + sqrt(17))x = 8y
-
-x = 8y / (1 + sqrt(17))
-
-v_1 = [8 / (1 + sqrt(17))]
- [1 ]
-
-Do the same for \lam_2 to find
-
-v_2 = [8 / (1 - sqrt(17))]
- [1 ]
-
-We then have
-
-V = [v_1 v_2]
- = [8/(1+sqrt(17)) 8/(1-sqrt(17))]
- [1 1]
-
-A = [8/(1+sqrt(17)) 8/(1-sqrt(17))] [2 + sqrt(17) 0] V^-1
- [1 1] [0 2 - sqrt(17)]
-
-= [8/(1+sqrt(17)) 8/(1-sqrt(17))] [2 + sqrt(17) 0] 1/sqrt(17)[1 -8 / (1 - sqrt(17))]
- [1 1] [0 2 - sqrt(17)] [-1 8/ (1 + sqrt(17))]
diff --git a/work/deep-learning/solvingWithInversion.py b/work/deep-learning/solvingWithInversion.py
@@ -1,7 +0,0 @@
-import numpy as np
-
-A = np.array([[10, 2, 3], [1, 4, 1], [9, 1, 3]])
-b = np.array([10, 2, 3])
-A_inv = np.linalg.inv(A)
-result = A_inv @ b
-print(result)
diff --git a/work/linear-algebra/01-20-2025.md b/work/linear-algebra/01-20-2025.md
@@ -1,5 +0,0 @@
-Nullspace:
-
-Given that the nullspace is the set of all vectors multiplied by a matrix that result in the zero vector, it seems reasonable to conclude that whenever our matrix spans R^n where n is the span of our matrix and the matrix is linearly independent, then we only have one vector, the zero vector, in the nullspace. Additionally, if our matrix is in R^n but only spans R^n-1 then there is a subspace of V with a basis of <0, 0, ..., 1> where there is only one coordinate that has a 1 and all the rest are zeroes. We know this because there is one dimension for which our matrix does not account when doing multiplication and as such, varying that value does not impact the final result thus everything else must be zero, but that coordinate that is unaccounted for will not impact the final result.
-
-Sometimes this is also referred to as the kernel.
diff --git a/work/linear-algebra/01-21-2025.md b/work/linear-algebra/01-21-2025.md
@@ -1,34 +0,0 @@
-1.
-
-Gaussian Elimination
-
-1 2 1 | 2
-3 8 1 | 12
-0 4 1 | 2
-
-1 2 1 | 2
-0 2 -2 | 6
-0 4 1 | 2
-
-1 2 1 | 2
-0 2 -2 | 6
-0 0 5 | -10
-
-c = <2, 6, -10>
-
-
-x + 2y + z = 2
- 2y + -2z = 6
- 5z = -10
-
-z = -2
-y = 1
-x = 2
-
----
-
-2.
-
-1 2 1 | 2
-3 8 1 | 12
-0 4 1 | 2
diff --git a/work/linear-algebra/01-22-2025.md b/work/linear-algebra/01-22-2025.md
@@ -1,40 +0,0 @@
-[2] [2 12]
-[3] * [1 6] = [3 18]
-[4] [4 24]
-
-
- [2]
-[1 6] * [3] = not possible, size mismatch
- [4]
-
-
-INVERT THE MATRIX:
-
-A = [1 3]
- [2 7]
-
-
-A^-1 [1 3] = [1 0]
- [2 7] = [0 1]
-
-
-[1 3] .. [1 0]
-[2 7] [0 1]
-
-[1 3] .. [1 0]
-[0 1] [-2 1]
-
-[1 0] .. [7 -3]
-[0 1] [-2 1]
-
-inverse of A is
-
-[7 -3]
-[-2 1]
-
-To verify:
-
-[1 3] * [7 -3] = [7 - 6 -3 + 3] = [1 0]
-[2 7] [-2 1] [14 - 14 -6 + 7] [0 1]
-
-yay...
diff --git a/work/linear-algebra/01-23-2025.md b/work/linear-algebra/01-23-2025.md
@@ -1,99 +0,0 @@
-how do I get the inverse of AB?
-
-A A^-1 = I = A^-1 A
-
-Let's assume A and B are both invertible.
-
-(AB) (AB)^-1 = I
-
-(AB)^-1 = B^-1 A^-1
-
-(AB)(B^-1 A^-1) = I
-
----
-
-A A^-1 = I
-
-we use the knowledge that I = I^T to find this and then apply the same distribution from above in inversion for multiplied matricies
-this is useful because if we know A^-1 then we can also find (A^-1)^T without doing too much more work.
-
-(A^-1)^T A^T = I
-
----
-
-A = [2 1]
- [8 7]
-
-E_2,1 = [ 1 0]
- [-4 1]
-
-Elementary matrix to clear 2,1
-
-(u)
-E_2,1 A = [2 1]
- [0 3]
-
-A = L u
-
-we see L must be the inversion of E_2,1
-
-// inversion of E_2,1
-L = [1 0]
- [4 1]
-
-A = Lu
-
-// original
-A = [2 1]
- [8 7]
-
-// lower triangular
-L = [1 0]
- [4 1]
-
-// upper triangular
-u = [2 1]
- [0 3]
-
-we can also define another matrix that makes the diagonals nice and 1, but that is likely not necessary... likely.
-
----
-
-assume A is 3x3
-
-the steps to get a reduced form is to get a 0 in 2,1
-then next we do 3,1
-the last one is to get 3,2
-
-this will give us u (upper traingular)
-this process assumes there are no 0's in places we don't want them to be otherwise
-row changes are an order. This also assumes linear independence.
-
-based on the elimination matrix above, defined as E which is the combination of all eliminations,
-we can then invert this to find L because AE = u ... so if we get the inverse and multiply both
-sides we have A = E^-1u and thus A = Lu.
-
-one thing I forgot to mention above, we don't necessarily need to combine the matricies. given that AB^-1 = B^-1 A^-1 we can
-flip the order of our transformations, take each of there inverses, and then we have L. why would we do this?
-we do this because it is easier to compute the inverses of these simple matricies.
-
-A = Lu
-
----
-
-why does AB^-1 = B^-1 A^-1?
-
-if we assume it true we have
-
-(AB)^-1 B^-1 A^-1 = I
-
-we can then replace the first portion with:
-
-B^-1 (A^-1 B^-1) A^-1 = I
-
-B^-1 I A^-1 = I
-
-B^-1 A^-1 = I
-
-sick, although it might be bad form to be stating something is true then showing it is so. Not sure about that as a proof
-technique, but this is still pretty cool.
diff --git a/work/linear-algebra/01-24-2025.md b/work/linear-algebra/01-24-2025.md
@@ -1,40 +0,0 @@
-A = LU
-
-The multipliers go into L.
-
----
-
-This is pretty much Gaussian elimination but with augmented matrices.
-
----
-
-How expensive is elimination?
-
-Let's consider 3x3.
-
-There are at most, assuming no row reordering, 3 operations.
-
-This does not scale linearly though because each time we add one more row we add n-1 to the total number of computations where n is the number of columns (or rows as the matrix is assumed to be square).
-
-R(n) = R(n-1) + (n-1)
-
-n-1 + n-2 + n-3 + ... + 0
-
-duh...
-
-this can be stated as:
-
-
-this assumes it is one operation to multiply a row and then subtract. If we don't, which we may not want to, then we would find another factor of 2n added to our asymptotic function because we need to compute the multiplied row and then subtract all of the elements from that row to the other row.
-
-**_ R(n) = (n(n-1)) / 2 _**
-
-3(3 - 1) / 2 = 6 / 2 = 3
-
----
-
-This scales as a factor of n^2 because each element adds itself.
-
----
-
-this is kinda wrong; the issue with this is the assumption that we can do one operation to zero everything except the indices we don't want zeroed which would really never happen.
diff --git a/work/security/02-03-2025.md b/work/security/02-03-2025.md
@@ -1,11 +0,0 @@
-$\mathbb{Z}_m^*$ is the unit group of $\mathbb{Z_m}$ that with an inverse in $\mathbb{Z}_m$. This is all elements s.t. gcd(a,m) = 1.
-
-Z_4 = {0,1,2,3}
-
-gcd(1,4) = 1, gcd(3,4) = 1, gcd(2,4) = 2
-
-So Z_4^* = {1,3}.
-
-This is the set of the Euler Totient Function, and it's cardinality is the Eurler Totient Function's output of the specified number.
-
-Totient function is also sometimes referred to as Euler's phi function.