From 562ba9a9b6efd8cc27fc506f83b1125c2cfa4619 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunt Date: Mon, 30 Oct 2023 19:07:43 -0600 Subject: [PATCH] hw 5 --- doc/software_manual.org | 257 ++++++++++++++++++++++++++++++++-------- doc/software_manual.pdf | Bin 180558 -> 179781 bytes doc/software_manual.tex | 96 +++++++-------- homeworks/hw-5.org | 59 +++++++++ homeworks/hw-5.pdf | Bin 0 -> 81313 bytes homeworks/hw-5.tex | 95 +++++++++++++++ inc/lizfcm.h | 8 +- inc/macros.h | 4 +- notes/Oct-27.org | 26 ++++ notes/Oct-30.org | 34 ++++++ src/matrix.c | 96 ++++++++++++++- src/vector.c | 15 +++ test/matrix.t.c | 114 ++++++++++++++++-- test/vector.t.c | 22 ++++ 14 files changed, 717 insertions(+), 109 deletions(-) create mode 100644 homeworks/hw-5.org create mode 100644 homeworks/hw-5.pdf create mode 100644 homeworks/hw-5.tex create mode 100644 notes/Oct-27.org create mode 100644 notes/Oct-30.org diff --git a/doc/software_manual.org b/doc/software_manual.org index 981d863..eebcf17 100644 --- a/doc/software_manual.org +++ b/doc/software_manual.org @@ -5,7 +5,7 @@ #+STARTUP: entitiespretty fold inlineimages * Design -The LIZFCM static library (at [[https://github.com/Simponic/math-4610][[https://github.com/Simponic/math-4610]] is a successor to my +The LIZFCM static library (at [[https://github.com/Simponic/math-4610]]) is a successor to my attempt at writing codes for the Fundamentals of Computational Mathematics course in Common Lisp, but the effort required to meet the requirement of creating a static library became too difficult to integrate outside of the ~ASDF~ solution that Common Lisp already brings @@ -14,13 +14,14 @@ to the table. All of the work established in ~deprecated-cl~ has been painstakingly translated into the C programming language. I have a couple tenets for its design: -+ Implemntations of routines should all be done immutably in respect to arguments. ++ Implementations of routines should all be done immutably in respect to arguments. + Functional programming is good (it's... rough in C though). -+ Routines are separated into "module" c files, and not individual files per function. ++ Routines are separated into "modules" that follow a form of separation of concerns + in files, and not individual files per function. * Compilation -A provided ~Makefile~ is added for convencience. It has been tested on an M1 machine running MacOS as -well as Arch Linux. +A provided ~Makefile~ is added for convencience. It has been tested on an ~arm~-based M1 machine running +MacOS as well as ~x86~ Arch Linux. 1. ~cd~ into the root of the repo 2. ~make~ @@ -317,6 +318,39 @@ void free_vector(Array_double *v) { } #+END_SRC +*** ~add_element~ ++ Author: Elizabeth Hunt ++ Name: ~add_element~ ++ Location: ~src/vector.c~ ++ Input: a pointer to an ~Array_double~ ++ Output: a new ~Array_double~ with element ~x~ appended. + +#+BEGIN_SRC c +Array_double *add_element(Array_double *v, double x) { + Array_double *pushed = InitArrayWithSize(double, v->size + 1, 0.0); + for (size_t i = 0; i < v->size; ++i) + pushed->data[i] = v->data[i]; + pushed->data[v->size] = x; + return pushed; +} +#+END_SRC + +*** ~slice_element~ ++ Author: Elizabeth Hunt ++ Name: ~slice_element~ ++ Location: ~src/vector.c~ ++ Input: a pointer to an ~Array_double~ ++ Output: a new ~Array_double~ with element ~x~ sliced. + +#+BEGIN_SRC c +Array_double *slice_element(Array_double *v, size_t x) { + Array_double *sliced = InitArrayWithSize(double, v->size - 1, 0.0); + for (size_t i = 0; i < v->size - 1; ++i) + sliced->data[i] = i >= x ? v->data[i + 1] : v->data[i]; + return sliced; +} +#+END_SRC + *** ~copy_vector~ + Author: Elizabeth Hunt + Name: ~copy_vector~ @@ -370,55 +404,54 @@ void format_vector_into(Array_double *v, char *s) { matrix $L$, $U$, respectively such that $LU = m$. + Output: a pointer to the location in memory in which two ~Matrix_double~'s reside: the first representing $L$, the second, $U$. -+ Errors: Exits and throws a status code of ~-1~ when encountering a matrix that cannot be ++ Errors: Fails assertions when encountering a matrix that cannot be decomposed #+BEGIN_SRC c - Matrix_double **lu_decomp(Matrix_double *m) { - assert(m->cols == m->rows); +Matrix_double **lu_decomp(Matrix_double *m) { + assert(m->cols == m->rows); - Matrix_double *u = copy_matrix(m); - Matrix_double *l_empt = InitMatrixWithSize(double, m->rows, m->cols, 0.0); - Matrix_double *l = put_identity_diagonal(l_empt); - free(l_empt); + Matrix_double *u = copy_matrix(m); + Matrix_double *l_empt = InitMatrixWithSize(double, m->rows, m->cols, 0.0); + Matrix_double *l = put_identity_diagonal(l_empt); + free_matrix(l_empt); + Matrix_double **u_l = malloc(sizeof(Matrix_double *) * 2); - Matrix_double **u_l = malloc(sizeof(Matrix_double *) * 2); - - for (size_t y = 0; y < m->rows; y++) { - if (u->data[y]->data[y] == 0) { - printf("ERROR: a pivot is zero in given matrix\n"); - exit(-1); - } + for (size_t y = 0; y < m->rows; y++) { + if (u->data[y]->data[y] == 0) { + printf("ERROR: a pivot is zero in given matrix\n"); + assert(false); } - - if (u && l) { - for (size_t x = 0; x < m->cols; x++) { - for (size_t y = x + 1; y < m->rows; y++) { - double denom = u->data[x]->data[x]; - - if (denom == 0) { - printf("ERROR: non-factorable matrix\n"); - exit(-1); - } - - double factor = -(u->data[y]->data[x] / denom); - - Array_double *scaled = scale_v(u->data[x], factor); - Array_double *added = add_v(scaled, u->data[y]); - free_vector(scaled); - free_vector(u->data[y]); - - u->data[y] = added; - l->data[y]->data[x] = -factor; - } - } - } - - u_l[0] = u; - u_l[1] = l; - return u_l; } + + if (u && l) { + for (size_t x = 0; x < m->cols; x++) { + for (size_t y = x + 1; y < m->rows; y++) { + double denom = u->data[x]->data[x]; + + if (denom == 0) { + printf("ERROR: non-factorable matrix\n"); + assert(false); + } + + double factor = -(u->data[y]->data[x] / denom); + + Array_double *scaled = scale_v(u->data[x], factor); + Array_double *added = add_v(scaled, u->data[y]); + free_vector(scaled); + free_vector(u->data[y]); + + u->data[y] = added; + l->data[y]->data[x] = -factor; + } + } + } + + u_l[0] = u; + u_l[1] = l; + return u_l; +} #+END_SRC *** ~bsubst~ + Author: Elizabeth Hunt @@ -467,7 +500,7 @@ Array_double *fsubst(Matrix_double *l, Array_double *b) { } #+END_SRC -*** ~solve_matrix~ +*** ~solve_matrix_lu_bsubst~ + Author: Elizabeth Hunt + Location: ~src/matrix.c~ + Input: a pointer to a ~Matrix_double~ $m$ and a pointer to an ~Array_double~ $b$ @@ -480,7 +513,7 @@ Here we make use of forward substitution to first solve $Ly = b$ given $L$ as th Then, $LUx = b$, thus $x$ is a solution. #+BEGIN_SRC c -Array_double *solve_matrix(Matrix_double *m, Array_double *b) { +Array_double *solve_matrix_lu_bsubst(Matrix_double *m, Array_double *b) { assert(b->size == m->rows); assert(m->rows == m->cols); @@ -495,11 +528,97 @@ Array_double *solve_matrix(Matrix_double *m, Array_double *b) { free_matrix(u); free_matrix(l); + free(u_l); return x; } #+END_SRC +*** ~gaussian_elimination~ ++ Author: Elizabeth Hunt ++ Location: ~src/matrix.c~ ++ Input: a pointer to a ~Matrix_double~ $m$ ++ Output: a pointer to a copy of $m$ in reduced echelon form + +This works by finding the row with a maximum value in the column $k$. Then, it uses that as a pivot, and +applying reduction to all other rows. The general idea is available at [[https://en.wikipedia.org/wiki/Gaussian_elimination]]. + +#+BEGIN_SRC c +Matrix_double *gaussian_elimination(Matrix_double *m) { + uint64_t h = 0; + uint64_t k = 0; + + Matrix_double *m_cp = copy_matrix(m); + + while (h < m_cp->rows && k < m_cp->cols) { + uint64_t max_row = 0; + double total_max = 0.0; + + for (uint64_t row = h; row < m_cp->rows; row++) { + double this_max = c_max(fabs(m_cp->data[row]->data[k]), total_max); + if (c_max(this_max, total_max) == this_max) { + max_row = row; + } + } + + if (max_row == 0) { + k++; + continue; + } + + Array_double *swp = m_cp->data[max_row]; + m_cp->data[max_row] = m_cp->data[h]; + m_cp->data[h] = swp; + + for (uint64_t row = h + 1; row < m_cp->rows; row++) { + double factor = m_cp->data[row]->data[k] / m_cp->data[h]->data[k]; + m_cp->data[row]->data[k] = 0.0; + + for (uint64_t col = k + 1; col < m_cp->cols; col++) { + m_cp->data[row]->data[col] -= m_cp->data[h]->data[col] * factor; + } + } + + h++; + k++; + } + + return m_cp; +} +#+END_SRC + +*** ~solve_matrix_gaussian~ ++ Author: Elizabeth Hunt ++ Location: ~src/matrix.c~ ++ Input: a pointer to a ~Matrix_double~ $m$ and a target ~Array_double~ $b$ ++ Output: a pointer to a vector $x$ being the solution to the equation $mx = b$ + +We first perform ~gaussian_elimination~ after augmenting $m$ and $b$. Then, as $m$ is in reduced echelon form, it's an upper +triangular matrix, so we can perform back substitution to compute $x$. + +#+BEGIN_SRC c +Array_double *solve_matrix_gaussian(Matrix_double *m, Array_double *b) { + assert(b->size == m->rows); + assert(m->rows == m->cols); + + Matrix_double *m_augment_b = add_column(m, b); + Matrix_double *eliminated = gaussian_elimination(m_augment_b); + + Array_double *b_gauss = col_v(eliminated, m->cols); + Matrix_double *u = slice_column(eliminated, m->rows); + + Array_double *solution = bsubst(u, b_gauss); + + free_matrix(m_augment_b); + free_matrix(eliminated); + free_matrix(u); + free_vector(b_gauss); + + return solution; +} +#+END_SRC + + *** ~m_dot_v~ + Author: Elizabeth Hunt + Location: ~src/matrix.c~ @@ -535,6 +654,48 @@ Matrix_double *put_identity_diagonal(Matrix_double *m) { } #+END_SRC +*** ~slice_column~ ++ Author: Elizabeth Hunt ++ Location: ~src/matrix.c~ ++ Input: a pointer to a ~Matrix_double~ ++ Output: a pointer to a copy of the given ~Matrix_double~ with column at ~x~ sliced + +#+BEGIN_SRC c +Matrix_double *slice_column(Matrix_double *m, size_t x) { + Matrix_double *sliced = copy_matrix(m); + + for (size_t row = 0; row < m->rows; row++) { + Array_double *old_row = sliced->data[row]; + sliced->data[row] = slice_element(old_row, x); + free_vector(old_row); + } + sliced->cols--; + + return sliced; +} +#+END_SRC + +*** ~add_column~ ++ Author: Elizabet Hunt ++ Location: ~src/matrix.c~ ++ Input: a pointer to a ~Matrix_double~ and a new vector representing the appended column ~x~ ++ Output: a pointer to a copy of the given ~Matrix_double~ with a new column ~x~ + +#+BEGIN_SRC c +Matrix_double *add_column(Matrix_double *m, Array_double *v) { + Matrix_double *pushed = copy_matrix(m); + + for (size_t row = 0; row < m->rows; row++) { + Array_double *old_row = pushed->data[row]; + pushed->data[row] = add_element(old_row, v->data[row]); + free_vector(old_row); + } + + pushed->cols++; + return pushed; +} +#+END_SRC + *** ~copy_matrix~ + Author: Elizabeth Hunt + Location: ~src/matrix.c~ diff --git a/doc/software_manual.pdf b/doc/software_manual.pdf index ba0b14b8cac4cc141cce0e5d0d3faf1218278404..8cd70f44d3246a6c57671a2c7571cdb848f117fb 100644 GIT binary patch delta 14419 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 diff --git a/doc/software_manual.tex b/doc/software_manual.tex index 292f868..c6eb910 100644 --- a/doc/software_manual.tex +++ b/doc/software_manual.tex @@ -1,4 +1,4 @@ -% Created 2023-10-18 Wed 13:06 +% Created 2023-10-30 Mon 09:44 % Intended LaTeX compiler: pdflatex \documentclass[11pt]{article} \usepackage[utf8]{inputenc} @@ -31,8 +31,8 @@ \setlength\parindent{0pt} \section{Design} -\label{sec:org7204e7c} -The LIZFCM static library (at \href{https://github.com/Simponic/math-4610}{[https://github.com/Simponic/math-4610} is a successor to my +\label{sec:org7f9c526} +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 Lisp, but the effort required to meet the requirement of creating a static library became too difficult to integrate outside of the \texttt{ASDF} solution that Common Lisp already brings @@ -42,13 +42,13 @@ All of the work established in \texttt{deprecated-cl} has been painstakingly tra the C programming language. I have a couple tenets for its design: \begin{itemize} -\item Implemntations of routines should all be done immutably in respect to arguments. +\item Implementations of routines should all be done immutably in respect to arguments. \item Functional programming is good (it's\ldots{} rough in C though). \item Routines are separated into "module" c files, and not individual files per function. \end{itemize} \section{Compilation} -\label{sec:org16cc307} +\label{sec:org911a41e} A provided \texttt{Makefile} is added for convencience. It has been tested on an M1 machine running MacOS as well as Arch Linux. @@ -74,11 +74,11 @@ Which is then bundled into a static library in \texttt{lib/lizfcm.a} which can b in the standard method. \section{The LIZFCM API} -\label{sec:org832532a} +\label{sec:orgd74cd2d} \subsection{Simple Routines} -\label{sec:org540b602} +\label{sec:org66bba13} \subsubsection{\texttt{smaceps}} -\label{sec:org4d03b6e} +\label{sec:orgeae9531} \begin{itemize} \item Author: Elizabeth Hunt \item Name: \texttt{smaceps} @@ -104,7 +104,7 @@ float smaceps() { \end{verbatim} \subsubsection{\texttt{dmaceps}} -\label{sec:org2603bfc} +\label{sec:org237c904} \begin{itemize} \item Author: Elizabeth Hunt \item Name: \texttt{dmaceps} @@ -130,9 +130,9 @@ double dmaceps() { \end{verbatim} \subsection{Derivative Routines} -\label{sec:org95c28e9} +\label{sec:org9cf9027} \subsubsection{\texttt{central\_derivative\_at}} -\label{sec:org950de62} +\label{sec:org1fcd333} \begin{itemize} \item Author: Elizabeth Hunt \item Name: \texttt{central\_derivative\_at} @@ -163,7 +163,7 @@ double central_derivative_at(double (*f)(double), double a, double h) { \end{verbatim} \subsubsection{\texttt{forward\_derivative\_at}} -\label{sec:org832eda6} +\label{sec:org6a768fc} \begin{itemize} \item Author: Elizabeth Hunt \item Name: \texttt{forward\_derivative\_at} @@ -194,7 +194,7 @@ double forward_derivative_at(double (*f)(double), double a, double h) { \end{verbatim} \subsubsection{\texttt{backward\_derivative\_at}} -\label{sec:org591836d} +\label{sec:org610ce76} \begin{itemize} \item Author: Elizabeth Hunt \item Name: \texttt{backward\_derivative\_at} @@ -225,9 +225,9 @@ double backward_derivative_at(double (*f)(double), double a, double h) { \end{verbatim} \subsection{Vector Routines} -\label{sec:org5254fe4} +\label{sec:orgfd176e6} \subsubsection{Vector Arithmetic: \texttt{add\_v, minus\_v}} -\label{sec:orgf802d61} +\label{sec:org2dbc55f} \begin{itemize} \item Author: Elizabeth Hunt \item Name(s): \texttt{add\_v}, \texttt{minus\_v} @@ -258,7 +258,7 @@ Array_double *minus_v(Array_double *v1, Array_double *v2) { \end{verbatim} \subsubsection{Norms: \texttt{l1\_norm}, \texttt{l2\_norm}, \texttt{linf\_norm}} -\label{sec:orgc56e22d} +\label{sec:org53a2ffc} \begin{itemize} \item Author: Elizabeth Hunt \item Name(s): \texttt{l1\_norm}, \texttt{l2\_norm}, \texttt{linf\_norm} @@ -292,7 +292,7 @@ double linf_norm(Array_double *v) { \end{verbatim} \subsubsection{\texttt{vector\_distance}} -\label{sec:orgb54922f} +\label{sec:org1fb3f8c} \begin{itemize} \item Author: Elizabeth Hunt \item Name: \texttt{vector\_distance} @@ -313,7 +313,7 @@ double vector_distance(Array_double *v1, Array_double *v2, \end{verbatim} \subsubsection{Distances: \texttt{l1\_distance}, \texttt{l2\_distance}, \texttt{linf\_distance}} -\label{sec:orgf22f8e0} +\label{sec:org4a25a94} \begin{itemize} \item Author: Elizabeth Hunt \item Name(s): \texttt{l1\_distance}, \texttt{l2\_distance}, \texttt{linf\_distance} @@ -339,7 +339,7 @@ double linf_distance(Array_double *v1, Array_double *v2) { \end{verbatim} \subsubsection{\texttt{sum\_v}} -\label{sec:org4593341} +\label{sec:org035a547} \begin{itemize} \item Author: Elizabeth Hunt \item Name: \texttt{sum\_v} @@ -359,7 +359,7 @@ double sum_v(Array_double *v) { \subsubsection{\texttt{scale\_v}} -\label{sec:org3123f61} +\label{sec:org12b0853} \begin{itemize} \item Author: Elizabeth Hunt \item Name: \texttt{scale\_v} @@ -378,7 +378,7 @@ Array_double *scale_v(Array_double *v, double m) { \end{verbatim} \subsubsection{\texttt{free\_vector}} -\label{sec:org983efcf} +\label{sec:org70ba90c} \begin{itemize} \item Author: Elizabeth Hunt \item Name: \texttt{free\_vector} @@ -396,7 +396,7 @@ void free_vector(Array_double *v) { \end{verbatim} \subsubsection{\texttt{copy\_vector}} -\label{sec:orgde05d32} +\label{sec:org57afc74} \begin{itemize} \item Author: Elizabeth Hunt \item Name: \texttt{copy\_vector} @@ -416,7 +416,7 @@ Array_double *copy_vector(Array_double *v) { \end{verbatim} \subsubsection{\texttt{format\_vector\_into}} -\label{sec:org2e779f3} +\label{sec:orgc346c3c} \begin{itemize} \item Author: Elizabeth Hunt \item Name: \texttt{format\_vector\_into} @@ -446,9 +446,9 @@ void format_vector_into(Array_double *v, char *s) { \end{verbatim} \subsection{Matrix Routines} -\label{sec:org2354147} +\label{sec:org3b053ab} \subsubsection{\texttt{lu\_decomp}} -\label{sec:org3690faa} +\label{sec:org5553968} \begin{itemize} \item Author: Elizabeth Hunt \item Name: \texttt{lu\_decomp} @@ -509,7 +509,7 @@ Matrix_double **lu_decomp(Matrix_double *m) { } \end{verbatim} \subsubsection{\texttt{bsubst}} -\label{sec:orgdeba296} +\label{sec:org253efdc} \begin{itemize} \item Author: Elizabeth Hunt \item Name: \texttt{bsubst} @@ -534,7 +534,7 @@ Array_double *bsubst(Matrix_double *u, Array_double *b) { } \end{verbatim} \subsubsection{\texttt{fsubst}} -\label{sec:org60d3435} +\label{sec:orge0c7bc6} \begin{itemize} \item Author: Elizabeth Hunt \item Name: \texttt{fsubst} @@ -562,7 +562,7 @@ Array_double *fsubst(Matrix_double *l, Array_double *b) { \end{verbatim} \subsubsection{\texttt{solve\_matrix}} -\label{sec:org914121f} +\label{sec:orgbcd445a} \begin{itemize} \item Author: Elizabeth Hunt \item Location: \texttt{src/matrix.c} @@ -598,7 +598,7 @@ Array_double *solve_matrix(Matrix_double *m, Array_double *b) { \end{verbatim} \subsubsection{\texttt{m\_dot\_v}} -\label{sec:orgae0f4c9} +\label{sec:orga9b1f68} \begin{itemize} \item Author: Elizabeth Hunt \item Location: \texttt{src/matrix.c} @@ -620,7 +620,7 @@ Array_double *m_dot_v(Matrix_double *m, Array_double *v) { \end{verbatim} \subsubsection{\texttt{put\_identity\_diagonal}} -\label{sec:org6d84f6a} +\label{sec:org33ead5e} \begin{itemize} \item Author: Elizabeth Hunt \item Location: \texttt{src/matrix.c} @@ -639,7 +639,7 @@ Matrix_double *put_identity_diagonal(Matrix_double *m) { \end{verbatim} \subsubsection{\texttt{copy\_matrix}} -\label{sec:orge750c56} +\label{sec:org34b3f5b} \begin{itemize} \item Author: Elizabeth Hunt \item Location: \texttt{src/matrix.c} @@ -659,7 +659,7 @@ Matrix_double *copy_matrix(Matrix_double *m) { \end{verbatim} \subsubsection{\texttt{free\_matrix}} -\label{sec:org4ebcf85} +\label{sec:org9c91101} \begin{itemize} \item Author: Elizabeth Hunt \item Location: \texttt{src/matrix.c} @@ -678,7 +678,7 @@ void free_matrix(Matrix_double *m) { \end{verbatim} \subsubsection{\texttt{format\_matrix\_into}} -\label{sec:org308ee0d} +\label{sec:org51f3e27} \begin{itemize} \item Author: Elizabeth Hunt \item Name: \texttt{format\_matrix\_into} @@ -705,9 +705,9 @@ void format_matrix_into(Matrix_double *m, char *s) { } \end{verbatim} \subsection{Root Finding Methods} -\label{sec:org8981156} +\label{sec:org0e83d47} \subsubsection{\texttt{find\_ivt\_range}} -\label{sec:orga5835b0} +\label{sec:org3e4e34e} \begin{itemize} \item Author: Elizabeth Hunt \item Name: \texttt{find\_ivt\_range} @@ -737,7 +737,7 @@ double *find_ivt_range(double (*f)(double), double start_x, double delta, } \end{verbatim} \subsubsection{\texttt{bisect\_find\_root}} -\label{sec:orgb118fc7} +\label{sec:org48f0967} \begin{itemize} \item Author: Elizabeth Hunt \item Name(s): \texttt{bisect\_find\_root} @@ -765,7 +765,7 @@ double bisect_find_root(double (*f)(double), double a, double b, } \end{verbatim} \subsubsection{\texttt{bisect\_find\_root\_with\_error\_assumption}} -\label{sec:orgf5124e7} +\label{sec:org15e3c2d} \begin{itemize} \item Author: Elizabeth Hunt \item Name: \texttt{bisect\_find\_root\_with\_error\_assumption} @@ -789,9 +789,9 @@ double bisect_find_root_with_error_assumption(double (*f)(double), double a, \end{verbatim} \subsection{Linear Routines} -\label{sec:org6f4fce5} +\label{sec:org98cb54b} \subsubsection{\texttt{least\_squares\_lin\_reg}} -\label{sec:orge810f5f} +\label{sec:org0c0c5d7} \begin{itemize} \item Author: Elizabeth Hunt \item Name: \texttt{least\_squares\_lin\_reg} @@ -821,12 +821,12 @@ Line *least_squares_lin_reg(Array_double *x, Array_double *y) { } \end{verbatim} \subsection{Appendix / Miscellaneous} -\label{sec:org85d2eae} +\label{sec:orge34af18} \subsubsection{Data Types} -\label{sec:org198ca2d} +\label{sec:org0f2f877} \begin{enumerate} \item \texttt{Line} -\label{sec:org1866885} +\label{sec:org3f27166} \begin{itemize} \item Author: Elizabeth Hunt \item Location: \texttt{inc/types.h} @@ -839,7 +839,7 @@ typedef struct Line { } Line; \end{verbatim} \item The \texttt{Array\_} and \texttt{Matrix\_} -\label{sec:org4a1c956} +\label{sec:org83fc1f3} \begin{itemize} \item Author: Elizabeth Hunt \item Location: \texttt{inc/types.h} @@ -871,10 +871,10 @@ typedef struct { \end{enumerate} \subsubsection{Macros} -\label{sec:org1976330} +\label{sec:org2bf9bf0} \begin{enumerate} \item \texttt{c\_max} and \texttt{c\_min} -\label{sec:org208b148} +\label{sec:orgcaa569e} \begin{itemize} \item Author: Elizabeth Hunt \item Location: \texttt{inc/macros.h} @@ -888,7 +888,7 @@ typedef struct { \end{verbatim} \item \texttt{InitArray} -\label{sec:orgccc4528} +\label{sec:org5805999} \begin{itemize} \item Author: Elizabeth Hunt \item Location: \texttt{inc/macros.h} @@ -909,7 +909,7 @@ typedef struct { \end{verbatim} \item \texttt{InitArrayWithSize} -\label{sec:org7e87550} +\label{sec:org264d6b7} \begin{itemize} \item Author: Elizabeth Hunt \item Location: \texttt{inc/macros.h} @@ -930,7 +930,7 @@ typedef struct { \end{verbatim} \item \texttt{InitMatrixWithSize} -\label{sec:orge6ec2b1} +\label{sec:org310d41a} \begin{itemize} \item Author: Elizabeth Hunt \item Location: \texttt{inc/macros.h} diff --git a/homeworks/hw-5.org b/homeworks/hw-5.org new file mode 100644 index 0000000..d650375 --- /dev/null +++ b/homeworks/hw-5.org @@ -0,0 +1,59 @@ +#+TITLE: Homework 5 +#+AUTHOR: Elizabeth Hunt +#+LATEX_HEADER: \notindent \notag \usepackage{amsmath} \usepackage[a4paper,margin=1in,portrait]{geometry} +#+LATEX: \setlength\parindent{0pt} +#+OPTIONS: toc:nil + +* Question One +See LIZFCM \rightarrow Matrix Routines \rightarrow ~lu decomp~ & ~bsubst~. + +The test ~UTEST(matrix, lu_decomp)~ is a unit test for the ~lu_decomp~ routine, +and ~UTEST(matrix, bsubst)~ verifies back substitution on an upper triangular +3 \times 3 matrix with a known solution that can be verified manually. + +Both can be found in ~tests/matrix.t.c~. + +* Question Two +Unless the following are met, the resulting solution will be garbage. + +1. The matrix $U$ must be not be singular. +2. $U$ must be square (or it will fail the ~assert~). +3. The system created by $Ux = b$ must be consistent. +4. $U$ is in (obviously) upper-triangular form. + +Thus, the actual calculation performing the $LU$ decomposition +(in ~lu_decomp~) does a sanity +check for 1-3 will fail an assert, should a point along the diagonal (pivot) be +zero, or the matrix be non-factorable. + +* Question Three +See LIZFCM \rightarrow Matrix Routines \rightarrow ~fsubst~. + +~UTEST(matrix, fsubst)~ verifies forward substitution on a lower triangular 3 \times 3 +matrix with a known solution that can be verified manually. + +* Question Four + +See LIZFCM \rightarrow Matrix Routines \rightarrow ~gaussian_elimination~ and ~solve_gaussian_elimination~. + +* Question Five +See LIZFCM \rightarrow Matrix Routines \rightarrow ~m_dot_v~, and the ~UTEST(matrix, m_dot_v)~ in +~tests/matrix.t.c~. + +* Question Six +See ~UTEST(matrix, solve_gaussian_elimination)~ in ~tests/matrix.t.c~, which generates a diagonally dominant 10 \times 10 matrix +and shows that the solution is consistent with the initial matrix, according to the steps given. Then, +we do a dot product between each row of the diagonally dominant matrix and the solution vector to ensure +it is near equivalent to the input vector. + +* Question Seven +See ~UTEST(matrix, solve_matrix_lu_bsubst)~ which does the same test in Question Six with the solution according to +~solve_matrix_lu_bsubst~ as shown in the Software Manual. + +* Question Eight +No, since the time complexity for Gaussian Elimination is always less than that of the LU factorization solution by $O(n^2)$ operations +(in LU factorization we perform both backwards and forwards substitutions proceeding the LU decomp, in Gaussian Elimination we only need +back substitution). + +* Question Nine, Ten +See LIZFCM Software manual and shared library in ~dist~ after compiling. diff --git a/homeworks/hw-5.pdf b/homeworks/hw-5.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ce43787173cae4e212e33dec66774d0cc299410e GIT binary patch literal 81313 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 bhxQJ-b`H*VU&LdlXJTgqkdO$=hyeZ%rfBmm literal 0 HcmV?d00001 diff --git a/homeworks/hw-5.tex b/homeworks/hw-5.tex new file mode 100644 index 0000000..8b9d24b --- /dev/null +++ b/homeworks/hw-5.tex @@ -0,0 +1,95 @@ +% Created 2023-10-30 Mon 19:05 +% 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 5} +\hypersetup{ + pdfauthor={Elizabeth Hunt}, + pdftitle={Homework 5}, + pdfkeywords={}, + pdfsubject={}, + pdfcreator={Emacs 28.2 (Org mode 9.7-pre)}, + pdflang={English}} +\begin{document} + +\maketitle +\setlength\parindent{0pt} + +\section{Question One} +\label{sec:org88abf18} +See LIZFCM \(\rightarrow\) Matrix Routines \(\rightarrow\) \texttt{lu decomp} \& \texttt{bsubst}. + +The test \texttt{UTEST(matrix, lu\_decomp)} is a unit test for the \texttt{lu\_decomp} routine, +and \texttt{UTEST(matrix, bsubst)} verifies back substitution on an upper triangular +3 \texttimes{} 3 matrix with a known solution that can be verified manually. + +Both can be found in \texttt{tests/matrix.t.c}. + +\section{Question Two} +\label{sec:org098a7f1} +Unless the following are met, the resulting solution will be garbage. + +\begin{enumerate} +\item The matrix \(U\) must be not be singular. +\item \(U\) must be square (or it will fail the \texttt{assert}). +\item The system created by \(Ux = b\) must be consistent. +\item \(U\) is in (obviously) upper-triangular form. +\end{enumerate} + +Thus, the actual calculation performing the \(LU\) decomposition +(in \texttt{lu\_decomp}) does a sanity +check for 1-3 will fail an assert, should a point along the diagonal (pivot) be +zero, or the matrix be non-factorable. + +\section{Question Three} +\label{sec:org40d5983} +See LIZFCM \(\rightarrow\) Matrix Routines \(\rightarrow\) \texttt{fsubst}. + +\texttt{UTEST(matrix, fsubst)} verifies forward substitution on a lower triangular 3 \texttimes{} 3 +matrix with a known solution that can be verified manually. + +\section{Question Four} +\label{sec:orgf7d23bb} + +See LIZFCM \(\rightarrow\) Matrix Routines \(\rightarrow\) \texttt{gaussian\_elimination} and \texttt{solve\_gaussian\_elimination}. + +\section{Question Five} +\label{sec:org54e966c} +See LIZFCM \(\rightarrow\) Matrix Routines \(\rightarrow\) \texttt{m\_dot\_v}, and the \texttt{UTEST(matrix, m\_dot\_v)} in +\texttt{tests/matrix.t.c}. + +\section{Question Six} +\label{sec:org413b527} +See \texttt{UTEST(matrix, solve\_gaussian\_elimination)} in \texttt{tests/matrix.t.c}, which generates a diagonally dominant 10 \texttimes{} 10 matrix +and shows that the solution is consistent with the initial matrix, according to the steps given. Then, +we do a dot product between each row of the diagonally dominant matrix and the solution vector to ensure +it is near equivalent to the input vector. + +\section{Question Seven} +\label{sec:orgd3d7443} +See \texttt{UTEST(matrix, solve\_matrix\_lu\_bsubst)} which does the same test in Question Six with the solution according to +\texttt{solve\_matrix\_lu\_bsubst} as shown in the Software Manual. + +\section{Question Eight} +\label{sec:orgf8ac9bf} +No, since the time complexity for Gaussian Elimination is always less than that of the LU factorization solution by \(O(n^2)\) operations +(in LU factorization we perform both backwards and forwards substitutions proceeding the LU decomp, in Gaussian Elimination we only need +back substitution). + +\section{Question Nine, Ten} +\label{sec:orgb270171} +See LIZFCM Software manual and shared library in \texttt{dist} after compiling. +\end{document} \ No newline at end of file diff --git a/inc/lizfcm.h b/inc/lizfcm.h index 12c1278..24b7fa9 100644 --- a/inc/lizfcm.h +++ b/inc/lizfcm.h @@ -25,6 +25,8 @@ extern double l2_distance(Array_double *v1, Array_double *v2); extern double l1_distance(Array_double *v1, Array_double *v2); extern double linf_distance(Array_double *v1, Array_double *v2); extern Array_double *copy_vector(Array_double *v1); +extern Array_double *add_element(Array_double *v, double x); +extern Array_double *slice_element(Array_double *v, size_t x); extern void free_vector(Array_double *v); extern void format_vector_into(Array_double *v, char *s); extern int vector_equal(Array_double *a, Array_double *b); @@ -33,11 +35,15 @@ extern Matrix_double *put_identity_diagonal(Matrix_double *m); extern Matrix_double **lu_decomp(Matrix_double *m); extern Array_double *bsubst(Matrix_double *u, Array_double *b); extern Array_double *fsubst(Matrix_double *l, Array_double *b); -extern Array_double *solve_matrix(Matrix_double *m, Array_double *b); +extern Array_double *solve_matrix_lu_bsubst(Matrix_double *m, Array_double *b); +extern Matrix_double *gaussian_elimination(Matrix_double *m); +extern Array_double *solve_matrix_gaussian(Matrix_double *m, Array_double *b); extern Array_double *m_dot_v(Matrix_double *m, Array_double *v); extern Matrix_double *m_dot_m(Matrix_double *a, Matrix_double *b); extern Array_double *col_v(Matrix_double *m, size_t x); extern Matrix_double *copy_matrix(Matrix_double *m); +extern Matrix_double *add_column(Matrix_double *m, Array_double *col); +extern Matrix_double *slice_column(Matrix_double *m, size_t col); extern void free_matrix(Matrix_double *m); extern void format_matrix_into(Matrix_double *m, char *s); extern int matrix_equal(Matrix_double *a, Matrix_double *b); diff --git a/inc/macros.h b/inc/macros.h index eab1b41..d081869 100644 --- a/inc/macros.h +++ b/inc/macros.h @@ -52,7 +52,7 @@ #define c_max(x, y) (((x) >= (y)) ? (x) : (y)) #define c_min(x, y) (((x) <= (y)) ? (x) : (y)) -#define true 1; -#define false 0; +#define true 1 +#define false 0 #endif // MACROS_H diff --git a/notes/Oct-27.org b/notes/Oct-27.org new file mode 100644 index 0000000..6d23576 --- /dev/null +++ b/notes/Oct-27.org @@ -0,0 +1,26 @@ +Use a bisection criterion for a start + +Hybrid Method: combine Bisection and Higher Order Method: +- Newton's Method +- Secant Method (Newton's method with secant approx.) + + +#+BEGIN_SRC c +fa = f(a) +fb = f(b) +if (fa * fb >= 0) return + +error = 10 * tol +iter = 0 + +while (error > tol && iter < maxiter) { +x0 = 0.5 * (a + b) +x1 = x0 - f(x0) / f'(x0) +if (abs(x1 - x0) > 0.5 * (b - a)) { +// do bisection +} else{ +// do newton's method +} +} +#+END_SRC + diff --git a/notes/Oct-30.org b/notes/Oct-30.org new file mode 100644 index 0000000..7d6ee03 --- /dev/null +++ b/notes/Oct-30.org @@ -0,0 +1,34 @@ +* Power Method for computing the largest eigenvalue of a square matrix + +An eigenvector, v \in R^n is a nonzero vector such that for some number, \lambda \in C, Av = \lambda v +\Rightarrow || v || = 1 + + +Suppose we start with some vector v and assume, v = \alpha_0 v_0 + \alpha_1 v_1 + \cdots + \alpha_n v_n, where {v_1, \cdots, v_n} +are the eigenvectors of A. Assume {v_1, \cdots, v_n} is a basis for R^n + +We can order the eigenvalues such that \lambda_1 \ge \lambda_2 \ge \lambda_3 \ge \cdots \ge \lambda_n + +Compute u = Av += A(\alpha_1 v_1 + \cdots + \alpha_n v_n) += \alpha_1 Av_1 + A(\cdots) + \alpha_n A v_n += \alpha_1 \lambda_1 v_1 + \alpha_2 \lambda_2 v_2 + \cdots + \alpha_n \lambda_n v_n + +w = A (Av) += \alpha_1 \lambda_1^2 v_1 + \alpha_2 \lambda_2^2 v_2 + \cdots + \alpha_n \lambda_n^2 v_n + +Thus, +A^k v = \alpha_1 \lambda_1^k v_1 + \alpha_2 \lambda_2^k v_2 + \cdots + \alpha_n \lambda_n^k v_n += \lambda_1^k ( \alpha_1 v_1 + \alpha_2 \frac{\lambda_2^k}{\lambda_1^k} v_2 + \cdots + \alpha_n \frac{\lambda_3^k}{\lambda_1^k} v_n) + +As k \rightarrow \infty +A^k v = \lambda_1^k (\alpha_1 v_1) + \text{negligble terms} + +Algorithm: +v \ne 0 with v \in R^n +y = Av = \alpha_1 v_1 + \cdots + \alpha_n v_n + +w = \frac{1}{||y||} \cdot y + +Rayleigh Quotient: +If $v$ is an eigenvector of A with eigenvalue \lambda then \frac{v^T A v}{v^T v} = \lambda diff --git a/src/matrix.c b/src/matrix.c index 22dd171..0891734 100644 --- a/src/matrix.c +++ b/src/matrix.c @@ -1,5 +1,6 @@ #include "lizfcm.h" #include +#include #include #include @@ -71,7 +72,7 @@ Matrix_double **lu_decomp(Matrix_double *m) { for (size_t y = 0; y < m->rows; y++) { if (u->data[y]->data[y] == 0) { printf("ERROR: a pivot is zero in given matrix\n"); - exit(-1); + assert(false); } } @@ -82,7 +83,7 @@ Matrix_double **lu_decomp(Matrix_double *m) { if (denom == 0) { printf("ERROR: non-factorable matrix\n"); - exit(-1); + assert(false); } double factor = -(u->data[y]->data[x] / denom); @@ -129,7 +130,7 @@ Array_double *fsubst(Matrix_double *l, Array_double *b) { return x; } -Array_double *solve_matrix(Matrix_double *m, Array_double *b) { +Array_double *solve_matrix_lu_bsubst(Matrix_double *m, Array_double *b) { assert(b->size == m->rows); assert(m->rows == m->cols); @@ -144,10 +145,99 @@ Array_double *solve_matrix(Matrix_double *m, Array_double *b) { free_matrix(u); free_matrix(l); + free(u_l); return x; } +Matrix_double *gaussian_elimination(Matrix_double *m) { + uint64_t h = 0; + uint64_t k = 0; + + Matrix_double *m_cp = copy_matrix(m); + + while (h < m_cp->rows && k < m_cp->cols) { + uint64_t max_row = 0; + double total_max = 0.0; + + for (uint64_t row = h; row < m_cp->rows; row++) { + double this_max = c_max(fabs(m_cp->data[row]->data[k]), total_max); + if (c_max(this_max, total_max) == this_max) { + max_row = row; + } + } + + if (max_row == 0) { + k++; + continue; + } + + Array_double *swp = m_cp->data[max_row]; + m_cp->data[max_row] = m_cp->data[h]; + m_cp->data[h] = swp; + + for (uint64_t row = h + 1; row < m_cp->rows; row++) { + double factor = m_cp->data[row]->data[k] / m_cp->data[h]->data[k]; + m_cp->data[row]->data[k] = 0.0; + + for (uint64_t col = k + 1; col < m_cp->cols; col++) { + m_cp->data[row]->data[col] -= m_cp->data[h]->data[col] * factor; + } + } + + h++; + k++; + } + + return m_cp; +} + +Array_double *solve_matrix_gaussian(Matrix_double *m, Array_double *b) { + assert(b->size == m->rows); + assert(m->rows == m->cols); + + Matrix_double *m_augment_b = add_column(m, b); + Matrix_double *eliminated = gaussian_elimination(m_augment_b); + + Array_double *b_gauss = col_v(eliminated, m->cols); + Matrix_double *u = slice_column(eliminated, m->rows); + + Array_double *solution = bsubst(u, b_gauss); + + free_matrix(m_augment_b); + free_matrix(eliminated); + free_matrix(u); + free_vector(b_gauss); + + return solution; +} + +Matrix_double *slice_column(Matrix_double *m, size_t x) { + Matrix_double *sliced = copy_matrix(m); + + for (size_t row = 0; row < m->rows; row++) { + Array_double *old_row = sliced->data[row]; + sliced->data[row] = slice_element(old_row, x); + free_vector(old_row); + } + sliced->cols--; + + return sliced; +} + +Matrix_double *add_column(Matrix_double *m, Array_double *v) { + Matrix_double *pushed = copy_matrix(m); + + for (size_t row = 0; row < m->rows; row++) { + Array_double *old_row = pushed->data[row]; + pushed->data[row] = add_element(old_row, v->data[row]); + free_vector(old_row); + } + + pushed->cols++; + return pushed; +} + void free_matrix(Matrix_double *m) { for (size_t y = 0; y < m->rows; ++y) free_vector(m->data[y]); diff --git a/src/vector.c b/src/vector.c index 3e4f62d..1b3e0b0 100644 --- a/src/vector.c +++ b/src/vector.c @@ -88,6 +88,21 @@ Array_double *copy_vector(Array_double *v) { return copy; } +Array_double *add_element(Array_double *v, double x) { + Array_double *pushed = InitArrayWithSize(double, v->size + 1, 0.0); + for (size_t i = 0; i < v->size; ++i) + pushed->data[i] = v->data[i]; + pushed->data[v->size] = x; + return pushed; +} + +Array_double *slice_element(Array_double *v, size_t x) { + Array_double *sliced = InitArrayWithSize(double, v->size - 1, 0.0); + for (size_t i = 0; i < v->size - 1; ++i) + sliced->data[i] = i >= x ? v->data[i + 1] : v->data[i]; + return sliced; +} + void free_vector(Array_double *v) { free(v->data); free(v); diff --git a/test/matrix.t.c b/test/matrix.t.c index 5386635..1c72b85 100644 --- a/test/matrix.t.c +++ b/test/matrix.t.c @@ -7,6 +7,38 @@ UTEST(matrix, free) { EXPECT_NE(data_addr, (uint64_t)(m->data)); } +UTEST(matrix, add_column) { + Matrix_double *m = InitMatrixWithSize(double, 5, 5, 0.0); + Array_double *col = InitArray(double, {1.0, 2.0, 3.0, 4.0, 5.0}); + Matrix_double *new_m = add_column(m, col); + + for (size_t row = 0; row < m->rows; row++) + EXPECT_EQ(new_m->data[row]->data[m->cols], col->data[row]); + EXPECT_EQ(new_m->cols, m->cols + 1); + + free_matrix(m); + free_matrix(new_m); + free_vector(col); +} + +UTEST(matrix, slice_column) { + size_t slice = 1; + + Matrix_double *m = InitMatrixWithSize(double, 5, 5, 1.0 * (rand() % 10)); + Matrix_double *new_m = slice_column(m, slice); + + for (size_t row = 0; row < m->rows; row++) { + Array_double *sliced_row = slice_element(m->data[row], slice); + + EXPECT_TRUE(vector_equal(new_m->data[row], sliced_row)); + free_vector(sliced_row); + } + EXPECT_EQ(new_m->cols, m->cols - 1); + + free_matrix(m); + free_matrix(new_m); +} + UTEST(matrix, put_identity_diagonal) { Matrix_double *m = InitMatrixWithSize(double, 8, 8, 0.0); Matrix_double *ident = put_identity_diagonal(m); @@ -47,11 +79,53 @@ UTEST(matrix, m_dot_v) { free_vector(dotted); } +UTEST(matrix, bsubst) { + Matrix_double *u = InitMatrixWithSize(double, 3, 3, 0.0); + u->data[0]->data[0] = 1.0; + u->data[0]->data[1] = 2.0; + u->data[0]->data[2] = 3.0; + u->data[1]->data[1] = 4.0; + u->data[1]->data[2] = 5.0; + u->data[2]->data[2] = 6.0; + + Array_double *b = InitArray(double, {14.0, 29.0, 30.0}); + + Array_double *solution = bsubst(u, b); + EXPECT_NEAR(solution->data[0], -3.0, 0.0001); + EXPECT_NEAR(solution->data[1], 1.0, 0.0001); + EXPECT_NEAR(solution->data[2], 5.0, 0.0001); + + free_matrix(u); + free_vector(b); + free_vector(solution); +} + +UTEST(matrix, fsubst) { + Matrix_double *l = InitMatrixWithSize(double, 3, 3, 0.0); + l->data[0]->data[0] = 1.0; + l->data[1]->data[0] = 2.0; + l->data[1]->data[1] = 3.0; + l->data[2]->data[0] = 4.0; + l->data[2]->data[1] = 5.0; + l->data[2]->data[2] = 6.0; + + Array_double *b = InitArray(double, {14.0, 13.0, 32.0}); + + Array_double *solution = fsubst(l, b); + EXPECT_NEAR(solution->data[0], 14.0, 0.0001); + EXPECT_NEAR(solution->data[1], -5.0, 0.0001); + EXPECT_NEAR(solution->data[2], 0.16667, 0.0001); + + free_matrix(l); + free_vector(b); + free_vector(solution); +} + UTEST(matrix, lu_decomp) { - Matrix_double *m = InitMatrixWithSize(double, 8, 8, 0.0); + Matrix_double *m = InitMatrixWithSize(double, 10, 10, 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); + m->data[y]->data[x] = x == y ? 20.0 : (100.0 - rand() % 100) / 100.0; } Matrix_double **ul = lu_decomp(m); @@ -75,15 +149,40 @@ UTEST(matrix, lu_decomp) { free(ul); } -UTEST(matrix, solve_matrix) { - Matrix_double *m = InitMatrixWithSize(double, 8, 8, 0.0); +UTEST(matrix, solve_gaussian_elimination) { + Matrix_double *m = InitMatrixWithSize(double, 10, 10, 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); + m->data[y]->data[x] = x == y ? 20.0 : (100.0 - rand() % 100) / 100.0; } - 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); + Array_double *b_1 = InitArrayWithSize(double, m->rows, 1.0); + Array_double *b = m_dot_v(m, b_1); + + Array_double *solution = solve_matrix_gaussian(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_vector(b_1); + free_matrix(m); + free_vector(b); + free_vector(solution); +} + +UTEST(matrix, solve_matrix_lu_bsubst) { + Matrix_double *m = InitMatrixWithSize(double, 10, 10, 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 ? 20.0 : (100.0 - rand() % 100) / 100.0; + } + + Array_double *b_1 = InitArrayWithSize(double, m->rows, 1.0); + Array_double *b = m_dot_v(m, b_1); + + Array_double *solution = solve_matrix_lu_bsubst(m, b); for (size_t y = 0; y < m->rows; y++) { double dot = v_dot_v(m->data[y], solution); @@ -92,6 +191,7 @@ UTEST(matrix, solve_matrix) { free_matrix(m); free_vector(b); + free_vector(b_1); free_vector(solution); } diff --git a/test/vector.t.c b/test/vector.t.c index 5dc8ba9..4811113 100644 --- a/test/vector.t.c +++ b/test/vector.t.c @@ -10,6 +10,28 @@ UTEST(vector, copy_vector) { free_vector(w); } +UTEST(vector, add_element) { + Array_double *v = InitArray(double, {3, 1, -4}); + Array_double *w = add_element(v, -2); + Array_double *w_expect = InitArray(double, {3, 1, -4, -2}); + EXPECT_TRUE(vector_equal(w, w_expect)); + + free_vector(v); + free_vector(w); + free_vector(w_expect); +} + +UTEST(vector, slice_element) { + Array_double *v = InitArray(double, {3, 1, -4}); + Array_double *w = slice_element(v, 1); + Array_double *w_expect = InitArray(double, {3, -4}); + EXPECT_TRUE(vector_equal(w, w_expect)); + + free_vector(v); + free_vector(w); + free_vector(w_expect); +} + UTEST(vector, free_vector) { Array_double *v = InitArray(double, {3, 1, -4}); uint64_t arr_addr = (uint64_t)v->data;