oct 16, 18 notes. add unit tests with utest, and bisection root finding methods
This commit is contained in:
parent
1b4d91e623
commit
9e7166a52e
15
Makefile
15
Makefile
@ -1,9 +1,12 @@
|
|||||||
TEST_SRC := test/main.c
|
|
||||||
SRC_DIR := src
|
SRC_DIR := src
|
||||||
OBJ_DIR := build
|
OBJ_DIR := build
|
||||||
BIN_DIR := dist
|
BIN_DIR := dist
|
||||||
LIB_DIR := lib
|
LIB_DIR := lib
|
||||||
|
|
||||||
|
TEST_SRC_DIR := test
|
||||||
|
TEST_SRC := $(wildcard $(TEST_SRC_DIR)/*.c)
|
||||||
|
TEST_OBJ := $(TEST_SRC:$(TEST_SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
|
||||||
|
|
||||||
TEST_EXE := $(BIN_DIR)/lizfcm.test
|
TEST_EXE := $(BIN_DIR)/lizfcm.test
|
||||||
EXE := $(BIN_DIR)/lizfcm
|
EXE := $(BIN_DIR)/lizfcm
|
||||||
LIBRARY := $(LIB_DIR)/lizfcm.a
|
LIBRARY := $(LIB_DIR)/lizfcm.a
|
||||||
@ -18,20 +21,26 @@ LDFLAGS := -lm
|
|||||||
|
|
||||||
all: $(TEST_EXE)
|
all: $(TEST_EXE)
|
||||||
|
|
||||||
$(TEST_EXE): $(BIN_DIR) | $(LIBRARY)
|
$(TEST_EXE): $(TEST_OBJ) $(LIBRARY) | $(BIN_DIR)
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(TEST_SRC) $(LIBRARY) -o $@
|
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $^ -o $@
|
||||||
|
|
||||||
$(LIBRARY): $(OBJ) | $(LIB_DIR)
|
$(LIBRARY): $(OBJ) | $(LIB_DIR)
|
||||||
ar rcs $(LIBRARY) $(OBJ_DIR)/*.o
|
ar rcs $(LIBRARY) $(OBJ_DIR)/*.o
|
||||||
ranlib $(LIBRARY)
|
ranlib $(LIBRARY)
|
||||||
|
|
||||||
|
$(OBJ_DIR)/%.o: $(TEST_SRC_DIR)/%.c | $(OBJ_DIR)
|
||||||
|
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR)
|
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR)
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
|
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
$(BIN_DIR) $(OBJ_DIR) $(LIB_DIR):
|
$(BIN_DIR) $(OBJ_DIR) $(LIB_DIR):
|
||||||
mkdir -p $@
|
mkdir -p $@
|
||||||
|
|
||||||
|
print-% : ; @echo $* = $($*)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@$(RM) -r $(BIN_DIR) $(OBJ_DIR) $(LIB_DIR)
|
@$(RM) -r $(BIN_DIR) $(OBJ_DIR) $(LIB_DIR)
|
||||||
|
|
||||||
-include $(OBJ:.o=.d)
|
-include $(OBJ:.o=.d)
|
||||||
|
-include $(TEST_OBJ:.o=.d)
|
||||||
|
Binary file not shown.
@ -1,4 +1,4 @@
|
|||||||
% Created 2023-10-13 Fri 20:54
|
% Created 2023-10-13 Fri 21:11
|
||||||
% Intended LaTeX compiler: pdflatex
|
% Intended LaTeX compiler: pdflatex
|
||||||
\documentclass[11pt]{article}
|
\documentclass[11pt]{article}
|
||||||
\usepackage[utf8]{inputenc}
|
\usepackage[utf8]{inputenc}
|
||||||
@ -29,17 +29,17 @@
|
|||||||
\setlength\parindent{0pt}
|
\setlength\parindent{0pt}
|
||||||
|
|
||||||
\section{Question 1}
|
\section{Question 1}
|
||||||
\label{sec:org0ce46da}
|
\label{sec:orgf7348d4}
|
||||||
See the attached LIZFCM Software Manual.
|
See the attached LIZFCM Software Manual.
|
||||||
|
|
||||||
\section{Question 2, 3, 4}
|
\section{Question 2, 3, 4}
|
||||||
\label{sec:org0794d50}
|
\label{sec:orgaf52510}
|
||||||
\begin{center}
|
\begin{center}
|
||||||
\includegraphics[width=350px]{./img/make_run.png}
|
\includegraphics[width=350px]{./img/make_run.png}
|
||||||
\end{center}
|
\end{center}
|
||||||
|
|
||||||
\section{Question 5}
|
\section{Question 5}
|
||||||
\label{sec:orgf7b84cc}
|
\label{sec:orgd0fe6e8}
|
||||||
\begin{center}
|
\begin{center}
|
||||||
\includegraphics[width=350px]{./img/test_routine_1.png}
|
\includegraphics[width=350px]{./img/test_routine_1.png}
|
||||||
\end{center}
|
\end{center}
|
||||||
@ -49,22 +49,22 @@ See the attached LIZFCM Software Manual.
|
|||||||
\end{center}
|
\end{center}
|
||||||
|
|
||||||
\section{Question 6}
|
\section{Question 6}
|
||||||
\label{sec:orgee1884d}
|
\label{sec:org9e2023c}
|
||||||
See the LIZFCM Software Manual.
|
See the LIZFCM Software Manual.
|
||||||
|
|
||||||
\section{Question 7}
|
\section{Question 7}
|
||||||
\label{sec:org6f86e09}
|
\label{sec:org6c11571}
|
||||||
See \texttt{src/matrix.c -> lu\_decomp, fsubst, bsubst, solve\_matrix}
|
See \texttt{src/matrix.c -> lu\_decomp, fsubst, bsubst, solve\_matrix}
|
||||||
|
|
||||||
\section{Question 8}
|
\section{Question 8}
|
||||||
\label{sec:orga79c31e}
|
\label{sec:org9ba7792}
|
||||||
See \texttt{test/main.c -> lines 109 - 113} in correspondence to the run in Question 5
|
See \texttt{test/main.c -> lines 109 - 113} in correspondence to the run in Question 5
|
||||||
|
|
||||||
\section{Question 9}
|
\section{Question 9}
|
||||||
\label{sec:org5b1b74d}
|
\label{sec:org3cff888}
|
||||||
See \texttt{test/main.c -> lines 118 - 121} in correspondence to the run in Question 5
|
See \texttt{test/main.c -> lines 118 - 121} in correspondence to the run in Question 5
|
||||||
|
|
||||||
\section{Question 10}
|
\section{Question 10}
|
||||||
\label{sec:org7409683}
|
\label{sec:org522eabc}
|
||||||
See the TOC on the first page of the LIZFCM Software Manual.
|
See the TOC on the first page of the LIZFCM Software Manual.
|
||||||
\end{document}
|
\end{document}
|
10
inc/lizfcm.h
10
inc/lizfcm.h
@ -27,6 +27,7 @@ extern double linf_distance(Array_double *v1, Array_double *v2);
|
|||||||
extern Array_double *copy_vector(Array_double *v1);
|
extern Array_double *copy_vector(Array_double *v1);
|
||||||
extern void free_vector(Array_double *v);
|
extern void free_vector(Array_double *v);
|
||||||
extern void format_vector_into(Array_double *v, char *s);
|
extern void format_vector_into(Array_double *v, char *s);
|
||||||
|
extern int vector_equal(Array_double *a, Array_double *b);
|
||||||
|
|
||||||
extern Matrix_double *put_identity_diagonal(Matrix_double *m);
|
extern Matrix_double *put_identity_diagonal(Matrix_double *m);
|
||||||
extern Matrix_double **lu_decomp(Matrix_double *m);
|
extern Matrix_double **lu_decomp(Matrix_double *m);
|
||||||
@ -37,7 +38,16 @@ extern Array_double *m_dot_v(Matrix_double *m, Array_double *v);
|
|||||||
extern Matrix_double *copy_matrix(Matrix_double *m);
|
extern Matrix_double *copy_matrix(Matrix_double *m);
|
||||||
extern void free_matrix(Matrix_double *m);
|
extern void free_matrix(Matrix_double *m);
|
||||||
extern void format_matrix_into(Matrix_double *m, char *s);
|
extern void format_matrix_into(Matrix_double *m, char *s);
|
||||||
|
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,
|
||||||
|
size_t max_steps);
|
||||||
|
extern double bisect_find_root(double (*f)(double), double a, double b,
|
||||||
|
double tolerance, size_t max_iterations);
|
||||||
|
extern double bisect_find_root_with_error_assumption(double (*f)(double),
|
||||||
|
double a, double b,
|
||||||
|
double tolerance);
|
||||||
|
|
||||||
#endif // LIZFCM_H
|
#endif // LIZFCM_H
|
||||||
|
@ -52,4 +52,7 @@
|
|||||||
#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))
|
||||||
|
|
||||||
|
#define true 1;
|
||||||
|
#define false 0;
|
||||||
|
|
||||||
#endif // MACROS_H
|
#endif // MACROS_H
|
||||||
|
77
notes/Oct-16.org
Normal file
77
notes/Oct-16.org
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
Find x \in R st f(x) = 0
|
||||||
|
|
||||||
|
if f(x^*) = 0 then define x^* = g(x^*) = x^* + f(x^*)
|
||||||
|
|
||||||
|
Suppose we approximate x^* by x_0. Then Using the fixed point equations:
|
||||||
|
|
||||||
|
x_1 = g(x_0) = x_0 + f(x_0)
|
||||||
|
x_2 = g(g_1) \cdots x_{k+1} = g(x_k)
|
||||||
|
|
||||||
|
This generates a sequence of approximations to x^*
|
||||||
|
|
||||||
|
{X_k} \rightarrow x^*
|
||||||
|
|
||||||
|
The algorithm is: Given f(x), x_0, compute x_{k+1} = g(x_k), k = 0, 1, 2, \cdots
|
||||||
|
= x_k + f(x_k)
|
||||||
|
|
||||||
|
Examples for g(x)
|
||||||
|
|
||||||
|
1. x_{k+1} = x_k + f(x_k)
|
||||||
|
2. x_{k+1} = x_k - f(x_k)
|
||||||
|
3. x_{k+1} = x_k - mf(x_k)
|
||||||
|
4. x_{k+q} = s_k - sin(f(x_k))
|
||||||
|
|
||||||
|
x^* = root of f
|
||||||
|
y^* = solution of y^* = g(y^*)
|
||||||
|
|
||||||
|
| x^* - y^* | = x^* - (y^* - f(y^*))
|
||||||
|
|x_{k+1} - x^* | = | g(x_k) - g(x^*) |
|
||||||
|
= |g(x^*) + g'(x^k)(x_k - x^*) + \cdots) - g(x^*)|
|
||||||
|
= |g'(x^*)(x_k - x^*) + hot|
|
||||||
|
\leq | g'(x^*)(x_k - x^*)| + (pos val)
|
||||||
|
\leq |g'(x^*)| (|x_k - x^*|)
|
||||||
|
|
||||||
|
\Rightarrow |x_{k+1} - x^*| \leq |g'(x^*)| \cdot |x_k - x^*|
|
||||||
|
|
||||||
|
For this to converge, we need |g'(x^*)| \lt 1
|
||||||
|
|
||||||
|
* Example
|
||||||
|
f(x) = xe^{-x}
|
||||||
|
|
||||||
|
Then x^* = 0
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
However if g(x)) = x - (xe^-x), g'(x) = 1 - (e^-x - xe^-x) \Rightarrow g'(x^*) = 0
|
||||||
|
|
||||||
|
Then assume x_0 = 1/10
|
||||||
|
Then x_1 = g(x_0) = 1/10 - 1/10(e^{-1/10})
|
||||||
|
\cdots
|
||||||
|
|
||||||
|
* More General, Robust Algorithm
|
||||||
|
** Theorem: Intermediate Value Theorem
|
||||||
|
Suppose that f(x) is a continuous function on [a, b] then
|
||||||
|
|
||||||
|
\lim_{x -> x_0} (f(x)) = f(x_0)
|
||||||
|
|
||||||
|
For all x_0 \in (a, b) and at the endpoints:
|
||||||
|
|
||||||
|
\lim_{a^+} f(x) = f(a)
|
||||||
|
\lim_{x -> b^-} f(x) = f(b)
|
||||||
|
|
||||||
|
Then if s is a number between f(a) and f(b), there exists a point c \in (a, b) such that f(c) = s.
|
||||||
|
|
||||||
|
To use this to ensure there is a root, we just take evaluations f(a) and f(b) that cross 0
|
||||||
|
|
||||||
|
So the condition we construct is:
|
||||||
|
f(a) \cdot f(b) \lt 0
|
||||||
|
|
||||||
|
** Next Step: compute the midpoint of [a, b]
|
||||||
|
c = 1/2 (a + b)
|
||||||
|
|
||||||
|
do binary search on c by taking this midpoint and ensuring f(a) \cdot f(c) \lt 0 or f(c) \cdot f(b) \lt 0 is met,
|
||||||
|
choosing the correct interval
|
||||||
|
|
||||||
|
|
18
notes/Oct-18.org
Normal file
18
notes/Oct-18.org
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
Error Analysis Of Bisection Root Finding:
|
||||||
|
|
||||||
|
e_0 \le b - a = b_0 - a_0
|
||||||
|
e_1 \le b_1 - a_1 = 1/2(b_0 - a_0)
|
||||||
|
e_2 \le b_2 - a_2 = 1/2(b_1 - a_1) = (1/2)^2(b_0 - a_0)
|
||||||
|
e_k \le b_k - a_k = 1/2(b_{k-1} - a_{k-1}) = \cdots = (1/2)^k (b_0 - a_0)
|
||||||
|
|
||||||
|
|
||||||
|
e_k \le (1/2)^k (b_0 - a_0) = tolerance
|
||||||
|
\Rightarrow log(1/2^k) + log(b_0 - a_0) = log(tolerance)
|
||||||
|
\Rightarrow k log(1/2) + log(tolerance) - log(b_0 - a_0)
|
||||||
|
\Rightarrow k log(1/2) = log(tolerance / (b_0 - a_0))
|
||||||
|
\Rightarrow k \ge log(tolerance / (b_0 - a_0)) / log(1/2)
|
||||||
|
|
||||||
|
The Bisection Method applied to an interval [a, b] for a continous function will reduce the error
|
||||||
|
each time through by at least one half.
|
||||||
|
|
||||||
|
| x_{k+1} - x_k | \le 1/2|x_k - x^* |
|
13
src/matrix.c
13
src/matrix.c
@ -37,7 +37,7 @@ Matrix_double **lu_decomp(Matrix_double *m) {
|
|||||||
Matrix_double *u = copy_matrix(m);
|
Matrix_double *u = copy_matrix(m);
|
||||||
Matrix_double *l_empt = InitMatrixWithSize(double, m->rows, m->cols, 0.0);
|
Matrix_double *l_empt = InitMatrixWithSize(double, m->rows, m->cols, 0.0);
|
||||||
Matrix_double *l = put_identity_diagonal(l_empt);
|
Matrix_double *l = put_identity_diagonal(l_empt);
|
||||||
free(l_empt);
|
free_matrix(l_empt);
|
||||||
|
|
||||||
Matrix_double **u_l = malloc(sizeof(Matrix_double *) * 2);
|
Matrix_double **u_l = malloc(sizeof(Matrix_double *) * 2);
|
||||||
|
|
||||||
@ -140,3 +140,14 @@ void format_matrix_into(Matrix_double *m, char *s) {
|
|||||||
}
|
}
|
||||||
strcat(s, "\n");
|
strcat(s, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int matrix_equal(Matrix_double *a, Matrix_double *b) {
|
||||||
|
if (a->cols != b->cols || a->rows != b->rows)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (size_t y = 0; y < a->rows; ++y)
|
||||||
|
if (!vector_equal(a->data[y], b->data[y])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
46
src/roots.c
Normal file
46
src/roots.c
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#include "lizfcm.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
// f is well defined at start_x + delta*n for all n on the integer range [0,
|
||||||
|
// max_steps]
|
||||||
|
double *find_ivt_range(double (*f)(double), double start_x, double delta,
|
||||||
|
size_t max_steps) {
|
||||||
|
double *range = malloc(sizeof(double) * 2);
|
||||||
|
|
||||||
|
double a = start_x;
|
||||||
|
|
||||||
|
while (f(a) * f(start_x) >= 0 && max_steps-- > 0)
|
||||||
|
a += delta;
|
||||||
|
|
||||||
|
if (max_steps == 0 && f(a) * f(start_x) > 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
range[0] = start_x;
|
||||||
|
range[1] = a + delta;
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
|
||||||
|
// f is continuous on [a, b]
|
||||||
|
double bisect_find_root(double (*f)(double), double a, double b,
|
||||||
|
double tolerance, size_t max_iterations) {
|
||||||
|
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)
|
||||||
|
return c;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
return bisect_find_root(f, a, b, tolerance, max_iterations);
|
||||||
|
}
|
11
src/vector.c
11
src/vector.c
@ -115,3 +115,14 @@ double sum_v(Array_double *v) {
|
|||||||
sum += v->data[i];
|
sum += v->data[i];
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int vector_equal(Array_double *a, Array_double *b) {
|
||||||
|
if (a->size != b->size)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < a->size; ++i) {
|
||||||
|
if (a->data[i] != b->data[i])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
32
test/approx_derivative.t.c
Normal file
32
test/approx_derivative.t.c
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#include "lizfcm.test.h"
|
||||||
|
|
||||||
|
double f(double x) { return x * x; }
|
||||||
|
|
||||||
|
double f_prime(double x) { return 2 * x; }
|
||||||
|
|
||||||
|
double H = 0.0001;
|
||||||
|
double ACCEPTED_DERIVATIVE_ERROR = 0.0001;
|
||||||
|
|
||||||
|
UTEST(derivative, central) {
|
||||||
|
double a = 3.0;
|
||||||
|
double expected = f_prime(a);
|
||||||
|
double f_prime_x = central_derivative_at(&f, a, H);
|
||||||
|
|
||||||
|
EXPECT_NEAR(expected, f_prime_x, ACCEPTED_DERIVATIVE_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
UTEST(derivative, forward) {
|
||||||
|
double a = 3.0;
|
||||||
|
double expected = f_prime(a);
|
||||||
|
double f_prime_x = forward_derivative_at(&f, a, H);
|
||||||
|
|
||||||
|
EXPECT_NEAR(expected, f_prime_x, ACCEPTED_DERIVATIVE_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
UTEST(derivative, backward) {
|
||||||
|
double a = 3.0;
|
||||||
|
double expected = f_prime(a);
|
||||||
|
double f_prime_x = backward_derivative_at(&f, a, H);
|
||||||
|
|
||||||
|
EXPECT_NEAR(expected, f_prime_x, ACCEPTED_DERIVATIVE_ERROR);
|
||||||
|
}
|
20
test/lin.t.c
Normal file
20
test/lin.t.c
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#include "lizfcm.test.h"
|
||||||
|
|
||||||
|
UTEST(Lin, least_squares_lin_reg_perfect) {
|
||||||
|
Array_double *x = InitArray(double, {0, 1, 2, 3, 4});
|
||||||
|
Array_double *y = InitArray(double, {1, 2, 3, 4, 5});
|
||||||
|
|
||||||
|
Line *line = least_squares_lin_reg(x, y);
|
||||||
|
|
||||||
|
EXPECT_EQ(line->m, 1.0);
|
||||||
|
EXPECT_EQ(line->a, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UTEST(Lin, least_squares_lin_reg_estimate) {
|
||||||
|
Array_double *x = InitArray(double, {1, 2, 3, 4, 5, 6, 7});
|
||||||
|
Array_double *y = InitArray(double, {0.5, 3, 2, 3.5, 5, 6, 7.5});
|
||||||
|
|
||||||
|
Line *line = least_squares_lin_reg(x, y);
|
||||||
|
|
||||||
|
EXPECT_NEAR(line->m, 1.0, 0.2);
|
||||||
|
}
|
7
test/lizfcm.test.h
Normal file
7
test/lizfcm.test.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#include "lizfcm.h"
|
||||||
|
#include "utest.h"
|
||||||
|
|
||||||
|
#ifndef LIZFCM_TEST_H
|
||||||
|
#define LIZFCM_TEST_H
|
||||||
|
|
||||||
|
#endif // LIZFCM_TEST_H
|
18
test/maceps.t.c
Normal file
18
test/maceps.t.c
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#include "lizfcm.test.h"
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
UTEST(maceps, smaceps) {
|
||||||
|
float epsilon = smaceps();
|
||||||
|
float one = 1.0;
|
||||||
|
float approx_one = one + epsilon;
|
||||||
|
|
||||||
|
EXPECT_LE(approx_one - one, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UTEST(maceps, dmaceps) {
|
||||||
|
double epsilon = dmaceps();
|
||||||
|
double one = 1.0;
|
||||||
|
double approx_one = one + epsilon;
|
||||||
|
|
||||||
|
EXPECT_LE(approx_one - one, 0);
|
||||||
|
}
|
125
test/main.c
125
test/main.c
@ -1,124 +1,5 @@
|
|||||||
#include "lizfcm.h"
|
#include "lizfcm.test.h"
|
||||||
#include <math.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
double f(double x) { return (x - 1) / (x + 1); }
|
UTEST(basic, unit_tests) { ASSERT_TRUE(1); }
|
||||||
|
|
||||||
int main() {
|
UTEST_MAIN();
|
||||||
char s[2048];
|
|
||||||
|
|
||||||
printf("Basic Routines\n");
|
|
||||||
printf("smaceps(): %.10e\n", smaceps());
|
|
||||||
printf("dmaceps(): %.10e\n", dmaceps());
|
|
||||||
printf("========\n");
|
|
||||||
|
|
||||||
printf("Norm, Distance\n");
|
|
||||||
Array_double *v = InitArray(double, {3, 1, -4});
|
|
||||||
strcpy(s, "");
|
|
||||||
format_vector_into(v, s);
|
|
||||||
printf("v: %s", s);
|
|
||||||
|
|
||||||
Array_double *w = InitArray(double, {-2, 7, 1});
|
|
||||||
strcpy(s, "");
|
|
||||||
format_vector_into(w, s);
|
|
||||||
printf("w: %s", s);
|
|
||||||
|
|
||||||
printf("l1_norm(v): %f\n", l1_norm(v));
|
|
||||||
printf("l2_norm(v): %f\n", l2_norm(v));
|
|
||||||
printf("linf_norm(v): %f\n", linf_norm(v));
|
|
||||||
printf("l1_dist(v, w): %f\n", l1_distance(v, w));
|
|
||||||
printf("l2_dist(v, w): %f\n", l2_distance(v, w));
|
|
||||||
printf("linf_dist(v, w): %f\n", linf_distance(v, w));
|
|
||||||
printf("========\n");
|
|
||||||
|
|
||||||
double h = 0.001;
|
|
||||||
printf("Derivative Approxs\n");
|
|
||||||
printf("f(x) = (x-1)/(x+1)\n");
|
|
||||||
printf("approx f'(1) w/ c.d.: %f\n", central_derivative_at(&f, 1, h));
|
|
||||||
printf("approx f'(1) w/ fw.d.: %f\n", forward_derivative_at(&f, 1, h));
|
|
||||||
printf("approx f'(1) w/ bw.d.: %f\n", backward_derivative_at(&f, 1, h));
|
|
||||||
printf("========\n");
|
|
||||||
printf("Least Squares\n");
|
|
||||||
|
|
||||||
v = InitArray(double, {1, 2, 3, 4, 5});
|
|
||||||
strcpy(s, "");
|
|
||||||
format_vector_into(v, s);
|
|
||||||
printf("v: %s", s);
|
|
||||||
w = InitArray(double, {2, 3, 4, 5, 6});
|
|
||||||
strcpy(s, "");
|
|
||||||
format_vector_into(w, s);
|
|
||||||
printf("w: %s", s);
|
|
||||||
|
|
||||||
Line *line = least_squares_lin_reg(v, w);
|
|
||||||
printf("least_squares_lin_reg(v, w): (%f)x + %f\n", line->m, line->a);
|
|
||||||
v = InitArray(double, {1, 2, 3, 4, 5, 6, 7});
|
|
||||||
strcpy(s, "");
|
|
||||||
format_vector_into(v, s);
|
|
||||||
printf("v: %s", s);
|
|
||||||
w = InitArray(double, {0.5, 3, 2, 3.5, 5, 6, 7.5});
|
|
||||||
strcpy(s, "");
|
|
||||||
format_vector_into(w, s);
|
|
||||||
printf("w: %s", s);
|
|
||||||
|
|
||||||
line = least_squares_lin_reg(v, w);
|
|
||||||
printf("least_squares_lin_reg(v, w): (%f)x + %f\n", line->m, line->a);
|
|
||||||
free(line);
|
|
||||||
printf("========\n");
|
|
||||||
|
|
||||||
printf("LU Decomp\n");
|
|
||||||
uint32_t n = 10;
|
|
||||||
Matrix_double *a = InitMatrixWithSize(double, n, n, 0.0);
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
for (int j = 0; j < n; j++)
|
|
||||||
a->data[i]->data[j] = (100 - rand() % 200);
|
|
||||||
}
|
|
||||||
strcpy(s, "");
|
|
||||||
format_matrix_into(a, s);
|
|
||||||
printf("a = %s", s);
|
|
||||||
|
|
||||||
uint32_t solution = 1;
|
|
||||||
Array_double *y = InitArrayWithSize(double, n, (double)solution);
|
|
||||||
Array_double *b = m_dot_v(a, y); // q8 steps
|
|
||||||
Matrix_double **u_l = lu_decomp(a);
|
|
||||||
Matrix_double *u = u_l[0];
|
|
||||||
Matrix_double *l = u_l[1];
|
|
||||||
|
|
||||||
strcpy(s, "");
|
|
||||||
format_matrix_into(u, s);
|
|
||||||
printf("u = %s", s);
|
|
||||||
strcpy(s, "");
|
|
||||||
format_matrix_into(l, s);
|
|
||||||
printf("l = %s", s);
|
|
||||||
strcpy(s, "");
|
|
||||||
format_vector_into(b, s);
|
|
||||||
printf("(after following q8) b = %s", s);
|
|
||||||
printf("========\n");
|
|
||||||
printf("Forward / Backward Substitution Solution to ax=b\n");
|
|
||||||
|
|
||||||
Array_double *b_fsub = fsubst(l, b);
|
|
||||||
strcpy(s, "");
|
|
||||||
format_vector_into(b_fsub, s);
|
|
||||||
printf("b_fsub: %s", s);
|
|
||||||
|
|
||||||
Array_double *x_bsub = bsubst(u, b_fsub);
|
|
||||||
strcpy(s, "");
|
|
||||||
format_vector_into(x_bsub, s);
|
|
||||||
printf("x_bsub: %s", s);
|
|
||||||
|
|
||||||
Array_double *x_solve_matrix = solve_matrix(a, b);
|
|
||||||
free_vector(b);
|
|
||||||
strcpy(s, "");
|
|
||||||
format_vector_into(x_solve_matrix, s);
|
|
||||||
printf("\\--> == x_solve_matrix: %s", s);
|
|
||||||
|
|
||||||
free_vector(b_fsub);
|
|
||||||
free_vector(x_solve_matrix);
|
|
||||||
|
|
||||||
printf("Verifications\n");
|
|
||||||
for (size_t i = 0; i < x_bsub->size; i++)
|
|
||||||
printf("in row %zu, solution = %f, true value err=%.10e\n", i,
|
|
||||||
x_bsub->data[i], fabs(x_bsub->data[i] - solution));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
96
test/matrix.t.c
Normal file
96
test/matrix.t.c
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
#include "lizfcm.test.h"
|
||||||
|
|
||||||
|
UTEST(matrix, free) {
|
||||||
|
Matrix_double *m = InitMatrixWithSize(double, 8, 8, 0.0);
|
||||||
|
uint64_t data_addr = (uint64_t)(m->data);
|
||||||
|
free_matrix(m);
|
||||||
|
EXPECT_NE(data_addr, (uint64_t)(m->data));
|
||||||
|
}
|
||||||
|
|
||||||
|
UTEST(matrix, put_identity_diagonal) {
|
||||||
|
Matrix_double *m = InitMatrixWithSize(double, 8, 8, 0.0);
|
||||||
|
Matrix_double *ident = put_identity_diagonal(m);
|
||||||
|
|
||||||
|
for (size_t y = 0; y < m->rows; ++y)
|
||||||
|
for (size_t x = 0; x < m->cols; ++x)
|
||||||
|
EXPECT_EQ(ident->data[y]->data[x], x == y ? 1.0 : 0.0);
|
||||||
|
|
||||||
|
free_matrix(m);
|
||||||
|
free_matrix(ident);
|
||||||
|
}
|
||||||
|
|
||||||
|
UTEST(matrix, copy) {
|
||||||
|
Matrix_double *m = InitMatrixWithSize(double, 8, 8, 0.0);
|
||||||
|
Matrix_double *ident = put_identity_diagonal(m);
|
||||||
|
|
||||||
|
Matrix_double *copy = copy_matrix(ident);
|
||||||
|
|
||||||
|
EXPECT_TRUE(matrix_equal(ident, copy));
|
||||||
|
|
||||||
|
free_matrix(m);
|
||||||
|
free_matrix(ident);
|
||||||
|
free_matrix(copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
UTEST(matrix, m_dot_v) {
|
||||||
|
Matrix_double *m = InitMatrixWithSize(double, 8, 8, 0.0);
|
||||||
|
Matrix_double *ident = put_identity_diagonal(m);
|
||||||
|
|
||||||
|
Array_double *x = InitArray(double, {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0});
|
||||||
|
Array_double *dotted = m_dot_v(ident, x);
|
||||||
|
|
||||||
|
EXPECT_TRUE(vector_equal(dotted, x));
|
||||||
|
|
||||||
|
free_matrix(m);
|
||||||
|
free_matrix(ident);
|
||||||
|
free_vector(x);
|
||||||
|
free_vector(dotted);
|
||||||
|
}
|
||||||
|
|
||||||
|
UTEST(matrix, lu_decomp) {
|
||||||
|
Matrix_double *m = InitMatrixWithSize(double, 8, 8, 0.0);
|
||||||
|
for (size_t y = 0; y < m->rows; ++y) {
|
||||||
|
for (size_t x = 0; x < m->cols; ++x)
|
||||||
|
m->data[y]->data[x] = x == y ? 5.0 : (5.0 - rand() % 10 + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix_double **ul = lu_decomp(m);
|
||||||
|
Matrix_double *u = ul[0];
|
||||||
|
Matrix_double *l = ul[1];
|
||||||
|
for (int y = 0; y < m->rows; y++) {
|
||||||
|
for (size_t x = 0; x < c_max(y - 1, 0); x++) {
|
||||||
|
double u_yx = u->data[y]->data[x];
|
||||||
|
EXPECT_NEAR(u_yx, 0.0, 0.0001);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t x = c_min(m->cols, y + 1); x < m->cols; ++x) {
|
||||||
|
double l_yx = l->data[y]->data[x];
|
||||||
|
EXPECT_NEAR(l_yx, 0.0, 0.0001);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free_matrix(m);
|
||||||
|
free_matrix(l);
|
||||||
|
free_matrix(u);
|
||||||
|
free(ul);
|
||||||
|
}
|
||||||
|
|
||||||
|
UTEST(matrix, solve_matrix) {
|
||||||
|
Matrix_double *m = InitMatrixWithSize(double, 8, 8, 0.0);
|
||||||
|
for (size_t y = 0; y < m->rows; ++y) {
|
||||||
|
for (size_t x = 0; x < m->cols; ++x)
|
||||||
|
m->data[y]->data[x] = x == y ? 10.0 : (5.0 - rand() % 10 + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Array_double *b = InitArray(double, {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0});
|
||||||
|
Array_double *solution = solve_matrix(m, b);
|
||||||
|
|
||||||
|
for (size_t y = 0; y < m->rows; y++) {
|
||||||
|
double dot = v_dot_v(m->data[y], solution);
|
||||||
|
EXPECT_NEAR(b->data[y], dot, 0.0001);
|
||||||
|
}
|
||||||
|
|
||||||
|
free_matrix(m);
|
||||||
|
free_vector(b);
|
||||||
|
free_vector(solution);
|
||||||
|
}
|
17
test/roots.t.c
Normal file
17
test/roots.t.c
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#include "lizfcm.test.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
double g(double x) { return x * x - 9; }
|
||||||
|
|
||||||
|
UTEST(ivt, find_interval) {
|
||||||
|
double *range = find_ivt_range(&g, -100.0, 1.0, 200);
|
||||||
|
EXPECT_LT(g(range[0]) * g(range[1]), 0);
|
||||||
|
|
||||||
|
free(range);
|
||||||
|
}
|
||||||
|
|
||||||
|
UTEST(root, bisection_with_error_assumption) {
|
||||||
|
double root = bisect_find_root_with_error_assumption(&g, -5, 0, 0.01);
|
||||||
|
|
||||||
|
EXPECT_NEAR(-3, root, 0.01);
|
||||||
|
}
|
1668
test/utest.h
Normal file
1668
test/utest.h
Normal file
File diff suppressed because it is too large
Load Diff
93
test/vector.t.c
Normal file
93
test/vector.t.c
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#include "lizfcm.test.h"
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
UTEST(vector, copy_vector) {
|
||||||
|
Array_double *v = InitArray(double, {3, 1, -4});
|
||||||
|
Array_double *w = copy_vector(v);
|
||||||
|
EXPECT_TRUE(vector_equal(v, w));
|
||||||
|
|
||||||
|
free_vector(v);
|
||||||
|
free_vector(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
UTEST(vector, free_vector) {
|
||||||
|
Array_double *v = InitArray(double, {3, 1, -4});
|
||||||
|
uint64_t arr_addr = (uint64_t)v->data;
|
||||||
|
free_vector(v);
|
||||||
|
EXPECT_NE((uint64_t)v->data, arr_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
UTEST(vector, sum_vector) {
|
||||||
|
Array_double *v = InitArray(double, {3, 1, -4});
|
||||||
|
EXPECT_EQ(0.0, sum_v(v));
|
||||||
|
free_vector(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
UTEST(vector, add_v) {
|
||||||
|
Array_double *a = InitArray(double, {1.0, 3.0, -4.0});
|
||||||
|
Array_double *b = InitArray(double, {2.0, -1.0, 0});
|
||||||
|
Array_double *expected_sum = InitArray(double, {3.0, 2.0, -4.0});
|
||||||
|
Array_double *sum = add_v(a, b);
|
||||||
|
|
||||||
|
EXPECT_TRUE(vector_equal(sum, expected_sum));
|
||||||
|
|
||||||
|
free_vector(a);
|
||||||
|
free_vector(b);
|
||||||
|
free_vector(expected_sum);
|
||||||
|
free_vector(sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
UTEST(vector, minus_v) {
|
||||||
|
Array_double *a = InitArray(double, {1.0, 3.0, -4.0});
|
||||||
|
Array_double *b = InitArray(double, {2.0, -1.0, 0});
|
||||||
|
Array_double *expected_sub = InitArray(double, {-1.0, 4.0, -4.0});
|
||||||
|
Array_double *sub = minus_v(a, b);
|
||||||
|
|
||||||
|
EXPECT_TRUE(vector_equal(sub, expected_sub));
|
||||||
|
|
||||||
|
free_vector(a);
|
||||||
|
free_vector(b);
|
||||||
|
free_vector(expected_sub);
|
||||||
|
free_vector(sub);
|
||||||
|
}
|
||||||
|
|
||||||
|
UTEST(vector, scale_v) {
|
||||||
|
double factor = 3.0;
|
||||||
|
Array_double *a = InitArray(double, {1.0, 3.0, -4.0});
|
||||||
|
Array_double *expected_scaled = InitArray(double, {3.0, 9.0, -12.0});
|
||||||
|
Array_double *scaled = scale_v(a, factor);
|
||||||
|
|
||||||
|
EXPECT_TRUE(vector_equal(scaled, expected_scaled));
|
||||||
|
|
||||||
|
free_vector(a);
|
||||||
|
free_vector(expected_scaled);
|
||||||
|
free_vector(scaled);
|
||||||
|
}
|
||||||
|
|
||||||
|
UTEST(vector, l1_norm) {
|
||||||
|
Array_double *v = InitArray(double, {3, 1, -4});
|
||||||
|
EXPECT_EQ(l1_norm(v), 8.0);
|
||||||
|
free_vector(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
UTEST(vector, l2_norm) {
|
||||||
|
Array_double *v = InitArray(double, {3, 1, -4});
|
||||||
|
EXPECT_EQ(l2_norm(v), sqrt(3 * 3 + 1 * 1 + 4 * 4));
|
||||||
|
free_vector(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
UTEST(vector, linf_norm) {
|
||||||
|
Array_double *v = InitArray(double, {3, 1, -4});
|
||||||
|
EXPECT_EQ(linf_norm(v), c_max(c_max(3.0, 1.0), -4.0));
|
||||||
|
free_vector(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
UTEST(vector, vector_distance) {
|
||||||
|
Array_double *v = InitArray(double, {3, 1, -4});
|
||||||
|
Array_double *w = InitArray(double, {3, 1, -4});
|
||||||
|
Array_double *minus = minus_v(v, w);
|
||||||
|
EXPECT_EQ(vector_distance(v, w, &l2_norm), l2_norm(minus));
|
||||||
|
free_vector(v);
|
||||||
|
free_vector(w);
|
||||||
|
free_vector(minus);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user