This commit is contained in:
Elizabeth Hunt 2023-11-11 13:15:59 -07:00
parent 586d8056c1
commit 3f1f18b149
Signed by: simponic
GPG Key ID: 52B3774857EB24B1
14 changed files with 1158 additions and 202 deletions

View File

@ -1,4 +1,4 @@
#+TITLE: LIZFCM Software Manual (v0.2) #+TITLE: LIZFCM Software Manual (v0.3)
#+AUTHOR: Elizabeth Hunt #+AUTHOR: Elizabeth Hunt
#+LATEX_HEADER: \notindent \notag \usepackage{amsmath} \usepackage[a4paper,margin=1in,portrait]{geometry} #+LATEX_HEADER: \notindent \notag \usepackage{amsmath} \usepackage[a4paper,margin=1in,portrait]{geometry}
#+LATEX: \setlength\parindent{0pt} #+LATEX: \setlength\parindent{0pt}
@ -110,8 +110,8 @@ double central_derivative_at(double (*f)(double), double a, double h) {
double x2 = a + h; double x2 = a + h;
double x1 = a - h; double x1 = a - h;
double y2 = (*f)(x2); double y2 = f(x2);
double y1 = (*f)(x1); double y1 = f(x1);
return (y2 - y1) / (x2 - x1); return (y2 - y1) / (x2 - x1);
} }
@ -136,8 +136,8 @@ double forward_derivative_at(double (*f)(double), double a, double h) {
double x2 = a + h; double x2 = a + h;
double x1 = a; double x1 = a;
double y2 = (*f)(x2); double y2 = f(x2);
double y1 = (*f)(x1); double y1 = f(x1);
return (y2 - y1) / (x2 - x1); return (y2 - y1) / (x2 - x1);
} }
@ -162,8 +162,8 @@ double backward_derivative_at(double (*f)(double), double a, double h) {
double x2 = a; double x2 = a;
double x1 = a - h; double x1 = a - h;
double y2 = (*f)(x2); double y2 = f(x2);
double y1 = (*f)(x1); double y1 = f(x1);
return (y2 - y1) / (x2 - x1); return (y2 - y1) / (x2 - x1);
} }
@ -761,46 +761,51 @@ void format_matrix_into(Matrix_double *m, char *s) {
+ Input: a pointer to a oneary function taking a double and producing a double, the beginning point + 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 ~delta~ step that is taken, and a ~max_steps~ number of maximum in $R$ to search for a range, a ~delta~ step that is taken, and a ~max_steps~ number of maximum
iterations to perform. iterations to perform.
+ Output: a pair of ~double~'s representing a closed closed interval ~[beginning, end]~ + Output: a pair of ~double~'s in an ~Array_double~ representing a closed closed interval ~[beginning, end]~
#+BEGIN_SRC c #+BEGIN_SRC c
double *find_ivt_range(double (*f)(double), double start_x, double delta, // f is well defined at start_x + delta*n for all n on the integer range [0,
size_t max_steps) { // max_iterations]
double *range = malloc(sizeof(double) * 2); Array_double *find_ivt_range(double (*f)(double), double start_x, double delta,
size_t max_iterations) {
double a = start_x; double a = start_x;
while (f(a) * f(start_x) >= 0 && max_steps-- > 0) while (f(a) * f(a + delta) >= 0 && max_iterations > 0) {
max_iterations--;
a += delta; a += delta;
}
if (max_steps == 0 && f(a) * f(start_x) > 0) double end = a + delta;
double begin = a - delta;
if (max_iterations == 0 && f(begin) * f(end) >= 0)
return NULL; return NULL;
return InitArray(double, {begin, end});
range[0] = start_x;
range[1] = a + delta;
return range;
} }
#+END_SRC #+END_SRC
*** ~bisect_find_root~ *** ~bisect_find_root~
+ Author: Elizabeth Hunt + Author: Elizabeth Hunt
+ Name(s): ~bisect_find_root~ + Name(s): ~bisect_find_root~
+ Input: a one-ary function taking a double and producing a double, a closed interval represented + Input: a one-ary function taking a double and producing a double, a closed interval represented
by ~a~ and ~b~: ~[a, b]~, a ~tolerance~ at which we return the estimated root, and a by ~a~ and ~b~: ~[a, b]~, a ~tolerance~ at which we return the estimated root once $b-a < \text{tolerance}$, and a
~max_iterations~ to break us out of a loop if we can never reach the ~tolerance~ ~max_iterations~ to break us out of a loop if we can never reach the ~tolerance~.
+ Output: a ~double~ representing the estimated root + Output: a vector of size of 3, ~double~'s representing first the range ~[a,b]~ and then the midpoint,
~c~ of the range.
+ Description: recursively uses binary search to split the interval until we reach ~tolerance~. We + Description: recursively uses binary search to split the interval until we reach ~tolerance~. We
also assume the function ~f~ is continuous on ~[a, b]~. also assume the function ~f~ is continuous on ~[a, b]~.
#+BEGIN_SRC c #+BEGIN_SRC c
double bisect_find_root(double (*f)(double), double a, double b, // f is continuous on [a, b]
double tolerance, size_t max_iterations) { Array_double *bisect_find_root(double (*f)(double), double a, double b,
double tolerance, size_t max_iterations) {
assert(a <= b); assert(a <= b);
// guarantee there's a root somewhere between a and b by IVT // guarantee there's a root somewhere between a and b by IVT
assert(f(a) * f(b) < 0); assert(f(a) * f(b) < 0);
double c = (1.0 / 2) * (a + b); double c = (1.0 / 2) * (a + b);
if (b - a < tolerance || max_iterations == 0) if (b - a < tolerance || max_iterations == 0)
return c; return InitArray(double, {a, b, c});
if (f(a) * f(c) < 0) if (f(a) * f(c) < 0)
return bisect_find_root(f, a, c, tolerance, max_iterations - 1); return bisect_find_root(f, a, c, tolerance, max_iterations - 1);
return bisect_find_root(f, c, b, tolerance, max_iterations - 1); return bisect_find_root(f, c, b, tolerance, max_iterations - 1);
@ -810,7 +815,7 @@ double bisect_find_root(double (*f)(double), double a, double b,
+ Author: Elizabeth Hunt + Author: Elizabeth Hunt
+ Name: ~bisect_find_root_with_error_assumption~ + Name: ~bisect_find_root_with_error_assumption~
+ Input: a one-ary function taking a double and producing a double, a closed interval represented + Input: a one-ary function taking a double and producing a double, a closed interval represented
by ~a~ and ~b~: ~[a, b]~, and a ~tolerance~ at which we return the estimated root by ~a~ and ~b~: ~[a, b]~, and a ~tolerance~ equivalent to the above definition in ~bisect_find_root~
+ Output: a ~double~ representing the estimated root + Output: a ~double~ representing the estimated root
+ Description: using the bisection method we know that $e_k \le (\frac{1}{2})^k (b_0 - a_0)$. So we can + 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 calculate $k$ at the worst possible case (that the error is exactly the tolerance) to be
@ -823,7 +828,140 @@ double bisect_find_root_with_error_assumption(double (*f)(double), double a,
uint64_t max_iterations = uint64_t max_iterations =
(uint64_t)ceil((log(tolerance) - log(b - a)) / log(1 / 2.0)); (uint64_t)ceil((log(tolerance) - log(b - a)) / log(1 / 2.0));
return bisect_find_root(f, a, b, tolerance, max_iterations);
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;
}
#+END_SRC
*** ~fixed_point_iteration_method~
+ Author: Elizabeth Hunt
+ Name: ~fixed_point_iteration_method~
+ Location: ~src/roots.c~
+ 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
~max_iterations~ representing the maximum number of "steps" to take before arriving at our
approximation and a ~tolerance~ to return our root if it becomes within [0 - tolerance, 0 + tolerance].
+ Assumptions: $g(x)$ must be a function such that at the point $x^*$ (the found root) the derivative
$|g'(x^*)| \lt 1$
+ Output: a double representing the found approximate root $\approx x^*$.
#+BEGIN_SRC c
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_SRC
*** ~fixed_point_newton_method~
+ Author: Elizabeth Hunt
+ Name: ~fixed_point_newton_method~
+ Location: ~src/roots.c~
+ 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 ~max_iterations~ and ~tolerance~ as defined in the above method are required inputs.
+ Description: continually computes elements in the sequence $x_n = x_{n-1} - \frac{f(x_{n-1})}{f'p(x_{n-1})}$
+ Output: a double representing the found approximate root $\approx x^*$ recursively applied to the sequence
given
#+BEGIN_SRC c
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_SRC
*** ~fixed_point_secant_method~
+ Author: Elizabeth Hunt
+ Name: ~fixed_point_secant_method~
+ Location: ~src/roots.c~
+ 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 $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})}$.
Additionally, a ~max_iterations~ and ~tolerance~ as defined in the above method are required
inputs.
+ Output: a double representing the found approximate root $\approx x^*$ recursively applied to the sequence.
#+BEGIN_SRC c
double fixed_point_secant_method(double (*f)(double), double x_0, double x_1,
double tolerance, size_t max_iterations) {
if (max_iterations == 0)
return x_1;
double root = x_1 - f(x_1) * ((x_1 - x_0) / (f(x_1) - f(x_0)));
if (tolerance >= fabs(f(root)))
return root;
return fixed_point_secant_method(f, x_1, root, tolerance, max_iterations - 1);
}
#+END_SRC
*** ~fixed_point_secant_bisection_method~
+ Author: Elizabeth Hunt
+ Name: ~fixed_point_secant_method~
+ Location: ~src/roots.c~
+ 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 $x_1$ of which we define our first interval $[x_0, x_1]$.
Then, we perform a single iteration of the ~fixed_point_secant_method~ on this interval; if it
produces a root outside, we refresh the interval and root respectively with the given
~bisect_find_root~ method. Additionally, a ~max_iterations~ and ~tolerance~ as defined in the above method are required
inputs.
+ Output: a double representing the found approximate root $\approx x^*$ continually applied with the
constraints defined.
#+BEGIN_SRC c
double fixed_point_secant_bisection_method(double (*f)(double), double x_0,
double x_1, double tolerance,
size_t max_iterations) {
double begin = x_0;
double end = x_1;
double root = x_0;
while (tolerance < fabs(f(root)) && max_iterations > 0) {
max_iterations--;
double secant_root = fixed_point_secant_method(f, begin, end, tolerance, 1);
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;
if (f(root) * f(begin) < 0)
end = secant_root; // the root exists in [begin, secant_root]
else
begin = secant_root;
}
return root;
} }
#+END_SRC #+END_SRC
@ -914,14 +1052,14 @@ a collection of pointers of ~Array_int~'s and its dimensions.
+ Output: a new ~Array_type~ with the size of the given array and its data + Output: a new ~Array_type~ with the size of the given array and its data
#+BEGIN_SRC c #+BEGIN_SRC c
#define InitArray(TYPE, ...) \ #define InitArray(TYPE, ...) \
({ \ ({ \
TYPE temp[] = __VA_ARGS__; \ TYPE temp[] = __VA_ARGS__; \
Array_##TYPE *arr = malloc(sizeof(Array_##TYPE)); \ Array_##TYPE *arr = malloc(sizeof(Array_##TYPE)); \
arr->size = sizeof(temp) / sizeof(temp[0]); \ arr->size = sizeof(temp) / sizeof(temp[0]); \
arr->data = malloc(arr->size * sizeof(TYPE)); \ arr->data = malloc(arr->size * sizeof(TYPE)); \
memcpy(arr->data, temp, arr->size * sizeof(TYPE)); \ memcpy(arr->data, temp, arr->size * sizeof(TYPE)); \
arr; \ arr; \
}) })
#+END_SRC #+END_SRC
@ -932,14 +1070,14 @@ a collection of pointers of ~Array_int~'s and its dimensions.
+ Output: a new ~Array_type~ with the given size filled with the initial value + Output: a new ~Array_type~ with the given size filled with the initial value
#+BEGIN_SRC c #+BEGIN_SRC c
#define InitArrayWithSize(TYPE, SIZE, INIT_VALUE) \ #define InitArrayWithSize(TYPE, SIZE, INIT_VALUE) \
({ \ ({ \
Array_##TYPE *arr = malloc(sizeof(Array_##TYPE)); \ Array_##TYPE *arr = malloc(sizeof(Array_##TYPE)); \
arr->size = SIZE; \ arr->size = SIZE; \
arr->data = malloc(arr->size * sizeof(TYPE)); \ arr->data = malloc(arr->size * sizeof(TYPE)); \
for (size_t i = 0; i < arr->size; i++) \ for (size_t i = 0; i < arr->size; i++) \
arr->data[i] = INIT_VALUE; \ arr->data[i] = INIT_VALUE; \
arr; \ arr; \
}) })
#+END_SRC #+END_SRC

Binary file not shown.

View File

@ -1,4 +1,4 @@
% Created 2023-11-01 Wed 20:52 % Created 2023-11-10 Fri 20:54
% Intended LaTeX compiler: pdflatex % Intended LaTeX compiler: pdflatex
\documentclass[11pt]{article} \documentclass[11pt]{article}
\usepackage[utf8]{inputenc} \usepackage[utf8]{inputenc}
@ -15,13 +15,13 @@
\notindent \notag \usepackage{amsmath} \usepackage[a4paper,margin=1in,portrait]{geometry} \notindent \notag \usepackage{amsmath} \usepackage[a4paper,margin=1in,portrait]{geometry}
\author{Elizabeth Hunt} \author{Elizabeth Hunt}
\date{\today} \date{\today}
\title{LIZFCM Software Manual (v0.2)} \title{LIZFCM Software Manual (v0.3)}
\hypersetup{ \hypersetup{
pdfauthor={Elizabeth Hunt}, pdfauthor={Elizabeth Hunt},
pdftitle={LIZFCM Software Manual (v0.2)}, pdftitle={LIZFCM Software Manual (v0.3)},
pdfkeywords={}, pdfkeywords={},
pdfsubject={}, pdfsubject={},
pdfcreator={Emacs 28.2 (Org mode 9.7-pre)}, pdfcreator={Emacs 29.1 (Org mode 9.7-pre)},
pdflang={English}} pdflang={English}}
\begin{document} \begin{document}
@ -29,9 +29,8 @@
\tableofcontents \tableofcontents
\setlength\parindent{0pt} \setlength\parindent{0pt}
\section{Design} \section{Design}
\label{sec:org9458aa0} \label{sec:orgdac8577}
The LIZFCM static library (at \url{https://github.com/Simponic/math-4610}) is a successor to my The LIZFCM static library (at \url{https://github.com/Simponic/math-4610}) is a successor to my
attempt at writing codes for the Fundamentals of Computational Mathematics course in Common 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 Lisp, but the effort required to meet the requirement of creating a static library became
@ -47,9 +46,8 @@ the C programming language. I have a couple tenets for its design:
\item Routines are separated into "modules" that follow a form of separation of concerns \item Routines are separated into "modules" that follow a form of separation of concerns
in files, and not individual files per function. in files, and not individual files per function.
\end{itemize} \end{itemize}
\section{Compilation} \section{Compilation}
\label{sec:orge0bab70} \label{sec:org7755023}
A provided \texttt{Makefile} is added for convencience. It has been tested on an \texttt{arm}-based M1 machine running 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. MacOS as well as \texttt{x86} Arch Linux.
@ -71,15 +69,14 @@ produce an object file:
gcc -Iinc/ -lm -Wall -c src/<the_routine>.c -o build/<the_routine>.o gcc -Iinc/ -lm -Wall -c src/<the_routine>.c -o build/<the_routine>.o
\end{verbatim} \end{verbatim}
Which is then bundled into a static library in \texttt{lib/lizfcm.a} which can be linked Which is then bundled into a static library in \texttt{lib/lizfcm.a} and can be linked
in the standard method. in the standard method.
\section{The LIZFCM API} \section{The LIZFCM API}
\label{sec:org91f4707} \label{sec:org940357c}
\subsection{Simple Routines} \subsection{Simple Routines}
\label{sec:orgc8c57e4} \label{sec:org28486b0}
\subsubsection{\texttt{smaceps}} \subsubsection{\texttt{smaceps}}
\label{sec:orgfeb6ef6} \label{sec:org1de3a4e}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Name: \texttt{smaceps} \item Name: \texttt{smaceps}
@ -103,9 +100,8 @@ float smaceps() {
return machine_epsilon; return machine_epsilon;
} }
\end{verbatim} \end{verbatim}
\subsubsection{\texttt{dmaceps}} \subsubsection{\texttt{dmaceps}}
\label{sec:orgb3dc0f2} \label{sec:org742e61e}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Name: \texttt{dmaceps} \item Name: \texttt{dmaceps}
@ -129,11 +125,10 @@ double dmaceps() {
return machine_epsilon; return machine_epsilon;
} }
\end{verbatim} \end{verbatim}
\subsection{Derivative Routines} \subsection{Derivative Routines}
\label{sec:orge88d677} \label{sec:org21233d3}
\subsubsection{\texttt{central\_derivative\_at}} \subsubsection{\texttt{central\_derivative\_at}}
\label{sec:org32a8384} \label{sec:org6a00f6c}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Name: \texttt{central\_derivative\_at} \item Name: \texttt{central\_derivative\_at}
@ -162,9 +157,8 @@ double central_derivative_at(double (*f)(double), double a, double h) {
return (y2 - y1) / (x2 - x1); return (y2 - y1) / (x2 - x1);
} }
\end{verbatim} \end{verbatim}
\subsubsection{\texttt{forward\_derivative\_at}} \subsubsection{\texttt{forward\_derivative\_at}}
\label{sec:orgb6fdb9a} \label{sec:org78f40a9}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Name: \texttt{forward\_derivative\_at} \item Name: \texttt{forward\_derivative\_at}
@ -193,9 +187,8 @@ double forward_derivative_at(double (*f)(double), double a, double h) {
return (y2 - y1) / (x2 - x1); return (y2 - y1) / (x2 - x1);
} }
\end{verbatim} \end{verbatim}
\subsubsection{\texttt{backward\_derivative\_at}} \subsubsection{\texttt{backward\_derivative\_at}}
\label{sec:org8b6070e} \label{sec:org888d29e}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Name: \texttt{backward\_derivative\_at} \item Name: \texttt{backward\_derivative\_at}
@ -224,11 +217,10 @@ double backward_derivative_at(double (*f)(double), double a, double h) {
return (y2 - y1) / (x2 - x1); return (y2 - y1) / (x2 - x1);
} }
\end{verbatim} \end{verbatim}
\subsection{Vector Routines} \subsection{Vector Routines}
\label{sec:org161e049} \label{sec:org73b87ea}
\subsubsection{Vector Arithmetic: \texttt{add\_v, minus\_v}} \subsubsection{Vector Arithmetic: \texttt{add\_v, minus\_v}}
\label{sec:org938756a} \label{sec:orgf8b5da1}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Name(s): \texttt{add\_v}, \texttt{minus\_v} \item Name(s): \texttt{add\_v}, \texttt{minus\_v}
@ -257,9 +249,8 @@ Array_double *minus_v(Array_double *v1, Array_double *v2) {
return sub; return sub;
} }
\end{verbatim} \end{verbatim}
\subsubsection{Norms: \texttt{l1\_norm}, \texttt{l2\_norm}, \texttt{linf\_norm}} \subsubsection{Norms: \texttt{l1\_norm}, \texttt{l2\_norm}, \texttt{linf\_norm}}
\label{sec:org53e3d42} \label{sec:orgc5368a1}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Name(s): \texttt{l1\_norm}, \texttt{l2\_norm}, \texttt{linf\_norm} \item Name(s): \texttt{l1\_norm}, \texttt{l2\_norm}, \texttt{linf\_norm}
@ -291,9 +282,8 @@ double linf_norm(Array_double *v) {
return max; return max;
} }
\end{verbatim} \end{verbatim}
\subsubsection{\texttt{vector\_distance}} \subsubsection{\texttt{vector\_distance}}
\label{sec:org31d6d43} \label{sec:org0505e0b}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Name: \texttt{vector\_distance} \item Name: \texttt{vector\_distance}
@ -312,9 +302,8 @@ double vector_distance(Array_double *v1, Array_double *v2,
return dist; return dist;
} }
\end{verbatim} \end{verbatim}
\subsubsection{Distances: \texttt{l1\_distance}, \texttt{l2\_distance}, \texttt{linf\_distance}} \subsubsection{Distances: \texttt{l1\_distance}, \texttt{l2\_distance}, \texttt{linf\_distance}}
\label{sec:org3c2cede} \label{sec:org1c45dae}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Name(s): \texttt{l1\_distance}, \texttt{l2\_distance}, \texttt{linf\_distance} \item Name(s): \texttt{l1\_distance}, \texttt{l2\_distance}, \texttt{linf\_distance}
@ -338,9 +327,8 @@ double linf_distance(Array_double *v1, Array_double *v2) {
return vector_distance(v1, v2, &linf_norm); return vector_distance(v1, v2, &linf_norm);
} }
\end{verbatim} \end{verbatim}
\subsubsection{\texttt{sum\_v}} \subsubsection{\texttt{sum\_v}}
\label{sec:orgde8ccf4} \label{sec:org687d1bd}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Name: \texttt{sum\_v} \item Name: \texttt{sum\_v}
@ -357,10 +345,8 @@ double sum_v(Array_double *v) {
return sum; return sum;
} }
\end{verbatim} \end{verbatim}
\subsubsection{\texttt{scale\_v}} \subsubsection{\texttt{scale\_v}}
\label{sec:orgb6465fa} \label{sec:org5926df1}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Name: \texttt{scale\_v} \item Name: \texttt{scale\_v}
@ -377,9 +363,8 @@ Array_double *scale_v(Array_double *v, double m) {
return copy; return copy;
} }
\end{verbatim} \end{verbatim}
\subsubsection{\texttt{free\_vector}} \subsubsection{\texttt{free\_vector}}
\label{sec:org38c1352} \label{sec:org3458f6a}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Name: \texttt{free\_vector} \item Name: \texttt{free\_vector}
@ -395,9 +380,8 @@ void free_vector(Array_double *v) {
free(v); free(v);
} }
\end{verbatim} \end{verbatim}
\subsubsection{\texttt{add\_element}} \subsubsection{\texttt{add\_element}}
\label{sec:org9fa4fc9} \label{sec:org54cba50}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Name: \texttt{add\_element} \item Name: \texttt{add\_element}
@ -415,9 +399,8 @@ Array_double *add_element(Array_double *v, double x) {
return pushed; return pushed;
} }
\end{verbatim} \end{verbatim}
\subsubsection{\texttt{slice\_element}} \subsubsection{\texttt{slice\_element}}
\label{sec:orga743fd5} \label{sec:org02cd40a}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Name: \texttt{slice\_element} \item Name: \texttt{slice\_element}
@ -434,9 +417,8 @@ Array_double *slice_element(Array_double *v, size_t x) {
return sliced; return sliced;
} }
\end{verbatim} \end{verbatim}
\subsubsection{\texttt{copy\_vector}} \subsubsection{\texttt{copy\_vector}}
\label{sec:org8918aa7} \label{sec:org4b0c599}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Name: \texttt{copy\_vector} \item Name: \texttt{copy\_vector}
@ -454,9 +436,8 @@ Array_double *copy_vector(Array_double *v) {
return copy; return copy;
} }
\end{verbatim} \end{verbatim}
\subsubsection{\texttt{format\_vector\_into}} \subsubsection{\texttt{format\_vector\_into}}
\label{sec:org744df1b} \label{sec:orgde12441}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Name: \texttt{format\_vector\_into} \item Name: \texttt{format\_vector\_into}
@ -484,11 +465,10 @@ void format_vector_into(Array_double *v, char *s) {
strcat(s, "\n"); strcat(s, "\n");
} }
\end{verbatim} \end{verbatim}
\subsection{Matrix Routines} \subsection{Matrix Routines}
\label{sec:orge1c8a5a} \label{sec:orgd85d8ec}
\subsubsection{\texttt{lu\_decomp}} \subsubsection{\texttt{lu\_decomp}}
\label{sec:org19cc6a1} \label{sec:org6a14cbd}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Name: \texttt{lu\_decomp} \item Name: \texttt{lu\_decomp}
@ -548,7 +528,7 @@ Matrix_double **lu_decomp(Matrix_double *m) {
} }
\end{verbatim} \end{verbatim}
\subsubsection{\texttt{bsubst}} \subsubsection{\texttt{bsubst}}
\label{sec:org786580f} \label{sec:org8b51171}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Name: \texttt{bsubst} \item Name: \texttt{bsubst}
@ -573,7 +553,7 @@ Array_double *bsubst(Matrix_double *u, Array_double *b) {
} }
\end{verbatim} \end{verbatim}
\subsubsection{\texttt{fsubst}} \subsubsection{\texttt{fsubst}}
\label{sec:org1d422c6} \label{sec:orgf9180a0}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Name: \texttt{fsubst} \item Name: \texttt{fsubst}
@ -599,9 +579,8 @@ Array_double *fsubst(Matrix_double *l, Array_double *b) {
return x; return x;
} }
\end{verbatim} \end{verbatim}
\subsubsection{\texttt{solve\_matrix\_lu\_bsubst}} \subsubsection{\texttt{solve\_matrix\_lu\_bsubst}}
\label{sec:orgbf1dbcb} \label{sec:orgf3845f4}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Location: \texttt{src/matrix.c} \item Location: \texttt{src/matrix.c}
@ -636,9 +615,8 @@ Array_double *solve_matrix_lu_bsubst(Matrix_double *m, Array_double *b) {
return x; return x;
} }
\end{verbatim} \end{verbatim}
\subsubsection{\texttt{gaussian\_elimination}} \subsubsection{\texttt{gaussian\_elimination}}
\label{sec:orgc3ceb7b} \label{sec:orge926b79}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Location: \texttt{src/matrix.c} \item Location: \texttt{src/matrix.c}
@ -692,9 +670,8 @@ Matrix_double *gaussian_elimination(Matrix_double *m) {
return m_cp; return m_cp;
} }
\end{verbatim} \end{verbatim}
\subsubsection{\texttt{solve\_matrix\_gaussian}} \subsubsection{\texttt{solve\_matrix\_gaussian}}
\label{sec:orgb8fc210} \label{sec:orgc4f0d99}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Location: \texttt{src/matrix.c} \item Location: \texttt{src/matrix.c}
@ -726,10 +703,8 @@ Array_double *solve_matrix_gaussian(Matrix_double *m, Array_double *b) {
return solution; return solution;
} }
\end{verbatim} \end{verbatim}
\subsubsection{\texttt{m\_dot\_v}} \subsubsection{\texttt{m\_dot\_v}}
\label{sec:org304f5e5} \label{sec:orgb7015af}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Location: \texttt{src/matrix.c} \item Location: \texttt{src/matrix.c}
@ -749,9 +724,8 @@ Array_double *m_dot_v(Matrix_double *m, Array_double *v) {
return product; return product;
} }
\end{verbatim} \end{verbatim}
\subsubsection{\texttt{put\_identity\_diagonal}} \subsubsection{\texttt{put\_identity\_diagonal}}
\label{sec:orga145f39} \label{sec:orge955396}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Location: \texttt{src/matrix.c} \item Location: \texttt{src/matrix.c}
@ -768,9 +742,8 @@ Matrix_double *put_identity_diagonal(Matrix_double *m) {
return copy; return copy;
} }
\end{verbatim} \end{verbatim}
\subsubsection{\texttt{slice\_column}} \subsubsection{\texttt{slice\_column}}
\label{sec:org1ea6d1a} \label{sec:org886997f}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Location: \texttt{src/matrix.c} \item Location: \texttt{src/matrix.c}
@ -792,9 +765,8 @@ Matrix_double *slice_column(Matrix_double *m, size_t x) {
return sliced; return sliced;
} }
\end{verbatim} \end{verbatim}
\subsubsection{\texttt{add\_column}} \subsubsection{\texttt{add\_column}}
\label{sec:org733cc61} \label{sec:org405e1c5}
\begin{itemize} \begin{itemize}
\item Author: Elizabet Hunt \item Author: Elizabet Hunt
\item Location: \texttt{src/matrix.c} \item Location: \texttt{src/matrix.c}
@ -816,9 +788,8 @@ Matrix_double *add_column(Matrix_double *m, Array_double *v) {
return pushed; return pushed;
} }
\end{verbatim} \end{verbatim}
\subsubsection{\texttt{copy\_matrix}} \subsubsection{\texttt{copy\_matrix}}
\label{sec:orge8936ce} \label{sec:org01ea984}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Location: \texttt{src/matrix.c} \item Location: \texttt{src/matrix.c}
@ -836,9 +807,8 @@ Matrix_double *copy_matrix(Matrix_double *m) {
return copy; return copy;
} }
\end{verbatim} \end{verbatim}
\subsubsection{\texttt{free\_matrix}} \subsubsection{\texttt{free\_matrix}}
\label{sec:orgf7b674e} \label{sec:orgab8c2cf}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Location: \texttt{src/matrix.c} \item Location: \texttt{src/matrix.c}
@ -855,9 +825,8 @@ void free_matrix(Matrix_double *m) {
free(m); free(m);
} }
\end{verbatim} \end{verbatim}
\subsubsection{\texttt{format\_matrix\_into}} \subsubsection{\texttt{format\_matrix\_into}}
\label{sec:org22902bd} \label{sec:org9e01978}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Name: \texttt{format\_matrix\_into} \item Name: \texttt{format\_matrix\_into}
@ -884,9 +853,9 @@ void format_matrix_into(Matrix_double *m, char *s) {
} }
\end{verbatim} \end{verbatim}
\subsection{Root Finding Methods} \subsection{Root Finding Methods}
\label{sec:org6c22e6c} \label{sec:org81f315b}
\subsubsection{\texttt{find\_ivt\_range}} \subsubsection{\texttt{find\_ivt\_range}}
\label{sec:org43ba5e5} \label{sec:orgc1dde4d}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Name: \texttt{find\_ivt\_range} \item Name: \texttt{find\_ivt\_range}
@ -894,62 +863,66 @@ void format_matrix_into(Matrix_double *m, char *s) {
\item Input: a pointer to a oneary function taking a double and producing a double, the beginning point \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 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. iterations to perform.
\item Output: a pair of \texttt{double}'s representing a closed closed interval \texttt{[beginning, end]} \item Output: a pair of \texttt{double}'s in an \texttt{Array\_double} representing a closed closed interval \texttt{[beginning, end]}
\end{itemize} \end{itemize}
\begin{verbatim} \begin{verbatim}
double *find_ivt_range(double (*f)(double), double start_x, double delta, // f is well defined at start_x + delta*n for all n on the integer range [0,
size_t max_steps) { // max_iterations]
double *range = malloc(sizeof(double) * 2); Array_double *find_ivt_range(double (*f)(double), double start_x, double delta,
size_t max_iterations) {
double a = start_x; double a = start_x;
while (f(a) * f(start_x) >= 0 && max_steps-- > 0) while (f(a) * f(a + delta) >= 0 && max_iterations > 0) {
max_iterations--;
a += delta; a += delta;
}
if (max_steps == 0 && f(a) * f(start_x) > 0) double end = a + delta;
double begin = a - delta;
if (max_iterations == 0 && f(begin) * f(end) >= 0)
return NULL; return NULL;
return InitArray(double, {begin, end});
range[0] = start_x;
range[1] = a + delta;
return range;
} }
\end{verbatim} \end{verbatim}
\subsubsection{\texttt{bisect\_find\_root}} \subsubsection{\texttt{bisect\_find\_root}}
\label{sec:orgf8a3f0e} \label{sec:orgb42a836}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Name(s): \texttt{bisect\_find\_root} \item Name(s): \texttt{bisect\_find\_root}
\item Input: a one-ary function taking a double and producing a double, a closed interval represented \item Input: a one-ary function taking a double and producing a double, a closed interval represented
by \texttt{a} and \texttt{b}: \texttt{[a, b]}, a \texttt{tolerance} at which we return the estimated root, and a 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} \texttt{max\_iterations} to break us out of a loop if we can never reach the \texttt{tolerance}.
\item Output: a \texttt{double} representing the estimated root \item Output: a vector of size of 3 \texttt{double}'s representing first the .
\item Description: recursively uses binary search to split the interval until we reach \texttt{tolerance}. We \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]}. also assume the function \texttt{f} is continuous on \texttt{[a, b]}.
\end{itemize} \end{itemize}
\begin{verbatim} \begin{verbatim}
double bisect_find_root(double (*f)(double), double a, double b, // f is continuous on [a, b]
double tolerance, size_t max_iterations) { Array_double *bisect_find_root(double (*f)(double), double a, double b,
double tolerance, size_t max_iterations) {
assert(a <= b); assert(a <= b);
// guarantee there's a root somewhere between a and b by IVT // guarantee there's a root somewhere between a and b by IVT
assert(f(a) * f(b) < 0); assert(f(a) * f(b) < 0);
double c = (1.0 / 2) * (a + b); double c = (1.0 / 2) * (a + b);
if (b - a < tolerance || max_iterations == 0) if (b - a < tolerance || max_iterations == 0)
return c; return InitArray(double, a, b, c);
if (f(a) * f(c) < 0) if (f(a) * f(c) < 0)
return bisect_find_root(f, a, c, tolerance, max_iterations - 1); return bisect_find_root(f, a, c, tolerance, max_iterations - 1);
return bisect_find_root(f, c, b, tolerance, max_iterations - 1); return bisect_find_root(f, c, b, tolerance, max_iterations - 1);
} }
\end{verbatim} \end{verbatim}
\subsubsection{\texttt{bisect\_find\_root\_with\_error\_assumption}} \subsubsection{\texttt{bisect\_find\_root\_with\_error\_assumption}}
\label{sec:orgeb72b17} \label{sec:org762134e}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Name: \texttt{bisect\_find\_root\_with\_error\_assumption} \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 \item Input: a one-ary function taking a double and producing a double, a closed interval represented
by \texttt{a} and \texttt{b}: \texttt{[a, b]}, and a \texttt{tolerance} at which we return the estimated root by \texttt{a} and \texttt{b}: \texttt{[a, b]}, and a \texttt{tolerance} equivalent to the above definition in \texttt{bisect\_find\_root}
\item Output: a \texttt{double} representing the estimated root \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 \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 calculate \(k\) at the worst possible case (that the error is exactly the tolerance) to be
@ -963,14 +936,160 @@ double bisect_find_root_with_error_assumption(double (*f)(double), double a,
uint64_t max_iterations = uint64_t max_iterations =
(uint64_t)ceil((log(tolerance) - log(b - a)) / log(1 / 2.0)); (uint64_t)ceil((log(tolerance) - log(b - a)) / log(1 / 2.0));
return bisect_find_root(f, a, b, tolerance, max_iterations);
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;
} }
\end{verbatim} \end{verbatim}
\subsubsection{\texttt{fixed\_point\_iteration\_method}}
\label{sec:org9f210ad}
\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}
\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}
\subsubsection{\texttt{fixed\_point\_newton\_method}}
\label{sec:orgedecc45}
\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}
\subsubsection{\texttt{fixed\_point\_secant\_method}}
\label{sec:org63bcbe2}
\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
trying to find a root, a guess \(x_0\), and a \(\delta\) of our first guess at which we draw the first
secant line according to 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})}\) which
thus simplifies to \(x_1 = (x_0 + \delta) - f(x_0 + \delta) \frac{(x_0 + \delta) - x_0}{f(x_0 + \delta) - f(x_0)} = (x_0 + \delta) - f(x_0 + \delta) \frac{\delta}{f(x_0 + \delta) - f(x_0)}\).
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}
double fixed_point_secant_method(double (*f)(double), double x_0, double delta,
double tolerance, size_t max_iterations) {
if (max_iterations <= 0)
return x_0;
double x_1 = x_0 + delta;
double root = x_1 - f(x_1) * (delta / (f(x_1) - f(x_0)));
if (tolerance >= fabs(f(root)))
return root;
double new_delta = root - x_1;
return fixed_point_secant_method(f, x_1, new_delta, tolerance,
max_iterations);
}
\end{verbatim}
\subsubsection{\texttt{fixed\_point\_secant\_bisection\_method}}
\label{sec:org72d3074}
\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
trying to find a root, a guess \(x_0\), and a \(\delta\) of which we define our first interval \([x_0, x_0 + \delta]\).
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,
double delta, double tolerance,
size_t max_iterations) {
double begin = x_0;
double end = x_0 + delta;
double root = x_0;
while (tolerance < fabs(f(root)) && max_iterations > 0) {
max_iterations--;
double secant_root =
fixed_point_secant_method(f, begin, end - begin, tolerance, 1);
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;
// the root exists in [begin, secant_root]
if (f(root) * f(begin) < 0)
end = secant_root;
else
begin = secant_root;
}
return root;
}
\end{verbatim}
\subsection{Linear Routines} \subsection{Linear Routines}
\label{sec:org4e14ee5} \label{sec:org04f3e56}
\subsubsection{\texttt{least\_squares\_lin\_reg}} \subsubsection{\texttt{least\_squares\_lin\_reg}}
\label{sec:orge0ed136} \label{sec:orgbd48d8e}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Name: \texttt{least\_squares\_lin\_reg} \item Name: \texttt{least\_squares\_lin\_reg}
@ -1000,12 +1119,12 @@ Line *least_squares_lin_reg(Array_double *x, Array_double *y) {
} }
\end{verbatim} \end{verbatim}
\subsection{Appendix / Miscellaneous} \subsection{Appendix / Miscellaneous}
\label{sec:org0130d70} \label{sec:orgf6b30a5}
\subsubsection{Data Types} \subsubsection{Data Types}
\label{sec:org8aa1c01} \label{sec:orgd382789}
\begin{enumerate} \begin{enumerate}
\item \texttt{Line} \item \texttt{Line}
\label{sec:org596b0e7} \label{sec:orgab590b9}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Location: \texttt{inc/types.h} \item Location: \texttt{inc/types.h}
@ -1018,7 +1137,7 @@ typedef struct Line {
} Line; } Line;
\end{verbatim} \end{verbatim}
\item The \texttt{Array\_<type>} and \texttt{Matrix\_<type>} \item The \texttt{Array\_<type>} and \texttt{Matrix\_<type>}
\label{sec:org9d1c7c3} \label{sec:org5be3024}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Location: \texttt{inc/types.h} \item Location: \texttt{inc/types.h}
@ -1048,12 +1167,11 @@ typedef struct {
} Matrix_int } Matrix_int
\end{verbatim} \end{verbatim}
\end{enumerate} \end{enumerate}
\subsubsection{Macros} \subsubsection{Macros}
\label{sec:orgb835bfa} \label{sec:org20a391c}
\begin{enumerate} \begin{enumerate}
\item \texttt{c\_max} and \texttt{c\_min} \item \texttt{c\_max} and \texttt{c\_min}
\label{sec:org9ca763b} \label{sec:orgfc6117a}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Location: \texttt{inc/macros.h} \item Location: \texttt{inc/macros.h}
@ -1065,9 +1183,8 @@ typedef struct {
#define c_max(x, y) (((x) >= (y)) ? (x) : (y)) #define c_max(x, y) (((x) >= (y)) ? (x) : (y))
#define c_min(x, y) (((x) <= (y)) ? (x) : (y)) #define c_min(x, y) (((x) <= (y)) ? (x) : (y))
\end{verbatim} \end{verbatim}
\item \texttt{InitArray} \item \texttt{InitArray}
\label{sec:org3454dab} \label{sec:org472f039}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Location: \texttt{inc/macros.h} \item Location: \texttt{inc/macros.h}
@ -1076,19 +1193,18 @@ typedef struct {
\end{itemize} \end{itemize}
\begin{verbatim} \begin{verbatim}
#define InitArray(TYPE, ...) \ #define InitArray(TYPE, ...) \
({ \ ({ \
TYPE temp[] = __VA_ARGS__; \ TYPE temp[] = __VA_ARGS__; \
Array_##TYPE *arr = malloc(sizeof(Array_##TYPE)); \ Array_##TYPE *arr = malloc(sizeof(Array_##TYPE)); \
arr->size = sizeof(temp) / sizeof(temp[0]); \ arr->size = sizeof(temp) / sizeof(temp[0]); \
arr->data = malloc(arr->size * sizeof(TYPE)); \ arr->data = malloc(arr->size * sizeof(TYPE)); \
memcpy(arr->data, temp, arr->size * sizeof(TYPE)); \ memcpy(arr->data, temp, arr->size * sizeof(TYPE)); \
arr; \ arr; \
}) })
\end{verbatim} \end{verbatim}
\item \texttt{InitArrayWithSize} \item \texttt{InitArrayWithSize}
\label{sec:orga4ec165} \label{sec:orgbe950b8}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Location: \texttt{inc/macros.h} \item Location: \texttt{inc/macros.h}
@ -1097,19 +1213,18 @@ typedef struct {
\end{itemize} \end{itemize}
\begin{verbatim} \begin{verbatim}
#define InitArrayWithSize(TYPE, SIZE, INIT_VALUE) \ #define InitArrayWithSize(TYPE, SIZE, INIT_VALUE) \
({ \ ({ \
Array_##TYPE *arr = malloc(sizeof(Array_##TYPE)); \ Array_##TYPE *arr = malloc(sizeof(Array_##TYPE)); \
arr->size = SIZE; \ arr->size = SIZE; \
arr->data = malloc(arr->size * sizeof(TYPE)); \ arr->data = malloc(arr->size * sizeof(TYPE)); \
for (size_t i = 0; i < arr->size; i++) \ for (size_t i = 0; i < arr->size; i++) \
arr->data[i] = INIT_VALUE; \ arr->data[i] = INIT_VALUE; \
arr; \ arr; \
}) })
\end{verbatim} \end{verbatim}
\item \texttt{InitMatrixWithSize} \item \texttt{InitMatrixWithSize}
\label{sec:org0748f30} \label{sec:org5965f3b}
\begin{itemize} \begin{itemize}
\item Author: Elizabeth Hunt \item Author: Elizabeth Hunt
\item Location: \texttt{inc/macros.h} \item Location: \texttt{inc/macros.h}
@ -1131,4 +1246,4 @@ value
}) })
\end{verbatim} \end{verbatim}
\end{enumerate} \end{enumerate}
\end{document} \end{document}

BIN
homeworks/a.out Executable file

Binary file not shown.

199
homeworks/hw-6.org Normal file
View File

@ -0,0 +1,199 @@
#+TITLE: Homework 6
#+AUTHOR: Elizabeth Hunt
#+LATEX_HEADER: \notindent \notag \usepackage{amsmath} \usepackage[a4paper,margin=1in,portrait]{geometry}
#+LATEX: \setlength\parindent{0pt}
#+OPTIONS: toc:nil
* Question One
For $g(x) = x + f(x)$ then we know $g'(x) = 1 + 2x - 5$ and thus $|g'(x)| \lt 1$ is only true
on the interval $(1.5, 2.5)$, and for $g(x) = x - f(x)$ then we know $g'(x) = 1 - (2x - 5)$
and thus $|g'(x)| < 1$ is only true on the interval $(2.5, 3.5)$.
Because we know the roots of $f$ are $2, 3$ ($f(x) = (x-2)(x-3)$) then we can only be
certain that $g(x) = x + f(x)$ will converge to the root $2$ if we pick an initial
guess between $(1.5, 2.5)$, and likewise for $g(x) = x - f(x)$, $3$:
#+BEGIN_SRC c
// tests/roots.t.c
UTEST(root, fixed_point_iteration_method) {
// x^2 - 5x + 6 = (x - 3)(x - 2)
double expect_x1 = 3.0;
double expect_x2 = 2.0;
double tolerance = 0.001;
uint64_t max_iterations = 10;
double x_0 = 1.55; // 1.5 < 1.55 < 2.5
// g1(x) = x + f(x)
double root1 =
fixed_point_iteration_method(&f2, &g1, x_0, tolerance, max_iterations);
EXPECT_NEAR(root1, expect_x2, tolerance);
// g2(x) = x - f(x)
x_0 = 3.4; // 2.5 < 3.4 < 3.5
double root2 =
fixed_point_iteration_method(&f2, &g2, x_0, tolerance, max_iterations);
EXPECT_NEAR(root2, expect_x1, tolerance);
}
#+END_SRC
And by this method passing in ~tests/roots.t.c~ we know they converged within ~tolerance~ before
10 iterations.
* Question Two
Yes, we showed that for $\epsilon = 1$ in Question One, we can converge upon a root in the range $(2.5, 3.5)$, and
when $\epsilon = -1$ we can converge upon a root in the range $(1.5, 2.5)$.
See the above unit tests in Question One for each $\epsilon$.
* Question Three
See ~test/roots.t.c -> UTEST(root, bisection_with_error_assumption)~
and the software manual entry ~bisect_find_root_with_error_assumption~.
* Question Four
See ~test/roots.t.c -> UTEST(root, fixed_point_newton_method)~
and the software manual entry ~fixed_point_newton_method~.
* Question Five
See ~test/roots.t.c -> UTEST(root, fixed_point_secant_method)~
and the software manual entry ~fixed_point_secant_method~.
* Question Six
See ~test/roots.t.c -> UTEST(root, fixed_point_bisection_secant_method)~
and the software manual entry ~fixed_point_bisection_secant_method~.
* Question Seven
The existance of ~test/roots.t.c~'s compilation into ~dist/lizfcm.test~ via ~make~
shows that the compiled ~lizfcm.a~ contains the root methods mentioned; a user
could link the library and use them, as we do in Question Eight.
* Question Eight
The given ODE $\frac{dP}{dt} = \alpha P - \beta P$ has a trivial solution by separation:
\begin{equation*}
P(t) = C e^{t(\alpha - \beta)}
\end{equation*}
And
\begin{equation*}
P_0 = P(0) = C e^0 = C
\end{equation*}
So $P(t) = P_0 e^{t(\alpha - \beta)}$.
We're trying to find $t$ such that $P(t) = P_\infty$, thus we're finding roots of $P(t) - P_\infty$.
The following code (in ~homeworks/hw_6_p_8.c~) produces this output:
\begin{verbatim}
$ gcc -I../inc/ -Wall hw_6_p_8.c ../lib/lizfcm.a -lm -o hw_6_p_8 && ./hw_6_p_8
a ~ 27.269515; P(27.269515) - P_infty = -0.000000
b ~ 40.957816; P(40.957816) - P_infty = -0.000000
c ~ 40.588827; P(40.588827) - P_infty = -0.000000
d ~ 483.611967; P(483.611967) - P_infty = -0.000000
e ~ 4.894274; P(4.894274) - P_infty = -0.000000
\end{verbatim}
#+BEGIN_SRC c
// compile & test w/
// \--> gcc -I../inc/ -Wall hw_6_p_8.c ../lib/lizfcm.a -lm -o hw_6_p_8
// \--> ./hw_6_p_8
#include "lizfcm.h"
#include <math.h>
#include <stdio.h>
double a(double t) {
double alpha = 0.1;
double beta = 0.001;
double p_0 = 2;
double p_infty = 29.75;
return p_0 * exp(t * (alpha - beta)) - p_infty;
}
double b(double t) {
double alpha = 0.1;
double beta = 0.001;
double p_0 = 2;
double p_infty = 115.35;
return p_0 * exp(t * (alpha - beta)) - p_infty;
}
double c(double t) {
double alpha = 0.1;
double beta = 0.0001;
double p_0 = 2;
double p_infty = 115.35;
return p_0 * exp(t * (alpha - beta)) - p_infty;
}
double d(double t) {
double alpha = 0.01;
double beta = 0.001;
double p_0 = 2;
double p_infty = 155.346;
return p_0 * exp(t * (alpha - beta)) - p_infty;
}
double e(double t) {
double alpha = 0.1;
double beta = 0.01;
double p_0 = 100;
double p_infty = 155.346;
return p_0 * exp(t * (alpha - beta)) - p_infty;
}
int main() {
uint64_t max_iterations = 1000;
double tolerance = 0.0000001;
Array_double *ivt_range = find_ivt_range(&a, -5.0, 3.0, 1000);
double approx_a = fixed_point_secant_bisection_method(
&a, ivt_range->data[0], ivt_range->data[1], tolerance, max_iterations);
free_vector(ivt_range);
ivt_range = find_ivt_range(&b, -5.0, 3.0, 1000);
double approx_b = fixed_point_secant_bisection_method(
&b, ivt_range->data[0], ivt_range->data[1], tolerance, max_iterations);
free_vector(ivt_range);
ivt_range = find_ivt_range(&c, -5.0, 3.0, 1000);
double approx_c = fixed_point_secant_bisection_method(
&c, ivt_range->data[0], ivt_range->data[1], tolerance, max_iterations);
free_vector(ivt_range);
ivt_range = find_ivt_range(&d, -5.0, 3.0, 1000);
double approx_d = fixed_point_secant_bisection_method(
&d, ivt_range->data[0], ivt_range->data[1], tolerance, max_iterations);
free_vector(ivt_range);
ivt_range = find_ivt_range(&e, -5.0, 3.0, 1000);
double approx_e = fixed_point_secant_bisection_method(
&e, ivt_range->data[0], ivt_range->data[1], tolerance, max_iterations);
printf("a ~ %f; P(%f) = %f\n", approx_a, approx_a, a(approx_a));
printf("b ~ %f; P(%f) = %f\n", approx_b, approx_b, b(approx_b));
printf("c ~ %f; P(%f) = %f\n", approx_c, approx_c, c(approx_c));
printf("d ~ %f; P(%f) = %f\n", approx_d, approx_d, d(approx_d));
printf("e ~ %f; P(%f) = %f\n", approx_e, approx_e, e(approx_e));
return 0;
}
#+END_SRC

BIN
homeworks/hw-6.pdf Normal file

Binary file not shown.

223
homeworks/hw-6.tex Normal file
View File

@ -0,0 +1,223 @@
% Created 2023-11-11 Sat 13:13
% 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}
\title{Homework 6}
\hypersetup{
pdfauthor={Elizabeth Hunt},
pdftitle={Homework 6},
pdfkeywords={},
pdfsubject={},
pdfcreator={Emacs 29.1 (Org mode 9.7-pre)},
pdflang={English}}
\begin{document}
\maketitle
\setlength\parindent{0pt}
\section{Question One}
\label{sec:org206b859}
For \(g(x) = x + f(x)\) then we know \(g'(x) = 1 + 2x - 5\) and thus \(|g'(x)| \lt 1\) is only true
on the interval \((1.5, 2.5)\), and for \(g(x) = x - f(x)\) then we know \(g'(x) = 1 - (2x - 5)\)
and thus \(|g'(x)| < 1\) is only true on the interval \((2.5, 3.5)\).
Because we know the roots of \(f\) are \(2, 3\) (\(f(x) = (x-2)(x-3)\)) then we can only be
certain that \(g(x) = x + f(x)\) will converge to the root \(2\) if we pick an initial
guess between \((1.5, 2.5)\), and likewise for \(g(x) = x - f(x)\), \(3\):
\begin{verbatim}
// tests/roots.t.c
UTEST(root, fixed_point_iteration_method) {
// x^2 - 5x + 6 = (x - 3)(x - 2)
double expect_x1 = 3.0;
double expect_x2 = 2.0;
double tolerance = 0.001;
uint64_t max_iterations = 10;
double x_0 = 1.55; // 1.5 < 1.55 < 2.5
// g1(x) = x + f(x)
double root1 =
fixed_point_iteration_method(&f2, &g1, x_0, tolerance, max_iterations);
EXPECT_NEAR(root1, expect_x2, tolerance);
// g2(x) = x - f(x)
x_0 = 3.4; // 2.5 < 3.4 < 3.5
double root2 =
fixed_point_iteration_method(&f2, &g2, x_0, tolerance, max_iterations);
EXPECT_NEAR(root2, expect_x1, tolerance);
}
\end{verbatim}
And by this method passing in \texttt{tests/roots.t.c} we know they converged within \texttt{tolerance} before
10 iterations.
\section{Question Two}
\label{sec:orga0f5b42}
Yes, we showed that for \(\epsilon = 1\) in Question One, we can converge upon a root in the range \((2.5, 3.5)\), and
when \(\epsilon = -1\) we can converge upon a root in the range \((1.5, 2.5)\).
See the above unit tests in Question One for each \(\epsilon\).
\section{Question Three}
\label{sec:org19aa326}
See \texttt{test/roots.t.c -> UTEST(root, bisection\_with\_error\_assumption)}
and the software manual entry \texttt{bisect\_find\_root\_with\_error\_assumption}.
\section{Question Four}
\label{sec:org722aa6a}
See \texttt{test/roots.t.c -> UTEST(root, fixed\_point\_newton\_method)}
and the software manual entry \texttt{fixed\_point\_newton\_method}.
\section{Question Five}
\label{sec:org587ee52}
See \texttt{test/roots.t.c -> UTEST(root, fixed\_point\_secant\_method)}
and the software manual entry \texttt{fixed\_point\_secant\_method}.
\section{Question Six}
\label{sec:org79bf754}
See \texttt{test/roots.t.c -> UTEST(root, fixed\_point\_bisection\_secant\_method)}
and the software manual entry \texttt{fixed\_point\_bisection\_secant\_method}.
\section{Question Seven}
\label{sec:org4cb47e5}
The existance of \texttt{test/roots.t.c}'s compilation into \texttt{dist/lizfcm.test} via \texttt{make}
shows that the compiled \texttt{lizfcm.a} contains the root methods mentioned; a user
could link the library and use them, as we do in Question Eight.
\section{Question Eight}
\label{sec:org4a8160d}
The given ODE \(\frac{dP}{dt} = \alpha P - \beta P\) has a trivial solution by separation:
\begin{equation*}
P(t) = C e^{t(\alpha - \beta)}
\end{equation*}
And
\begin{equation*}
P_0 = P(0) = C e^0 = C
\end{equation*}
So \(P(t) = P_0 e^{t(\alpha - \beta)}\).
We're trying to find \(t\) such that \(P(t) = P_\infty\), thus we're finding roots of \(P(t) - P_\infty\).
The following code (in \texttt{homeworks/hw\_6\_p\_8.c}) produces this output:
\begin{verbatim}
$ gcc -I../inc/ -Wall hw_6_p_8.c ../lib/lizfcm.a -lm -o hw_6_p_8 && ./hw_6_p_8
a ~ 27.303411; P(27.303411) - P_infty = -0.000000
b ~ 40.957816; P(40.957816) - P_infty = -0.000000
c ~ 40.588827; P(40.588827) - P_infty = -0.000000
d ~ 483.611967; P(483.611967) - P_infty = -0.000000
e ~ 4.894274; P(4.894274) - P_infty = -0.000000
\end{verbatim}
\begin{verbatim}
// compile & test w/
// \--> gcc -I../inc/ -Wall hw_6_p_8.c ../lib/lizfcm.a -lm -o hw_6_p_8
// \--> ./hw_6_p_8
#include "lizfcm.h"
#include <math.h>
#include <stdio.h>
double a(double t) {
double alpha = 0.1;
double beta = 0.001;
double p_0 = 2;
double p_infty = 29.85;
return p_0 * exp(t * (alpha - beta)) - p_infty;
}
double b(double t) {
double alpha = 0.1;
double beta = 0.001;
double p_0 = 2;
double p_infty = 115.35;
return p_0 * exp(t * (alpha - beta)) - p_infty;
}
double c(double t) {
double alpha = 0.1;
double beta = 0.0001;
double p_0 = 2;
double p_infty = 115.35;
return p_0 * exp(t * (alpha - beta)) - p_infty;
}
double d(double t) {
double alpha = 0.01;
double beta = 0.001;
double p_0 = 2;
double p_infty = 155.346;
return p_0 * exp(t * (alpha - beta)) - p_infty;
}
double e(double t) {
double alpha = 0.1;
double beta = 0.01;
double p_0 = 100;
double p_infty = 155.346;
return p_0 * exp(t * (alpha - beta)) - p_infty;
}
int main() {
uint64_t max_iterations = 1000;
double tolerance = 0.0000001;
Array_double *ivt_range = find_ivt_range(&a, -5.0, 3.0, 1000);
double approx_a = fixed_point_secant_bisection_method(
&a, ivt_range->data[0], ivt_range->data[1], tolerance, max_iterations);
free_vector(ivt_range);
ivt_range = find_ivt_range(&b, -5.0, 3.0, 1000);
double approx_b = fixed_point_secant_bisection_method(
&b, ivt_range->data[0], ivt_range->data[1], tolerance, max_iterations);
free_vector(ivt_range);
ivt_range = find_ivt_range(&c, -5.0, 3.0, 1000);
double approx_c = fixed_point_secant_bisection_method(
&c, ivt_range->data[0], ivt_range->data[1], tolerance, max_iterations);
free_vector(ivt_range);
ivt_range = find_ivt_range(&d, -5.0, 3.0, 1000);
double approx_d = fixed_point_secant_bisection_method(
&d, ivt_range->data[0], ivt_range->data[1], tolerance, max_iterations);
free_vector(ivt_range);
ivt_range = find_ivt_range(&e, -5.0, 3.0, 1000);
double approx_e = fixed_point_secant_bisection_method(
&e, ivt_range->data[0], ivt_range->data[1], tolerance, max_iterations);
printf("a ~ %f; P(%f) = %f\n", approx_a, approx_a, a(approx_a));
printf("b ~ %f; P(%f) = %f\n", approx_b, approx_b, b(approx_b));
printf("c ~ %f; P(%f) = %f\n", approx_c, approx_c, c(approx_c));
printf("d ~ %f; P(%f) = %f\n", approx_d, approx_d, d(approx_d));
printf("e ~ %f; P(%f) = %f\n", approx_e, approx_e, e(approx_e));
return 0;
}
\end{verbatim}
\end{document}

BIN
homeworks/hw_6_p_8 Executable file

Binary file not shown.

89
homeworks/hw_6_p_8.c Normal file
View File

@ -0,0 +1,89 @@
// compile & test w/
// \--> gcc -I../inc/ -Wall hw_6_p_8.c ../lib/lizfcm.a -lm -o hw_6_p_8
// \--> ./hw_6_p_8
#include "lizfcm.h"
#include <math.h>
#include <stdio.h>
double a(double t) {
double alpha = 0.1;
double beta = 0.001;
double p_0 = 2;
double p_infty = 29.75;
return p_0 * exp(t * (alpha - beta)) - p_infty;
}
double b(double t) {
double alpha = 0.1;
double beta = 0.001;
double p_0 = 2;
double p_infty = 115.35;
return p_0 * exp(t * (alpha - beta)) - p_infty;
}
double c(double t) {
double alpha = 0.1;
double beta = 0.0001;
double p_0 = 2;
double p_infty = 115.35;
return p_0 * exp(t * (alpha - beta)) - p_infty;
}
double d(double t) {
double alpha = 0.01;
double beta = 0.001;
double p_0 = 2;
double p_infty = 155.346;
return p_0 * exp(t * (alpha - beta)) - p_infty;
}
double e(double t) {
double alpha = 0.1;
double beta = 0.01;
double p_0 = 100;
double p_infty = 155.346;
return p_0 * exp(t * (alpha - beta)) - p_infty;
}
int main() {
uint64_t max_iterations = 1000;
double tolerance = 0.0000001;
Array_double *ivt_range = find_ivt_range(&a, -5.0, 3.0, 1000);
double approx_a = fixed_point_secant_bisection_method(
&a, ivt_range->data[0], ivt_range->data[1], tolerance, max_iterations);
free_vector(ivt_range);
ivt_range = find_ivt_range(&b, -5.0, 3.0, 1000);
double approx_b = fixed_point_secant_bisection_method(
&b, ivt_range->data[0], ivt_range->data[1], tolerance, max_iterations);
free_vector(ivt_range);
ivt_range = find_ivt_range(&c, -5.0, 3.0, 1000);
double approx_c = fixed_point_secant_bisection_method(
&c, ivt_range->data[0], ivt_range->data[1], tolerance, max_iterations);
free_vector(ivt_range);
ivt_range = find_ivt_range(&d, -5.0, 3.0, 1000);
double approx_d = fixed_point_secant_bisection_method(
&d, ivt_range->data[0], ivt_range->data[1], tolerance, max_iterations);
free_vector(ivt_range);
ivt_range = find_ivt_range(&e, -5.0, 3.0, 1000);
double approx_e = fixed_point_secant_bisection_method(
&e, ivt_range->data[0], ivt_range->data[1], tolerance, max_iterations);
printf("a ~ %f; P(%f) - P_infty = %f\n", approx_a, approx_a, a(approx_a));
printf("b ~ %f; P(%f) - P_infty = %f\n", approx_b, approx_b, b(approx_b));
printf("c ~ %f; P(%f) - P_infty = %f\n", approx_c, approx_c, c(approx_c));
printf("d ~ %f; P(%f) - P_infty = %f\n", approx_d, approx_d, d(approx_d));
printf("e ~ %f; P(%f) - P_infty = %f\n", approx_e, approx_e, e(approx_e));
return 0;
}

View File

@ -50,12 +50,26 @@ extern int matrix_equal(Matrix_double *a, Matrix_double *b);
extern Line *least_squares_lin_reg(Array_double *x, Array_double *y); extern Line *least_squares_lin_reg(Array_double *x, Array_double *y);
extern double *find_ivt_range(double (*f)(double), double start_x, double delta, extern Array_double *find_ivt_range(double (*f)(double), double start_x,
size_t max_steps); double delta, size_t max_steps);
extern double bisect_find_root(double (*f)(double), double a, double b, extern Array_double *bisect_find_root(double (*f)(double), double a, double b,
double tolerance, size_t max_iterations); double tolerance, size_t max_iterations);
extern double bisect_find_root_with_error_assumption(double (*f)(double), extern double bisect_find_root_with_error_assumption(double (*f)(double),
double a, double b, double a, double b,
double tolerance); double tolerance);
extern double fixed_point_iteration_method(double (*f)(double),
double (*g)(double), double x_0,
double tolerance,
size_t max_iterations);
extern double fixed_point_newton_method(double (*f)(double),
double (*fprime)(double), double x_0,
double tolerance,
size_t max_iterations);
extern double fixed_point_secant_method(double (*f)(double), double x_0,
double x_1, double tolerance,
size_t max_iterations);
extern double fixed_point_secant_bisection_method(double (*f)(double),
double x_0, double x_1,
double tolerance,
size_t max_iterations);
#endif // LIZFCM_H #endif // LIZFCM_H

View File

@ -42,7 +42,7 @@ Then x^* = 0
If we construct g(x) = 10x + xe^-x If we construct g(x) = 10x + xe^-x
Then g'(x) = 10 + (e^-x - xe^-x) \Rightarrow g'(x) = 10 + e^0 - 0 = 11 (this wouldn't converge)n Then g'(x) = 10 + (e^-x - xe^-x) \Rightarrow g'(x) = 10 + e^0 - 0 = 11 (this wouldn't converge)
However if g(x)) = x - (xe^-x), g'(x) = 1 - (e^-x - xe^-x) \Rightarrow g'(x^*) = 0 However if g(x)) = x - (xe^-x), g'(x) = 1 - (e^-x - xe^-x) \Rightarrow g'(x^*) = 0

View File

@ -7,8 +7,8 @@ double central_derivative_at(double (*f)(double), double a, double h) {
double x2 = a + h; double x2 = a + h;
double x1 = a - h; double x1 = a - h;
double y2 = (*f)(x2); double y2 = f(x2);
double y1 = (*f)(x1); double y1 = f(x1);
return (y2 - y1) / (x2 - x1); return (y2 - y1) / (x2 - x1);
} }
@ -19,8 +19,8 @@ double forward_derivative_at(double (*f)(double), double a, double h) {
double x2 = a + h; double x2 = a + h;
double x1 = a; double x1 = a;
double y2 = (*f)(x2); double y2 = f(x2);
double y1 = (*f)(x1); double y1 = f(x1);
return (y2 - y1) / (x2 - x1); return (y2 - y1) / (x2 - x1);
} }
@ -31,8 +31,8 @@ double backward_derivative_at(double (*f)(double), double a, double h) {
double x2 = a; double x2 = a;
double x1 = a - h; double x1 = a - h;
double y2 = (*f)(x2); double y2 = f(x2);
double y1 = (*f)(x1); double y1 = f(x1);
return (y2 - y1) / (x2 - x1); return (y2 - y1) / (x2 - x1);
} }

View File

@ -3,34 +3,35 @@
#include <math.h> #include <math.h>
// f is well defined at start_x + delta*n for all n on the integer range [0, // f is well defined at start_x + delta*n for all n on the integer range [0,
// max_steps] // max_iterations]
double *find_ivt_range(double (*f)(double), double start_x, double delta, Array_double *find_ivt_range(double (*f)(double), double start_x, double delta,
size_t max_steps) { size_t max_iterations) {
double *range = malloc(sizeof(double) * 2);
double a = start_x; double a = start_x;
while (f(a) * f(start_x) >= 0 && max_steps-- > 0) while (f(a) * f(a + delta) >= 0 && max_iterations > 0) {
max_iterations--;
a += delta; a += delta;
}
if (max_steps == 0 && f(a) * f(start_x) > 0) double end = a + delta;
double begin = a - delta;
if (max_iterations == 0 && f(begin) * f(end) >= 0)
return NULL; return NULL;
return InitArray(double, {begin, end});
range[0] = start_x;
range[1] = a + delta;
return range;
} }
// f is continuous on [a, b] // f is continuous on [a, b]
double bisect_find_root(double (*f)(double), double a, double b, Array_double *bisect_find_root(double (*f)(double), double a, double b,
double tolerance, size_t max_iterations) { double tolerance, size_t max_iterations) {
assert(a <= b); assert(a <= b);
// guarantee there's a root somewhere between a and b by IVT // guarantee there's a root somewhere between a and b by IVT
assert(f(a) * f(b) < 0); assert(f(a) * f(b) < 0);
double c = (1.0 / 2) * (a + b); double c = (1.0 / 2) * (a + b);
if (b - a < tolerance || max_iterations == 0) if (b - a < tolerance || max_iterations == 0)
return c; return InitArray(double, {a, b, c});
if (f(a) * f(c) < 0) if (f(a) * f(c) < 0)
return bisect_find_root(f, a, c, tolerance, max_iterations - 1); return bisect_find_root(f, a, c, tolerance, max_iterations - 1);
return bisect_find_root(f, c, b, tolerance, max_iterations - 1); return bisect_find_root(f, c, b, tolerance, max_iterations - 1);
@ -42,5 +43,85 @@ double bisect_find_root_with_error_assumption(double (*f)(double), double a,
uint64_t max_iterations = uint64_t max_iterations =
(uint64_t)ceil((log(tolerance) - log(b - a)) / log(1 / 2.0)); (uint64_t)ceil((log(tolerance) - log(b - a)) / log(1 / 2.0));
return bisect_find_root(f, a, b, tolerance, max_iterations);
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;
}
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);
}
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);
}
double fixed_point_secant_method(double (*f)(double), double x_0, double x_1,
double tolerance, size_t max_iterations) {
if (max_iterations == 0)
return x_1;
double root = x_1 - f(x_1) * ((x_1 - x_0) / (f(x_1) - f(x_0)));
if (tolerance >= fabs(f(root)))
return root;
return fixed_point_secant_method(f, x_1, root, tolerance, max_iterations - 1);
}
double fixed_point_secant_bisection_method(double (*f)(double), double x_0,
double x_1, double tolerance,
size_t max_iterations) {
double begin = x_0;
double end = x_1;
double root = x_0;
while (tolerance < fabs(f(root)) && max_iterations > 0) {
max_iterations--;
double secant_root = fixed_point_secant_method(f, begin, end, tolerance, 1);
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;
if (f(root) * f(begin) < 0)
end = secant_root; // the root exists in [begin, secant_root]
else
begin = secant_root;
}
return root;
} }

View File

@ -1,17 +1,114 @@
#include "lizfcm.test.h" #include "lizfcm.test.h"
#include <math.h>
#include <stdio.h> #include <stdio.h>
double g(double x) { return x * x - 9; } double f1(double x) { return x * x - 9; }
double f2(double x) { return x * x - 5 * x + 6; }
double f2prime(double x) { return 2 * x - 5; }
double g1(double x) { return x + f2(x); }
double g2(double x) { return x - f2(x); }
UTEST(ivt, find_interval) { UTEST(ivt, find_interval) {
double *range = find_ivt_range(&g, -100.0, 1.0, 200); Array_double *range = find_ivt_range(&f1, -10.0, 0.10, 200);
EXPECT_LT(g(range[0]) * g(range[1]), 0); EXPECT_LT(f1(range->data[0]) * f1(range->data[1]), 0);
free(range); free_vector(range);
} }
UTEST(root, bisection_with_error_assumption) { UTEST(root, bisection_with_error_assumption) {
double root = bisect_find_root_with_error_assumption(&g, -5, 0, 0.01); Array_double *range = find_ivt_range(&f2, 2.5, 0.10, 200);
EXPECT_NEAR(-3, root, 0.01); double tolerance = 0.01;
double root1 = bisect_find_root_with_error_assumption(
&f2, range->data[0], range->data[1], tolerance);
free_vector(range);
range = find_ivt_range(&f2, 0, 0.01, 500);
double root2 = bisect_find_root_with_error_assumption(
&f2, range->data[0], range->data[1], tolerance);
free_vector(range);
EXPECT_NEAR(3.0, root1, tolerance);
EXPECT_NEAR(2.0, root2, tolerance);
}
UTEST(root, fixed_point_iteration_method) {
// x^2 - 5x + 6 = (x - 3)(x - 2)
double expect_x2 = 3.0;
double expect_x1 = 2.0;
double tolerance = 0.001;
uint64_t max_iterations = 10;
double x_0 = 1.55; // 1.5 < 1.55 < 2.5
// g1(x) = x + f(x)
double root1 =
fixed_point_iteration_method(&f2, &g1, x_0, tolerance, max_iterations);
EXPECT_NEAR(root1, expect_x1, tolerance);
// g2(x) = x - f(x)
x_0 = 3.4; // 2.5 < 3.4 < 3.5
double root2 =
fixed_point_iteration_method(&f2, &g2, x_0, tolerance, max_iterations);
EXPECT_NEAR(root2, expect_x2, tolerance);
}
UTEST(root, fixed_point_newton_method) {
// x^2 - 5x + 6 = (x - 3)(x - 2)
double expect_x2 = 3.0;
double expect_x1 = 2.0;
double tolerance = 0.01;
uint64_t max_iterations = 10;
double x_0 = 1.55; // 1.5 < 1.55 < 2.5
double root1 =
fixed_point_newton_method(&f2, &f2prime, x_0, tolerance, max_iterations);
EXPECT_NEAR(root1, expect_x1, tolerance);
x_0 = 3.4; // 2.5 < 3.4 < 3.5
double root2 =
fixed_point_newton_method(&f2, &f2prime, x_0, tolerance, max_iterations);
EXPECT_NEAR(root2, expect_x2, tolerance);
}
UTEST(root, fixed_point_secant_method) {
// x^2 - 5x + 6 = (x - 3)(x - 2)
double expect_x2 = 3.0;
double expect_x1 = 2.0;
double delta = 0.01;
double tolerance = 0.01;
uint64_t max_iterations = 10;
double x_0 = 1.55; // 1.5 < 1.55 < 2.5
double root1 = fixed_point_secant_method(&f2, x_0, x_0 + delta, tolerance,
max_iterations);
EXPECT_NEAR(root1, expect_x1, tolerance);
x_0 = 3.4; // 2.5 < 3.4 < 3.5
double root2 = fixed_point_secant_method(&f2, x_0, x_0 + delta, tolerance,
max_iterations);
EXPECT_NEAR(root2, expect_x2, tolerance);
}
UTEST(root, fixed_point_hybrid_method) {
// x^2 - 5x + 6 = (x - 3)(x - 2)
double expect_x2 = 3.0;
double expect_x1 = 2.0;
double delta = 1.0;
double tolerance = 0.01;
uint64_t max_iterations = 10;
double x_0 = 1.55;
double root1 = fixed_point_secant_bisection_method(&f2, x_0, x_0 + delta,
tolerance, max_iterations);
EXPECT_NEAR(root1, expect_x1, tolerance);
x_0 = 2.5;
double root2 = fixed_point_secant_bisection_method(&f2, x_0, x_0 + delta,
tolerance, max_iterations);
EXPECT_NEAR(root2, expect_x2, tolerance);
} }