2023-12-11 21:24:33 -05:00
% Created 2023-12-11 Mon 19:22
2023-10-13 23:00:07 -04:00
% Intended LaTeX compiler: pdflatex
\documentclass [11pt] { article}
\usepackage [utf8] { inputenc}
\usepackage [T1] { fontenc}
\usepackage { graphicx}
\usepackage { longtable}
\usepackage { wrapfig}
\usepackage { rotating}
\usepackage [normalem] { ulem}
\usepackage { amsmath}
\usepackage { amssymb}
\usepackage { capt-of}
\usepackage { hyperref}
\notindent \notag \usepackage { amsmath} \usepackage [a4paper,margin=1in,portrait] { geometry}
\author { Elizabeth Hunt}
\date { \today }
2023-12-11 21:24:33 -05:00
\title { LIZFCM Software Manual (v0.6)}
2023-10-13 23:00:07 -04:00
\hypersetup {
pdfauthor={ Elizabeth Hunt} ,
2023-12-11 21:24:33 -05:00
pdftitle={ LIZFCM Software Manual (v0.6)} ,
2023-10-13 23:00:07 -04:00
pdfkeywords={ } ,
pdfsubject={ } ,
2023-12-11 21:24:33 -05:00
pdfcreator={ Emacs 28.2 (Org mode 9.7-pre)} ,
2023-10-13 23:00:07 -04:00
pdflang={ English} }
\begin { document}
\maketitle
\tableofcontents
\setlength \parindent { 0pt}
2023-12-11 21:24:33 -05:00
2023-10-13 23:00:07 -04:00
\section { Design}
2023-12-11 21:24:33 -05:00
\label { sec:org63deaf6}
2023-10-30 21:07:43 -04:00
The LIZFCM static library (at \url { https://github.com/Simponic/math-4610} ) is a successor to my
2023-10-13 23:09:27 -04:00
attempt at writing codes for the Fundamentals of Computational Mathematics course in Common
Lisp, but the effort required to meet the requirement of creating a static library became
too difficult to integrate outside of the \texttt { ASDF} solution that Common Lisp already brings
to the table.
2023-10-13 23:00:07 -04:00
All of the work established in \texttt { deprecated-cl} has been painstakingly translated into
the C programming language. I have a couple tenets for its design:
\begin { itemize}
2023-10-30 21:07:43 -04:00
\item Implementations of routines should all be done immutably in respect to arguments.
2023-10-13 23:09:27 -04:00
\item Functional programming is good (it's\ldots { } rough in C though).
2023-11-06 10:52:40 -05:00
\item Routines are separated into "modules" that follow a form of separation of concerns
in files, and not individual files per function.
2023-10-13 23:00:07 -04:00
\end { itemize}
2023-12-11 21:24:33 -05:00
2023-10-13 23:00:07 -04:00
\section { Compilation}
2023-12-11 21:24:33 -05:00
\label { sec:org7291327}
2023-11-06 10:52:40 -05:00
A provided \texttt { Makefile} is added for convencience. It has been tested on an \texttt { arm} -based M1 machine running
MacOS as well as \texttt { x86} Arch Linux.
2023-10-13 23:00:07 -04:00
\begin { enumerate}
\item \texttt { cd} into the root of the repo
\item \texttt { make}
\end { enumerate}
2023-10-18 15:08:22 -04:00
Then, as of homework 5, the testing routines are provided in \texttt { test} and utilize the
2023-11-06 10:52:40 -05:00
\texttt { utest} "micro"library. They compile to a binary in \texttt { ./dist/lizfcm.test} .
2023-10-13 23:00:07 -04:00
Execution of the Makefile will perform compilation of individual routines.
But, in the requirement of manual intervention (should the little alien workers
inside the computer fail to do their job), one can use the following command to
produce an object file:
\begin { verbatim}
gcc -Iinc/ -lm -Wall -c src/<the_ routine>.c -o build/<the_ routine>.o
\end { verbatim}
2023-11-11 15:15:59 -05:00
Which is then bundled into a static library in \texttt { lib/lizfcm.a} and can be linked
2023-10-13 23:00:07 -04:00
in the standard method.
2023-12-11 21:24:33 -05:00
2023-10-13 23:00:07 -04:00
\section { The LIZFCM API}
2023-12-11 21:24:33 -05:00
\label { sec:org1ebe7fa}
2023-10-13 23:00:07 -04:00
\subsection { Simple Routines}
2023-12-11 21:24:33 -05:00
\label { sec:orgff18c6b}
2023-10-13 23:00:07 -04:00
\subsubsection { \texttt { smaceps} }
2023-12-11 21:24:33 -05:00
\label { sec:org443df5e}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { smaceps}
\item Location: \texttt { src/maceps.c}
\item Input: none
\item Output: a \texttt { float} returning the specific "Machine Epsilon" of a machine on a
single precision floating point number at which it becomes "indistinguishable".
\end { itemize}
\begin { verbatim}
float smaceps() {
float one = 1.0;
float machine_ epsilon = 1.0;
float one_ approx = one + machine_ epsilon;
while (fabsf(one_ approx - one) > 0) {
machine_ epsilon /= 2;
one_ approx = one + machine_ epsilon;
}
return machine_ epsilon;
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-10-13 23:00:07 -04:00
\subsubsection { \texttt { dmaceps} }
2023-12-11 21:24:33 -05:00
\label { sec:org5121603}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { dmaceps}
\item Location: \texttt { src/maceps.c}
\item Input: none
\item Output: a \texttt { double} returning the specific "Machine Epsilon" of a machine on a
double precision floating point number at which it becomes "indistinguishable".
\end { itemize}
\begin { verbatim}
double dmaceps() {
double one = 1.0;
double machine_ epsilon = 1.0;
double one_ approx = one + machine_ epsilon;
while (fabs(one_ approx - one) > 0) {
machine_ epsilon /= 2;
one_ approx = one + machine_ epsilon;
}
return machine_ epsilon;
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-10-13 23:00:07 -04:00
\subsection { Derivative Routines}
2023-12-11 21:24:33 -05:00
\label { sec:org6fd324c}
2023-10-13 23:00:07 -04:00
\subsubsection { \texttt { central\_ derivative\_ at} }
2023-12-11 21:24:33 -05:00
\label { sec:orge9f0821}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { central\_ derivative\_ at}
\item Location: \texttt { src/approx\_ derivative.c}
\item Input:
\begin { itemize}
\item \texttt { f} is a pointer to a one-ary function that takes a double as input and produces
a double as output
\item \texttt { a} is the domain value at which we approximate \texttt { f'}
\item \texttt { h} is the step size
\end { itemize}
\item Output: a \texttt { double} of the approximate value of \texttt { f'(a)} via the central difference
method.
\end { itemize}
\begin { verbatim}
double central_ derivative_ at(double (*f)(double), double a, double h) {
assert(h > 0);
double x2 = a + h;
double x1 = a - h;
2023-11-27 12:14:50 -05:00
double y2 = f(x2);
double y1 = f(x1);
2023-10-13 23:00:07 -04:00
return (y2 - y1) / (x2 - x1);
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-10-13 23:00:07 -04:00
\subsubsection { \texttt { forward\_ derivative\_ at} }
2023-12-11 21:24:33 -05:00
\label { sec:org8720f28}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { forward\_ derivative\_ at}
\item Location: \texttt { src/approx\_ derivative.c}
\item Input:
\begin { itemize}
\item \texttt { f} is a pointer to a one-ary function that takes a double as input and produces
a double as output
\item \texttt { a} is the domain value at which we approximate \texttt { f'}
\item \texttt { h} is the step size
\end { itemize}
\item Output: a \texttt { double} of the approximate value of \texttt { f'(a)} via the forward difference
method.
\end { itemize}
\begin { verbatim}
double forward_ derivative_ at(double (*f)(double), double a, double h) {
assert(h > 0);
double x2 = a + h;
double x1 = a;
2023-11-27 12:14:50 -05:00
double y2 = f(x2);
double y1 = f(x1);
2023-10-13 23:00:07 -04:00
return (y2 - y1) / (x2 - x1);
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-10-13 23:00:07 -04:00
\subsubsection { \texttt { backward\_ derivative\_ at} }
2023-12-11 21:24:33 -05:00
\label { sec:org1589b19}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { backward\_ derivative\_ at}
\item Location: \texttt { src/approx\_ derivative.c}
\item Input:
\begin { itemize}
\item \texttt { f} is a pointer to a one-ary function that takes a double as input and produces
a double as output
\item \texttt { a} is the domain value at which we approximate \texttt { f'}
\item \texttt { h} is the step size
\end { itemize}
\item Output: a \texttt { double} of the approximate value of \texttt { f'(a)} via the backward difference
method.
\end { itemize}
\begin { verbatim}
double backward_ derivative_ at(double (*f)(double), double a, double h) {
assert(h > 0);
double x2 = a;
double x1 = a - h;
2023-11-27 12:14:50 -05:00
double y2 = f(x2);
double y1 = f(x1);
2023-10-13 23:00:07 -04:00
return (y2 - y1) / (x2 - x1);
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-10-13 23:00:07 -04:00
\subsection { Vector Routines}
2023-12-11 21:24:33 -05:00
\label { sec:org493841e}
2023-10-13 23:00:07 -04:00
\subsubsection { Vector Arithmetic: \texttt { add\_ v, minus\_ v} }
2023-12-11 21:24:33 -05:00
\label { sec:org3912c29}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name(s): \texttt { add\_ v} , \texttt { minus\_ v}
\item Location: \texttt { src/vector.c}
\item Input: two pointers to locations in memory wherein \texttt { Array\_ double} 's lie
\item Output: a pointer to a new \texttt { Array\_ double} as the result of addition or subtraction
of the two input \texttt { Array\_ double} 's
\end { itemize}
\begin { verbatim}
Array_ double *add_ v(Array_ double *v1, Array_ double *v2) {
assert(v1->size == v2->size);
Array_ double *sum = copy_ vector(v1);
for (size_ t i = 0; i < v1->size; i++)
sum->data[i] += v2->data[i];
return sum;
}
Array_ double *minus_ v(Array_ double *v1, Array_ double *v2) {
assert(v1->size == v2->size);
Array_ double *sub = InitArrayWithSize(double, v1->size, 0);
for (size_ t i = 0; i < v1->size; i++)
sub->data[i] = v1->data[i] - v2->data[i];
return sub;
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-10-13 23:00:07 -04:00
\subsubsection { Norms: \texttt { l1\_ norm} , \texttt { l2\_ norm} , \texttt { linf\_ norm} }
2023-12-11 21:24:33 -05:00
\label { sec:orged74cfb}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name(s): \texttt { l1\_ norm} , \texttt { l2\_ norm} , \texttt { linf\_ norm}
\item Location: \texttt { src/vector.c}
\item Input: a pointer to a location in memory wherein an \texttt { Array\_ double} lies
\item Output: a \texttt { double} representing the value of the norm the function applies
\end { itemize}
\begin { verbatim}
double l1_ norm(Array_ double *v) {
double sum = 0;
for (size_ t i = 0; i < v->size; ++i)
sum += fabs(v->data[i]);
return sum;
}
double l2_ norm(Array_ double *v) {
double norm = 0;
for (size_ t i = 0; i < v->size; ++i)
norm += v->data[i] * v->data[i];
return sqrt(norm);
}
double linf_ norm(Array_ double *v) {
assert(v->size > 0);
double max = v->data[0];
for (size_ t i = 0; i < v->size; ++i)
max = c_ max(v->data[i], max);
return max;
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-10-13 23:00:07 -04:00
\subsubsection { \texttt { vector\_ distance} }
2023-12-11 21:24:33 -05:00
\label { sec:org20a5773}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { vector\_ distance}
\item Location: \texttt { src/vector.c}
\item Input: two pointers to locations in memory wherein \texttt { Array\_ double} 's lie, and a pointer to a
one-ary function \texttt { norm} taking as input a pointer to an \texttt { Array\_ double} and returning a double
representing the norm of that \texttt { Array\_ double}
\end { itemize}
\begin { verbatim}
double vector_ distance(Array_ double *v1, Array_ double *v2,
double (*norm)(Array_ double *)) {
Array_ double *minus = minus_ v(v1, v2);
double dist = (*norm)(minus);
free(minus);
return dist;
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-10-13 23:00:07 -04:00
\subsubsection { Distances: \texttt { l1\_ distance} , \texttt { l2\_ distance} , \texttt { linf\_ distance} }
2023-12-11 21:24:33 -05:00
\label { sec:orgac16178}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name(s): \texttt { l1\_ distance} , \texttt { l2\_ distance} , \texttt { linf\_ distance}
\item Location: \texttt { src/vector.c}
\item Input: two pointers to locations in memory wherein \texttt { Array\_ double} 's lie, and the distance
via the corresponding \texttt { l1} , \texttt { l2} , or \texttt { linf} norms
\item Output: A \texttt { double} representing the distance between the two \texttt { Array\_ doubles} 's by the given
norm.
\end { itemize}
\begin { verbatim}
double l1_ distance(Array_ double *v1, Array_ double *v2) {
return vector_ distance(v1, v2, & l1_ norm);
}
double l2_ distance(Array_ double *v1, Array_ double *v2) {
return vector_ distance(v1, v2, & l2_ norm);
}
double linf_ distance(Array_ double *v1, Array_ double *v2) {
return vector_ distance(v1, v2, & linf_ norm);
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-10-13 23:00:07 -04:00
\subsubsection { \texttt { sum\_ v} }
2023-12-11 21:24:33 -05:00
\label { sec:org876aafa}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { sum\_ v}
\item Location: \texttt { src/vector.c}
\item Input: a pointer to an \texttt { Array\_ double}
\item Output: a \texttt { double} representing the sum of all the elements of an \texttt { Array\_ double}
\end { itemize}
\begin { verbatim}
double sum_ v(Array_ double *v) {
double sum = 0;
for (size_ t i = 0; i < v->size; i++)
sum += v->data[i];
return sum;
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-10-13 23:00:07 -04:00
\subsubsection { \texttt { scale\_ v} }
2023-12-11 21:24:33 -05:00
\label { sec:orgf1d236c}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { scale\_ v}
\item Location: \texttt { src/vector.c}
\item Input: a pointer to an \texttt { Array\_ double} and a scalar \texttt { double} to scale the vector
\item Output: a pointer to a new \texttt { Array\_ double} of the scaled input \texttt { Array\_ double}
\end { itemize}
\begin { verbatim}
Array_ double *scale_ v(Array_ double *v, double m) {
Array_ double *copy = copy_ vector(v);
for (size_ t i = 0; i < v->size; i++)
copy->data[i] *= m;
return copy;
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-10-13 23:00:07 -04:00
\subsubsection { \texttt { free\_ vector} }
2023-12-11 21:24:33 -05:00
\label { sec:org2ca163d}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { free\_ vector}
\item Location: \texttt { src/vector.c}
\item Input: a pointer to an \texttt { Array\_ double}
\item Output: nothing.
\item Side effect: free the memory of the reserved \texttt { Array\_ double} on the heap
\end { itemize}
\begin { verbatim}
void free_ vector(Array_ double *v) {
free(v->data);
free(v);
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-11-06 10:52:40 -05:00
\subsubsection { \texttt { add\_ element} }
2023-12-11 21:24:33 -05:00
\label { sec:org7a99233}
2023-11-06 10:52:40 -05:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { add\_ element}
\item Location: \texttt { src/vector.c}
\item Input: a pointer to an \texttt { Array\_ double}
\item Output: a new \texttt { Array\_ double} with element \texttt { x} appended.
\end { itemize}
\begin { verbatim}
Array_ double *add_ element(Array_ double *v, double x) {
Array_ double *pushed = InitArrayWithSize(double, v->size + 1, 0.0);
for (size_ t i = 0; i < v->size; ++i)
pushed->data[i] = v->data[i];
pushed->data[v->size] = x;
return pushed;
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-11-06 10:52:40 -05:00
\subsubsection { \texttt { slice\_ element} }
2023-12-11 21:24:33 -05:00
\label { sec:org6c07c99}
2023-11-06 10:52:40 -05:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { slice\_ element}
\item Location: \texttt { src/vector.c}
\item Input: a pointer to an \texttt { Array\_ double}
\item Output: a new \texttt { Array\_ double} with element \texttt { x} sliced.
\end { itemize}
\begin { verbatim}
Array_ double *slice_ element(Array_ double *v, size_ t x) {
Array_ double *sliced = InitArrayWithSize(double, v->size - 1, 0.0);
for (size_ t i = 0; i < v->size - 1; ++i)
sliced->data[i] = i >= x ? v->data[i + 1] : v->data[i];
return sliced;
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-10-13 23:00:07 -04:00
\subsubsection { \texttt { copy\_ vector} }
2023-12-11 21:24:33 -05:00
\label { sec:org81f7cc1}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { copy\_ vector}
\item Location: \texttt { src/vector.c}
\item Input: a pointer to an \texttt { Array\_ double}
\item Output: a pointer to a new \texttt { Array\_ double} whose \texttt { data} and \texttt { size} are copied from the input
\texttt { Array\_ double}
\end { itemize}
\begin { verbatim}
Array_ double *copy_ vector(Array_ double *v) {
Array_ double *copy = InitArrayWithSize(double, v->size, 0.0);
for (size_ t i = 0; i < copy->size; ++i)
copy->data[i] = v->data[i];
return copy;
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-10-13 23:00:07 -04:00
\subsubsection { \texttt { format\_ vector\_ into} }
2023-12-11 21:24:33 -05:00
\label { sec:orgd168171}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { format\_ vector\_ into}
\item Location: \texttt { src/vector.c}
\item Input: a pointer to an \texttt { Array\_ double} and a pointer to a c-string \texttt { s} to "print" the vector out
into
\item Output: nothing.
\item Side effect: overwritten memory into \texttt { s}
\end { itemize}
\begin { verbatim}
void format_ vector_ into(Array_ double *v, char *s) {
if (v->size == 0) {
strcat(s, "empty");
return;
}
for (size_ t i = 0; i < v->size; ++i) {
char num[64];
strcpy(num, "");
sprintf(num, "%f,", v->data[i]);
strcat(s, num);
}
strcat(s, "\n ");
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-10-13 23:00:07 -04:00
\subsection { Matrix Routines}
2023-12-11 21:24:33 -05:00
\label { sec:org5c45c12}
2023-10-13 23:00:07 -04:00
\subsubsection { \texttt { lu\_ decomp} }
2023-12-11 21:24:33 -05:00
\label { sec:orgf1e0ac3}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { lu\_ decomp}
\item Location: \texttt { src/matrix.c}
\item Input: a pointer to a \texttt { Matrix\_ double} \( m \) to decompose into a lower triangular and upper triangular
matrix \( L \) , \( U \) , respectively such that \( LU = m \) .
\item Output: a pointer to the location in memory in which two \texttt { Matrix\_ double} 's reside: the first
representing \( L \) , the second, \( U \) .
2023-11-06 10:52:40 -05:00
\item Errors: Fails assertions when encountering a matrix that cannot be
2023-10-13 23:00:07 -04:00
decomposed
\end { itemize}
\begin { verbatim}
Matrix_ double **lu_ decomp(Matrix_ double *m) {
assert(m->cols == m->rows);
Matrix_ double *u = copy_ matrix(m);
2023-10-13 23:09:27 -04:00
Matrix_ double *l_ empt = InitMatrixWithSize(double, m->rows, m->cols, 0.0);
Matrix_ double *l = put_ identity_ diagonal(l_ empt);
2023-11-06 10:52:40 -05:00
free_ matrix(l_ empt);
2023-10-13 23:00:07 -04:00
Matrix_ double **u_ l = malloc(sizeof(Matrix_ double *) * 2);
for (size_ t y = 0; y < m->rows; y++) {
if (u->data[y]->data[y] == 0) {
printf("ERROR: a pivot is zero in given matrix\n ");
2023-11-06 10:52:40 -05:00
assert(false);
2023-10-13 23:00:07 -04:00
}
}
if (u & & l) {
for (size_ t x = 0; x < m->cols; x++) {
for (size_ t y = x + 1; y < m->rows; y++) {
double denom = u->data[x]->data[x];
if (denom == 0) {
printf("ERROR: non-factorable matrix\n ");
2023-11-06 10:52:40 -05:00
assert(false);
2023-10-13 23:00:07 -04:00
}
double factor = -(u->data[y]->data[x] / denom);
Array_ double *scaled = scale_ v(u->data[x], factor);
Array_ double *added = add_ v(scaled, u->data[y]);
free_ vector(scaled);
free_ vector(u->data[y]);
u->data[y] = added;
l->data[y]->data[x] = -factor;
}
}
}
u_ l[0] = u;
u_ l[1] = l;
return u_ l;
}
\end { verbatim}
\subsubsection { \texttt { bsubst} }
2023-12-11 21:24:33 -05:00
\label { sec:orgec7e4b5}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { bsubst}
\item Location: \texttt { src/matrix.c}
\item Input: a pointer to an upper-triangular \texttt { Matrix\_ double} \( u \) and a \texttt { Array\_ double}
\( b \)
\item Output: a pointer to a new \texttt { Array\_ double} whose entries are given by performing
back substitution
\end { itemize}
\begin { verbatim}
Array_ double *bsubst(Matrix_ double *u, Array_ double *b) {
assert(u->rows == b->size & & u->cols == u->rows);
Array_ double *x = copy_ vector(b);
for (int64_ t row = b->size - 1; row >= 0; row--) {
for (size_ t col = b->size - 1; col > row; col--)
x->data[row] -= x->data[col] * u->data[row]->data[col];
x->data[row] /= u->data[row]->data[row];
}
return x;
}
\end { verbatim}
\subsubsection { \texttt { fsubst} }
2023-12-11 21:24:33 -05:00
\label { sec:org72ff2ed}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { fsubst}
\item Location: \texttt { src/matrix.c}
\item Input: a pointer to a lower-triangular \texttt { Matrix\_ double} \( l \) and a \texttt { Array\_ double}
\( b \)
\item Output: a pointer to a new \texttt { Array\_ double} whose entries are given by performing
forward substitution
\end { itemize}
\begin { verbatim}
Array_ double *fsubst(Matrix_ double *l, Array_ double *b) {
assert(l->rows == b->size & & l->cols == l->rows);
Array_ double *x = copy_ vector(b);
for (size_ t row = 0; row < b->size; row++) {
for (size_ t col = 0; col < row; col++)
x->data[row] -= x->data[col] * l->data[row]->data[col];
x->data[row] /= l->data[row]->data[row];
}
return x;
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-11-06 10:52:40 -05:00
\subsubsection { \texttt { solve\_ matrix\_ lu\_ bsubst} }
2023-12-11 21:24:33 -05:00
\label { sec:orga735557}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Location: \texttt { src/matrix.c}
\item Input: a pointer to a \texttt { Matrix\_ double} \( m \) and a pointer to an \texttt { Array\_ double} \( b \)
\item Output: \( x \) such that \( mx = b \) if such a solution exists (else it's non LU-factorable as discussed
above)
\end { itemize}
Here we make use of forward substitution to first solve \( Ly = b \) given \( L \) as the \( L \) factor in
\texttt { lu\_ decomp} . Then we use back substitution to solve \( Ux = y \) for \( x \) similarly given \( U \) .
Then, \( LUx = b \) , thus \( x \) is a solution.
\begin { verbatim}
2023-11-06 10:52:40 -05:00
Array_ double *solve_ matrix_ lu_ bsubst(Matrix_ double *m, Array_ double *b) {
2023-10-13 23:00:07 -04:00
assert(b->size == m->rows);
assert(m->rows == m->cols);
Array_ double *x = copy_ vector(b);
Matrix_ double **u_ l = lu_ decomp(m);
Matrix_ double *u = u_ l[0];
Matrix_ double *l = u_ l[1];
Array_ double *b_ fsub = fsubst(l, b);
x = bsubst(u, b_ fsub);
free_ vector(b_ fsub);
free_ matrix(u);
free_ matrix(l);
2023-11-06 10:52:40 -05:00
free(u_ l);
2023-10-13 23:00:07 -04:00
return x;
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-11-06 10:52:40 -05:00
\subsubsection { \texttt { gaussian\_ elimination} }
2023-12-11 21:24:33 -05:00
\label { sec:org71d2519}
2023-11-06 10:52:40 -05:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Location: \texttt { src/matrix.c}
\item Input: a pointer to a \texttt { Matrix\_ double} \( m \)
\item Output: a pointer to a copy of \( m \) in reduced echelon form
\end { itemize}
This works by finding the row with a maximum value in the column \( k \) . Then, it uses that as a pivot, and
applying reduction to all other rows. The general idea is available at \url { https://en.wikipedia.org/wiki/Gaussian\_ elimination} .
\begin { verbatim}
Matrix_ double *gaussian_ elimination(Matrix_ double *m) {
2023-12-11 21:24:33 -05:00
uint64_ t h = 0, k = 0;
2023-11-06 10:52:40 -05:00
Matrix_ double *m_ cp = copy_ matrix(m);
while (h < m_ cp->rows & & k < m_ cp->cols) {
2023-12-11 21:24:33 -05:00
uint64_ t max_ row = h;
double max_ val = 0.0;
2023-11-06 10:52:40 -05:00
for (uint64_ t row = h; row < m_ cp->rows; row++) {
2023-12-11 21:24:33 -05:00
double val = fabs(m_ cp->data[row]->data[k]);
if (val > max_ val) {
max_ val = val;
2023-11-06 10:52:40 -05:00
max_ row = row;
}
}
2023-12-11 21:24:33 -05:00
if (max_ val == 0.0) {
2023-11-06 10:52:40 -05:00
k++;
continue;
}
2023-12-11 21:24:33 -05:00
if (max_ row != h) {
Array_ double *swp = m_ cp->data[max_ row];
m_ cp->data[max_ row] = m_ cp->data[h];
m_ cp->data[h] = swp;
}
2023-11-06 10:52:40 -05:00
for (uint64_ t row = h + 1; row < m_ cp->rows; row++) {
double factor = m_ cp->data[row]->data[k] / m_ cp->data[h]->data[k];
m_ cp->data[row]->data[k] = 0.0;
for (uint64_ t col = k + 1; col < m_ cp->cols; col++) {
m_ cp->data[row]->data[col] -= m_ cp->data[h]->data[col] * factor;
}
}
h++;
k++;
}
return m_ cp;
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-11-06 10:52:40 -05:00
\subsubsection { \texttt { solve\_ matrix\_ gaussian} }
2023-12-11 21:24:33 -05:00
\label { sec:org230915f}
2023-11-06 10:52:40 -05:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Location: \texttt { src/matrix.c}
\item Input: a pointer to a \texttt { Matrix\_ double} \( m \) and a target \texttt { Array\_ double} \( b \)
\item Output: a pointer to a vector \( x \) being the solution to the equation \( mx = b \)
\end { itemize}
We first perform \texttt { gaussian\_ elimination} after augmenting \( m \) and \( b \) . Then, as \( m \) is in reduced echelon form, it's an upper
triangular matrix, so we can perform back substitution to compute \( x \) .
\begin { verbatim}
Array_ double *solve_ matrix_ gaussian(Matrix_ double *m, Array_ double *b) {
assert(b->size == m->rows);
assert(m->rows == m->cols);
Matrix_ double *m_ augment_ b = add_ column(m, b);
Matrix_ double *eliminated = gaussian_ elimination(m_ augment_ b);
Array_ double *b_ gauss = col_ v(eliminated, m->cols);
Matrix_ double *u = slice_ column(eliminated, m->rows);
Array_ double *solution = bsubst(u, b_ gauss);
free_ matrix(m_ augment_ b);
free_ matrix(eliminated);
free_ matrix(u);
free_ vector(b_ gauss);
return solution;
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-10-13 23:00:07 -04:00
\subsubsection { \texttt { m\_ dot\_ v} }
2023-12-11 21:24:33 -05:00
\label { sec:org83c8351}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Location: \texttt { src/matrix.c}
\item Input: a pointer to a \texttt { Matrix\_ double} \( m \) and \texttt { Array\_ double} \( v \)
\item Output: the dot product \( mv \) as an \texttt { Array\_ double}
\end { itemize}
\begin { verbatim}
Array_ double *m_ dot_ v(Matrix_ double *m, Array_ double *v) {
assert(v->size == m->cols);
Array_ double *product = copy_ vector(v);
for (size_ t row = 0; row < v->size; ++row)
product->data[row] = v_ dot_ v(m->data[row], v);
return product;
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-10-13 23:00:07 -04:00
\subsubsection { \texttt { put\_ identity\_ diagonal} }
2023-12-11 21:24:33 -05:00
\label { sec:orge3fcb3e}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Location: \texttt { src/matrix.c}
\item Input: a pointer to a \texttt { Matrix\_ double}
\item Output: a pointer to a copy to \texttt { Matrix\_ double} whose diagonal is full of 1's
\end { itemize}
\begin { verbatim}
Matrix_ double *put_ identity_ diagonal(Matrix_ double *m) {
assert(m->rows == m->cols);
Matrix_ double *copy = copy_ matrix(m);
for (size_ t y = 0; y < m->rows; ++y)
copy->data[y]->data[y] = 1.0;
return copy;
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-11-06 10:52:40 -05:00
\subsubsection { \texttt { slice\_ column} }
2023-12-11 21:24:33 -05:00
\label { sec:org95e39ba}
2023-11-06 10:52:40 -05:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Location: \texttt { src/matrix.c}
\item Input: a pointer to a \texttt { Matrix\_ double}
\item Output: a pointer to a copy of the given \texttt { Matrix\_ double} with column at \texttt { x} sliced
\end { itemize}
\begin { verbatim}
Matrix_ double *slice_ column(Matrix_ double *m, size_ t x) {
Matrix_ double *sliced = copy_ matrix(m);
for (size_ t row = 0; row < m->rows; row++) {
Array_ double *old_ row = sliced->data[row];
sliced->data[row] = slice_ element(old_ row, x);
free_ vector(old_ row);
}
sliced->cols--;
return sliced;
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-11-06 10:52:40 -05:00
\subsubsection { \texttt { add\_ column} }
2023-12-11 21:24:33 -05:00
\label { sec:org9a2ad93}
2023-11-06 10:52:40 -05:00
\begin { itemize}
\item Author: Elizabet Hunt
\item Location: \texttt { src/matrix.c}
\item Input: a pointer to a \texttt { Matrix\_ double} and a new vector representing the appended column \texttt { x}
\item Output: a pointer to a copy of the given \texttt { Matrix\_ double} with a new column \texttt { x}
\end { itemize}
\begin { verbatim}
Matrix_ double *add_ column(Matrix_ double *m, Array_ double *v) {
Matrix_ double *pushed = copy_ matrix(m);
for (size_ t row = 0; row < m->rows; row++) {
Array_ double *old_ row = pushed->data[row];
pushed->data[row] = add_ element(old_ row, v->data[row]);
free_ vector(old_ row);
}
pushed->cols++;
return pushed;
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-10-13 23:00:07 -04:00
\subsubsection { \texttt { copy\_ matrix} }
2023-12-11 21:24:33 -05:00
\label { sec:org63765c0}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Location: \texttt { src/matrix.c}
\item Input: a pointer to a \texttt { Matrix\_ double}
\item Output: a pointer to a copy of the given \texttt { Matrix\_ double}
\end { itemize}
\begin { verbatim}
Matrix_ double *copy_ matrix(Matrix_ double *m) {
Matrix_ double *copy = InitMatrixWithSize(double, m->rows, m->cols, 0.0);
for (size_ t y = 0; y < copy->rows; y++) {
free_ vector(copy->data[y]);
copy->data[y] = copy_ vector(m->data[y]);
}
return copy;
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-10-13 23:00:07 -04:00
\subsubsection { \texttt { free\_ matrix} }
2023-12-11 21:24:33 -05:00
\label { sec:orgc337967}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Location: \texttt { src/matrix.c}
\item Input: a pointer to a \texttt { Matrix\_ double}
\item Output: none.
\item Side Effects: frees memory reserved by a given \texttt { Matrix\_ double} and its member
\texttt { Array\_ double} vectors describing its rows.
\end { itemize}
\begin { verbatim}
void free_ matrix(Matrix_ double *m) {
for (size_ t y = 0; y < m->rows; ++y)
free_ vector(m->data[y]);
free(m);
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-10-13 23:00:07 -04:00
\subsubsection { \texttt { format\_ matrix\_ into} }
2023-12-11 21:24:33 -05:00
\label { sec:org6b188b4}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { format\_ matrix\_ into}
\item Location: \texttt { src/matrix.c}
\item Input: a pointer to a \texttt { Matrix\_ double} and a pointer to a c-string \texttt { s} to "print" the vector out
into
\item Output: nothing.
\item Side effect: overwritten memory into \texttt { s}
\end { itemize}
\begin { verbatim}
void format_ matrix_ into(Matrix_ double *m, char *s) {
if (m->rows == 0)
strcpy(s, "empty");
for (size_ t y = 0; y < m->rows; ++y) {
2023-12-11 21:24:33 -05:00
char row_ s[5192];
2023-10-13 23:00:07 -04:00
strcpy(row_ s, "");
format_ vector_ into(m->data[y], row_ s);
strcat(s, row_ s);
}
strcat(s, "\n ");
}
\end { verbatim}
2023-10-18 15:08:22 -04:00
\subsection { Root Finding Methods}
2023-12-11 21:24:33 -05:00
\label { sec:org352ccdf}
2023-10-18 15:08:22 -04:00
\subsubsection { \texttt { find\_ ivt\_ range} }
2023-12-11 21:24:33 -05:00
\label { sec:orgb9a0d16}
2023-10-18 15:08:22 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { find\_ ivt\_ range}
\item Location: \texttt { src/roots.c}
\item Input: a pointer to a oneary function taking a double and producing a double, the beginning point
in \( R \) to search for a range, a \texttt { delta} step that is taken, and a \texttt { max\_ steps} number of maximum
iterations to perform.
2023-11-11 15:15:59 -05:00
\item Output: a pair of \texttt { double} 's in an \texttt { Array\_ double} representing a closed closed interval \texttt { [beginning, end]}
2023-10-18 15:08:22 -04:00
\end { itemize}
\begin { verbatim}
2023-11-11 15:15:59 -05:00
// f is well defined at start_ x + delta*n for all n on the integer range [0,
// max_ iterations]
Array_ double *find_ ivt_ range(double (*f)(double), double start_ x, double delta,
size_ t max_ iterations) {
2023-10-18 15:08:22 -04:00
double a = start_ x;
2023-11-11 15:15:59 -05:00
while (f(a) * f(a + delta) >= 0 & & max_ iterations > 0) {
max_ iterations--;
2023-10-18 15:08:22 -04:00
a += delta;
2023-11-11 15:15:59 -05:00
}
2023-10-18 15:08:22 -04:00
2023-11-11 15:15:59 -05:00
double end = a + delta;
double begin = a - delta;
2023-10-18 15:08:22 -04:00
2023-11-11 15:15:59 -05:00
if (max_ iterations == 0 & & f(begin) * f(end) >= 0)
return NULL;
return InitArray(double, { begin, end} );
2023-10-18 15:08:22 -04:00
}
\end { verbatim}
\subsubsection { \texttt { bisect\_ find\_ root} }
2023-12-11 21:24:33 -05:00
\label { sec:org25382b3}
2023-10-18 15:08:22 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name(s): \texttt { bisect\_ find\_ root}
\item Input: a one-ary function taking a double and producing a double, a closed interval represented
2023-11-11 15:15:59 -05:00
by \texttt { a} and \texttt { b} : \texttt { [a, b]} , a \texttt { tolerance} at which we return the estimated root once \( b - a < \text { tolerance } \) , and a
\texttt { max\_ iterations} to break us out of a loop if we can never reach the \texttt { tolerance} .
2023-11-27 12:14:50 -05:00
\item Output: a vector of size of 3, \texttt { double} 's representing first the range \texttt { [a,b]} and then the midpoint,
\texttt { c} of the range.
2023-10-18 15:08:22 -04:00
\item Description: recursively uses binary search to split the interval until we reach \texttt { tolerance} . We
also assume the function \texttt { f} is continuous on \texttt { [a, b]} .
\end { itemize}
\begin { verbatim}
2023-11-11 15:15:59 -05:00
// f is continuous on [a, b]
Array_ double *bisect_ find_ root(double (*f)(double), double a, double b,
double tolerance, size_ t max_ iterations) {
2023-10-18 15:08:22 -04:00
assert(a <= b);
// guarantee there's a root somewhere between a and b by IVT
assert(f(a) * f(b) < 0);
double c = (1.0 / 2) * (a + b);
if (b - a < tolerance || max_ iterations == 0)
2023-11-27 12:14:50 -05:00
return InitArray(double, { a, b, c} );
2023-11-11 15:15:59 -05:00
2023-10-18 15:08:22 -04:00
if (f(a) * f(c) < 0)
return bisect_ find_ root(f, a, c, tolerance, max_ iterations - 1);
return bisect_ find_ root(f, c, b, tolerance, max_ iterations - 1);
}
\end { verbatim}
\subsubsection { \texttt { bisect\_ find\_ root\_ with\_ error\_ assumption} }
2023-12-11 21:24:33 -05:00
\label { sec:org4b9cb72}
2023-10-18 15:08:22 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { bisect\_ find\_ root\_ with\_ error\_ assumption}
\item Input: a one-ary function taking a double and producing a double, a closed interval represented
2023-11-11 15:15:59 -05:00
by \texttt { a} and \texttt { b} : \texttt { [a, b]} , and a \texttt { tolerance} equivalent to the above definition in \texttt { bisect\_ find\_ root}
2023-10-18 15:08:22 -04:00
\item Output: a \texttt { double} representing the estimated root
\item Description: using the bisection method we know that \( e _ k \le ( \frac { 1 } { 2 } ) ^ k ( b _ 0 - a _ 0 ) \) . So we can
calculate \( k \) at the worst possible case (that the error is exactly the tolerance) to be
\( \frac { log ( tolerance ) - log ( b _ 0 - a _ 0 ) } { log ( \frac { 1 } { 2 } ) } \) . We pass this value into the \texttt { max\_ iterations}
of \texttt { bisect\_ find\_ root} as above.
\end { itemize}
\begin { verbatim}
double bisect_ find_ root_ with_ error_ assumption(double (*f)(double), double a,
double b, double tolerance) {
assert(a <= b);
uint64_ t max_ iterations =
(uint64_ t)ceil((log(tolerance) - log(b - a)) / log(1 / 2.0));
2023-11-11 15:15:59 -05:00
Array_ double *a_ b_ root = bisect_ find_ root(f, a, b, tolerance, max_ iterations);
double root = a_ b_ root->data[2];
free_ vector(a_ b_ root);
return root;
2023-10-18 15:08:22 -04:00
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-11-11 15:15:59 -05:00
\subsubsection { \texttt { fixed\_ point\_ iteration\_ method} }
2023-12-11 21:24:33 -05:00
\label { sec:org4cee2bd}
2023-11-11 15:15:59 -05:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { fixed\_ point\_ iteration\_ method}
\item Location: \texttt { src/roots.c}
\item Input: a pointer to a oneary function \( f \) taking a double and producing a double of which we are
trying to find a root, a guess \( x _ 0 \) , and a function \( g \) of the same signature of \( f \) at which we
"step" our guesses according to the fixed point iteration method: \( x _ k = g ( x _ { k - 1 } ) \) . Additionally, a
\texttt { max\_ iterations} representing the maximum number of "steps" to take before arriving at our
approximation and a \texttt { tolerance} to return our root if it becomes within [0 - tolerance, 0 + tolerance].
\item Assumptions: \( g ( x ) \) must be a function such that at the point \( x ^ * \) (the found root) the derivative
\( |g' ( x ^ * ) | \lt 1 \)
\item Output: a double representing the found approximate root \( \approx x ^ * \) .
\end { itemize}
2023-10-18 15:08:22 -04:00
2023-11-11 15:15:59 -05:00
\begin { verbatim}
double fixed_ point_ iteration_ method(double (*f)(double), double (*g)(double),
double x_ 0, double tolerance,
size_ t max_ iterations) {
if (max_ iterations <= 0)
return x_ 0;
double root = g(x_ 0);
if (tolerance >= fabs(f(root)))
return root;
return fixed_ point_ iteration_ method(f, g, root, tolerance,
max_ iterations - 1);
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-11-11 15:15:59 -05:00
\subsubsection { \texttt { fixed\_ point\_ newton\_ method} }
2023-12-11 21:24:33 -05:00
\label { sec:org93e3999}
2023-11-11 15:15:59 -05:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { fixed\_ point\_ newton\_ method}
\item Location: \texttt { src/roots.c}
\item Input: a pointer to a oneary function \( f \) taking a double and producing a double of which we are
trying to find a root and another pointer to a function fprime of the same signature, a guess \( x _ 0 \) ,
and a \texttt { max\_ iterations} and \texttt { tolerance} as defined in the above method are required inputs.
\item Description: continually computes elements in the sequence \( x _ n = x _ { n - 1 } - \frac { f ( x _ { n - 1 } ) } { f'p ( x _ { n - 1 } ) } \)
\item Output: a double representing the found approximate root \( \approx x ^ * \) recursively applied to the sequence
given
\end { itemize}
\begin { verbatim}
double fixed_ point_ newton_ method(double (*f)(double), double (*fprime)(double),
double x_ 0, double tolerance,
size_ t max_ iterations) {
if (max_ iterations <= 0)
return x_ 0;
double root = x_ 0 - f(x_ 0) / fprime(x_ 0);
if (tolerance >= fabs(f(root)))
return root;
return fixed_ point_ newton_ method(f, fprime, root, tolerance,
max_ iterations - 1);
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-11-11 15:15:59 -05:00
\subsubsection { \texttt { fixed\_ point\_ secant\_ method} }
2023-12-11 21:24:33 -05:00
\label { sec:orgf3f0711}
2023-11-11 15:15:59 -05:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { fixed\_ point\_ secant\_ method}
\item Location: \texttt { src/roots.c}
\item Input: a pointer to a oneary function \( f \) taking a double and producing a double of which we are
2023-11-27 12:14:50 -05:00
trying to find a root, a guess \( x _ 0 \) and \( x _ 1 \) in which a root lies between \( [ x _ 0 , x _ 1 ] \) ; applying the
sequence \( x _ n = x _ { n - 1 } - f ( x _ { n - 1 } ) \frac { x _ { n - 1 } - x _ { n - 2 } } { f ( x _ { n - 1 } ) - f ( x _ { n - 2 } ) } \) .
2023-11-11 15:15:59 -05:00
Additionally, a \texttt { max\_ iterations} and \texttt { tolerance} as defined in the above method are required
inputs.
\item Output: a double representing the found approximate root \( \approx x ^ * \) recursively applied to the sequence.
\end { itemize}
\begin { verbatim}
2023-11-27 12:14:50 -05:00
double fixed_ point_ secant_ method(double (*f)(double), double x_ 0, double x_ 1,
2023-11-11 15:15:59 -05:00
double tolerance, size_ t max_ iterations) {
2023-11-27 12:14:50 -05:00
if (max_ iterations == 0)
return x_ 1;
2023-11-11 15:15:59 -05:00
2023-11-27 12:14:50 -05:00
double root = x_ 1 - f(x_ 1) * ((x_ 1 - x_ 0) / (f(x_ 1) - f(x_ 0)));
2023-11-11 15:15:59 -05:00
if (tolerance >= fabs(f(root)))
return root;
2023-11-27 12:14:50 -05:00
return fixed_ point_ secant_ method(f, x_ 1, root, tolerance, max_ iterations - 1);
2023-11-11 15:15:59 -05:00
}
\end { verbatim}
\subsubsection { \texttt { fixed\_ point\_ secant\_ bisection\_ method} }
2023-12-11 21:24:33 -05:00
\label { sec:orgeaef048}
2023-11-11 15:15:59 -05:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { fixed\_ point\_ secant\_ method}
\item Location: \texttt { src/roots.c}
\item Input: a pointer to a oneary function \( f \) taking a double and producing a double of which we are
2023-11-27 12:14:50 -05:00
trying to find a root, a guess \( x _ 0 \) , and a \( x _ 1 \) of which we define our first interval \( [ x _ 0 , x _ 1 ] \) .
2023-11-11 15:15:59 -05:00
Then, we perform a single iteration of the \texttt { fixed\_ point\_ secant\_ method} on this interval; if it
produces a root outside, we refresh the interval and root respectively with the given
\texttt { bisect\_ find\_ root} method. Additionally, a \texttt { max\_ iterations} and \texttt { tolerance} as defined in the above method are required
inputs.
\item Output: a double representing the found approximate root \( \approx x ^ * \) continually applied with the
constraints defined.
\end { itemize}
\begin { verbatim}
double fixed_ point_ secant_ bisection_ method(double (*f)(double), double x_ 0,
2023-11-27 12:14:50 -05:00
double x_ 1, double tolerance,
2023-11-11 15:15:59 -05:00
size_ t max_ iterations) {
double begin = x_ 0;
2023-11-27 12:14:50 -05:00
double end = x_ 1;
2023-11-11 15:15:59 -05:00
double root = x_ 0;
while (tolerance < fabs(f(root)) & & max_ iterations > 0) {
max_ iterations--;
2023-11-27 12:14:50 -05:00
double secant_ root = fixed_ point_ secant_ method(f, begin, end, tolerance, 1);
2023-11-11 15:15:59 -05:00
if (secant_ root < begin || secant_ root > end) {
Array_ double *range_ root = bisect_ find_ root(f, begin, end, tolerance, 1);
begin = range_ root->data[0];
end = range_ root->data[1];
root = range_ root->data[2];
free_ vector(range_ root);
continue;
}
root = secant_ root;
2023-11-27 12:14:50 -05:00
2023-11-11 15:15:59 -05:00
if (f(root) * f(begin) < 0)
2023-11-27 12:14:50 -05:00
end = secant_ root; // the root exists in [begin, secant_ root]
2023-11-11 15:15:59 -05:00
else
begin = secant_ root;
}
return root;
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-10-13 23:00:07 -04:00
\subsection { Linear Routines}
2023-12-11 21:24:33 -05:00
\label { sec:orge3b6d97}
2023-10-13 23:00:07 -04:00
\subsubsection { \texttt { least\_ squares\_ lin\_ reg} }
2023-12-11 21:24:33 -05:00
\label { sec:orgcc90c4a}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { least\_ squares\_ lin\_ reg}
\item Location: \texttt { src/lin.c}
\item Input: two pointers to \texttt { Array\_ double} 's whose entries correspond two ordered
pairs in R\textsuperscript { 2}
\item Output: a linear model best representing the ordered pairs via least squares
regression
\end { itemize}
\begin { verbatim}
Line *least_ squares_ lin_ reg(Array_ double *x, Array_ double *y) {
assert(x->size == y->size);
uint64_ t n = x->size;
double sum_ x = sum_ v(x);
double sum_ y = sum_ v(y);
double sum_ xy = v_ dot_ v(x, y);
double sum_ xx = v_ dot_ v(x, x);
double denom = ((n * sum_ xx) - (sum_ x * sum_ x));
Line *line = malloc(sizeof(Line));
line->m = ((sum_ xy * n) - (sum_ x * sum_ y)) / denom;
line->a = ((sum_ y * sum_ xx) - (sum_ x * sum_ xy)) / denom;
return line;
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-11-27 12:14:50 -05:00
\subsection { Eigen-Adjacent}
2023-12-11 21:24:33 -05:00
\label { sec:orga3c637f}
2023-11-27 12:14:50 -05:00
\subsubsection { \texttt { dominant\_ eigenvalue} }
2023-12-11 21:24:33 -05:00
\label { sec:org0306c8a}
2023-11-27 12:14:50 -05:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { dominant\_ eigenvalue}
\item Location: \texttt { src/eigen.c}
\item Input: a pointer to an invertible matrix \texttt { m} , an initial eigenvector guess \texttt { v} (that is non
zero or orthogonal to an eigenvector with the dominant eigenvalue), a \texttt { tolerance} and
\texttt { max\_ iterations} that act as stop conditions
\item Output: the dominant eigenvalue with the highest magnitude, approximated with the Power
Iteration Method
\end { itemize}
\begin { verbatim}
double dominant_ eigenvalue(Matrix_ double *m, Array_ double *v, double tolerance,
size_ t max_ iterations) {
assert(m->rows == m->cols);
assert(m->rows == v->size);
double error = tolerance;
size_ t iter = max_ iterations;
double lambda = 0.0;
Array_ double *eigenvector_ 1 = copy_ vector(v);
while (error >= tolerance & & (--iter) > 0) {
Array_ double *eigenvector_ 2 = m_ dot_ v(m, eigenvector_ 1);
2023-11-27 17:13:34 -05:00
Array_ double *normalized_ eigenvector_ 2 =
scale_ v(eigenvector_ 2, 1.0 / linf_ norm(eigenvector_ 2));
free_ vector(eigenvector_ 2);
eigenvector_ 2 = normalized_ eigenvector_ 2;
2023-11-27 12:14:50 -05:00
Array_ double *mx = m_ dot_ v(m, eigenvector_ 2);
double new_ lambda =
v_ dot_ v(mx, eigenvector_ 2) / v_ dot_ v(eigenvector_ 2, eigenvector_ 2);
error = fabs(new_ lambda - lambda);
lambda = new_ lambda;
free_ vector(eigenvector_ 1);
eigenvector_ 1 = eigenvector_ 2;
}
return lambda;
}
\end { verbatim}
2023-11-27 17:13:34 -05:00
\subsubsection { \texttt { shift\_ inverse\_ power\_ eigenvalue} }
2023-12-11 21:24:33 -05:00
\label { sec:orgc29637a}
2023-11-27 17:13:34 -05:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { least\_ dominant\_ eigenvalue}
\item Location: \texttt { src/eigen.c}
\item Input: a pointer to an invertible matrix \texttt { m} , an initial eigenvector guess \texttt { v} (that is non
zero or orthogonal to an eigenvector with the dominant eigenvalue), a \texttt { shift} to act as the
shifted \( \delta \) , and \texttt { tolerance} and \texttt { max\_ iterations} that act as stop conditions.
\item Output: the eigenvalue closest to \texttt { shift} with the lowest magnitude closest to 0, approximated
with the Inverse Power Iteration Method
\end { itemize}
\begin { verbatim}
double shift_ inverse_ power_ eigenvalue(Matrix_ double *m, Array_ double *v,
double shift, double tolerance,
size_ t max_ iterations) {
assert(m->rows == m->cols);
assert(m->rows == v->size);
Matrix_ double *m_ c = copy_ matrix(m);
for (size_ t y = 0; y < m_ c->rows; ++y)
m_ c->data[y]->data[y] = m_ c->data[y]->data[y] - shift;
double error = tolerance;
size_ t iter = max_ iterations;
double lambda = shift;
Array_ double *eigenvector_ 1 = copy_ vector(v);
while (error >= tolerance & & (--iter) > 0) {
Array_ double *eigenvector_ 2 = solve_ matrix_ lu_ bsubst(m_ c, eigenvector_ 1);
Array_ double *normalized_ eigenvector_ 2 =
scale_ v(eigenvector_ 2, 1.0 / linf_ norm(eigenvector_ 2));
free_ vector(eigenvector_ 2);
Array_ double *mx = m_ dot_ v(m, normalized_ eigenvector_ 2);
double new_ lambda =
v_ dot_ v(mx, normalized_ eigenvector_ 2) /
v_ dot_ v(normalized_ eigenvector_ 2, normalized_ eigenvector_ 2);
error = fabs(new_ lambda - lambda);
lambda = new_ lambda;
free_ vector(eigenvector_ 1);
eigenvector_ 1 = normalized_ eigenvector_ 2;
}
return lambda;
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-11-27 17:13:34 -05:00
\subsubsection { \texttt { least\_ dominant\_ eigenvalue} }
2023-12-11 21:24:33 -05:00
\label { sec:org5df73a2}
2023-11-27 17:13:34 -05:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { least\_ dominant\_ eigenvalue}
\item Location: \texttt { src/eigen.c}
\item Input: a pointer to an invertible matrix \texttt { m} , an initial eigenvector guess \texttt { v} (that is non
zero or orthogonal to an eigenvector with the dominant eigenvalue), a \texttt { tolerance} and
\texttt { max\_ iterations} that act as stop conditions.
\item Output: the least dominant eigenvalue with the lowest magnitude closest to 0, approximated
with the Inverse Power Iteration Method.
\end { itemize}
\begin { verbatim}
double least_ dominant_ eigenvalue(Matrix_ double *m, Array_ double *v,
double tolerance, size_ t max_ iterations) {
return shift_ inverse_ power_ eigenvalue(m, v, 0.0, tolerance, max_ iterations);
}
\end { verbatim}
\subsubsection { \texttt { partition\_ find\_ eigenvalues} }
2023-12-11 21:24:33 -05:00
\label { sec:org3dde7af}
2023-11-27 17:13:34 -05:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { partition\_ find\_ eigenvalues}
\item Location: \texttt { src/eigen.c}
\item Input: a pointer to an invertible matrix \texttt { m} , a matrix whose rows correspond to initial
eigenvector guesses at each "partition" which is computed from a uniform distribution
between the number of rows this "guess matrix" has and the distance between the least
dominant eigenvalue and the most dominant. Additionally, a \texttt { max\_ iterations} and a \texttt { tolerance}
that act as stop conditions.
\item Output: a vector of \texttt { doubles} corresponding to the "nearest" eigenvalue at the midpoint of
each partition, via the given guess of that partition.
\end { itemize}
\begin { verbatim}
Array_ double *partition_ find_ eigenvalues(Matrix_ double *m,
Matrix_ double *guesses,
double tolerance,
size_ t max_ iterations) {
assert(guesses->rows >=
2); // we need at least, the most and least dominant eigenvalues
double end = dominant_ eigenvalue(m, guesses->data[guesses->rows - 1],
tolerance, max_ iterations);
double begin =
least_ dominant_ eigenvalue(m, guesses->data[0], tolerance, max_ iterations);
double delta = (end - begin) / guesses->rows;
Array_ double *eigenvalues = InitArrayWithSize(double, guesses->rows, 0.0);
for (size_ t i = 0; i < guesses->rows; i++) {
double box_ midpoint = ((delta * i) + (delta * (i + 1))) / 2;
double nearest_ eigenvalue = shift_ inverse_ power_ eigenvalue(
m, guesses->data[i], box_ midpoint, tolerance, max_ iterations);
eigenvalues->data[i] = nearest_ eigenvalue;
}
return eigenvalues;
}
\end { verbatim}
2023-11-27 12:14:50 -05:00
\subsubsection { \texttt { leslie\_ matrix} }
2023-12-11 21:24:33 -05:00
\label { sec:orgca10ed3}
2023-11-27 12:14:50 -05:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { leslie\_ matrix}
\item Location: \texttt { src/eigen.c}
\item Input: two pointers to \texttt { Array\_ double} 's representing the ratio of individuals in an age class
\( x \) getting to the next age class \( x + 1 \) and the number of offspring that individuals in an age
class create in age class 0.
2023-11-27 17:13:34 -05:00
\item Output: the leslie matrix generated from the input vectors.
2023-11-27 12:14:50 -05:00
\end { itemize}
\begin { verbatim}
Matrix_ double *leslie_ matrix(Array_ double *age_ class_ surivor_ ratio,
Array_ double *age_ class_ offspring) {
assert(age_ class_ surivor_ ratio->size + 1 == age_ class_ offspring->size);
Matrix_ double *leslie = InitMatrixWithSize(double, age_ class_ offspring->size,
age_ class_ offspring->size, 0.0);
free_ vector(leslie->data[0]);
leslie->data[0] = age_ class_ offspring;
for (size_ t i = 0; i < age_ class_ surivor_ ratio->size; i++)
leslie->data[i + 1]->data[i] = age_ class_ surivor_ ratio->data[i];
return leslie;
}
\end { verbatim}
2023-12-11 21:24:33 -05:00
\subsection { Jacobi / Gauss-Siedel}
\label { sec:org91c563c}
\subsubsection { \texttt { jacobi\_ solve} }
\label { sec:org2cd6098}
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { jacobi\_ solve}
\item Location: \texttt { src/matrix.c}
\item Input: a pointer to a diagonally dominant square matrix \( m \) , a vector representing
the value \( b \) in \( mx = b \) , a double representing the maximum distance between
the solutions produced by iteration \( i \) and \( i + 1 \) (by L2 norm a.k.a cartesian
distance), and a \texttt { max\_ iterations} which we force stop.
\item Output: the converged-upon solution \( x \) to \( mx = b \)
\end { itemize}
\begin { verbatim}
Array_ double *jacobi_ solve(Matrix_ double *m, Array_ double *b,
double l2_ convergence_ tolerance,
size_ t max_ iterations) {
assert(m->rows == m->cols);
assert(b->size == m->cols);
size_ t iter = max_ iterations;
Array_ double *x_ k = InitArrayWithSize(double, b->size, 0.0);
Array_ double *x_ k_ 1 =
InitArrayWithSize(double, b->size, rand_ from(0.1, 10.0));
while ((--iter) > 0 & & l2_ distance(x_ k_ 1, x_ k) > l2_ convergence_ tolerance) {
for (size_ t i = 0; i < m->rows; i++) {
double delta = 0.0;
for (size_ t j = 0; j < m->cols; j++) {
if (i == j)
continue;
delta += m->data[i]->data[j] * x_ k->data[j];
}
x_ k_ 1->data[i] = (b->data[i] - delta) / m->data[i]->data[i];
}
Array_ double *tmp = x_ k;
x_ k = x_ k_ 1;
x_ k_ 1 = tmp;
}
free_ vector(x_ k);
return x_ k_ 1;
}
\end { verbatim}
\subsubsection { \texttt { gauss\_ siedel\_ solve} }
\label { sec:org6633923}
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { gauss\_ siedel\_ solve}
\item Location: \texttt { src/matrix.c}
\item Input: a pointer to a \href { https://en.wikipedia.org/wiki/Gauss\% E2\% 80\% 93Seidel\_ method} { diagonally dominant or symmetric and positive definite}
square matrix \( m \) , a vector representing
the value \( b \) in \( mx = b \) , a double representing the maximum distance between
the solutions produced by iteration \( i \) and \( i + 1 \) (by L2 norm a.k.a cartesian
distance), and a \texttt { max\_ iterations} which we force stop.
\item Output: the converged-upon solution \( x \) to \( mx = b \)
\item Description: we use almost the exact same method as \texttt { jacobi\_ solve} but modify
only one array in accordance to the Gauss-Siedel method, but which is necessarily
copied before due to the convergence check.
\end { itemize}
\begin { verbatim}
Array_ double *gauss_ siedel_ solve(Matrix_ double *m, Array_ double *b,
double l2_ convergence_ tolerance,
size_ t max_ iterations) {
assert(m->rows == m->cols);
assert(b->size == m->cols);
size_ t iter = max_ iterations;
Array_ double *x_ k = InitArrayWithSize(double, b->size, 0.0);
Array_ double *x_ k_ 1 =
InitArrayWithSize(double, b->size, rand_ from(0.1, 10.0));
while ((--iter) > 0) {
for (size_ t i = 0; i < x_ k->size; i++)
x_ k->data[i] = x_ k_ 1->data[i];
for (size_ t i = 0; i < m->rows; i++) {
double delta = 0.0;
for (size_ t j = 0; j < m->cols; j++) {
if (i == j)
continue;
delta += m->data[i]->data[j] * x_ k_ 1->data[j];
}
x_ k_ 1->data[i] = (b->data[i] - delta) / m->data[i]->data[i];
}
if (l2_ distance(x_ k_ 1, x_ k) <= l2_ convergence_ tolerance)
break;
}
free_ vector(x_ k);
return x_ k_ 1;
}
\end { verbatim}
2023-10-13 23:00:07 -04:00
\subsection { Appendix / Miscellaneous}
2023-12-11 21:24:33 -05:00
\label { sec:orga72494e}
\subsubsection { Random}
\label { sec:org4940c39}
\begin { itemize}
\item Author: Elizabeth Hunt
\item Name: \texttt { rand\_ from}
\item Location: \texttt { src/rand.c}
\item Input: a pair of doubles, min and max to generate a random number min
\( \le \) x \( \le \) max
\item Output: a random double in the constraints shown
\end { itemize}
\begin { verbatim}
double rand_ from(double min, double max) {
return min + (rand() / (RAND_ MAX / (max - min)));
}
\end { verbatim}
2023-10-13 23:00:07 -04:00
\subsubsection { Data Types}
2023-12-11 21:24:33 -05:00
\label { sec:org8d3f6e1}
2023-10-13 23:00:07 -04:00
\begin { enumerate}
\item \texttt { Line}
2023-12-11 21:24:33 -05:00
\label { sec:orgc0df901}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Location: \texttt { inc/types.h}
\end { itemize}
\begin { verbatim}
typedef struct Line {
double m;
double a;
} Line;
\end { verbatim}
\item The \texttt { Array\_ <type>} and \texttt { Matrix\_ <type>}
2023-12-11 21:24:33 -05:00
\label { sec:org435e816}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Location: \texttt { inc/types.h}
\end { itemize}
We define two Pre processor Macros \texttt { DEFINE\_ ARRAY} and \texttt { DEFINE\_ MATRIX} that take
as input a type, and construct a struct definition for the given type for
convenient access to the vector or matrices dimensions.
Such that \texttt { DEFINE\_ ARRAY(int)} would expand to:
\begin { verbatim}
typedef struct {
int* data;
size_ t size;
} Array_ int
\end { verbatim}
And \texttt { DEFINE\_ MATRIX(int)} would expand a to \texttt { Matrix\_ int} ; containing a pointer to
a collection of pointers of \texttt { Array\_ int} 's and its dimensions.
\begin { verbatim}
typedef struct {
Array_ int **data;
size_ t cols;
size_ t rows;
} Matrix_ int
\end { verbatim}
\end { enumerate}
2023-12-11 21:24:33 -05:00
2023-10-13 23:00:07 -04:00
\subsubsection { Macros}
2023-12-11 21:24:33 -05:00
\label { sec:orga2161be}
2023-10-13 23:00:07 -04:00
\begin { enumerate}
\item \texttt { c\_ max} and \texttt { c\_ min}
2023-12-11 21:24:33 -05:00
\label { sec:org16ca9c3}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Location: \texttt { inc/macros.h}
\item Input: two structures that define an order measure
\item Output: either the larger or smaller of the two depending on the measure
\end { itemize}
\begin { verbatim}
#define c_ max(x, y) (((x) >= (y)) ? (x) : (y))
#define c_ min(x, y) (((x) <= (y)) ? (x) : (y))
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-10-13 23:00:07 -04:00
\item \texttt { InitArray}
2023-12-11 21:24:33 -05:00
\label { sec:orgcaff993}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Location: \texttt { inc/macros.h}
\item Input: a type and array of values to initialze an array with such type
\item Output: a new \texttt { Array\_ type} with the size of the given array and its data
\end { itemize}
\begin { verbatim}
2023-11-11 15:15:59 -05:00
#define InitArray(TYPE, ...) \
({ \
TYPE temp[] = _ _ VA_ ARGS_ _ ; \
Array_ ##TYPE *arr = malloc(sizeof(Array_ ##TYPE)); \
arr->size = sizeof(temp) / sizeof(temp[0]); \
arr->data = malloc(arr->size * sizeof(TYPE)); \
memcpy(arr->data, temp, arr->size * sizeof(TYPE)); \
arr; \
2023-10-13 23:00:07 -04:00
} )
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-10-13 23:00:07 -04:00
\item \texttt { InitArrayWithSize}
2023-12-11 21:24:33 -05:00
\label { sec:orga925ddb}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Location: \texttt { inc/macros.h}
\item Input: a type, a size, and initial value
\item Output: a new \texttt { Array\_ type} with the given size filled with the initial value
\end { itemize}
\begin { verbatim}
2023-11-11 15:15:59 -05:00
#define InitArrayWithSize(TYPE, SIZE, INIT_ VALUE) \
({ \
Array_ ##TYPE *arr = malloc(sizeof(Array_ ##TYPE)); \
arr->size = SIZE; \
arr->data = malloc(arr->size * sizeof(TYPE)); \
for (size_ t i = 0; i < arr->size; i++) \
arr->data[i] = INIT_ VALUE; \
arr; \
2023-10-13 23:00:07 -04:00
} )
\end { verbatim}
2023-12-11 21:24:33 -05:00
2023-10-13 23:00:07 -04:00
\item \texttt { InitMatrixWithSize}
2023-12-11 21:24:33 -05:00
\label { sec:orgf90d7c8}
2023-10-13 23:00:07 -04:00
\begin { itemize}
\item Author: Elizabeth Hunt
\item Location: \texttt { inc/macros.h}
\item Input: a type, number of rows, columns, and initial value
\item Output: a new \texttt { Matrix\_ type} of size \texttt { rows x columns} filled with the initial
value
\end { itemize}
\begin { verbatim}
#define InitMatrixWithSize(TYPE, ROWS, COLS, INIT_ VALUE) \
({ \
Matrix_ ##TYPE *matrix = malloc(sizeof(Matrix_ ##TYPE)); \
matrix->rows = ROWS; \
matrix->cols = COLS; \
matrix->data = malloc(matrix->rows * sizeof(Array_ ##TYPE *)); \
for (size_ t y = 0; y < matrix->rows; y++) \
matrix->data[y] = InitArrayWithSize(TYPE, COLS, INIT_ VALUE); \
matrix; \
} )
\end { verbatim}
\end { enumerate}
2023-12-11 21:24:33 -05:00
\end { document}