summaryrefslogtreecommitdiff
path: root/Homework/math4610
diff options
context:
space:
mode:
Diffstat (limited to 'Homework/math4610')
-rw-r--r--Homework/math4610/Makefile46
-rw-r--r--Homework/math4610/build/approx_derivative.d8
-rw-r--r--Homework/math4610/build/approx_derivative.obin0 -> 1848 bytes
-rw-r--r--Homework/math4610/build/approx_derivative.t.d12
-rw-r--r--Homework/math4610/build/approx_derivative.t.obin0 -> 10712 bytes
-rw-r--r--Homework/math4610/build/eigen.d7
-rw-r--r--Homework/math4610/build/eigen.obin0 -> 4600 bytes
-rw-r--r--Homework/math4610/build/eigen.t.d12
-rw-r--r--Homework/math4610/build/eigen.t.obin0 -> 21104 bytes
-rw-r--r--Homework/math4610/build/jacobi.t.d12
-rw-r--r--Homework/math4610/build/jacobi.t.obin0 -> 8760 bytes
-rw-r--r--Homework/math4610/build/lin.d7
-rw-r--r--Homework/math4610/build/lin.obin0 -> 1280 bytes
-rw-r--r--Homework/math4610/build/lin.t.d12
-rw-r--r--Homework/math4610/build/lin.t.obin0 -> 11912 bytes
-rw-r--r--Homework/math4610/build/maceps.d7
-rw-r--r--Homework/math4610/build/maceps.obin0 -> 792 bytes
-rw-r--r--Homework/math4610/build/maceps.t.d12
-rw-r--r--Homework/math4610/build/maceps.t.obin0 -> 9464 bytes
-rw-r--r--Homework/math4610/build/main.d12
-rw-r--r--Homework/math4610/build/main.obin0 -> 15232 bytes
-rw-r--r--Homework/math4610/build/matrix.d7
-rw-r--r--Homework/math4610/build/matrix.obin0 -> 15392 bytes
-rw-r--r--Homework/math4610/build/matrix.t.d12
-rw-r--r--Homework/math4610/build/matrix.t.obin0 -> 46224 bytes
-rw-r--r--Homework/math4610/build/rand.d7
-rw-r--r--Homework/math4610/build/rand.obin0 -> 776 bytes
-rw-r--r--Homework/math4610/build/rand.t.d12
-rw-r--r--Homework/math4610/build/rand.t.obin0 -> 7384 bytes
-rw-r--r--Homework/math4610/build/roots.d7
-rw-r--r--Homework/math4610/build/roots.obin0 -> 4456 bytes
-rw-r--r--Homework/math4610/build/roots.t.d12
-rw-r--r--Homework/math4610/build/roots.t.obin0 -> 20472 bytes
-rw-r--r--Homework/math4610/build/vector.d7
-rw-r--r--Homework/math4610/build/vector.obin0 -> 6200 bytes
-rw-r--r--Homework/math4610/build/vector.t.d12
-rw-r--r--Homework/math4610/build/vector.t.obin0 -> 33240 bytes
-rw-r--r--Homework/math4610/compile_flags.txt5
-rw-r--r--Homework/math4610/deprecated-cl/approx,derivative.lisp25
-rw-r--r--Homework/math4610/deprecated-cl/approx,maceps.lisp12
-rw-r--r--Homework/math4610/deprecated-cl/approx,package.lisp7
-rw-r--r--Homework/math4610/deprecated-cl/lizfcm.asd33
-rw-r--r--Homework/math4610/deprecated-cl/main.lisp60
-rw-r--r--Homework/math4610/deprecated-cl/tests,approx.lisp48
-rw-r--r--Homework/math4610/deprecated-cl/tests,maceps.lisp27
-rw-r--r--Homework/math4610/deprecated-cl/tests,suite.lisp10
-rw-r--r--Homework/math4610/deprecated-cl/tests,table.lisp31
-rw-r--r--Homework/math4610/deprecated-cl/tests,vector.lisp42
-rw-r--r--Homework/math4610/deprecated-cl/utils,package.lisp5
-rw-r--r--Homework/math4610/deprecated-cl/utils,table.lisp11
-rw-r--r--Homework/math4610/deprecated-cl/utils,within-range.lisp5
-rw-r--r--Homework/math4610/deprecated-cl/vector,distance.lisp6
-rw-r--r--Homework/math4610/deprecated-cl/vector,least-squares.lisp14
-rw-r--r--Homework/math4610/deprecated-cl/vector,norm.lisp14
-rw-r--r--Homework/math4610/deprecated-cl/vector,package.lisp8
-rw-r--r--Homework/math4610/dist/lizfcm.testbin0 -> 54456 bytes
-rw-r--r--Homework/math4610/doc/software_manual.org1376
-rw-r--r--Homework/math4610/doc/software_manual.pdfbin0 -> 227425 bytes
-rw-r--r--Homework/math4610/doc/software_manual.tex1583
-rw-r--r--Homework/math4610/homeworks/a.outbin0 -> 16016 bytes
-rw-r--r--Homework/math4610/homeworks/hw-2.org182
-rw-r--r--Homework/math4610/homeworks/hw-2.pdfbin0 -> 68190 bytes
-rw-r--r--Homework/math4610/homeworks/hw-2.tex246
-rw-r--r--Homework/math4610/homeworks/hw-3.org242
-rw-r--r--Homework/math4610/homeworks/hw-3.pdfbin0 -> 152997 bytes
-rw-r--r--Homework/math4610/homeworks/hw-3.tex250
-rw-r--r--Homework/math4610/homeworks/hw-4.org34
-rw-r--r--Homework/math4610/homeworks/hw-4.pdfbin0 -> 222879 bytes
-rw-r--r--Homework/math4610/homeworks/hw-4.tex70
-rw-r--r--Homework/math4610/homeworks/hw-5.org59
-rw-r--r--Homework/math4610/homeworks/hw-5.pdfbin0 -> 81812 bytes
-rw-r--r--Homework/math4610/homeworks/hw-5.tex95
-rw-r--r--Homework/math4610/homeworks/hw-6.org199
-rw-r--r--Homework/math4610/homeworks/hw-6.pdfbin0 -> 147932 bytes
-rw-r--r--Homework/math4610/homeworks/hw-6.tex223
-rw-r--r--Homework/math4610/homeworks/hw-7.org76
-rw-r--r--Homework/math4610/homeworks/hw-7.pdfbin0 -> 119259 bytes
-rw-r--r--Homework/math4610/homeworks/hw-7.tex107
-rw-r--r--Homework/math4610/homeworks/hw-8.org311
-rw-r--r--Homework/math4610/homeworks/hw-8.pdfbin0 -> 104484 bytes
-rw-r--r--Homework/math4610/homeworks/hw-8.tex344
-rw-r--r--Homework/math4610/homeworks/hw-9.org222
-rw-r--r--Homework/math4610/homeworks/hw-9.pdfbin0 -> 53178 bytes
-rw-r--r--Homework/math4610/homeworks/hw-9.tex250
-rw-r--r--Homework/math4610/homeworks/hw_6_p_8bin0 -> 22000 bytes
-rw-r--r--Homework/math4610/homeworks/hw_6_p_8.c89
-rw-r--r--Homework/math4610/homeworks/img/make_run.pngbin0 -> 73679 bytes
-rw-r--r--Homework/math4610/homeworks/img/test_routine_1.pngbin0 -> 220296 bytes
-rw-r--r--Homework/math4610/homeworks/img/test_routine_2.pngbin0 -> 164395 bytes
-rw-r--r--Homework/math4610/homeworks/virtualization/hw1.pdfbin0 -> 62372 bytes
-rw-r--r--Homework/math4610/homeworks/virtualization/img/htop.pngbin0 -> 36968 bytes
-rw-r--r--Homework/math4610/homeworks/virtualization/img/no_virtualization.pngbin0 -> 37567 bytes
-rw-r--r--Homework/math4610/homeworks/virtualization/virtual_machines.md41
-rw-r--r--Homework/math4610/homeworks/virtualization/virtualization.md103
-rw-r--r--Homework/math4610/inc/lizfcm.h100
-rw-r--r--Homework/math4610/inc/macros.h58
-rw-r--r--Homework/math4610/inc/types.h24
-rw-r--r--Homework/math4610/lib/lizfcm.abin0 -> 227632 bytes
-rw-r--r--Homework/math4610/notes/29-Nov.org20
-rw-r--r--Homework/math4610/notes/4-Dec.org2
-rw-r--r--Homework/math4610/notes/Nov-27.org20
-rw-r--r--Homework/math4610/notes/Nov-3.org62
-rw-r--r--Homework/math4610/notes/Nov-6.org25
-rw-r--r--Homework/math4610/notes/Oct-11.org15
-rw-r--r--Homework/math4610/notes/Oct-13.org8
-rw-r--r--Homework/math4610/notes/Oct-16.org77
-rw-r--r--Homework/math4610/notes/Oct-18.org18
-rw-r--r--Homework/math4610/notes/Oct-27.org26
-rw-r--r--Homework/math4610/notes/Oct-30.org34
-rw-r--r--Homework/math4610/notes/Oct-4.org22
-rw-r--r--Homework/math4610/notes/Oct-6.org13
-rw-r--r--Homework/math4610/notes/Sep-11.org94
-rw-r--r--Homework/math4610/notes/Sep-13.org16
-rw-r--r--Homework/math4610/notes/Sep-15.org52
-rw-r--r--Homework/math4610/notes/Sep-15.pdfbin0 -> 123321 bytes
-rw-r--r--Homework/math4610/notes/Sep-15.tex88
-rw-r--r--Homework/math4610/notes/Sep-20.org21
-rw-r--r--Homework/math4610/notes/Sep-22.org45
-rw-r--r--Homework/math4610/notes/Sep-25.org48
-rw-r--r--Homework/math4610/src/approx_derivative.c38
-rw-r--r--Homework/math4610/src/eigen.c116
-rw-r--r--Homework/math4610/src/lin.c19
-rw-r--r--Homework/math4610/src/maceps.c28
-rw-r--r--Homework/math4610/src/matrix.c346
-rw-r--r--Homework/math4610/src/rand.c5
-rw-r--r--Homework/math4610/src/roots.c127
-rw-r--r--Homework/math4610/src/vector.c143
-rw-r--r--Homework/math4610/test/approx_derivative.t.c32
-rw-r--r--Homework/math4610/test/eigen.t.c147
-rw-r--r--Homework/math4610/test/jacobi.t.c93
-rw-r--r--Homework/math4610/test/lin.t.c20
-rw-r--r--Homework/math4610/test/lizfcm.test.h8
-rw-r--r--Homework/math4610/test/maceps.t.c18
-rw-r--r--Homework/math4610/test/main.c12
-rw-r--r--Homework/math4610/test/matrix.t.c247
-rw-r--r--Homework/math4610/test/rand.t.c10
-rw-r--r--Homework/math4610/test/roots.t.c114
-rw-r--r--Homework/math4610/test/utest.h1668
-rw-r--r--Homework/math4610/test/vector.t.c115
139 files changed, 10882 insertions, 0 deletions
diff --git a/Homework/math4610/Makefile b/Homework/math4610/Makefile
new file mode 100644
index 0000000..09e44d2
--- /dev/null
+++ b/Homework/math4610/Makefile
@@ -0,0 +1,46 @@
+SRC_DIR := src
+OBJ_DIR := build
+BIN_DIR := dist
+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
+EXE := $(BIN_DIR)/lizfcm
+LIBRARY := $(LIB_DIR)/lizfcm.a
+SRC := $(wildcard $(SRC_DIR)/*.c)
+OBJ := $(SRC:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
+
+CPPFLAGS := -Iinc -MMD -MP
+CFLAGS := -Wall
+LDFLAGS := -lm
+
+.PHONY: all clean
+
+all: $(TEST_EXE)
+
+$(TEST_EXE): $(TEST_OBJ) $(LIBRARY) | $(BIN_DIR)
+ $(CC) $(CPPFLAGS) $(CFLAGS) $^ -o $@ $(LDFLAGS)
+
+$(LIBRARY): $(OBJ) | $(LIB_DIR)
+ ar rcs $(LIBRARY) $(OBJ_DIR)/*.o
+ ranlib $(LIBRARY)
+
+$(OBJ_DIR)/%.o: $(TEST_SRC_DIR)/%.c | $(OBJ_DIR)
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
+
+$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR)
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
+
+$(BIN_DIR) $(OBJ_DIR) $(LIB_DIR):
+ mkdir -p $@
+
+print-% : ; @echo $* = $($*)
+
+clean:
+ @$(RM) -r $(BIN_DIR) $(OBJ_DIR) $(LIB_DIR)
+
+-include $(OBJ:.o=.d)
+-include $(TEST_OBJ:.o=.d)
diff --git a/Homework/math4610/build/approx_derivative.d b/Homework/math4610/build/approx_derivative.d
new file mode 100644
index 0000000..ce40007
--- /dev/null
+++ b/Homework/math4610/build/approx_derivative.d
@@ -0,0 +1,8 @@
+build/approx_derivative.o: src/approx_derivative.c inc/lizfcm.h \
+ inc/macros.h inc/types.h
+
+inc/lizfcm.h:
+
+inc/macros.h:
+
+inc/types.h:
diff --git a/Homework/math4610/build/approx_derivative.o b/Homework/math4610/build/approx_derivative.o
new file mode 100644
index 0000000..0eb579a
--- /dev/null
+++ b/Homework/math4610/build/approx_derivative.o
Binary files differ
diff --git a/Homework/math4610/build/approx_derivative.t.d b/Homework/math4610/build/approx_derivative.t.d
new file mode 100644
index 0000000..a5cc002
--- /dev/null
+++ b/Homework/math4610/build/approx_derivative.t.d
@@ -0,0 +1,12 @@
+build/approx_derivative.t.o: test/approx_derivative.t.c \
+ test/lizfcm.test.h inc/lizfcm.h inc/macros.h inc/types.h test/utest.h
+
+test/lizfcm.test.h:
+
+inc/lizfcm.h:
+
+inc/macros.h:
+
+inc/types.h:
+
+test/utest.h:
diff --git a/Homework/math4610/build/approx_derivative.t.o b/Homework/math4610/build/approx_derivative.t.o
new file mode 100644
index 0000000..32e1cf3
--- /dev/null
+++ b/Homework/math4610/build/approx_derivative.t.o
Binary files differ
diff --git a/Homework/math4610/build/eigen.d b/Homework/math4610/build/eigen.d
new file mode 100644
index 0000000..478e52c
--- /dev/null
+++ b/Homework/math4610/build/eigen.d
@@ -0,0 +1,7 @@
+build/eigen.o: src/eigen.c inc/lizfcm.h inc/macros.h inc/types.h
+
+inc/lizfcm.h:
+
+inc/macros.h:
+
+inc/types.h:
diff --git a/Homework/math4610/build/eigen.o b/Homework/math4610/build/eigen.o
new file mode 100644
index 0000000..94245e6
--- /dev/null
+++ b/Homework/math4610/build/eigen.o
Binary files differ
diff --git a/Homework/math4610/build/eigen.t.d b/Homework/math4610/build/eigen.t.d
new file mode 100644
index 0000000..7a0ea06
--- /dev/null
+++ b/Homework/math4610/build/eigen.t.d
@@ -0,0 +1,12 @@
+build/eigen.t.o: test/eigen.t.c test/lizfcm.test.h inc/lizfcm.h \
+ inc/macros.h inc/types.h test/utest.h
+
+test/lizfcm.test.h:
+
+inc/lizfcm.h:
+
+inc/macros.h:
+
+inc/types.h:
+
+test/utest.h:
diff --git a/Homework/math4610/build/eigen.t.o b/Homework/math4610/build/eigen.t.o
new file mode 100644
index 0000000..12730e7
--- /dev/null
+++ b/Homework/math4610/build/eigen.t.o
Binary files differ
diff --git a/Homework/math4610/build/jacobi.t.d b/Homework/math4610/build/jacobi.t.d
new file mode 100644
index 0000000..ee3573e
--- /dev/null
+++ b/Homework/math4610/build/jacobi.t.d
@@ -0,0 +1,12 @@
+build/jacobi.t.o: test/jacobi.t.c test/lizfcm.test.h inc/lizfcm.h \
+ inc/macros.h inc/types.h test/utest.h
+
+test/lizfcm.test.h:
+
+inc/lizfcm.h:
+
+inc/macros.h:
+
+inc/types.h:
+
+test/utest.h:
diff --git a/Homework/math4610/build/jacobi.t.o b/Homework/math4610/build/jacobi.t.o
new file mode 100644
index 0000000..b3feb59
--- /dev/null
+++ b/Homework/math4610/build/jacobi.t.o
Binary files differ
diff --git a/Homework/math4610/build/lin.d b/Homework/math4610/build/lin.d
new file mode 100644
index 0000000..f8eca56
--- /dev/null
+++ b/Homework/math4610/build/lin.d
@@ -0,0 +1,7 @@
+build/lin.o: src/lin.c inc/lizfcm.h inc/macros.h inc/types.h
+
+inc/lizfcm.h:
+
+inc/macros.h:
+
+inc/types.h:
diff --git a/Homework/math4610/build/lin.o b/Homework/math4610/build/lin.o
new file mode 100644
index 0000000..e34e656
--- /dev/null
+++ b/Homework/math4610/build/lin.o
Binary files differ
diff --git a/Homework/math4610/build/lin.t.d b/Homework/math4610/build/lin.t.d
new file mode 100644
index 0000000..20f8987
--- /dev/null
+++ b/Homework/math4610/build/lin.t.d
@@ -0,0 +1,12 @@
+build/lin.t.o: test/lin.t.c test/lizfcm.test.h inc/lizfcm.h inc/macros.h \
+ inc/types.h test/utest.h
+
+test/lizfcm.test.h:
+
+inc/lizfcm.h:
+
+inc/macros.h:
+
+inc/types.h:
+
+test/utest.h:
diff --git a/Homework/math4610/build/lin.t.o b/Homework/math4610/build/lin.t.o
new file mode 100644
index 0000000..a235333
--- /dev/null
+++ b/Homework/math4610/build/lin.t.o
Binary files differ
diff --git a/Homework/math4610/build/maceps.d b/Homework/math4610/build/maceps.d
new file mode 100644
index 0000000..ef8daf4
--- /dev/null
+++ b/Homework/math4610/build/maceps.d
@@ -0,0 +1,7 @@
+build/maceps.o: src/maceps.c inc/lizfcm.h inc/macros.h inc/types.h
+
+inc/lizfcm.h:
+
+inc/macros.h:
+
+inc/types.h:
diff --git a/Homework/math4610/build/maceps.o b/Homework/math4610/build/maceps.o
new file mode 100644
index 0000000..265527a
--- /dev/null
+++ b/Homework/math4610/build/maceps.o
Binary files differ
diff --git a/Homework/math4610/build/maceps.t.d b/Homework/math4610/build/maceps.t.d
new file mode 100644
index 0000000..d069a18
--- /dev/null
+++ b/Homework/math4610/build/maceps.t.d
@@ -0,0 +1,12 @@
+build/maceps.t.o: test/maceps.t.c test/lizfcm.test.h inc/lizfcm.h \
+ inc/macros.h inc/types.h test/utest.h
+
+test/lizfcm.test.h:
+
+inc/lizfcm.h:
+
+inc/macros.h:
+
+inc/types.h:
+
+test/utest.h:
diff --git a/Homework/math4610/build/maceps.t.o b/Homework/math4610/build/maceps.t.o
new file mode 100644
index 0000000..025076e
--- /dev/null
+++ b/Homework/math4610/build/maceps.t.o
Binary files differ
diff --git a/Homework/math4610/build/main.d b/Homework/math4610/build/main.d
new file mode 100644
index 0000000..9ff86d0
--- /dev/null
+++ b/Homework/math4610/build/main.d
@@ -0,0 +1,12 @@
+build/main.o: test/main.c test/lizfcm.test.h inc/lizfcm.h inc/macros.h \
+ inc/types.h test/utest.h
+
+test/lizfcm.test.h:
+
+inc/lizfcm.h:
+
+inc/macros.h:
+
+inc/types.h:
+
+test/utest.h:
diff --git a/Homework/math4610/build/main.o b/Homework/math4610/build/main.o
new file mode 100644
index 0000000..d3a9735
--- /dev/null
+++ b/Homework/math4610/build/main.o
Binary files differ
diff --git a/Homework/math4610/build/matrix.d b/Homework/math4610/build/matrix.d
new file mode 100644
index 0000000..7c13130
--- /dev/null
+++ b/Homework/math4610/build/matrix.d
@@ -0,0 +1,7 @@
+build/matrix.o: src/matrix.c inc/lizfcm.h inc/macros.h inc/types.h
+
+inc/lizfcm.h:
+
+inc/macros.h:
+
+inc/types.h:
diff --git a/Homework/math4610/build/matrix.o b/Homework/math4610/build/matrix.o
new file mode 100644
index 0000000..c28fc55
--- /dev/null
+++ b/Homework/math4610/build/matrix.o
Binary files differ
diff --git a/Homework/math4610/build/matrix.t.d b/Homework/math4610/build/matrix.t.d
new file mode 100644
index 0000000..f707d56
--- /dev/null
+++ b/Homework/math4610/build/matrix.t.d
@@ -0,0 +1,12 @@
+build/matrix.t.o: test/matrix.t.c test/lizfcm.test.h inc/lizfcm.h \
+ inc/macros.h inc/types.h test/utest.h
+
+test/lizfcm.test.h:
+
+inc/lizfcm.h:
+
+inc/macros.h:
+
+inc/types.h:
+
+test/utest.h:
diff --git a/Homework/math4610/build/matrix.t.o b/Homework/math4610/build/matrix.t.o
new file mode 100644
index 0000000..a3c56f6
--- /dev/null
+++ b/Homework/math4610/build/matrix.t.o
Binary files differ
diff --git a/Homework/math4610/build/rand.d b/Homework/math4610/build/rand.d
new file mode 100644
index 0000000..e3fef0e
--- /dev/null
+++ b/Homework/math4610/build/rand.d
@@ -0,0 +1,7 @@
+build/rand.o: src/rand.c inc/lizfcm.h inc/macros.h inc/types.h
+
+inc/lizfcm.h:
+
+inc/macros.h:
+
+inc/types.h:
diff --git a/Homework/math4610/build/rand.o b/Homework/math4610/build/rand.o
new file mode 100644
index 0000000..97ea05a
--- /dev/null
+++ b/Homework/math4610/build/rand.o
Binary files differ
diff --git a/Homework/math4610/build/rand.t.d b/Homework/math4610/build/rand.t.d
new file mode 100644
index 0000000..28a7d0f
--- /dev/null
+++ b/Homework/math4610/build/rand.t.d
@@ -0,0 +1,12 @@
+build/rand.t.o: test/rand.t.c test/lizfcm.test.h inc/lizfcm.h \
+ inc/macros.h inc/types.h test/utest.h
+
+test/lizfcm.test.h:
+
+inc/lizfcm.h:
+
+inc/macros.h:
+
+inc/types.h:
+
+test/utest.h:
diff --git a/Homework/math4610/build/rand.t.o b/Homework/math4610/build/rand.t.o
new file mode 100644
index 0000000..2c55eff
--- /dev/null
+++ b/Homework/math4610/build/rand.t.o
Binary files differ
diff --git a/Homework/math4610/build/roots.d b/Homework/math4610/build/roots.d
new file mode 100644
index 0000000..666ae7b
--- /dev/null
+++ b/Homework/math4610/build/roots.d
@@ -0,0 +1,7 @@
+build/roots.o: src/roots.c inc/lizfcm.h inc/macros.h inc/types.h
+
+inc/lizfcm.h:
+
+inc/macros.h:
+
+inc/types.h:
diff --git a/Homework/math4610/build/roots.o b/Homework/math4610/build/roots.o
new file mode 100644
index 0000000..f766021
--- /dev/null
+++ b/Homework/math4610/build/roots.o
Binary files differ
diff --git a/Homework/math4610/build/roots.t.d b/Homework/math4610/build/roots.t.d
new file mode 100644
index 0000000..833625f
--- /dev/null
+++ b/Homework/math4610/build/roots.t.d
@@ -0,0 +1,12 @@
+build/roots.t.o: test/roots.t.c test/lizfcm.test.h inc/lizfcm.h \
+ inc/macros.h inc/types.h test/utest.h
+
+test/lizfcm.test.h:
+
+inc/lizfcm.h:
+
+inc/macros.h:
+
+inc/types.h:
+
+test/utest.h:
diff --git a/Homework/math4610/build/roots.t.o b/Homework/math4610/build/roots.t.o
new file mode 100644
index 0000000..3457048
--- /dev/null
+++ b/Homework/math4610/build/roots.t.o
Binary files differ
diff --git a/Homework/math4610/build/vector.d b/Homework/math4610/build/vector.d
new file mode 100644
index 0000000..806d770
--- /dev/null
+++ b/Homework/math4610/build/vector.d
@@ -0,0 +1,7 @@
+build/vector.o: src/vector.c inc/lizfcm.h inc/macros.h inc/types.h
+
+inc/lizfcm.h:
+
+inc/macros.h:
+
+inc/types.h:
diff --git a/Homework/math4610/build/vector.o b/Homework/math4610/build/vector.o
new file mode 100644
index 0000000..8053730
--- /dev/null
+++ b/Homework/math4610/build/vector.o
Binary files differ
diff --git a/Homework/math4610/build/vector.t.d b/Homework/math4610/build/vector.t.d
new file mode 100644
index 0000000..32b1404
--- /dev/null
+++ b/Homework/math4610/build/vector.t.d
@@ -0,0 +1,12 @@
+build/vector.t.o: test/vector.t.c test/lizfcm.test.h inc/lizfcm.h \
+ inc/macros.h inc/types.h test/utest.h
+
+test/lizfcm.test.h:
+
+inc/lizfcm.h:
+
+inc/macros.h:
+
+inc/types.h:
+
+test/utest.h:
diff --git a/Homework/math4610/build/vector.t.o b/Homework/math4610/build/vector.t.o
new file mode 100644
index 0000000..bca5a4d
--- /dev/null
+++ b/Homework/math4610/build/vector.t.o
Binary files differ
diff --git a/Homework/math4610/compile_flags.txt b/Homework/math4610/compile_flags.txt
new file mode 100644
index 0000000..b47959f
--- /dev/null
+++ b/Homework/math4610/compile_flags.txt
@@ -0,0 +1,5 @@
+-lm
+-Iinc
+-MMD
+-MP
+-Wall
diff --git a/Homework/math4610/deprecated-cl/approx,derivative.lisp b/Homework/math4610/deprecated-cl/approx,derivative.lisp
new file mode 100644
index 0000000..631a5c0
--- /dev/null
+++ b/Homework/math4610/deprecated-cl/approx,derivative.lisp
@@ -0,0 +1,25 @@
+(in-package :lizfcm.approx)
+
+(defun central-derivative-at (f x &optional (delta 0.01))
+ (let* ((x2 (+ x delta))
+ (x1 (- x delta))
+ (y2 (apply f (list x2)))
+ (y1 (apply f (list x1))))
+ (/ (- y2 y1)
+ (- x2 x1))))
+
+(defun forward-derivative-at (f x &optional (delta 0.01))
+ (let* ((x2 (+ x delta))
+ (x1 x)
+ (y2 (apply f (list x2)))
+ (y1 (apply f (list x1))))
+ (/ (- y2 y1)
+ (- x2 x1))))
+
+(defun backward-derivative-at (f x &optional (delta 0.01))
+ (let* ((x2 x)
+ (x1 (- x delta))
+ (y2 (apply f (list x2)))
+ (y1 (apply f (list x1))))
+ (/ (- y2 y1)
+ (- x2 x1))))
diff --git a/Homework/math4610/deprecated-cl/approx,maceps.lisp b/Homework/math4610/deprecated-cl/approx,maceps.lisp
new file mode 100644
index 0000000..e2738e4
--- /dev/null
+++ b/Homework/math4610/deprecated-cl/approx,maceps.lisp
@@ -0,0 +1,12 @@
+(in-package :lizfcm.approx)
+
+(defun compute-maceps (f a init)
+ (let ((h init)
+ (err init))
+ (loop collect (list a h err)
+ do
+ (setf h (/ h 2)
+ err (abs (- (funcall f (+ a h))
+ (funcall f a))))
+ while (> err 0))))
+
diff --git a/Homework/math4610/deprecated-cl/approx,package.lisp b/Homework/math4610/deprecated-cl/approx,package.lisp
new file mode 100644
index 0000000..a0eac80
--- /dev/null
+++ b/Homework/math4610/deprecated-cl/approx,package.lisp
@@ -0,0 +1,7 @@
+(in-package :cl-user)
+(defpackage lizfcm.approx
+ (:use :cl)
+ (:export :central-derivative-at
+ :forward-derivative-at
+ :backward-derivative-at
+ :compute-maceps))
diff --git a/Homework/math4610/deprecated-cl/lizfcm.asd b/Homework/math4610/deprecated-cl/lizfcm.asd
new file mode 100644
index 0000000..dea3ddd
--- /dev/null
+++ b/Homework/math4610/deprecated-cl/lizfcm.asd
@@ -0,0 +1,33 @@
+(asdf:defsystem "lizfcm"
+ :version "0.1.0"
+ :author "Elizabeth Hunt"
+ :license "MIT"
+ :components
+ ((:file "utils,within-range" :depends-on ("utils,package"))
+ (:file "utils,table" :depends-on ("utils,package"))
+ (:file "utils,package")
+ (:file "approx,maceps" :depends-on ("approx,package"))
+ (:file "approx,derivative" :depends-on ("approx,package"))
+ (:file "approx,package")
+ (:file "vector,least-squares" :depends-on ("vector,package"))
+ (:file "vector,distance" :depends-on ("vector,norm" "vector,package"))
+ (:file "vector,norm" :depends-on ("vector,package"))
+ (:file "vector,package")))
+
+
+(asdf:defsystem "lizfcm/tests"
+ :author "Elizabeth Hunt"
+ :license "MIT"
+ :depends-on
+ (:fiveam
+ :lizfcm)
+ :components
+ ((:file "tests,table" :depends-on ("tests,suite"))
+ (:file "tests,maceps" :depends-on ("tests,suite"))
+ (:file "tests,approx" :depends-on ("tests,suite"))
+ (:file "tests,vector" :depends-on ("tests,suite"))
+ (:file "tests,suite"))
+ :perform
+ (asdf:test-op (o c) (uiop:symbol-call
+ :fiveam :run!
+ (uiop:find-symbol* :lizfcm-test-suite :lizfcm/tests))))
diff --git a/Homework/math4610/deprecated-cl/main.lisp b/Homework/math4610/deprecated-cl/main.lisp
new file mode 100644
index 0000000..7a8b455
--- /dev/null
+++ b/Homework/math4610/deprecated-cl/main.lisp
@@ -0,0 +1,60 @@
+(load "lizfcm.asd")
+(ql:quickload :lizfcm)
+
+;; this is a collection showcasing the library developed for math4610, required
+;; from the Shared Library definition
+
+(defun smaceps ()
+ (cadar (last (lizfcm.approx:compute-maceps
+ (lambda (x) x) 1.0 1.0))))
+
+(defun dmaceps ()
+ (cadar (last (lizfcm.approx:compute-maceps
+ (lambda (x) x) 1.0d0 1.0d0))))
+
+(defun l2-norm (v)
+ (let ((2-norm (lizfcm.vector:p-norm 2)))
+ (funcall 2-norm v)))
+
+(defun l1-norm (v)
+ (let ((1-norm (lizfcm.vector:p-norm 1)))
+ (funcall 1-norm v)))
+
+(defun linf-norm (v)
+ (lizfcm.vector:max-norm v))
+
+(defun l2-distance (v1 v2)
+ (let ((2-norm (lizfcm.vector:p-norm 2)))
+ (lizfcm.vector:distance v1 v2 2-norm)))
+
+(defun l1-distance (v1 v2)
+ (let ((1-norm (lizfcm.vector:p-norm 1)))
+ (lizfcm.vector:distance v1 v2 1-norm)))
+
+(defun linf-distance (v1 v2)
+ (lizfcm.vector:distance v1 v2 'lizfcm.vector:max-norm))
+
+(defun f (x)
+ (/ (- x 1) (+ x 1)))
+
+(defun fprime (x)
+ (/ 2 (expt (+ x 1) 2)))
+
+(defmacro showcase (s-expr)
+ `(format t "~a = ~a~%" ,(format nil "~a" s-expr) ,s-expr))
+
+(defun main ()
+ (showcase (smaceps))
+ (showcase (dmaceps))
+ (showcase (l2-norm '(1 2)))
+ (showcase (l1-norm '(1 2)))
+ (showcase (linf-norm '(1 2)))
+ (showcase (l1-distance '(1 2) '(-3 4)))
+ (showcase (l2-distance '(1 2) '(-3 4)))
+ (showcase (linf-distance '(1 2) '(-3 4)))
+ (showcase (lizfcm.vector:least-squares-reg '(1 2 3 4 5 6 7)
+ '(0.5 3 2 3.5 5 6 7.5)))
+ (showcase (lizfcm.approx:forward-derivative-at 'f 1 0.00001))
+ (showcase (lizfcm.approx:central-derivative-at 'f 1 0.00001))
+ (showcase (lizfcm.approx:backward-derivative-at 'f 1 0.00001)))
+
diff --git a/Homework/math4610/deprecated-cl/tests,approx.lisp b/Homework/math4610/deprecated-cl/tests,approx.lisp
new file mode 100644
index 0000000..678ff8c
--- /dev/null
+++ b/Homework/math4610/deprecated-cl/tests,approx.lisp
@@ -0,0 +1,48 @@
+(defpackage lizfcm/tests.approx
+ (:use :cl
+ :fiveam
+ :lizfcm.approx
+ :lizfcm.utils
+ :lizfcm/tests)
+ (:export :approx-suite))
+(in-package :lizfcm/tests.approx)
+
+(def-suite approx-suite
+ :in lizfcm-test-suite)
+(in-suite approx-suite)
+
+(test central-derivative-at
+ :description "derivative at is within bounds"
+ (let ((f (lambda (x) (* x x)))
+ (x 2)
+ (accepted-delta 0.02)
+ (f-prime-at-x 4)
+ (delta 0.01))
+ (is (within-range-p
+ (central-derivative-at f x delta)
+ f-prime-at-x
+ accepted-delta))))
+
+(test fwd-derivative-at
+ :description "forward derivative at is within bounds"
+ (let ((f (lambda (x) (* x x)))
+ (x 2)
+ (accepted-delta 0.02)
+ (f-prime-at-x 4)
+ (delta 0.01))
+ (is (within-range-p
+ (forward-derivative-at f x delta)
+ f-prime-at-x
+ accepted-delta))))
+
+(test bwd-derivative-at
+ :description "backward derivative at is within bounds"
+ (let ((f (lambda (x) (* x x)))
+ (x 2)
+ (accepted-delta 0.02)
+ (f-prime-at-x 4)
+ (delta 0.01))
+ (is (within-range-p
+ (backward-derivative-at f x delta)
+ f-prime-at-x
+ accepted-delta))))
diff --git a/Homework/math4610/deprecated-cl/tests,maceps.lisp b/Homework/math4610/deprecated-cl/tests,maceps.lisp
new file mode 100644
index 0000000..cd5ced9
--- /dev/null
+++ b/Homework/math4610/deprecated-cl/tests,maceps.lisp
@@ -0,0 +1,27 @@
+(defpackage lizfcm/tests.maceps
+ (:use :cl
+ :fiveam
+ :lizfcm.approx
+ :lizfcm.utils
+ :lizfcm/tests)
+ (:export :approx-suite))
+(in-package :lizfcm/tests.maceps)
+
+(def-suite maceps-suite
+ :in lizfcm-test-suite)
+(in-suite maceps-suite)
+
+(test maceps
+ :description "double precision provides precision about (mac eps of single precision) squared"
+ (let* ((maceps-computation-double (compute-maceps (lambda (x) x)
+ 1.0d0
+ 1.0d0))
+ (maceps-computation-single (compute-maceps (lambda (x) x)
+ 1.0
+ 1.0))
+ (last-double-h (cadar (last maceps-computation-double)))
+ (last-single-h (cadar (last maceps-computation-single))))
+ (is (within-range-p
+ (- last-double-h (* last-single-h last-single-h))
+ 0
+ last-single-h))))
diff --git a/Homework/math4610/deprecated-cl/tests,suite.lisp b/Homework/math4610/deprecated-cl/tests,suite.lisp
new file mode 100644
index 0000000..e23cfaf
--- /dev/null
+++ b/Homework/math4610/deprecated-cl/tests,suite.lisp
@@ -0,0 +1,10 @@
+(in-package :cl-user)
+(defpackage lizfcm/tests
+ (:use :cl
+ :fiveam)
+ (:export :run!
+ :lizfcm-test-suite))
+(in-package :lizfcm/tests)
+
+(def-suite lizfcm-test-suite
+ :description "The ultimate parent test suite")
diff --git a/Homework/math4610/deprecated-cl/tests,table.lisp b/Homework/math4610/deprecated-cl/tests,table.lisp
new file mode 100644
index 0000000..33d4e86
--- /dev/null
+++ b/Homework/math4610/deprecated-cl/tests,table.lisp
@@ -0,0 +1,31 @@
+(defpackage lizfcm/tests.table
+ (:use :cl
+ :fiveam
+ :lizfcm.utils
+ :lizfcm/tests)
+ (:export :approx-suite))
+(in-package :lizfcm/tests.table)
+
+(def-suite table-suite
+ :in lizfcm-test-suite)
+(in-suite table-suite)
+
+(defun fib (n)
+ (cond ((< n 2) n)
+ (t (+ (fib (- n 1)) (fib (- n 2))))))
+
+(test table-of-fib-vals
+ :description "table generates correctly"
+ (let* ((headers '("n" "fib(n)"))
+ (n-values '((1) (2) (3) (4)))
+ (expected `(("n" "fib(n)")
+ (1 ,(fib 1))
+ (2 ,(fib 2))
+ (3 ,(fib 3))
+ (4 ,(fib 4))))
+ (tabled (lizfcm.utils:table (:headers headers
+ :domain-order (n)
+ :domain-values n-values)
+ (fib n))))
+ (is (equal expected tabled))))
+
diff --git a/Homework/math4610/deprecated-cl/tests,vector.lisp b/Homework/math4610/deprecated-cl/tests,vector.lisp
new file mode 100644
index 0000000..6edb1ac
--- /dev/null
+++ b/Homework/math4610/deprecated-cl/tests,vector.lisp
@@ -0,0 +1,42 @@
+(defpackage lizfcm/tests.vector
+ (:use :cl
+ :fiveam
+ :lizfcm.vector
+ :lizfcm.utils
+ :lizfcm/tests)
+ (:export :vector-suite))
+(in-package :lizfcm/tests.vector)
+
+(def-suite vector-suite
+ :in lizfcm-test-suite)
+(in-suite vector-suite)
+
+(test p-norm
+ :description "computes p-norm"
+ (let ((v '(1 1))
+ (length (sqrt 2))
+ (2-norm (p-norm 2)))
+ (is (within-range-p (funcall 2-norm v)
+ length
+ 0.00001))))
+
+(test vector-distance
+ :description "computes distance via norm"
+ (let ((v1 '(0 0))
+ (v2 '(1 1))
+ (dist (sqrt 2)))
+ (is (within-range-p (distance v1 v2 (p-norm 2))
+ dist
+ 0.00001))))
+
+(test least-squares
+ :description "least squares is correct enough"
+ (let ((x '(0 1 2 3 4))
+ (y '(1 2 3 4 5)))
+ (destructuring-bind (m b) (lizfcm.vector:least-squares-reg x y)
+ (is (within-range-p m 1 0.00001))
+ (is (within-range-p b 1 0.00001))))
+ (let ((x '(1 2 3 4 5 6 7))
+ (y '(0.5 3 2 3.5 5 6 7.5)))
+ (destructuring-bind (m b) (lizfcm.vector:least-squares-reg x y)
+ (is (within-range-p m 1 0.3))))) ;; just a guestimate for best fit
diff --git a/Homework/math4610/deprecated-cl/utils,package.lisp b/Homework/math4610/deprecated-cl/utils,package.lisp
new file mode 100644
index 0000000..bdd5589
--- /dev/null
+++ b/Homework/math4610/deprecated-cl/utils,package.lisp
@@ -0,0 +1,5 @@
+(in-package :cl-user)
+(defpackage lizfcm.utils
+ (:use :cl)
+ (:export :within-range-p
+ :table))
diff --git a/Homework/math4610/deprecated-cl/utils,table.lisp b/Homework/math4610/deprecated-cl/utils,table.lisp
new file mode 100644
index 0000000..e96f37b
--- /dev/null
+++ b/Homework/math4610/deprecated-cl/utils,table.lisp
@@ -0,0 +1,11 @@
+(in-package :lizfcm.utils)
+
+(defmacro table ((&key headers domain-order domain-values) &body body)
+ `(cons
+ ,headers
+ (mapcar (lambda (tuple)
+ (destructuring-bind ,domain-order tuple
+ (append tuple
+ (list
+ ,@body))))
+ ,domain-values)))
diff --git a/Homework/math4610/deprecated-cl/utils,within-range.lisp b/Homework/math4610/deprecated-cl/utils,within-range.lisp
new file mode 100644
index 0000000..9a0b762
--- /dev/null
+++ b/Homework/math4610/deprecated-cl/utils,within-range.lisp
@@ -0,0 +1,5 @@
+(in-package :lizfcm.utils)
+
+(defun within-range-p (x true-value delta)
+ (and (< x (+ true-value delta))
+ (> x (- true-value delta))))
diff --git a/Homework/math4610/deprecated-cl/vector,distance.lisp b/Homework/math4610/deprecated-cl/vector,distance.lisp
new file mode 100644
index 0000000..74631ce
--- /dev/null
+++ b/Homework/math4610/deprecated-cl/vector,distance.lisp
@@ -0,0 +1,6 @@
+(in-package :lizfcm.vector)
+
+(defun distance (v1 v2 norm)
+ (let* ((d (mapcar #'- v1 v2))
+ (length (funcall norm d)))
+ length))
diff --git a/Homework/math4610/deprecated-cl/vector,least-squares.lisp b/Homework/math4610/deprecated-cl/vector,least-squares.lisp
new file mode 100644
index 0000000..687af32
--- /dev/null
+++ b/Homework/math4610/deprecated-cl/vector,least-squares.lisp
@@ -0,0 +1,14 @@
+(in-package :lizfcm.vector)
+
+(defun least-squares-reg (x y)
+ (let* ((n (length x))
+ (sum-y (reduce #'+ y))
+ (sum-x (reduce #'+ x))
+ (sum-xy (reduce #'+ (mapcar #'* x y)))
+ (sum-xsquared (reduce #'+ (mapcar #'* x x)))
+ (b (/ (- (* sum-y sum-xsquared) (* sum-x sum-xy))
+ (- (* n sum-xsquared) (* sum-x sum-x))))
+ (a (/ (- (* n sum-xy) (* sum-x sum-y))
+ (- (* n sum-xsquared) (* sum-x sum-x)))))
+ (list a b)))
+
diff --git a/Homework/math4610/deprecated-cl/vector,norm.lisp b/Homework/math4610/deprecated-cl/vector,norm.lisp
new file mode 100644
index 0000000..aa51bce
--- /dev/null
+++ b/Homework/math4610/deprecated-cl/vector,norm.lisp
@@ -0,0 +1,14 @@
+(in-package :lizfcm.vector)
+
+(defun p-norm (p)
+ (lambda (v)
+ (expt
+ (reduce #'+
+ (mapcar (lambda (x)
+ (abs
+ (expt x p)))
+ v))
+ (/ 1 p))))
+
+(defun max-norm (v)
+ (reduce #'max v))
diff --git a/Homework/math4610/deprecated-cl/vector,package.lisp b/Homework/math4610/deprecated-cl/vector,package.lisp
new file mode 100644
index 0000000..f491908
--- /dev/null
+++ b/Homework/math4610/deprecated-cl/vector,package.lisp
@@ -0,0 +1,8 @@
+(in-package :cl-user)
+(defpackage lizfcm.vector
+ (:use :cl)
+ (:export
+ :p-norm
+ :max-norm
+ :distance
+ :least-squares-reg))
diff --git a/Homework/math4610/dist/lizfcm.test b/Homework/math4610/dist/lizfcm.test
new file mode 100644
index 0000000..8e31a6c
--- /dev/null
+++ b/Homework/math4610/dist/lizfcm.test
Binary files differ
diff --git a/Homework/math4610/doc/software_manual.org b/Homework/math4610/doc/software_manual.org
new file mode 100644
index 0000000..b41ec03
--- /dev/null
+++ b/Homework/math4610/doc/software_manual.org
@@ -0,0 +1,1376 @@
+#+TITLE: LIZFCM Software Manual (v0.6)
+#+AUTHOR: Elizabeth Hunt
+#+LATEX_HEADER: \notindent \notag \usepackage{amsmath} \usepackage[a4paper,margin=1in,portrait]{geometry}
+#+LATEX: \setlength\parindent{0pt}
+#+STARTUP: entitiespretty fold inlineimages
+
+* Design
+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
+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:
+
++ 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 "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 ~arm~-based M1 machine running
+MacOS as well as ~x86~ Arch Linux.
+
+1. ~cd~ into the root of the repo
+2. ~make~
+
+Then, as of homework 5, the testing routines are provided in ~test~ and utilize the
+~utest~ "micro"library. They compile to a binary in ~./dist/lizfcm.test~.
+
+Execution of the Makefile will perform compilation of individual routines.
+
+But, in the requirement of manual intervention (should the little alien workers
+inside the computer fail to do their job), one can use the following command to
+produce an object file:
+
+\begin{verbatim}
+ gcc -Iinc/ -lm -Wall -c src/<the_routine>.c -o build/<the_routine>.o
+\end{verbatim}
+
+Which is then bundled into a static library in ~lib/lizfcm.a~ and can be linked
+in the standard method.
+
+* The LIZFCM API
+** Simple Routines
+*** ~smaceps~
++ Author: Elizabeth Hunt
++ Name: ~smaceps~
++ Location: ~src/maceps.c~
++ Input: none
++ Output: a ~float~ returning the specific "Machine Epsilon" of a machine on a
+ single precision floating point number at which it becomes "indistinguishable".
+
+#+BEGIN_SRC c
+float smaceps() {
+ float one = 1.0;
+ float machine_epsilon = 1.0;
+ float one_approx = one + machine_epsilon;
+
+ while (fabsf(one_approx - one) > 0) {
+ machine_epsilon /= 2;
+ one_approx = one + machine_epsilon;
+ }
+
+ return machine_epsilon;
+}
+#+END_SRC
+
+*** ~dmaceps~
++ Author: Elizabeth Hunt
++ Name: ~dmaceps~
++ Location: ~src/maceps.c~
++ Input: none
++ Output: a ~double~ returning the specific "Machine Epsilon" of a machine on a
+ double precision floating point number at which it becomes "indistinguishable".
+
+#+BEGIN_SRC c
+double dmaceps() {
+ double one = 1.0;
+ double machine_epsilon = 1.0;
+ double one_approx = one + machine_epsilon;
+
+ while (fabs(one_approx - one) > 0) {
+ machine_epsilon /= 2;
+ one_approx = one + machine_epsilon;
+ }
+
+ return machine_epsilon;
+}
+#+END_SRC
+
+** Derivative Routines
+*** ~central_derivative_at~
++ Author: Elizabeth Hunt
++ Name: ~central_derivative_at~
++ Location: ~src/approx_derivative.c~
++ Input:
+ - ~f~ is a pointer to a one-ary function that takes a double as input and produces
+ a double as output
+ - ~a~ is the domain value at which we approximate ~f'~
+ - ~h~ is the step size
++ Output: a ~double~ of the approximate value of ~f'(a)~ via the central difference
+ method.
+
+#+BEGIN_SRC c
+double central_derivative_at(double (*f)(double), double a, double h) {
+ assert(h > 0);
+
+ double x2 = a + h;
+ double x1 = a - h;
+
+ double y2 = f(x2);
+ double y1 = f(x1);
+
+ return (y2 - y1) / (x2 - x1);
+}
+#+END_SRC
+
+*** ~forward_derivative_at~
++ Author: Elizabeth Hunt
++ Name: ~forward_derivative_at~
++ Location: ~src/approx_derivative.c~
++ Input:
+ - ~f~ is a pointer to a one-ary function that takes a double as input and produces
+ a double as output
+ - ~a~ is the domain value at which we approximate ~f'~
+ - ~h~ is the step size
++ Output: a ~double~ of the approximate value of ~f'(a)~ via the forward difference
+ method.
+
+#+BEGIN_SRC c
+double forward_derivative_at(double (*f)(double), double a, double h) {
+ assert(h > 0);
+
+ double x2 = a + h;
+ double x1 = a;
+
+ double y2 = f(x2);
+ double y1 = f(x1);
+
+ return (y2 - y1) / (x2 - x1);
+}
+#+END_SRC
+
+*** ~backward_derivative_at~
++ Author: Elizabeth Hunt
++ Name: ~backward_derivative_at~
++ Location: ~src/approx_derivative.c~
++ Input:
+ - ~f~ is a pointer to a one-ary function that takes a double as input and produces
+ a double as output
+ - ~a~ is the domain value at which we approximate ~f'~
+ - ~h~ is the step size
++ Output: a ~double~ of the approximate value of ~f'(a)~ via the backward difference
+ method.
+
+#+BEGIN_SRC c
+double backward_derivative_at(double (*f)(double), double a, double h) {
+ assert(h > 0);
+
+ double x2 = a;
+ double x1 = a - h;
+
+ double y2 = f(x2);
+ double y1 = f(x1);
+
+ return (y2 - y1) / (x2 - x1);
+}
+#+END_SRC
+
+** Vector Routines
+*** Vector Arithmetic: ~add_v, minus_v~
++ Author: Elizabeth Hunt
++ Name(s): ~add_v~, ~minus_v~
++ Location: ~src/vector.c~
++ Input: two pointers to locations in memory wherein ~Array_double~'s lie
++ Output: a pointer to a new ~Array_double~ as the result of addition or subtraction
+ of the two input ~Array_double~'s
+
+#+BEGIN_SRC c
+Array_double *add_v(Array_double *v1, Array_double *v2) {
+ assert(v1->size == v2->size);
+
+ Array_double *sum = copy_vector(v1);
+ for (size_t i = 0; i < v1->size; i++)
+ sum->data[i] += v2->data[i];
+ return sum;
+}
+
+Array_double *minus_v(Array_double *v1, Array_double *v2) {
+ assert(v1->size == v2->size);
+
+ Array_double *sub = InitArrayWithSize(double, v1->size, 0);
+ for (size_t i = 0; i < v1->size; i++)
+ sub->data[i] = v1->data[i] - v2->data[i];
+ return sub;
+}
+#+END_SRC
+
+*** Norms: ~l1_norm~, ~l2_norm~, ~linf_norm~
++ Author: Elizabeth Hunt
++ Name(s): ~l1_norm~, ~l2_norm~, ~linf_norm~
++ Location: ~src/vector.c~
++ Input: a pointer to a location in memory wherein an ~Array_double~ lies
++ Output: a ~double~ representing the value of the norm the function applies
+
+#+BEGIN_SRC c
+double l1_norm(Array_double *v) {
+ double sum = 0;
+ for (size_t i = 0; i < v->size; ++i)
+ sum += fabs(v->data[i]);
+ return sum;
+}
+
+double l2_norm(Array_double *v) {
+ double norm = 0;
+ for (size_t i = 0; i < v->size; ++i)
+ norm += v->data[i] * v->data[i];
+ return sqrt(norm);
+}
+
+double linf_norm(Array_double *v) {
+ assert(v->size > 0);
+ double max = v->data[0];
+ for (size_t i = 0; i < v->size; ++i)
+ max = c_max(v->data[i], max);
+ return max;
+}
+#+END_SRC
+
+*** ~vector_distance~
++ Author: Elizabeth Hunt
++ Name: ~vector_distance~
++ Location: ~src/vector.c~
++ Input: two pointers to locations in memory wherein ~Array_double~'s lie, and a pointer to a
+ one-ary function ~norm~ taking as input a pointer to an ~Array_double~ and returning a double
+ representing the norm of that ~Array_double~
+
+#+BEGIN_SRC c
+double vector_distance(Array_double *v1, Array_double *v2,
+ double (*norm)(Array_double *)) {
+ Array_double *minus = minus_v(v1, v2);
+ double dist = (*norm)(minus);
+ free(minus);
+ return dist;
+}
+#+END_SRC
+
+*** Distances: ~l1_distance~, ~l2_distance~, ~linf_distance~
++ Author: Elizabeth Hunt
++ Name(s): ~l1_distance~, ~l2_distance~, ~linf_distance~
++ Location: ~src/vector.c~
++ Input: two pointers to locations in memory wherein ~Array_double~'s lie, and the distance
+ via the corresponding ~l1~, ~l2~, or ~linf~ norms
++ Output: A ~double~ representing the distance between the two ~Array_doubles~'s by the given
+ norm.
+
+#+BEGIN_SRC c
+double l1_distance(Array_double *v1, Array_double *v2) {
+ return vector_distance(v1, v2, &l1_norm);
+}
+
+double l2_distance(Array_double *v1, Array_double *v2) {
+ return vector_distance(v1, v2, &l2_norm);
+}
+
+double linf_distance(Array_double *v1, Array_double *v2) {
+ return vector_distance(v1, v2, &linf_norm);
+}
+#+END_SRC
+
+*** ~sum_v~
++ Author: Elizabeth Hunt
++ Name: ~sum_v~
++ Location: ~src/vector.c~
++ Input: a pointer to an ~Array_double~
++ Output: a ~double~ representing the sum of all the elements of an ~Array_double~
+
+#+BEGIN_SRC c
+double sum_v(Array_double *v) {
+ double sum = 0;
+ for (size_t i = 0; i < v->size; i++)
+ sum += v->data[i];
+ return sum;
+}
+#+END_SRC
+
+*** ~scale_v~
++ Author: Elizabeth Hunt
++ Name: ~scale_v~
++ Location: ~src/vector.c~
++ Input: a pointer to an ~Array_double~ and a scalar ~double~ to scale the vector
++ Output: a pointer to a new ~Array_double~ of the scaled input ~Array_double~
+
+#+BEGIN_SRC c
+Array_double *scale_v(Array_double *v, double m) {
+ Array_double *copy = copy_vector(v);
+ for (size_t i = 0; i < v->size; i++)
+ copy->data[i] *= m;
+ return copy;
+}
+#+END_SRC
+
+*** ~free_vector~
++ Author: Elizabeth Hunt
++ Name: ~free_vector~
++ Location: ~src/vector.c~
++ Input: a pointer to an ~Array_double~
++ Output: nothing.
++ Side effect: free the memory of the reserved ~Array_double~ on the heap
+
+#+BEGIN_SRC c
+void free_vector(Array_double *v) {
+ free(v->data);
+ free(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~
++ Location: ~src/vector.c~
++ Input: a pointer to an ~Array_double~
++ Output: a pointer to a new ~Array_double~ whose ~data~ and ~size~ are copied from the input
+ ~Array_double~
+
+#+BEGIN_SRC c
+Array_double *copy_vector(Array_double *v) {
+ Array_double *copy = InitArrayWithSize(double, v->size, 0.0);
+ for (size_t i = 0; i < copy->size; ++i)
+ copy->data[i] = v->data[i];
+ return copy;
+}
+#+END_SRC
+
+*** ~format_vector_into~
++ Author: Elizabeth Hunt
++ Name: ~format_vector_into~
++ Location: ~src/vector.c~
++ Input: a pointer to an ~Array_double~ and a pointer to a c-string ~s~ to "print" the vector out
+ into
++ Output: nothing.
++ Side effect: overwritten memory into ~s~
+
+#+BEGIN_SRC c
+void format_vector_into(Array_double *v, char *s) {
+ if (v->size == 0) {
+ strcat(s, "empty");
+ return;
+ }
+
+ for (size_t i = 0; i < v->size; ++i) {
+ char num[64];
+ strcpy(num, "");
+
+ sprintf(num, "%f,", v->data[i]);
+ strcat(s, num);
+ }
+ strcat(s, "\n");
+}
+#+END_SRC
+
+** Matrix Routines
+*** ~lu_decomp~
++ Author: Elizabeth Hunt
++ Name: ~lu_decomp~
++ Location: ~src/matrix.c~
++ Input: a pointer to a ~Matrix_double~ $m$ to decompose into a lower triangular and upper triangular
+ 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: 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 *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);
+
+ 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");
+ 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
++ Name: ~bsubst~
++ Location: ~src/matrix.c~
++ Input: a pointer to an upper-triangular ~Matrix_double~ $u$ and a ~Array_double~
+ $b$
++ Output: a pointer to a new ~Array_double~ whose entries are given by performing
+ back substitution
+
+#+BEGIN_SRC c
+Array_double *bsubst(Matrix_double *u, Array_double *b) {
+ assert(u->rows == b->size && u->cols == u->rows);
+
+ Array_double *x = copy_vector(b);
+ for (int64_t row = b->size - 1; row >= 0; row--) {
+ for (size_t col = b->size - 1; col > row; col--)
+ x->data[row] -= x->data[col] * u->data[row]->data[col];
+ x->data[row] /= u->data[row]->data[row];
+ }
+ return x;
+}
+#+END_SRC
+*** ~fsubst~
++ Author: Elizabeth Hunt
++ Name: ~fsubst~
++ Location: ~src/matrix.c~
++ Input: a pointer to a lower-triangular ~Matrix_double~ $l$ and a ~Array_double~
+ $b$
++ Output: a pointer to a new ~Array_double~ whose entries are given by performing
+ forward substitution
+
+#+BEGIN_SRC c
+Array_double *fsubst(Matrix_double *l, Array_double *b) {
+ assert(l->rows == b->size && l->cols == l->rows);
+
+ Array_double *x = copy_vector(b);
+
+ for (size_t row = 0; row < b->size; row++) {
+ for (size_t col = 0; col < row; col++)
+ x->data[row] -= x->data[col] * l->data[row]->data[col];
+ x->data[row] /= l->data[row]->data[row];
+ }
+
+ return x;
+}
+#+END_SRC
+
+*** ~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$
++ Output: $x$ such that $mx = b$ if such a solution exists (else it's non LU-factorable as discussed
+ above)
+
+Here we make use of forward substitution to first solve $Ly = b$ given $L$ as the $L$ factor in
+~lu_decomp~. Then we use back substitution to solve $Ux = y$ for $x$ similarly given $U$.
+
+Then, $LUx = b$, thus $x$ is a solution.
+
+#+BEGIN_SRC c
+Array_double *solve_matrix_lu_bsubst(Matrix_double *m, Array_double *b) {
+ assert(b->size == m->rows);
+ assert(m->rows == m->cols);
+
+ Array_double *x = copy_vector(b);
+ Matrix_double **u_l = lu_decomp(m);
+ Matrix_double *u = u_l[0];
+ Matrix_double *l = u_l[1];
+
+ Array_double *b_fsub = fsubst(l, b);
+ x = bsubst(u, b_fsub);
+ free_vector(b_fsub);
+
+ free_matrix(u);
+ free_matrix(l);
+ 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, k = 0;
+
+ Matrix_double *m_cp = copy_matrix(m);
+
+ while (h < m_cp->rows && k < m_cp->cols) {
+ uint64_t max_row = h;
+ double max_val = 0.0;
+
+ for (uint64_t row = h; row < m_cp->rows; row++) {
+ double val = fabs(m_cp->data[row]->data[k]);
+ if (val > max_val) {
+ max_val = val;
+ max_row = row;
+ }
+ }
+
+ if (max_val == 0.0) {
+ k++;
+ continue;
+ }
+
+ if (max_row != h) {
+ Array_double *swp = m_cp->data[max_row];
+ m_cp->data[max_row] = m_cp->data[h];
+ m_cp->data[h] = swp;
+ }
+
+ 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~
++ Input: a pointer to a ~Matrix_double~ $m$ and ~Array_double~ $v$
++ Output: the dot product $mv$ as an ~Array_double~
+
+#+BEGIN_SRC c
+Array_double *m_dot_v(Matrix_double *m, Array_double *v) {
+ assert(v->size == m->cols);
+
+ Array_double *product = copy_vector(v);
+
+ for (size_t row = 0; row < v->size; ++row)
+ product->data[row] = v_dot_v(m->data[row], v);
+
+ return product;
+}
+#+END_SRC
+
+*** ~put_identity_diagonal~
++ Author: Elizabeth Hunt
++ Location: ~src/matrix.c~
++ Input: a pointer to a ~Matrix_double~
++ Output: a pointer to a copy to ~Matrix_double~ whose diagonal is full of 1's
+
+#+BEGIN_SRC c
+Matrix_double *put_identity_diagonal(Matrix_double *m) {
+ assert(m->rows == m->cols);
+ Matrix_double *copy = copy_matrix(m);
+ for (size_t y = 0; y < m->rows; ++y)
+ copy->data[y]->data[y] = 1.0;
+ return copy;
+}
+#+END_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~
++ Input: a pointer to a ~Matrix_double~
++ Output: a pointer to a copy of the given ~Matrix_double~
+
+#+BEGIN_SRC c
+Matrix_double *copy_matrix(Matrix_double *m) {
+ Matrix_double *copy = InitMatrixWithSize(double, m->rows, m->cols, 0.0);
+ for (size_t y = 0; y < copy->rows; y++) {
+ free_vector(copy->data[y]);
+ copy->data[y] = copy_vector(m->data[y]);
+ }
+ return copy;
+}
+#+END_SRC
+
+*** ~free_matrix~
++ Author: Elizabeth Hunt
++ Location: ~src/matrix.c~
++ Input: a pointer to a ~Matrix_double~
++ Output: none.
++ Side Effects: frees memory reserved by a given ~Matrix_double~ and its member
+ ~Array_double~ vectors describing its rows.
+
+#+BEGIN_SRC c
+void free_matrix(Matrix_double *m) {
+ for (size_t y = 0; y < m->rows; ++y)
+ free_vector(m->data[y]);
+ free(m);
+}
+#+END_SRC
+
+*** ~format_matrix_into~
++ Author: Elizabeth Hunt
++ Name: ~format_matrix_into~
++ Location: ~src/matrix.c~
++ Input: a pointer to a ~Matrix_double~ and a pointer to a c-string ~s~ to "print" the vector out
+ into
++ Output: nothing.
++ Side effect: overwritten memory into ~s~
+
+#+BEGIN_SRC c
+void format_matrix_into(Matrix_double *m, char *s) {
+ if (m->rows == 0)
+ strcpy(s, "empty");
+
+ for (size_t y = 0; y < m->rows; ++y) {
+ char row_s[5192];
+ strcpy(row_s, "");
+
+ format_vector_into(m->data[y], row_s);
+ strcat(s, row_s);
+ }
+ strcat(s, "\n");
+}
+#+END_SRC
+** Root Finding Methods
+*** ~find_ivt_range~
++ Author: Elizabeth Hunt
++ Name: ~find_ivt_range~
++ Location: ~src/roots.c~
++ 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
+ iterations to perform.
++ Output: a pair of ~double~'s in an ~Array_double~ representing a closed closed interval ~[beginning, end]~
+
+#+BEGIN_SRC c
+// f is well defined at start_x + delta*n for all n on the integer range [0,
+// max_iterations]
+Array_double *find_ivt_range(double (*f)(double), double start_x, double delta,
+ size_t max_iterations) {
+ double a = start_x;
+
+ while (f(a) * f(a + delta) >= 0 && max_iterations > 0) {
+ max_iterations--;
+ a += delta;
+ }
+
+ double end = a + delta;
+ double begin = a - delta;
+
+ if (max_iterations == 0 && f(begin) * f(end) >= 0)
+ return NULL;
+ return InitArray(double, {begin, end});
+}
+#+END_SRC
+*** ~bisect_find_root~
++ Author: Elizabeth Hunt
++ Name(s): ~bisect_find_root~
++ 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 once $b-a < \text{tolerance}$, and a
+ ~max_iterations~ to break us out of a loop if we can never reach the ~tolerance~.
++ 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
+ also assume the function ~f~ is continuous on ~[a, b]~.
+
+#+BEGIN_SRC c
+// f is continuous on [a, b]
+Array_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 InitArray(double, {a, b, 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);
+}
+#+END_SRC
+*** ~bisect_find_root_with_error_assumption~
++ Author: Elizabeth Hunt
++ Name: ~bisect_find_root_with_error_assumption~
++ 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~ equivalent to the above definition in ~bisect_find_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
+ calculate $k$ at the worst possible case (that the error is exactly the tolerance) to be
+ $\frac{log(tolerance) - log(b_0 - a_0)}{log(\frac{1}{2})}$. We pass this value into the ~max_iterations~
+ of ~bisect_find_root~ as above.
+#+BEGIN_SRC c
+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));
+
+ 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
+
+** Linear Routines
+*** ~least_squares_lin_reg~
++ Author: Elizabeth Hunt
++ Name: ~least_squares_lin_reg~
++ Location: ~src/lin.c~
++ Input: two pointers to ~Array_double~'s whose entries correspond two ordered
+ pairs in R^2
++ Output: a linear model best representing the ordered pairs via least squares
+ regression
+
+#+BEGIN_SRC c
+Line *least_squares_lin_reg(Array_double *x, Array_double *y) {
+ assert(x->size == y->size);
+
+ uint64_t n = x->size;
+ double sum_x = sum_v(x);
+ double sum_y = sum_v(y);
+ double sum_xy = v_dot_v(x, y);
+ double sum_xx = v_dot_v(x, x);
+ double denom = ((n * sum_xx) - (sum_x * sum_x));
+
+ Line *line = malloc(sizeof(Line));
+ line->m = ((sum_xy * n) - (sum_x * sum_y)) / denom;
+ line->a = ((sum_y * sum_xx) - (sum_x * sum_xy)) / denom;
+
+ return line;
+}
+#+END_SRC
+
+** Eigen-Adjacent
+*** ~dominant_eigenvalue~
++ Author: Elizabeth Hunt
++ Name: ~dominant_eigenvalue~
++ Location: ~src/eigen.c~
++ Input: a pointer to an invertible matrix ~m~, an initial eigenvector guess ~v~ (that is non
+ zero or orthogonal to an eigenvector with the dominant eigenvalue), a ~tolerance~ and
+ ~max_iterations~ that act as stop conditions
++ Output: the dominant eigenvalue with the highest magnitude, approximated with the Power
+ Iteration Method
+
+#+BEGIN_SRC c
+double dominant_eigenvalue(Matrix_double *m, Array_double *v, double tolerance,
+ size_t max_iterations) {
+ assert(m->rows == m->cols);
+ assert(m->rows == v->size);
+
+ double error = tolerance;
+ size_t iter = max_iterations;
+ double lambda = 0.0;
+ Array_double *eigenvector_1 = copy_vector(v);
+
+ while (error >= tolerance && (--iter) > 0) {
+ Array_double *eigenvector_2 = m_dot_v(m, eigenvector_1);
+ Array_double *normalized_eigenvector_2 =
+ scale_v(eigenvector_2, 1.0 / linf_norm(eigenvector_2));
+ free_vector(eigenvector_2);
+ eigenvector_2 = normalized_eigenvector_2;
+
+ Array_double *mx = m_dot_v(m, eigenvector_2);
+ double new_lambda =
+ v_dot_v(mx, eigenvector_2) / v_dot_v(eigenvector_2, eigenvector_2);
+
+ error = fabs(new_lambda - lambda);
+ lambda = new_lambda;
+ free_vector(eigenvector_1);
+ eigenvector_1 = eigenvector_2;
+ }
+
+ return lambda;
+}
+#+END_SRC
+*** ~shift_inverse_power_eigenvalue~
++ Author: Elizabeth Hunt
++ Name: ~least_dominant_eigenvalue~
++ Location: ~src/eigen.c~
++ Input: a pointer to an invertible matrix ~m~, an initial eigenvector guess ~v~ (that is non
+ zero or orthogonal to an eigenvector with the dominant eigenvalue), a ~shift~ to act as the
+ shifted \delta, and ~tolerance~ and ~max_iterations~ that act as stop conditions.
++ Output: the eigenvalue closest to ~shift~ with the lowest magnitude closest to 0, approximated
+ with the Inverse Power Iteration Method
+#+BEGIN_SRC c
+double shift_inverse_power_eigenvalue(Matrix_double *m, Array_double *v,
+ double shift, double tolerance,
+ size_t max_iterations) {
+ assert(m->rows == m->cols);
+ assert(m->rows == v->size);
+
+ Matrix_double *m_c = copy_matrix(m);
+ for (size_t y = 0; y < m_c->rows; ++y)
+ m_c->data[y]->data[y] = m_c->data[y]->data[y] - shift;
+
+ double error = tolerance;
+ size_t iter = max_iterations;
+ double lambda = shift;
+ Array_double *eigenvector_1 = copy_vector(v);
+
+ while (error >= tolerance && (--iter) > 0) {
+ Array_double *eigenvector_2 = solve_matrix_lu_bsubst(m_c, eigenvector_1);
+ Array_double *normalized_eigenvector_2 =
+ scale_v(eigenvector_2, 1.0 / linf_norm(eigenvector_2));
+ free_vector(eigenvector_2);
+
+ Array_double *mx = m_dot_v(m, normalized_eigenvector_2);
+ double new_lambda =
+ v_dot_v(mx, normalized_eigenvector_2) /
+ v_dot_v(normalized_eigenvector_2, normalized_eigenvector_2);
+
+ error = fabs(new_lambda - lambda);
+ lambda = new_lambda;
+ free_vector(eigenvector_1);
+ eigenvector_1 = normalized_eigenvector_2;
+ }
+
+ return lambda;
+}
+#+END_SRC
+
+*** ~least_dominant_eigenvalue~
++ Author: Elizabeth Hunt
++ Name: ~least_dominant_eigenvalue~
++ Location: ~src/eigen.c~
++ Input: a pointer to an invertible matrix ~m~, an initial eigenvector guess ~v~ (that is non
+ zero or orthogonal to an eigenvector with the dominant eigenvalue), a ~tolerance~ and
+ ~max_iterations~ that act as stop conditions.
++ Output: the least dominant eigenvalue with the lowest magnitude closest to 0, approximated
+ with the Inverse Power Iteration Method.
+#+BEGIN_SRC c
+double least_dominant_eigenvalue(Matrix_double *m, Array_double *v,
+ double tolerance, size_t max_iterations) {
+ return shift_inverse_power_eigenvalue(m, v, 0.0, tolerance, max_iterations);
+}
+#+END_SRC
+*** ~partition_find_eigenvalues~
++ Author: Elizabeth Hunt
++ Name: ~partition_find_eigenvalues~
++ Location: ~src/eigen.c~
++ Input: a pointer to an invertible matrix ~m~, a matrix whose rows correspond to initial
+ eigenvector guesses at each "partition" which is computed from a uniform distribution
+ between the number of rows this "guess matrix" has and the distance between the least
+ dominant eigenvalue and the most dominant. Additionally, a ~max_iterations~ and a ~tolerance~
+ that act as stop conditions.
++ Output: a vector of ~doubles~ corresponding to the "nearest" eigenvalue at the midpoint of
+ each partition, via the given guess of that partition.
+#+BEGIN_SRC c
+Array_double *partition_find_eigenvalues(Matrix_double *m,
+ Matrix_double *guesses,
+ double tolerance,
+ size_t max_iterations) {
+ assert(guesses->rows >=
+ 2); // we need at least, the most and least dominant eigenvalues
+
+ double end = dominant_eigenvalue(m, guesses->data[guesses->rows - 1],
+ tolerance, max_iterations);
+ double begin =
+ least_dominant_eigenvalue(m, guesses->data[0], tolerance, max_iterations);
+
+ double delta = (end - begin) / guesses->rows;
+ Array_double *eigenvalues = InitArrayWithSize(double, guesses->rows, 0.0);
+ for (size_t i = 0; i < guesses->rows; i++) {
+ double box_midpoint = ((delta * i) + (delta * (i + 1))) / 2;
+
+ double nearest_eigenvalue = shift_inverse_power_eigenvalue(
+ m, guesses->data[i], box_midpoint, tolerance, max_iterations);
+
+ eigenvalues->data[i] = nearest_eigenvalue;
+ }
+
+ return eigenvalues;
+}
+#+END_SRC
+*** ~leslie_matrix~
++ Author: Elizabeth Hunt
++ Name: ~leslie_matrix~
++ Location: ~src/eigen.c~
++ Input: two pointers to ~Array_double~'s representing the ratio of individuals in an age class
+ $x$ getting to the next age class $x+1$ and the number of offspring that individuals in an age
+ class create in age class 0.
++ Output: the leslie matrix generated from the input vectors.
+
+#+BEGIN_SRC c
+Matrix_double *leslie_matrix(Array_double *age_class_surivor_ratio,
+ Array_double *age_class_offspring) {
+ assert(age_class_surivor_ratio->size + 1 == age_class_offspring->size);
+
+ Matrix_double *leslie = InitMatrixWithSize(double, age_class_offspring->size,
+ age_class_offspring->size, 0.0);
+
+ free_vector(leslie->data[0]);
+ leslie->data[0] = age_class_offspring;
+
+ for (size_t i = 0; i < age_class_surivor_ratio->size; i++)
+ leslie->data[i + 1]->data[i] = age_class_surivor_ratio->data[i];
+ return leslie;
+}
+#+END_SRC
+** Jacobi / Gauss-Siedel
+*** ~jacobi_solve~
++ Author: Elizabeth Hunt
++ Name: ~jacobi_solve~
++ Location: ~src/matrix.c~
++ Input: a pointer to a diagonally dominant square matrix $m$, a vector representing
+ the value $b$ in $mx = b$, a double representing the maximum distance between
+ the solutions produced by iteration $i$ and $i+1$ (by L2 norm a.k.a cartesian
+ distance), and a ~max_iterations~ which we force stop.
++ Output: the converged-upon solution $x$ to $mx = b$
+#+BEGIN_SRC c
+Array_double *jacobi_solve(Matrix_double *m, Array_double *b,
+ double l2_convergence_tolerance,
+ size_t max_iterations) {
+ assert(m->rows == m->cols);
+ assert(b->size == m->cols);
+ size_t iter = max_iterations;
+
+ Array_double *x_k = InitArrayWithSize(double, b->size, 0.0);
+ Array_double *x_k_1 =
+ InitArrayWithSize(double, b->size, rand_from(0.1, 10.0));
+
+ while ((--iter) > 0 && l2_distance(x_k_1, x_k) > l2_convergence_tolerance) {
+ for (size_t i = 0; i < m->rows; i++) {
+ double delta = 0.0;
+ for (size_t j = 0; j < m->cols; j++) {
+ if (i == j)
+ continue;
+ delta += m->data[i]->data[j] * x_k->data[j];
+ }
+ x_k_1->data[i] = (b->data[i] - delta) / m->data[i]->data[i];
+ }
+
+ Array_double *tmp = x_k;
+ x_k = x_k_1;
+ x_k_1 = tmp;
+ }
+
+ free_vector(x_k);
+ return x_k_1;
+}
+#+END_SRC
+
+*** ~gauss_siedel_solve~
++ Author: Elizabeth Hunt
++ Name: ~gauss_siedel_solve~
++ Location: ~src/matrix.c~
++ Input: a pointer to a [[https://en.wikipedia.org/wiki/Gauss%E2%80%93Seidel_method][diagonally dominant or symmetric and positive definite]]
+ square matrix $m$, a vector representing
+ the value $b$ in $mx = b$, a double representing the maximum distance between
+ the solutions produced by iteration $i$ and $i+1$ (by L2 norm a.k.a cartesian
+ distance), and a ~max_iterations~ which we force stop.
++ Output: the converged-upon solution $x$ to $mx = b$
++ Description: we use almost the exact same method as ~jacobi_solve~ but modify
+ only one array in accordance to the Gauss-Siedel method, but which is necessarily
+ copied before due to the convergence check.
+#+BEGIN_SRC c
+
+Array_double *gauss_siedel_solve(Matrix_double *m, Array_double *b,
+ double l2_convergence_tolerance,
+ size_t max_iterations) {
+ assert(m->rows == m->cols);
+ assert(b->size == m->cols);
+ size_t iter = max_iterations;
+
+ Array_double *x_k = InitArrayWithSize(double, b->size, 0.0);
+ Array_double *x_k_1 =
+ InitArrayWithSize(double, b->size, rand_from(0.1, 10.0));
+
+ while ((--iter) > 0) {
+ for (size_t i = 0; i < x_k->size; i++)
+ x_k->data[i] = x_k_1->data[i];
+
+ for (size_t i = 0; i < m->rows; i++) {
+ double delta = 0.0;
+ for (size_t j = 0; j < m->cols; j++) {
+ if (i == j)
+ continue;
+ delta += m->data[i]->data[j] * x_k_1->data[j];
+ }
+ x_k_1->data[i] = (b->data[i] - delta) / m->data[i]->data[i];
+ }
+
+ if (l2_distance(x_k_1, x_k) <= l2_convergence_tolerance)
+ break;
+ }
+
+ free_vector(x_k);
+ return x_k_1;
+}
+#+END_SRC
+
+** Appendix / Miscellaneous
+*** Random
++ Author: Elizabeth Hunt
++ Name: ~rand_from~
++ Location: ~src/rand.c~
++ Input: a pair of doubles, min and max to generate a random number min
+ \le x \le max
++ Output: a random double in the constraints shown
+
+#+BEGIN_SRC c
+double rand_from(double min, double max) {
+ return min + (rand() / (RAND_MAX / (max - min)));
+}
+#+END_SRC
+*** Data Types
+**** ~Line~
++ Author: Elizabeth Hunt
++ Location: ~inc/types.h~
+
+#+BEGIN_SRC c
+typedef struct Line {
+ double m;
+ double a;
+} Line;
+#+END_SRC
+**** The ~Array_<type>~ and ~Matrix_<type>~
++ Author: Elizabeth Hunt
++ Location: ~inc/types.h~
+
+We define two Pre processor Macros ~DEFINE_ARRAY~ and ~DEFINE_MATRIX~ that take
+as input a type, and construct a struct definition for the given type for
+convenient access to the vector or matrices dimensions.
+
+Such that ~DEFINE_ARRAY(int)~ would expand to:
+
+#+BEGIN_SRC c
+ typedef struct {
+ int* data;
+ size_t size;
+ } Array_int
+#+END_SRC
+
+And ~DEFINE_MATRIX(int)~ would expand a to ~Matrix_int~; containing a pointer to
+a collection of pointers of ~Array_int~'s and its dimensions.
+
+#+BEGIN_SRC c
+ typedef struct {
+ Array_int **data;
+ size_t cols;
+ size_t rows;
+ } Matrix_int
+#+END_SRC
+
+*** Macros
+**** ~c_max~ and ~c_min~
++ Author: Elizabeth Hunt
++ Location: ~inc/macros.h~
++ Input: two structures that define an order measure
++ Output: either the larger or smaller of the two depending on the measure
+
+#+BEGIN_SRC c
+#define c_max(x, y) (((x) >= (y)) ? (x) : (y))
+#define c_min(x, y) (((x) <= (y)) ? (x) : (y))
+#+END_SRC
+
+**** ~InitArray~
++ Author: Elizabeth Hunt
++ Location: ~inc/macros.h~
++ Input: a type and array of values to initialze an array with such type
++ Output: a new ~Array_type~ with the size of the given array and its data
+
+#+BEGIN_SRC c
+#define InitArray(TYPE, ...) \
+ ({ \
+ TYPE temp[] = __VA_ARGS__; \
+ Array_##TYPE *arr = malloc(sizeof(Array_##TYPE)); \
+ arr->size = sizeof(temp) / sizeof(temp[0]); \
+ arr->data = malloc(arr->size * sizeof(TYPE)); \
+ memcpy(arr->data, temp, arr->size * sizeof(TYPE)); \
+ arr; \
+ })
+#+END_SRC
+
+**** ~InitArrayWithSize~
++ Author: Elizabeth Hunt
++ Location: ~inc/macros.h~
++ Input: a type, a size, and initial value
++ Output: a new ~Array_type~ with the given size filled with the initial value
+
+#+BEGIN_SRC c
+#define InitArrayWithSize(TYPE, SIZE, INIT_VALUE) \
+ ({ \
+ Array_##TYPE *arr = malloc(sizeof(Array_##TYPE)); \
+ arr->size = SIZE; \
+ arr->data = malloc(arr->size * sizeof(TYPE)); \
+ for (size_t i = 0; i < arr->size; i++) \
+ arr->data[i] = INIT_VALUE; \
+ arr; \
+ })
+#+END_SRC
+
+**** ~InitMatrixWithSize~
++ Author: Elizabeth Hunt
++ Location: ~inc/macros.h~
++ Input: a type, number of rows, columns, and initial value
++ Output: a new ~Matrix_type~ of size ~rows x columns~ filled with the initial
+ value
+
+#+BEGIN_SRC c
+#define InitMatrixWithSize(TYPE, ROWS, COLS, INIT_VALUE) \
+ ({ \
+ Matrix_##TYPE *matrix = malloc(sizeof(Matrix_##TYPE)); \
+ matrix->rows = ROWS; \
+ matrix->cols = COLS; \
+ matrix->data = malloc(matrix->rows * sizeof(Array_##TYPE *)); \
+ for (size_t y = 0; y < matrix->rows; y++) \
+ matrix->data[y] = InitArrayWithSize(TYPE, COLS, INIT_VALUE); \
+ matrix; \
+ })
+#+END_SRC
+
diff --git a/Homework/math4610/doc/software_manual.pdf b/Homework/math4610/doc/software_manual.pdf
new file mode 100644
index 0000000..1772e7c
--- /dev/null
+++ b/Homework/math4610/doc/software_manual.pdf
Binary files differ
diff --git a/Homework/math4610/doc/software_manual.tex b/Homework/math4610/doc/software_manual.tex
new file mode 100644
index 0000000..dac099b
--- /dev/null
+++ b/Homework/math4610/doc/software_manual.tex
@@ -0,0 +1,1583 @@
+% Created 2023-12-11 Mon 19:22
+% 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{LIZFCM Software Manual (v0.6)}
+\hypersetup{
+ pdfauthor={Elizabeth Hunt},
+ pdftitle={LIZFCM Software Manual (v0.6)},
+ pdfkeywords={},
+ pdfsubject={},
+ pdfcreator={Emacs 28.2 (Org mode 9.7-pre)},
+ pdflang={English}}
+\begin{document}
+
+\maketitle
+\tableofcontents
+
+\setlength\parindent{0pt}
+
+\section{Design}
+\label{sec:org63deaf6}
+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
+to the table.
+
+All of the work established in \texttt{deprecated-cl} has been painstakingly translated into
+the C programming language. I have a couple tenets for its design:
+
+\begin{itemize}
+\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 "modules" that follow a form of separation of concerns
+in files, and not individual files per function.
+\end{itemize}
+
+\section{Compilation}
+\label{sec:org7291327}
+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.
+
+\begin{enumerate}
+\item \texttt{cd} into the root of the repo
+\item \texttt{make}
+\end{enumerate}
+
+Then, as of homework 5, the testing routines are provided in \texttt{test} and utilize the
+\texttt{utest} "micro"library. They compile to a binary in \texttt{./dist/lizfcm.test}.
+
+Execution of the Makefile will perform compilation of individual routines.
+
+But, in the requirement of manual intervention (should the little alien workers
+inside the computer fail to do their job), one can use the following command to
+produce an object file:
+
+\begin{verbatim}
+ gcc -Iinc/ -lm -Wall -c src/<the_routine>.c -o build/<the_routine>.o
+\end{verbatim}
+
+Which is then bundled into a static library in \texttt{lib/lizfcm.a} and can be linked
+in the standard method.
+
+\section{The LIZFCM API}
+\label{sec:org1ebe7fa}
+\subsection{Simple Routines}
+\label{sec:orgff18c6b}
+\subsubsection{\texttt{smaceps}}
+\label{sec:org443df5e}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name: \texttt{smaceps}
+\item Location: \texttt{src/maceps.c}
+\item Input: none
+\item Output: a \texttt{float} returning the specific "Machine Epsilon" of a machine on a
+single precision floating point number at which it becomes "indistinguishable".
+\end{itemize}
+
+\begin{verbatim}
+float smaceps() {
+ float one = 1.0;
+ float machine_epsilon = 1.0;
+ float one_approx = one + machine_epsilon;
+
+ while (fabsf(one_approx - one) > 0) {
+ machine_epsilon /= 2;
+ one_approx = one + machine_epsilon;
+ }
+
+ return machine_epsilon;
+}
+\end{verbatim}
+
+\subsubsection{\texttt{dmaceps}}
+\label{sec:org5121603}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name: \texttt{dmaceps}
+\item Location: \texttt{src/maceps.c}
+\item Input: none
+\item Output: a \texttt{double} returning the specific "Machine Epsilon" of a machine on a
+double precision floating point number at which it becomes "indistinguishable".
+\end{itemize}
+
+\begin{verbatim}
+double dmaceps() {
+ double one = 1.0;
+ double machine_epsilon = 1.0;
+ double one_approx = one + machine_epsilon;
+
+ while (fabs(one_approx - one) > 0) {
+ machine_epsilon /= 2;
+ one_approx = one + machine_epsilon;
+ }
+
+ return machine_epsilon;
+}
+\end{verbatim}
+
+\subsection{Derivative Routines}
+\label{sec:org6fd324c}
+\subsubsection{\texttt{central\_derivative\_at}}
+\label{sec:orge9f0821}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name: \texttt{central\_derivative\_at}
+\item Location: \texttt{src/approx\_derivative.c}
+\item Input:
+\begin{itemize}
+\item \texttt{f} is a pointer to a one-ary function that takes a double as input and produces
+a double as output
+\item \texttt{a} is the domain value at which we approximate \texttt{f'}
+\item \texttt{h} is the step size
+\end{itemize}
+\item Output: a \texttt{double} of the approximate value of \texttt{f'(a)} via the central difference
+method.
+\end{itemize}
+
+\begin{verbatim}
+double central_derivative_at(double (*f)(double), double a, double h) {
+ assert(h > 0);
+
+ double x2 = a + h;
+ double x1 = a - h;
+
+ double y2 = f(x2);
+ double y1 = f(x1);
+
+ return (y2 - y1) / (x2 - x1);
+}
+\end{verbatim}
+
+\subsubsection{\texttt{forward\_derivative\_at}}
+\label{sec:org8720f28}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name: \texttt{forward\_derivative\_at}
+\item Location: \texttt{src/approx\_derivative.c}
+\item Input:
+\begin{itemize}
+\item \texttt{f} is a pointer to a one-ary function that takes a double as input and produces
+a double as output
+\item \texttt{a} is the domain value at which we approximate \texttt{f'}
+\item \texttt{h} is the step size
+\end{itemize}
+\item Output: a \texttt{double} of the approximate value of \texttt{f'(a)} via the forward difference
+method.
+\end{itemize}
+
+\begin{verbatim}
+double forward_derivative_at(double (*f)(double), double a, double h) {
+ assert(h > 0);
+
+ double x2 = a + h;
+ double x1 = a;
+
+ double y2 = f(x2);
+ double y1 = f(x1);
+
+ return (y2 - y1) / (x2 - x1);
+}
+\end{verbatim}
+
+\subsubsection{\texttt{backward\_derivative\_at}}
+\label{sec:org1589b19}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name: \texttt{backward\_derivative\_at}
+\item Location: \texttt{src/approx\_derivative.c}
+\item Input:
+\begin{itemize}
+\item \texttt{f} is a pointer to a one-ary function that takes a double as input and produces
+a double as output
+\item \texttt{a} is the domain value at which we approximate \texttt{f'}
+\item \texttt{h} is the step size
+\end{itemize}
+\item Output: a \texttt{double} of the approximate value of \texttt{f'(a)} via the backward difference
+method.
+\end{itemize}
+
+\begin{verbatim}
+double backward_derivative_at(double (*f)(double), double a, double h) {
+ assert(h > 0);
+
+ double x2 = a;
+ double x1 = a - h;
+
+ double y2 = f(x2);
+ double y1 = f(x1);
+
+ return (y2 - y1) / (x2 - x1);
+}
+\end{verbatim}
+
+\subsection{Vector Routines}
+\label{sec:org493841e}
+\subsubsection{Vector Arithmetic: \texttt{add\_v, minus\_v}}
+\label{sec:org3912c29}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name(s): \texttt{add\_v}, \texttt{minus\_v}
+\item Location: \texttt{src/vector.c}
+\item Input: two pointers to locations in memory wherein \texttt{Array\_double}'s lie
+\item Output: a pointer to a new \texttt{Array\_double} as the result of addition or subtraction
+of the two input \texttt{Array\_double}'s
+\end{itemize}
+
+\begin{verbatim}
+Array_double *add_v(Array_double *v1, Array_double *v2) {
+ assert(v1->size == v2->size);
+
+ Array_double *sum = copy_vector(v1);
+ for (size_t i = 0; i < v1->size; i++)
+ sum->data[i] += v2->data[i];
+ return sum;
+}
+
+Array_double *minus_v(Array_double *v1, Array_double *v2) {
+ assert(v1->size == v2->size);
+
+ Array_double *sub = InitArrayWithSize(double, v1->size, 0);
+ for (size_t i = 0; i < v1->size; i++)
+ sub->data[i] = v1->data[i] - v2->data[i];
+ return sub;
+}
+\end{verbatim}
+
+\subsubsection{Norms: \texttt{l1\_norm}, \texttt{l2\_norm}, \texttt{linf\_norm}}
+\label{sec:orged74cfb}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name(s): \texttt{l1\_norm}, \texttt{l2\_norm}, \texttt{linf\_norm}
+\item Location: \texttt{src/vector.c}
+\item Input: a pointer to a location in memory wherein an \texttt{Array\_double} lies
+\item Output: a \texttt{double} representing the value of the norm the function applies
+\end{itemize}
+
+\begin{verbatim}
+double l1_norm(Array_double *v) {
+ double sum = 0;
+ for (size_t i = 0; i < v->size; ++i)
+ sum += fabs(v->data[i]);
+ return sum;
+}
+
+double l2_norm(Array_double *v) {
+ double norm = 0;
+ for (size_t i = 0; i < v->size; ++i)
+ norm += v->data[i] * v->data[i];
+ return sqrt(norm);
+}
+
+double linf_norm(Array_double *v) {
+ assert(v->size > 0);
+ double max = v->data[0];
+ for (size_t i = 0; i < v->size; ++i)
+ max = c_max(v->data[i], max);
+ return max;
+}
+\end{verbatim}
+
+\subsubsection{\texttt{vector\_distance}}
+\label{sec:org20a5773}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name: \texttt{vector\_distance}
+\item Location: \texttt{src/vector.c}
+\item Input: two pointers to locations in memory wherein \texttt{Array\_double}'s lie, and a pointer to a
+one-ary function \texttt{norm} taking as input a pointer to an \texttt{Array\_double} and returning a double
+representing the norm of that \texttt{Array\_double}
+\end{itemize}
+
+\begin{verbatim}
+double vector_distance(Array_double *v1, Array_double *v2,
+ double (*norm)(Array_double *)) {
+ Array_double *minus = minus_v(v1, v2);
+ double dist = (*norm)(minus);
+ free(minus);
+ return dist;
+}
+\end{verbatim}
+
+\subsubsection{Distances: \texttt{l1\_distance}, \texttt{l2\_distance}, \texttt{linf\_distance}}
+\label{sec:orgac16178}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name(s): \texttt{l1\_distance}, \texttt{l2\_distance}, \texttt{linf\_distance}
+\item Location: \texttt{src/vector.c}
+\item Input: two pointers to locations in memory wherein \texttt{Array\_double}'s lie, and the distance
+via the corresponding \texttt{l1}, \texttt{l2}, or \texttt{linf} norms
+\item Output: A \texttt{double} representing the distance between the two \texttt{Array\_doubles}'s by the given
+norm.
+\end{itemize}
+
+\begin{verbatim}
+double l1_distance(Array_double *v1, Array_double *v2) {
+ return vector_distance(v1, v2, &l1_norm);
+}
+
+double l2_distance(Array_double *v1, Array_double *v2) {
+ return vector_distance(v1, v2, &l2_norm);
+}
+
+double linf_distance(Array_double *v1, Array_double *v2) {
+ return vector_distance(v1, v2, &linf_norm);
+}
+\end{verbatim}
+
+\subsubsection{\texttt{sum\_v}}
+\label{sec:org876aafa}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name: \texttt{sum\_v}
+\item Location: \texttt{src/vector.c}
+\item Input: a pointer to an \texttt{Array\_double}
+\item Output: a \texttt{double} representing the sum of all the elements of an \texttt{Array\_double}
+\end{itemize}
+
+\begin{verbatim}
+double sum_v(Array_double *v) {
+ double sum = 0;
+ for (size_t i = 0; i < v->size; i++)
+ sum += v->data[i];
+ return sum;
+}
+\end{verbatim}
+
+\subsubsection{\texttt{scale\_v}}
+\label{sec:orgf1d236c}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name: \texttt{scale\_v}
+\item Location: \texttt{src/vector.c}
+\item Input: a pointer to an \texttt{Array\_double} and a scalar \texttt{double} to scale the vector
+\item Output: a pointer to a new \texttt{Array\_double} of the scaled input \texttt{Array\_double}
+\end{itemize}
+
+\begin{verbatim}
+Array_double *scale_v(Array_double *v, double m) {
+ Array_double *copy = copy_vector(v);
+ for (size_t i = 0; i < v->size; i++)
+ copy->data[i] *= m;
+ return copy;
+}
+\end{verbatim}
+
+\subsubsection{\texttt{free\_vector}}
+\label{sec:org2ca163d}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name: \texttt{free\_vector}
+\item Location: \texttt{src/vector.c}
+\item Input: a pointer to an \texttt{Array\_double}
+\item Output: nothing.
+\item Side effect: free the memory of the reserved \texttt{Array\_double} on the heap
+\end{itemize}
+
+\begin{verbatim}
+void free_vector(Array_double *v) {
+ free(v->data);
+ free(v);
+}
+\end{verbatim}
+
+\subsubsection{\texttt{add\_element}}
+\label{sec:org7a99233}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name: \texttt{add\_element}
+\item Location: \texttt{src/vector.c}
+\item Input: a pointer to an \texttt{Array\_double}
+\item Output: a new \texttt{Array\_double} with element \texttt{x} appended.
+\end{itemize}
+
+\begin{verbatim}
+Array_double *add_element(Array_double *v, double x) {
+ Array_double *pushed = InitArrayWithSize(double, v->size + 1, 0.0);
+ for (size_t i = 0; i < v->size; ++i)
+ pushed->data[i] = v->data[i];
+ pushed->data[v->size] = x;
+ return pushed;
+}
+\end{verbatim}
+
+\subsubsection{\texttt{slice\_element}}
+\label{sec:org6c07c99}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name: \texttt{slice\_element}
+\item Location: \texttt{src/vector.c}
+\item Input: a pointer to an \texttt{Array\_double}
+\item Output: a new \texttt{Array\_double} with element \texttt{x} sliced.
+\end{itemize}
+
+\begin{verbatim}
+Array_double *slice_element(Array_double *v, size_t x) {
+ Array_double *sliced = InitArrayWithSize(double, v->size - 1, 0.0);
+ for (size_t i = 0; i < v->size - 1; ++i)
+ sliced->data[i] = i >= x ? v->data[i + 1] : v->data[i];
+ return sliced;
+}
+\end{verbatim}
+
+\subsubsection{\texttt{copy\_vector}}
+\label{sec:org81f7cc1}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name: \texttt{copy\_vector}
+\item Location: \texttt{src/vector.c}
+\item Input: a pointer to an \texttt{Array\_double}
+\item Output: a pointer to a new \texttt{Array\_double} whose \texttt{data} and \texttt{size} are copied from the input
+\texttt{Array\_double}
+\end{itemize}
+
+\begin{verbatim}
+Array_double *copy_vector(Array_double *v) {
+ Array_double *copy = InitArrayWithSize(double, v->size, 0.0);
+ for (size_t i = 0; i < copy->size; ++i)
+ copy->data[i] = v->data[i];
+ return copy;
+}
+\end{verbatim}
+
+\subsubsection{\texttt{format\_vector\_into}}
+\label{sec:orgd168171}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name: \texttt{format\_vector\_into}
+\item Location: \texttt{src/vector.c}
+\item Input: a pointer to an \texttt{Array\_double} and a pointer to a c-string \texttt{s} to "print" the vector out
+into
+\item Output: nothing.
+\item Side effect: overwritten memory into \texttt{s}
+\end{itemize}
+
+\begin{verbatim}
+void format_vector_into(Array_double *v, char *s) {
+ if (v->size == 0) {
+ strcat(s, "empty");
+ return;
+ }
+
+ for (size_t i = 0; i < v->size; ++i) {
+ char num[64];
+ strcpy(num, "");
+
+ sprintf(num, "%f,", v->data[i]);
+ strcat(s, num);
+ }
+ strcat(s, "\n");
+}
+\end{verbatim}
+
+\subsection{Matrix Routines}
+\label{sec:org5c45c12}
+\subsubsection{\texttt{lu\_decomp}}
+\label{sec:orgf1e0ac3}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name: \texttt{lu\_decomp}
+\item Location: \texttt{src/matrix.c}
+\item Input: a pointer to a \texttt{Matrix\_double} \(m\) to decompose into a lower triangular and upper triangular
+matrix \(L\), \(U\), respectively such that \(LU = m\).
+\item Output: a pointer to the location in memory in which two \texttt{Matrix\_double}'s reside: the first
+representing \(L\), the second, \(U\).
+\item Errors: Fails assertions when encountering a matrix that cannot be
+decomposed
+\end{itemize}
+
+\begin{verbatim}
+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_matrix(l_empt);
+
+ 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");
+ 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");
+ 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{verbatim}
+\subsubsection{\texttt{bsubst}}
+\label{sec:orgec7e4b5}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name: \texttt{bsubst}
+\item Location: \texttt{src/matrix.c}
+\item Input: a pointer to an upper-triangular \texttt{Matrix\_double} \(u\) and a \texttt{Array\_double}
+\(b\)
+\item Output: a pointer to a new \texttt{Array\_double} whose entries are given by performing
+back substitution
+\end{itemize}
+
+\begin{verbatim}
+Array_double *bsubst(Matrix_double *u, Array_double *b) {
+ assert(u->rows == b->size && u->cols == u->rows);
+
+ Array_double *x = copy_vector(b);
+ for (int64_t row = b->size - 1; row >= 0; row--) {
+ for (size_t col = b->size - 1; col > row; col--)
+ x->data[row] -= x->data[col] * u->data[row]->data[col];
+ x->data[row] /= u->data[row]->data[row];
+ }
+ return x;
+}
+\end{verbatim}
+\subsubsection{\texttt{fsubst}}
+\label{sec:org72ff2ed}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name: \texttt{fsubst}
+\item Location: \texttt{src/matrix.c}
+\item Input: a pointer to a lower-triangular \texttt{Matrix\_double} \(l\) and a \texttt{Array\_double}
+\(b\)
+\item Output: a pointer to a new \texttt{Array\_double} whose entries are given by performing
+forward substitution
+\end{itemize}
+
+\begin{verbatim}
+Array_double *fsubst(Matrix_double *l, Array_double *b) {
+ assert(l->rows == b->size && l->cols == l->rows);
+
+ Array_double *x = copy_vector(b);
+
+ for (size_t row = 0; row < b->size; row++) {
+ for (size_t col = 0; col < row; col++)
+ x->data[row] -= x->data[col] * l->data[row]->data[col];
+ x->data[row] /= l->data[row]->data[row];
+ }
+
+ return x;
+}
+\end{verbatim}
+
+\subsubsection{\texttt{solve\_matrix\_lu\_bsubst}}
+\label{sec:orga735557}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Location: \texttt{src/matrix.c}
+\item Input: a pointer to a \texttt{Matrix\_double} \(m\) and a pointer to an \texttt{Array\_double} \(b\)
+\item Output: \(x\) such that \(mx = b\) if such a solution exists (else it's non LU-factorable as discussed
+above)
+\end{itemize}
+
+Here we make use of forward substitution to first solve \(Ly = b\) given \(L\) as the \(L\) factor in
+\texttt{lu\_decomp}. Then we use back substitution to solve \(Ux = y\) for \(x\) similarly given \(U\).
+
+Then, \(LUx = b\), thus \(x\) is a solution.
+
+\begin{verbatim}
+Array_double *solve_matrix_lu_bsubst(Matrix_double *m, Array_double *b) {
+ assert(b->size == m->rows);
+ assert(m->rows == m->cols);
+
+ Array_double *x = copy_vector(b);
+ Matrix_double **u_l = lu_decomp(m);
+ Matrix_double *u = u_l[0];
+ Matrix_double *l = u_l[1];
+
+ Array_double *b_fsub = fsubst(l, b);
+ x = bsubst(u, b_fsub);
+ free_vector(b_fsub);
+
+ free_matrix(u);
+ free_matrix(l);
+ free(u_l);
+
+ return x;
+}
+\end{verbatim}
+
+\subsubsection{\texttt{gaussian\_elimination}}
+\label{sec:org71d2519}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Location: \texttt{src/matrix.c}
+\item Input: a pointer to a \texttt{Matrix\_double} \(m\)
+\item Output: a pointer to a copy of \(m\) in reduced echelon form
+\end{itemize}
+
+This works by finding the row with a maximum value in the column \(k\). Then, it uses that as a pivot, and
+applying reduction to all other rows. The general idea is available at \url{https://en.wikipedia.org/wiki/Gaussian\_elimination}.
+
+\begin{verbatim}
+Matrix_double *gaussian_elimination(Matrix_double *m) {
+ uint64_t h = 0, k = 0;
+
+ Matrix_double *m_cp = copy_matrix(m);
+
+ while (h < m_cp->rows && k < m_cp->cols) {
+ uint64_t max_row = h;
+ double max_val = 0.0;
+
+ for (uint64_t row = h; row < m_cp->rows; row++) {
+ double val = fabs(m_cp->data[row]->data[k]);
+ if (val > max_val) {
+ max_val = val;
+ max_row = row;
+ }
+ }
+
+ if (max_val == 0.0) {
+ k++;
+ continue;
+ }
+
+ if (max_row != h) {
+ Array_double *swp = m_cp->data[max_row];
+ m_cp->data[max_row] = m_cp->data[h];
+ m_cp->data[h] = swp;
+ }
+
+ for (uint64_t row = h + 1; row < m_cp->rows; row++) {
+ double factor = m_cp->data[row]->data[k] / m_cp->data[h]->data[k];
+ m_cp->data[row]->data[k] = 0.0;
+
+ for (uint64_t col = k + 1; col < m_cp->cols; col++) {
+ m_cp->data[row]->data[col] -= m_cp->data[h]->data[col] * factor;
+ }
+ }
+
+ h++;
+ k++;
+ }
+
+ return m_cp;
+}
+\end{verbatim}
+
+\subsubsection{\texttt{solve\_matrix\_gaussian}}
+\label{sec:org230915f}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Location: \texttt{src/matrix.c}
+\item Input: a pointer to a \texttt{Matrix\_double} \(m\) and a target \texttt{Array\_double} \(b\)
+\item Output: a pointer to a vector \(x\) being the solution to the equation \(mx = b\)
+\end{itemize}
+
+We first perform \texttt{gaussian\_elimination} after augmenting \(m\) and \(b\). Then, as \(m\) is in reduced echelon form, it's an upper
+triangular matrix, so we can perform back substitution to compute \(x\).
+
+\begin{verbatim}
+Array_double *solve_matrix_gaussian(Matrix_double *m, Array_double *b) {
+ assert(b->size == m->rows);
+ assert(m->rows == m->cols);
+
+ Matrix_double *m_augment_b = add_column(m, b);
+ Matrix_double *eliminated = gaussian_elimination(m_augment_b);
+
+ Array_double *b_gauss = col_v(eliminated, m->cols);
+ Matrix_double *u = slice_column(eliminated, m->rows);
+
+ Array_double *solution = bsubst(u, b_gauss);
+
+ free_matrix(m_augment_b);
+ free_matrix(eliminated);
+ free_matrix(u);
+ free_vector(b_gauss);
+
+ return solution;
+}
+\end{verbatim}
+
+
+\subsubsection{\texttt{m\_dot\_v}}
+\label{sec:org83c8351}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Location: \texttt{src/matrix.c}
+\item Input: a pointer to a \texttt{Matrix\_double} \(m\) and \texttt{Array\_double} \(v\)
+\item Output: the dot product \(mv\) as an \texttt{Array\_double}
+\end{itemize}
+
+\begin{verbatim}
+Array_double *m_dot_v(Matrix_double *m, Array_double *v) {
+ assert(v->size == m->cols);
+
+ Array_double *product = copy_vector(v);
+
+ for (size_t row = 0; row < v->size; ++row)
+ product->data[row] = v_dot_v(m->data[row], v);
+
+ return product;
+}
+\end{verbatim}
+
+\subsubsection{\texttt{put\_identity\_diagonal}}
+\label{sec:orge3fcb3e}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Location: \texttt{src/matrix.c}
+\item Input: a pointer to a \texttt{Matrix\_double}
+\item Output: a pointer to a copy to \texttt{Matrix\_double} whose diagonal is full of 1's
+\end{itemize}
+
+\begin{verbatim}
+Matrix_double *put_identity_diagonal(Matrix_double *m) {
+ assert(m->rows == m->cols);
+ Matrix_double *copy = copy_matrix(m);
+ for (size_t y = 0; y < m->rows; ++y)
+ copy->data[y]->data[y] = 1.0;
+ return copy;
+}
+\end{verbatim}
+
+\subsubsection{\texttt{slice\_column}}
+\label{sec:org95e39ba}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Location: \texttt{src/matrix.c}
+\item Input: a pointer to a \texttt{Matrix\_double}
+\item Output: a pointer to a copy of the given \texttt{Matrix\_double} with column at \texttt{x} sliced
+\end{itemize}
+
+\begin{verbatim}
+Matrix_double *slice_column(Matrix_double *m, size_t x) {
+ Matrix_double *sliced = copy_matrix(m);
+
+ for (size_t row = 0; row < m->rows; row++) {
+ Array_double *old_row = sliced->data[row];
+ sliced->data[row] = slice_element(old_row, x);
+ free_vector(old_row);
+ }
+ sliced->cols--;
+
+ return sliced;
+}
+\end{verbatim}
+
+\subsubsection{\texttt{add\_column}}
+\label{sec:org9a2ad93}
+\begin{itemize}
+\item Author: Elizabet Hunt
+\item Location: \texttt{src/matrix.c}
+\item Input: a pointer to a \texttt{Matrix\_double} and a new vector representing the appended column \texttt{x}
+\item Output: a pointer to a copy of the given \texttt{Matrix\_double} with a new column \texttt{x}
+\end{itemize}
+
+\begin{verbatim}
+Matrix_double *add_column(Matrix_double *m, Array_double *v) {
+ Matrix_double *pushed = copy_matrix(m);
+
+ for (size_t row = 0; row < m->rows; row++) {
+ Array_double *old_row = pushed->data[row];
+ pushed->data[row] = add_element(old_row, v->data[row]);
+ free_vector(old_row);
+ }
+
+ pushed->cols++;
+ return pushed;
+}
+\end{verbatim}
+
+\subsubsection{\texttt{copy\_matrix}}
+\label{sec:org63765c0}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Location: \texttt{src/matrix.c}
+\item Input: a pointer to a \texttt{Matrix\_double}
+\item Output: a pointer to a copy of the given \texttt{Matrix\_double}
+\end{itemize}
+
+\begin{verbatim}
+Matrix_double *copy_matrix(Matrix_double *m) {
+ Matrix_double *copy = InitMatrixWithSize(double, m->rows, m->cols, 0.0);
+ for (size_t y = 0; y < copy->rows; y++) {
+ free_vector(copy->data[y]);
+ copy->data[y] = copy_vector(m->data[y]);
+ }
+ return copy;
+}
+\end{verbatim}
+
+\subsubsection{\texttt{free\_matrix}}
+\label{sec:orgc337967}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Location: \texttt{src/matrix.c}
+\item Input: a pointer to a \texttt{Matrix\_double}
+\item Output: none.
+\item Side Effects: frees memory reserved by a given \texttt{Matrix\_double} and its member
+\texttt{Array\_double} vectors describing its rows.
+\end{itemize}
+
+\begin{verbatim}
+void free_matrix(Matrix_double *m) {
+ for (size_t y = 0; y < m->rows; ++y)
+ free_vector(m->data[y]);
+ free(m);
+}
+\end{verbatim}
+
+\subsubsection{\texttt{format\_matrix\_into}}
+\label{sec:org6b188b4}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name: \texttt{format\_matrix\_into}
+\item Location: \texttt{src/matrix.c}
+\item Input: a pointer to a \texttt{Matrix\_double} and a pointer to a c-string \texttt{s} to "print" the vector out
+into
+\item Output: nothing.
+\item Side effect: overwritten memory into \texttt{s}
+\end{itemize}
+
+\begin{verbatim}
+void format_matrix_into(Matrix_double *m, char *s) {
+ if (m->rows == 0)
+ strcpy(s, "empty");
+
+ for (size_t y = 0; y < m->rows; ++y) {
+ char row_s[5192];
+ strcpy(row_s, "");
+
+ format_vector_into(m->data[y], row_s);
+ strcat(s, row_s);
+ }
+ strcat(s, "\n");
+}
+\end{verbatim}
+\subsection{Root Finding Methods}
+\label{sec:org352ccdf}
+\subsubsection{\texttt{find\_ivt\_range}}
+\label{sec:orgb9a0d16}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name: \texttt{find\_ivt\_range}
+\item Location: \texttt{src/roots.c}
+\item Input: a pointer to a oneary function taking a double and producing a double, the beginning point
+in \(R\) to search for a range, a \texttt{delta} step that is taken, and a \texttt{max\_steps} number of maximum
+iterations to perform.
+\item Output: a pair of \texttt{double}'s in an \texttt{Array\_double} representing a closed closed interval \texttt{[beginning, end]}
+\end{itemize}
+
+\begin{verbatim}
+// f is well defined at start_x + delta*n for all n on the integer range [0,
+// max_iterations]
+Array_double *find_ivt_range(double (*f)(double), double start_x, double delta,
+ size_t max_iterations) {
+ double a = start_x;
+
+ while (f(a) * f(a + delta) >= 0 && max_iterations > 0) {
+ max_iterations--;
+ a += delta;
+ }
+
+ double end = a + delta;
+ double begin = a - delta;
+
+ if (max_iterations == 0 && f(begin) * f(end) >= 0)
+ return NULL;
+ return InitArray(double, {begin, end});
+}
+\end{verbatim}
+\subsubsection{\texttt{bisect\_find\_root}}
+\label{sec:org25382b3}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name(s): \texttt{bisect\_find\_root}
+\item Input: a one-ary function taking a double and producing a double, a closed interval represented
+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}.
+\item Output: a vector of size of 3, \texttt{double}'s representing first the range \texttt{[a,b]} and then the midpoint,
+\texttt{c} of the range.
+\item Description: recursively uses binary search to split the interval until we reach \texttt{tolerance}. We
+also assume the function \texttt{f} is continuous on \texttt{[a, b]}.
+\end{itemize}
+
+\begin{verbatim}
+// f is continuous on [a, b]
+Array_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 InitArray(double, {a, b, 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);
+}
+\end{verbatim}
+\subsubsection{\texttt{bisect\_find\_root\_with\_error\_assumption}}
+\label{sec:org4b9cb72}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name: \texttt{bisect\_find\_root\_with\_error\_assumption}
+\item Input: a one-ary function taking a double and producing a double, a closed interval represented
+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 Description: using the bisection method we know that \(e_k \le (\frac{1}{2})^k (b_0 - a_0)\). So we can
+calculate \(k\) at the worst possible case (that the error is exactly the tolerance) to be
+\(\frac{log(tolerance) - log(b_0 - a_0)}{log(\frac{1}{2})}\). We pass this value into the \texttt{max\_iterations}
+of \texttt{bisect\_find\_root} as above.
+\end{itemize}
+\begin{verbatim}
+double bisect_find_root_with_error_assumption(double (*f)(double), double a,
+ double b, double tolerance) {
+ assert(a <= b);
+
+ uint64_t max_iterations =
+ (uint64_t)ceil((log(tolerance) - log(b - a)) / log(1 / 2.0));
+
+ 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}
+
+\subsubsection{\texttt{fixed\_point\_iteration\_method}}
+\label{sec:org4cee2bd}
+\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:org93e3999}
+\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:orgf3f0711}
+\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 \(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 \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 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{verbatim}
+\subsubsection{\texttt{fixed\_point\_secant\_bisection\_method}}
+\label{sec:orgeaef048}
+\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 \(x_1\) of which we define our first interval \([x_0, x_1]\).
+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 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{verbatim}
+
+\subsection{Linear Routines}
+\label{sec:orge3b6d97}
+\subsubsection{\texttt{least\_squares\_lin\_reg}}
+\label{sec:orgcc90c4a}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name: \texttt{least\_squares\_lin\_reg}
+\item Location: \texttt{src/lin.c}
+\item Input: two pointers to \texttt{Array\_double}'s whose entries correspond two ordered
+pairs in R\textsuperscript{2}
+\item Output: a linear model best representing the ordered pairs via least squares
+regression
+\end{itemize}
+
+\begin{verbatim}
+Line *least_squares_lin_reg(Array_double *x, Array_double *y) {
+ assert(x->size == y->size);
+
+ uint64_t n = x->size;
+ double sum_x = sum_v(x);
+ double sum_y = sum_v(y);
+ double sum_xy = v_dot_v(x, y);
+ double sum_xx = v_dot_v(x, x);
+ double denom = ((n * sum_xx) - (sum_x * sum_x));
+
+ Line *line = malloc(sizeof(Line));
+ line->m = ((sum_xy * n) - (sum_x * sum_y)) / denom;
+ line->a = ((sum_y * sum_xx) - (sum_x * sum_xy)) / denom;
+
+ return line;
+}
+\end{verbatim}
+
+\subsection{Eigen-Adjacent}
+\label{sec:orga3c637f}
+\subsubsection{\texttt{dominant\_eigenvalue}}
+\label{sec:org0306c8a}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name: \texttt{dominant\_eigenvalue}
+\item Location: \texttt{src/eigen.c}
+\item Input: a pointer to an invertible matrix \texttt{m}, an initial eigenvector guess \texttt{v} (that is non
+zero or orthogonal to an eigenvector with the dominant eigenvalue), a \texttt{tolerance} and
+\texttt{max\_iterations} that act as stop conditions
+\item Output: the dominant eigenvalue with the highest magnitude, approximated with the Power
+Iteration Method
+\end{itemize}
+
+\begin{verbatim}
+double dominant_eigenvalue(Matrix_double *m, Array_double *v, double tolerance,
+ size_t max_iterations) {
+ assert(m->rows == m->cols);
+ assert(m->rows == v->size);
+
+ double error = tolerance;
+ size_t iter = max_iterations;
+ double lambda = 0.0;
+ Array_double *eigenvector_1 = copy_vector(v);
+
+ while (error >= tolerance && (--iter) > 0) {
+ Array_double *eigenvector_2 = m_dot_v(m, eigenvector_1);
+ Array_double *normalized_eigenvector_2 =
+ scale_v(eigenvector_2, 1.0 / linf_norm(eigenvector_2));
+ free_vector(eigenvector_2);
+ eigenvector_2 = normalized_eigenvector_2;
+
+ Array_double *mx = m_dot_v(m, eigenvector_2);
+ double new_lambda =
+ v_dot_v(mx, eigenvector_2) / v_dot_v(eigenvector_2, eigenvector_2);
+
+ error = fabs(new_lambda - lambda);
+ lambda = new_lambda;
+ free_vector(eigenvector_1);
+ eigenvector_1 = eigenvector_2;
+ }
+
+ return lambda;
+}
+\end{verbatim}
+\subsubsection{\texttt{shift\_inverse\_power\_eigenvalue}}
+\label{sec:orgc29637a}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name: \texttt{least\_dominant\_eigenvalue}
+\item Location: \texttt{src/eigen.c}
+\item Input: a pointer to an invertible matrix \texttt{m}, an initial eigenvector guess \texttt{v} (that is non
+zero or orthogonal to an eigenvector with the dominant eigenvalue), a \texttt{shift} to act as the
+shifted \(\delta\), and \texttt{tolerance} and \texttt{max\_iterations} that act as stop conditions.
+\item Output: the eigenvalue closest to \texttt{shift} with the lowest magnitude closest to 0, approximated
+with the Inverse Power Iteration Method
+\end{itemize}
+\begin{verbatim}
+double shift_inverse_power_eigenvalue(Matrix_double *m, Array_double *v,
+ double shift, double tolerance,
+ size_t max_iterations) {
+ assert(m->rows == m->cols);
+ assert(m->rows == v->size);
+
+ Matrix_double *m_c = copy_matrix(m);
+ for (size_t y = 0; y < m_c->rows; ++y)
+ m_c->data[y]->data[y] = m_c->data[y]->data[y] - shift;
+
+ double error = tolerance;
+ size_t iter = max_iterations;
+ double lambda = shift;
+ Array_double *eigenvector_1 = copy_vector(v);
+
+ while (error >= tolerance && (--iter) > 0) {
+ Array_double *eigenvector_2 = solve_matrix_lu_bsubst(m_c, eigenvector_1);
+ Array_double *normalized_eigenvector_2 =
+ scale_v(eigenvector_2, 1.0 / linf_norm(eigenvector_2));
+ free_vector(eigenvector_2);
+
+ Array_double *mx = m_dot_v(m, normalized_eigenvector_2);
+ double new_lambda =
+ v_dot_v(mx, normalized_eigenvector_2) /
+ v_dot_v(normalized_eigenvector_2, normalized_eigenvector_2);
+
+ error = fabs(new_lambda - lambda);
+ lambda = new_lambda;
+ free_vector(eigenvector_1);
+ eigenvector_1 = normalized_eigenvector_2;
+ }
+
+ return lambda;
+}
+\end{verbatim}
+
+\subsubsection{\texttt{least\_dominant\_eigenvalue}}
+\label{sec:org5df73a2}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name: \texttt{least\_dominant\_eigenvalue}
+\item Location: \texttt{src/eigen.c}
+\item Input: a pointer to an invertible matrix \texttt{m}, an initial eigenvector guess \texttt{v} (that is non
+zero or orthogonal to an eigenvector with the dominant eigenvalue), a \texttt{tolerance} and
+\texttt{max\_iterations} that act as stop conditions.
+\item Output: the least dominant eigenvalue with the lowest magnitude closest to 0, approximated
+with the Inverse Power Iteration Method.
+\end{itemize}
+\begin{verbatim}
+double least_dominant_eigenvalue(Matrix_double *m, Array_double *v,
+ double tolerance, size_t max_iterations) {
+ return shift_inverse_power_eigenvalue(m, v, 0.0, tolerance, max_iterations);
+}
+\end{verbatim}
+\subsubsection{\texttt{partition\_find\_eigenvalues}}
+\label{sec:org3dde7af}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name: \texttt{partition\_find\_eigenvalues}
+\item Location: \texttt{src/eigen.c}
+\item Input: a pointer to an invertible matrix \texttt{m}, a matrix whose rows correspond to initial
+eigenvector guesses at each "partition" which is computed from a uniform distribution
+between the number of rows this "guess matrix" has and the distance between the least
+dominant eigenvalue and the most dominant. Additionally, a \texttt{max\_iterations} and a \texttt{tolerance}
+that act as stop conditions.
+\item Output: a vector of \texttt{doubles} corresponding to the "nearest" eigenvalue at the midpoint of
+each partition, via the given guess of that partition.
+\end{itemize}
+\begin{verbatim}
+Array_double *partition_find_eigenvalues(Matrix_double *m,
+ Matrix_double *guesses,
+ double tolerance,
+ size_t max_iterations) {
+ assert(guesses->rows >=
+ 2); // we need at least, the most and least dominant eigenvalues
+
+ double end = dominant_eigenvalue(m, guesses->data[guesses->rows - 1],
+ tolerance, max_iterations);
+ double begin =
+ least_dominant_eigenvalue(m, guesses->data[0], tolerance, max_iterations);
+
+ double delta = (end - begin) / guesses->rows;
+ Array_double *eigenvalues = InitArrayWithSize(double, guesses->rows, 0.0);
+ for (size_t i = 0; i < guesses->rows; i++) {
+ double box_midpoint = ((delta * i) + (delta * (i + 1))) / 2;
+
+ double nearest_eigenvalue = shift_inverse_power_eigenvalue(
+ m, guesses->data[i], box_midpoint, tolerance, max_iterations);
+
+ eigenvalues->data[i] = nearest_eigenvalue;
+ }
+
+ return eigenvalues;
+}
+\end{verbatim}
+\subsubsection{\texttt{leslie\_matrix}}
+\label{sec:orgca10ed3}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name: \texttt{leslie\_matrix}
+\item Location: \texttt{src/eigen.c}
+\item Input: two pointers to \texttt{Array\_double}'s representing the ratio of individuals in an age class
+\(x\) getting to the next age class \(x+1\) and the number of offspring that individuals in an age
+class create in age class 0.
+\item Output: the leslie matrix generated from the input vectors.
+\end{itemize}
+
+\begin{verbatim}
+Matrix_double *leslie_matrix(Array_double *age_class_surivor_ratio,
+ Array_double *age_class_offspring) {
+ assert(age_class_surivor_ratio->size + 1 == age_class_offspring->size);
+
+ Matrix_double *leslie = InitMatrixWithSize(double, age_class_offspring->size,
+ age_class_offspring->size, 0.0);
+
+ free_vector(leslie->data[0]);
+ leslie->data[0] = age_class_offspring;
+
+ for (size_t i = 0; i < age_class_surivor_ratio->size; i++)
+ leslie->data[i + 1]->data[i] = age_class_surivor_ratio->data[i];
+ return leslie;
+}
+\end{verbatim}
+\subsection{Jacobi / Gauss-Siedel}
+\label{sec:org91c563c}
+\subsubsection{\texttt{jacobi\_solve}}
+\label{sec:org2cd6098}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name: \texttt{jacobi\_solve}
+\item Location: \texttt{src/matrix.c}
+\item Input: a pointer to a diagonally dominant square matrix \(m\), a vector representing
+the value \(b\) in \(mx = b\), a double representing the maximum distance between
+the solutions produced by iteration \(i\) and \(i+1\) (by L2 norm a.k.a cartesian
+distance), and a \texttt{max\_iterations} which we force stop.
+\item Output: the converged-upon solution \(x\) to \(mx = b\)
+\end{itemize}
+\begin{verbatim}
+Array_double *jacobi_solve(Matrix_double *m, Array_double *b,
+ double l2_convergence_tolerance,
+ size_t max_iterations) {
+ assert(m->rows == m->cols);
+ assert(b->size == m->cols);
+ size_t iter = max_iterations;
+
+ Array_double *x_k = InitArrayWithSize(double, b->size, 0.0);
+ Array_double *x_k_1 =
+ InitArrayWithSize(double, b->size, rand_from(0.1, 10.0));
+
+ while ((--iter) > 0 && l2_distance(x_k_1, x_k) > l2_convergence_tolerance) {
+ for (size_t i = 0; i < m->rows; i++) {
+ double delta = 0.0;
+ for (size_t j = 0; j < m->cols; j++) {
+ if (i == j)
+ continue;
+ delta += m->data[i]->data[j] * x_k->data[j];
+ }
+ x_k_1->data[i] = (b->data[i] - delta) / m->data[i]->data[i];
+ }
+
+ Array_double *tmp = x_k;
+ x_k = x_k_1;
+ x_k_1 = tmp;
+ }
+
+ free_vector(x_k);
+ return x_k_1;
+}
+\end{verbatim}
+
+\subsubsection{\texttt{gauss\_siedel\_solve}}
+\label{sec:org6633923}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name: \texttt{gauss\_siedel\_solve}
+\item Location: \texttt{src/matrix.c}
+\item Input: a pointer to a \href{https://en.wikipedia.org/wiki/Gauss\%E2\%80\%93Seidel\_method}{diagonally dominant or symmetric and positive definite}
+square matrix \(m\), a vector representing
+the value \(b\) in \(mx = b\), a double representing the maximum distance between
+the solutions produced by iteration \(i\) and \(i+1\) (by L2 norm a.k.a cartesian
+distance), and a \texttt{max\_iterations} which we force stop.
+\item Output: the converged-upon solution \(x\) to \(mx = b\)
+\item Description: we use almost the exact same method as \texttt{jacobi\_solve} but modify
+only one array in accordance to the Gauss-Siedel method, but which is necessarily
+copied before due to the convergence check.
+\end{itemize}
+\begin{verbatim}
+
+Array_double *gauss_siedel_solve(Matrix_double *m, Array_double *b,
+ double l2_convergence_tolerance,
+ size_t max_iterations) {
+ assert(m->rows == m->cols);
+ assert(b->size == m->cols);
+ size_t iter = max_iterations;
+
+ Array_double *x_k = InitArrayWithSize(double, b->size, 0.0);
+ Array_double *x_k_1 =
+ InitArrayWithSize(double, b->size, rand_from(0.1, 10.0));
+
+ while ((--iter) > 0) {
+ for (size_t i = 0; i < x_k->size; i++)
+ x_k->data[i] = x_k_1->data[i];
+
+ for (size_t i = 0; i < m->rows; i++) {
+ double delta = 0.0;
+ for (size_t j = 0; j < m->cols; j++) {
+ if (i == j)
+ continue;
+ delta += m->data[i]->data[j] * x_k_1->data[j];
+ }
+ x_k_1->data[i] = (b->data[i] - delta) / m->data[i]->data[i];
+ }
+
+ if (l2_distance(x_k_1, x_k) <= l2_convergence_tolerance)
+ break;
+ }
+
+ free_vector(x_k);
+ return x_k_1;
+}
+\end{verbatim}
+
+\subsection{Appendix / Miscellaneous}
+\label{sec:orga72494e}
+\subsubsection{Random}
+\label{sec:org4940c39}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Name: \texttt{rand\_from}
+\item Location: \texttt{src/rand.c}
+\item Input: a pair of doubles, min and max to generate a random number min
+\(\le\) x \(\le\) max
+\item Output: a random double in the constraints shown
+\end{itemize}
+
+\begin{verbatim}
+double rand_from(double min, double max) {
+ return min + (rand() / (RAND_MAX / (max - min)));
+}
+\end{verbatim}
+\subsubsection{Data Types}
+\label{sec:org8d3f6e1}
+\begin{enumerate}
+\item \texttt{Line}
+\label{sec:orgc0df901}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Location: \texttt{inc/types.h}
+\end{itemize}
+
+\begin{verbatim}
+typedef struct Line {
+ double m;
+ double a;
+} Line;
+\end{verbatim}
+\item The \texttt{Array\_<type>} and \texttt{Matrix\_<type>}
+\label{sec:org435e816}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Location: \texttt{inc/types.h}
+\end{itemize}
+
+We define two Pre processor Macros \texttt{DEFINE\_ARRAY} and \texttt{DEFINE\_MATRIX} that take
+as input a type, and construct a struct definition for the given type for
+convenient access to the vector or matrices dimensions.
+
+Such that \texttt{DEFINE\_ARRAY(int)} would expand to:
+
+\begin{verbatim}
+typedef struct {
+ int* data;
+ size_t size;
+} Array_int
+\end{verbatim}
+
+And \texttt{DEFINE\_MATRIX(int)} would expand a to \texttt{Matrix\_int}; containing a pointer to
+a collection of pointers of \texttt{Array\_int}'s and its dimensions.
+
+\begin{verbatim}
+typedef struct {
+ Array_int **data;
+ size_t cols;
+ size_t rows;
+} Matrix_int
+\end{verbatim}
+\end{enumerate}
+
+\subsubsection{Macros}
+\label{sec:orga2161be}
+\begin{enumerate}
+\item \texttt{c\_max} and \texttt{c\_min}
+\label{sec:org16ca9c3}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Location: \texttt{inc/macros.h}
+\item Input: two structures that define an order measure
+\item Output: either the larger or smaller of the two depending on the measure
+\end{itemize}
+
+\begin{verbatim}
+#define c_max(x, y) (((x) >= (y)) ? (x) : (y))
+#define c_min(x, y) (((x) <= (y)) ? (x) : (y))
+\end{verbatim}
+
+\item \texttt{InitArray}
+\label{sec:orgcaff993}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Location: \texttt{inc/macros.h}
+\item Input: a type and array of values to initialze an array with such type
+\item Output: a new \texttt{Array\_type} with the size of the given array and its data
+\end{itemize}
+
+\begin{verbatim}
+#define InitArray(TYPE, ...) \
+ ({ \
+ TYPE temp[] = __VA_ARGS__; \
+ Array_##TYPE *arr = malloc(sizeof(Array_##TYPE)); \
+ arr->size = sizeof(temp) / sizeof(temp[0]); \
+ arr->data = malloc(arr->size * sizeof(TYPE)); \
+ memcpy(arr->data, temp, arr->size * sizeof(TYPE)); \
+ arr; \
+ })
+\end{verbatim}
+
+\item \texttt{InitArrayWithSize}
+\label{sec:orga925ddb}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Location: \texttt{inc/macros.h}
+\item Input: a type, a size, and initial value
+\item Output: a new \texttt{Array\_type} with the given size filled with the initial value
+\end{itemize}
+
+\begin{verbatim}
+#define InitArrayWithSize(TYPE, SIZE, INIT_VALUE) \
+ ({ \
+ Array_##TYPE *arr = malloc(sizeof(Array_##TYPE)); \
+ arr->size = SIZE; \
+ arr->data = malloc(arr->size * sizeof(TYPE)); \
+ for (size_t i = 0; i < arr->size; i++) \
+ arr->data[i] = INIT_VALUE; \
+ arr; \
+ })
+\end{verbatim}
+
+\item \texttt{InitMatrixWithSize}
+\label{sec:orgf90d7c8}
+\begin{itemize}
+\item Author: Elizabeth Hunt
+\item Location: \texttt{inc/macros.h}
+\item Input: a type, number of rows, columns, and initial value
+\item Output: a new \texttt{Matrix\_type} of size \texttt{rows x columns} filled with the initial
+value
+\end{itemize}
+
+\begin{verbatim}
+#define InitMatrixWithSize(TYPE, ROWS, COLS, INIT_VALUE) \
+ ({ \
+ Matrix_##TYPE *matrix = malloc(sizeof(Matrix_##TYPE)); \
+ matrix->rows = ROWS; \
+ matrix->cols = COLS; \
+ matrix->data = malloc(matrix->rows * sizeof(Array_##TYPE *)); \
+ for (size_t y = 0; y < matrix->rows; y++) \
+ matrix->data[y] = InitArrayWithSize(TYPE, COLS, INIT_VALUE); \
+ matrix; \
+ })
+\end{verbatim}
+\end{enumerate}
+\end{document} \ No newline at end of file
diff --git a/Homework/math4610/homeworks/a.out b/Homework/math4610/homeworks/a.out
new file mode 100644
index 0000000..410a7d5
--- /dev/null
+++ b/Homework/math4610/homeworks/a.out
Binary files differ
diff --git a/Homework/math4610/homeworks/hw-2.org b/Homework/math4610/homeworks/hw-2.org
new file mode 100644
index 0000000..f696ffb
--- /dev/null
+++ b/Homework/math4610/homeworks/hw-2.org
@@ -0,0 +1,182 @@
+#+TITLE: HW 02
+#+AUTHOR: Elizabeth Hunt
+#+STARTUP: entitiespretty fold inlineimages
+#+LATEX_HEADER: \notindent \notag \usepackage{amsmath} \usepackage[a4paper,margin=1in,portrait]{geometry}
+#+LATEX: \setlength\parindent{0pt}
+#+OPTIONS: toc:nil
+
+* Question One
+Computing $\epsilon_{\text{mac}}$ for single precision numbers
+
+#+BEGIN_SRC lisp :session t :results table
+ (load "../lizfcm.asd")
+ (ql:quickload :lizfcm)
+
+ (let ((domain-values (lizfcm.approx:compute-maceps (lambda (x) x)
+ 1.0
+ 1.0)))
+ (lizfcm.utils:table (:headers '("a" "h" "err")
+ :domain-order (a h err)
+ :domain-values domain-values)))
+#+END_SRC
+
+(with many rows truncated)
+
+| a | h | err |
+| 1.0 | 1.0 | 1.0 |
+| 1.0 | 0.5 | 0.5 |
+| 1.0 | 0.25 | 0.25 |
+| 1.0 | 0.125 | 0.125 |
+| 1.0 | 0.0625 | 0.0625 |
+| 1.0 | 0.03125 | 0.03125 |
+| 1.0 | 1.9073486e-06 | 1.9073486e-06 |
+| 1.0 | 9.536743e-07 | 9.536743e-07 |
+| 1.0 | 4.7683716e-07 | 4.7683716e-07 |
+| 1.0 | 2.3841858e-07 | 2.3841858e-07 |
+| 1.0 | 1.1920929e-07 | 1.1920929e-07 |
+
+$\epsilon_{\text{mac single precision}}$ \approx 1.192(10^-7)
+
+* Question Two
+Computing $\epsilon_{\text{mac}}$ for double precision numbers:
+
+#+BEGIN_SRC lisp :session t :results table
+ (let ((domain-values (lizfcm.approx:compute-maceps (lambda (x) x)
+ 1.0d0
+ 1.0d0)))
+ (lizfcm.utils:table (:headers '("a" "h" "err")
+ :domain-order (a h err)
+ :domain-values domain-values)))
+#+END_SRC
+
+(with many rows truncated)
+| a | h | err |
+| 1.0d0 | 1.0d0 | 1.0d0 |
+| 1.0d0 | 0.5d0 | 0.5d0 |
+| 1.0d0 | 0.25d0 | 0.25d0 |
+| 1.0d0 | 0.125d0 | 0.125d0 |
+| 1.0d0 | 0.0625d0 | 0.0625d0 |
+| 1.0d0 | 0.03125d0 | 0.03125d0 |
+| 1.0d0 | 0.015625d0 | 0.015625d0 |
+| 1.0d0 | 0.0078125d0 | 0.0078125d0 |
+| 1.0d0 | 0.00390625d0 | 0.00390625d0 |
+| 1.0d0 | 0.001953125d0 | 0.001953125d0 |
+| 1.0d0 | 7.105427357601002d-15 | 7.105427357601002d-15 |
+| 1.0d0 | 3.552713678800501d-15 | 3.552713678800501d-15 |
+| 1.0d0 | 1.7763568394002505d-15 | 1.7763568394002505d-15 |
+| 1.0d0 | 8.881784197001252d-16 | 8.881784197001252d-16 |
+| 1.0d0 | 4.440892098500626d-16 | 4.440892098500626d-16 |
+| 1.0d0 | 2.220446049250313d-16 | 2.220446049250313d-16 |
+
+Thus, $\epsilon_{\text{mac double precision}}$ \approx 2.220 \cdot 10^{-16}
+
+* Question Three - |v|_2
+#+BEGIN_SRC lisp :session t
+ (let ((vs '((1 1) (2 3) (4 5) (-1 2)))
+ (2-norm (lizfcm.vector:p-norm 2)))
+ (lizfcm.utils:table (:headers '("x" "y" "2norm")
+ :domain-order (x y)
+ :domain-values vs)
+ (funcall 2-norm (list x y))))
+#+END_SRC
+
+
+| x | y | 2norm |
+| 1 | 1 | 1.4142135 |
+| 2 | 3 | 3.6055512 |
+| 4 | 5 | 6.4031243 |
+| -1 | 2 | 2.236068 |
+
+* Question Four - |v|_1
+#+BEGIN_SRC lisp :session t
+ (let ((vs '((1 1) (2 3) (4 5) (-1 2)))
+ (1-norm (lizfcm.vector:p-norm 1)))
+ (lizfcm.utils:table (:headers '("x" "y" "1norm")
+ :domain-order (x y)
+ :domain-values vs)
+ (funcall 1-norm (list x y))))
+#+END_SRC
+
+
+| x | y | 1norm |
+| 1 | 1 | 2 |
+| 2 | 3 | 5 |
+| 4 | 5 | 9 |
+| -1 | 2 | 3 |
+
+* Question Five - |v|_{\infty}
+#+BEGIN_SRC lisp :session t
+ (let ((vs '((1 1) (2 3) (4 5) (-1 2))))
+ (lizfcm.utils:table (:headers '("x" "y" "max-norm")
+ :domain-order (x y)
+ :domain-values vs)
+ (lizfcm.vector:max-norm (list x y))))
+#+END_SRC
+
+
+| x | y | infty-norm |
+| 1 | 1 | 1 |
+| 2 | 3 | 3 |
+| 4 | 5 | 5 |
+| -1 | 2 | 2 |
+
+* Question Six - ||v - u|| via |v|_{2}
+#+BEGIN_SRC lisp :session t
+ (let ((vs '((1 1) (2 3) (4 5) (-1 2)))
+ (vs2 '((7 9) (2 2) (8 -1) (4 4)))
+ (2-norm (lizfcm.vector:p-norm 2)))
+ (lizfcm.utils:table (:headers '("v1" "v2" "2-norm-d")
+ :domain-order (v1 v2)
+ :domain-values (mapcar (lambda (v1 v2)
+ (list v1 v2))
+ vs
+ vs2))
+ (lizfcm.vector:distance v1 v2 2-norm)))
+#+END_SRC
+
+
+| v1 | v2 | 2-norm |
+| (1 1) | (7 9) | 10.0 |
+| (2 3) | (2 2) | 1.0 |
+| (4 5) | (8 -1) | 7.2111025 |
+| (-1 2) | (4 4) | 5.3851647 |
+
+* Question Seven - ||v - u|| via |v|_{1}
+#+BEGIN_SRC lisp :session t
+ (let ((vs '((1 1) (2 3) (4 5) (-1 2)))
+ (vs2 '((7 9) (2 2) (8 -1) (4 4)))
+ (1-norm (lizfcm.vector:p-norm 1)))
+ (lizfcm.utils:table (:headers '("v1" "v2" "1-norm-d")
+ :domain-order (v1 v2)
+ :domain-values (mapcar (lambda (v1 v2)
+ (list v1 v2))
+ vs
+ vs2))
+ (lizfcm.vector:distance v1 v2 1-norm)))
+#+END_SRC
+
+
+| v1 | v2 | 1-norm-d |
+| (1 1) | (7 9) | 14 |
+| (2 3) | (2 2) | 1 |
+| (4 5) | (8 -1) | 10 |
+| (-1 2) | (4 4) | 7 |
+
+* Question Eight - ||v - u|| via |v|_{\infty}
+#+BEGIN_SRC lisp :session t
+ (let ((vs '((1 1) (2 3) (4 5) (-1 2)))
+ (vs2 '((7 9) (2 2) (8 -1) (4 4))))
+ (lizfcm.utils:table (:headers '("v1" "v2" "max-norm-d")
+ :domain-order (v1 v2)
+ :domain-values (mapcar (lambda (v1 v2)
+ (list v1 v2))
+ vs
+ vs2))
+ (lizfcm.vector:distance v1 v2 'lizfcm.vector:max-norm)))
+#+END_SRC
+
+| v1 | v2 | max-norm-d |
+| (1 1) | (7 9) | -6 |
+| (2 3) | (2 2) | 1 |
+| (4 5) | (8 -1) | 6 |
+| (-1 2) | (4 4) | -2 |
diff --git a/Homework/math4610/homeworks/hw-2.pdf b/Homework/math4610/homeworks/hw-2.pdf
new file mode 100644
index 0000000..2dc4d28
--- /dev/null
+++ b/Homework/math4610/homeworks/hw-2.pdf
Binary files differ
diff --git a/Homework/math4610/homeworks/hw-2.tex b/Homework/math4610/homeworks/hw-2.tex
new file mode 100644
index 0000000..da8d3f5
--- /dev/null
+++ b/Homework/math4610/homeworks/hw-2.tex
@@ -0,0 +1,246 @@
+% Created 2023-10-07 Sat 14:51
+% 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{HW 02}
+\hypersetup{
+ pdfauthor={Elizabeth Hunt},
+ pdftitle={HW 02},
+ pdfkeywords={},
+ pdfsubject={},
+ pdfcreator={Emacs 28.2 (Org mode 9.7-pre)},
+ pdflang={English}}
+\begin{document}
+
+\maketitle
+\setlength\parindent{0pt}
+
+\section{Question One}
+\label{sec:org58b9af4}
+Computing \(\epsilon_{\text{mac}}\) for single precision numbers
+
+\begin{verbatim}
+(load "../lizfcm.asd")
+(ql:quickload :lizfcm)
+
+(let ((domain-values (lizfcm.approx:compute-maceps (lambda (x) x)
+ 1.0
+ 1.0)))
+ (lizfcm.utils:table (:headers '("a" "h" "err")
+ :domain-order (a h err)
+ :domain-values domain-values)))
+\end{verbatim}
+
+(with many rows truncated)
+
+\begin{center}
+\begin{tabular}{rrr}
+a & h & err\\[0pt]
+1.0 & 1.0 & 1.0\\[0pt]
+1.0 & 0.5 & 0.5\\[0pt]
+1.0 & 0.25 & 0.25\\[0pt]
+1.0 & 0.125 & 0.125\\[0pt]
+1.0 & 0.0625 & 0.0625\\[0pt]
+1.0 & 0.03125 & 0.03125\\[0pt]
+1.0 & 1.9073486e-06 & 1.9073486e-06\\[0pt]
+1.0 & 9.536743e-07 & 9.536743e-07\\[0pt]
+1.0 & 4.7683716e-07 & 4.7683716e-07\\[0pt]
+1.0 & 2.3841858e-07 & 2.3841858e-07\\[0pt]
+1.0 & 1.1920929e-07 & 1.1920929e-07\\[0pt]
+\end{tabular}
+\end{center}
+
+\(\epsilon_{\text{mac single precision}}\) \(\approx\) 1.192(10\textsuperscript{-7})
+
+\section{Question Two}
+\label{sec:org27557b4}
+Computing \(\epsilon_{\text{mac}}\) for double precision numbers:
+
+\begin{verbatim}
+(let ((domain-values (lizfcm.approx:compute-maceps (lambda (x) x)
+ 1.0d0
+ 1.0d0)))
+ (lizfcm.utils:table (:headers '("a" "h" "err")
+ :domain-order (a h err)
+ :domain-values domain-values)))
+\end{verbatim}
+
+(with many rows truncated)
+\begin{center}
+\begin{tabular}{rrr}
+a & h & err\\[0pt]
+1.0d0 & 1.0d0 & 1.0d0\\[0pt]
+1.0d0 & 0.5d0 & 0.5d0\\[0pt]
+1.0d0 & 0.25d0 & 0.25d0\\[0pt]
+1.0d0 & 0.125d0 & 0.125d0\\[0pt]
+1.0d0 & 0.0625d0 & 0.0625d0\\[0pt]
+1.0d0 & 0.03125d0 & 0.03125d0\\[0pt]
+1.0d0 & 0.015625d0 & 0.015625d0\\[0pt]
+1.0d0 & 0.0078125d0 & 0.0078125d0\\[0pt]
+1.0d0 & 0.00390625d0 & 0.00390625d0\\[0pt]
+1.0d0 & 0.001953125d0 & 0.001953125d0\\[0pt]
+1.0d0 & 7.105427357601002d-15 & 7.105427357601002d-15\\[0pt]
+1.0d0 & 3.552713678800501d-15 & 3.552713678800501d-15\\[0pt]
+1.0d0 & 1.7763568394002505d-15 & 1.7763568394002505d-15\\[0pt]
+1.0d0 & 8.881784197001252d-16 & 8.881784197001252d-16\\[0pt]
+1.0d0 & 4.440892098500626d-16 & 4.440892098500626d-16\\[0pt]
+1.0d0 & 2.220446049250313d-16 & 2.220446049250313d-16\\[0pt]
+\end{tabular}
+\end{center}
+
+Thus, \(\epsilon_{\text{mac double precision}}\) \(\approx\) 2.220 \(\cdot\) 10\textsuperscript{-16}
+
+\section{Question Three - |v|\textsubscript{2}}
+\label{sec:org59c6c10}
+\begin{verbatim}
+(let ((vs '((1 1) (2 3) (4 5) (-1 2)))
+ (2-norm (lizfcm.vector:p-norm 2)))
+ (lizfcm.utils:table (:headers '("x" "y" "2norm")
+ :domain-order (x y)
+ :domain-values vs)
+ (funcall 2-norm (list x y))))
+\end{verbatim}
+
+
+\begin{center}
+\begin{tabular}{rrr}
+x & y & 2norm\\[0pt]
+1 & 1 & 1.4142135\\[0pt]
+2 & 3 & 3.6055512\\[0pt]
+4 & 5 & 6.4031243\\[0pt]
+-1 & 2 & 2.236068\\[0pt]
+\end{tabular}
+\end{center}
+
+\section{Question Four - |v|\textsubscript{1}}
+\label{sec:org2b67b3e}
+\begin{verbatim}
+(let ((vs '((1 1) (2 3) (4 5) (-1 2)))
+ (1-norm (lizfcm.vector:p-norm 1)))
+ (lizfcm.utils:table (:headers '("x" "y" "1norm")
+ :domain-order (x y)
+ :domain-values vs)
+ (funcall 1-norm (list x y))))
+\end{verbatim}
+
+
+\begin{center}
+\begin{tabular}{rrr}
+x & y & 1norm\\[0pt]
+1 & 1 & 2\\[0pt]
+2 & 3 & 5\\[0pt]
+4 & 5 & 9\\[0pt]
+-1 & 2 & 3\\[0pt]
+\end{tabular}
+\end{center}
+
+\section{Question Five - |v|\textsubscript{\(\infty\)}}
+\label{sec:org922206e}
+\begin{verbatim}
+(let ((vs '((1 1) (2 3) (4 5) (-1 2))))
+ (lizfcm.utils:table (:headers '("x" "y" "max-norm")
+ :domain-order (x y)
+ :domain-values vs)
+ (lizfcm.vector:max-norm (list x y))))
+\end{verbatim}
+
+
+\begin{center}
+\begin{tabular}{rrr}
+x & y & infty-norm\\[0pt]
+1 & 1 & 1\\[0pt]
+2 & 3 & 3\\[0pt]
+4 & 5 & 5\\[0pt]
+-1 & 2 & 2\\[0pt]
+\end{tabular}
+\end{center}
+
+\section{Question Six - ||v - u|| via |v|\textsubscript{2}}
+\label{sec:org29ec18f}
+\begin{verbatim}
+(let ((vs '((1 1) (2 3) (4 5) (-1 2)))
+ (vs2 '((7 9) (2 2) (8 -1) (4 4)))
+ (2-norm (lizfcm.vector:p-norm 2)))
+ (lizfcm.utils:table (:headers '("v1" "v2" "2-norm-d")
+ :domain-order (v1 v2)
+ :domain-values (mapcar (lambda (v1 v2)
+ (list v1 v2))
+ vs
+ vs2))
+ (lizfcm.vector:distance v1 v2 2-norm)))
+\end{verbatim}
+
+
+\begin{center}
+\begin{tabular}{llr}
+v1 & v2 & 2-norm\\[0pt]
+(1 1) & (7 9) & 10.0\\[0pt]
+(2 3) & (2 2) & 1.0\\[0pt]
+(4 5) & (8 -1) & 7.2111025\\[0pt]
+(-1 2) & (4 4) & 5.3851647\\[0pt]
+\end{tabular}
+\end{center}
+
+\section{Question Seven - ||v - u|| via |v|\textsubscript{1}}
+\label{sec:org7a87810}
+\begin{verbatim}
+(let ((vs '((1 1) (2 3) (4 5) (-1 2)))
+ (vs2 '((7 9) (2 2) (8 -1) (4 4)))
+ (1-norm (lizfcm.vector:p-norm 1)))
+ (lizfcm.utils:table (:headers '("v1" "v2" "1-norm-d")
+ :domain-order (v1 v2)
+ :domain-values (mapcar (lambda (v1 v2)
+ (list v1 v2))
+ vs
+ vs2))
+ (lizfcm.vector:distance v1 v2 1-norm)))
+\end{verbatim}
+
+
+\begin{center}
+\begin{tabular}{llr}
+v1 & v2 & 1-norm-d\\[0pt]
+(1 1) & (7 9) & 14\\[0pt]
+(2 3) & (2 2) & 1\\[0pt]
+(4 5) & (8 -1) & 10\\[0pt]
+(-1 2) & (4 4) & 7\\[0pt]
+\end{tabular}
+\end{center}
+
+\section{Question Eight - ||v - u|| via |v|\textsubscript{\(\infty\)}}
+\label{sec:org0f3b64f}
+\begin{verbatim}
+(let ((vs '((1 1) (2 3) (4 5) (-1 2)))
+ (vs2 '((7 9) (2 2) (8 -1) (4 4))))
+ (lizfcm.utils:table (:headers '("v1" "v2" "max-norm-d")
+ :domain-order (v1 v2)
+ :domain-values (mapcar (lambda (v1 v2)
+ (list v1 v2))
+ vs
+ vs2))
+ (lizfcm.vector:distance v1 v2 'lizfcm.vector:max-norm)))
+\end{verbatim}
+
+\begin{center}
+\begin{tabular}{llr}
+v1 & v2 & max-norm-d\\[0pt]
+(1 1) & (7 9) & -6\\[0pt]
+(2 3) & (2 2) & 1\\[0pt]
+(4 5) & (8 -1) & 6\\[0pt]
+(-1 2) & (4 4) & -2\\[0pt]
+\end{tabular}
+\end{center}
+\end{document} \ No newline at end of file
diff --git a/Homework/math4610/homeworks/hw-3.org b/Homework/math4610/homeworks/hw-3.org
new file mode 100644
index 0000000..8d7edcc
--- /dev/null
+++ b/Homework/math4610/homeworks/hw-3.org
@@ -0,0 +1,242 @@
+#+TITLE: HW 03
+#+AUTHOR: Elizabeth Hunt
+#+STARTUP: entitiespretty fold inlineimages
+#+LATEX_HEADER: \notindent \notag \usepackage{amsmath} \usepackage[a4paper,margin=1in,portrait]{geometry}
+#+LATEX: \setlength\parindent{0pt}
+#+OPTIONS: toc:nil
+
+* Question One
+** Three Terms
+\begin{align*}
+Si_3(x) &= \int_0^x \frac{s - \frac{s^3}{3!} + \frac{s^5}{5!}}{s} dx \\
+&= x - \frac{x^3}{(3!)(3)} + \frac{x^5}{(5!)(5)}
+\end{align*}
+** Five Terms
+\begin{align*}
+Si_3(x) &= \int_0^x \frac{s - \frac{s^3}{3!} + \frac{s^5}{5!} - \frac{s^7}{7!} + \frac{s^9}{9!}}{s} dx \\
+&= x - \frac{x^3}{(3!)(3)} + \frac{x^5}{(5!)(5)} - \frac{x^7}{(7!)(7)} + \frac{s^9}{(9!)(9)}
+\end{align*}
+** Ten Terms
+\begin{align*}
+Si_{10}(x) &= \int_0^x \frac{s - \frac{s^3}{3!} + \frac{s^5}{5!} - \frac{s^7}{7!} + \frac{s^9}{9!} - \frac{s^{11}}{11!} + \frac{s^{13}}{13!} - \frac{s^{15}}{15!} + \frac{s^{17}}{17!} - \frac{s^{19}}{19!}}{s} ds \\
+&= x - \frac{x^3}{(3!)(3)} + \frac{x^5}{(5!)(5)} - \frac{x^7}{(7!)(7)} + \frac{s^9}{(9!)(9)} - \frac{s^{11}}{(11!)(11)} + \frac{s^{13}}{(13!)(13)} - \frac{s^{15}}{(15!)(15)} \\
+&+ \frac{s^{17}}{(17!)(17)} - \frac{s^{19}}{(19!)(19)}
+\end{align*}
+* Question Three
+For the second term in the difference quotient, we can expand the taylor series centered at x=a:
+
+\begin{equation*}
+f(x) = f(a) + f'(a)(x-a) + \frac{f''(a)}{2}(x-a)^2 + \cdots \\
+\end{equation*}
+
+Which we substitute into the difference quotient:
+
+\begin{equation*}
+\frac{f(a) - f(a - h)}{h} = \frac{f(a) - (f(a) + f'(a)(x-a) + \frac{f''(a)}{2}(x-a)^2 + \cdots)}{h}
+\end{equation*}
+
+And subs. $x=a-h$:
+
+\begin{align*}
+\frac{f(a) - (f(a) + f'(a)(x-a) + \frac{f''(a)}{2}(x-a)^2 + \cdots)}{h} &= -f'(a)(-1) + -\frac{1}{2}f''(a)h \\
+&= f'(a) - \frac{1}{2}f''(a)h + \cdots \\
+\end{align*}
+
+Which we now plug into the initial $e_{\text{abs}}$:
+
+\begin{align*}
+e_{\text{abs}} &= |f'(a) - \frac{f(a) - f(a - h)}{h}| \\
+&= |f'(a) - (f'(a) + -\frac{f''(a)}{2}h + \cdots)| \\
+&= |- \frac{1}{2}f''(a)h + \cdots | \\
+\end{align*}
+
+With the Taylor Remainder theorem we can absorb the series following the second term:
+
+\begin{equation*}
+e_{\text{abs}} = |- \frac{1}{2}f''(a)h + \cdots | = |\frac{1}{2}f''(\xi)h| \leq Ch
+\end{equation*}
+
+Thus our error is bounded linearly with $h$.
+
+* Question Four
+For the first term in the difference quotient we know, from the given notes,
+
+\begin{equation*}
+f(a+h) = f(a) + f'(a)h + \frac{1}{2}f''(a)h^2 + \frac{1}{6}f'''(a)(h^3)
+\end{equation*}
+
+And from some of the work in Question Three,
+
+\begin{equation*}
+f(a - h) = f(a) + f'(a)(-h) + \frac{1}{2}f''(a)(-h)^2 + \frac{1}{6}f'''(a)(-h^3)
+\end{equation*}
+
+We can substitute immediately into $e_{\text{abs}} = |f'(a) - (\frac{f(a+h) - f(a-h)}{2h})|$:
+
+\begin{align*}
+e_{\text{abs}} &= |f'(a) - \frac{1}{2h}((f(a) + f'(a)h + \frac{1}{2}f''(a)h^2 + \cdots) - (f(a) - f'(a)h + \frac{1}{2}f''(a)h^2 + \cdots))| \\
+&= |f'(a) - \frac{1}{2h}(2f'(a)h + \frac{1}{6}f'''(a)h^3 + \cdots)| \\
+&= |f'(a) - f'(a) - \frac{1}{12}f'''(a)h^2 + \cdots| \\
+&= |-\frac{1}{12}f'''(a)h^2 + \cdots|
+\end{align*}
+
+Finally, with the Taylor Remainder theorem we can absorb the series following the third term:
+
+\begin{equation*}
+e_{\text{abs}} = |-\frac{1}{12}f'''(\xi)h^2| = |\frac{1}{12}f'''(\xi)h^2| \leq Ch^2
+\end{equation*}
+
+Meaning that as $h$ scales linearly, our error is bounded by $h^2$ as opposed to linearly as in Question Three.
+
+* Question Six
+** A
+#+BEGIN_SRC lisp
+ (load "../lizfcm.asd")
+ (ql:quickload :lizfcm)
+
+ (defun f (x)
+ (/ (- x 1) (+ x 1)))
+
+ (defun fprime (x)
+ (/ 2 (expt (+ x 1) 2)))
+
+ (let ((domain-values (loop for a from 0 to 2
+ append
+ (loop for i from 0 to 9
+ for h = (/ 1.0 (expt 2 i))
+ collect (list a h)))))
+ (lizfcm.utils:table (:headers '("a" "h" "f'" "\\approx f'" "e_{\\text{abs}}")
+ :domain-order (a h)
+ :domain-values domain-values)
+ (fprime a)
+ (lizfcm.approx:fwd-derivative-at 'f a h)
+ (abs (- (fprime a)
+ (lizfcm.approx:fwd-derivative-at 'f a h)))))
+#+END_SRC
+
+#+RESULTS:
+| a | h | f' | \approx f' | e_{\text{abs}} |
+| 0 | 1.0 | 2 | 1.0 | 1.0 |
+| 0 | 0.5 | 2 | 1.3333333 | 0.66666675 |
+| 0 | 0.25 | 2 | 1.5999999 | 0.4000001 |
+| 0 | 0.125 | 2 | 1.7777777 | 0.22222233 |
+| 0 | 0.0625 | 2 | 1.8823528 | 0.11764717 |
+| 0 | 0.03125 | 2 | 1.939394 | 0.060606003 |
+| 0 | 0.015625 | 2 | 1.9692307 | 0.030769348 |
+| 0 | 0.0078125 | 2 | 1.9844971 | 0.01550293 |
+| 0 | 0.00390625 | 2 | 1.992218 | 0.0077819824 |
+| 0 | 0.001953125 | 2 | 1.9960938 | 0.00390625 |
+| 1 | 1.0 | 1/2 | 0.33333334 | 0.16666666 |
+| 1 | 0.5 | 1/2 | 0.4 | 0.099999994 |
+| 1 | 0.25 | 1/2 | 0.44444445 | 0.055555552 |
+| 1 | 0.125 | 1/2 | 0.47058824 | 0.029411763 |
+| 1 | 0.0625 | 1/2 | 0.4848485 | 0.015151501 |
+| 1 | 0.03125 | 1/2 | 0.4923077 | 0.0076923072 |
+| 1 | 0.015625 | 1/2 | 0.49612403 | 0.0038759708 |
+| 1 | 0.0078125 | 1/2 | 0.49805447 | 0.0019455254 |
+| 1 | 0.00390625 | 1/2 | 0.49902534 | 0.00097465515 |
+| 1 | 0.001953125 | 1/2 | 0.4995122 | 0.0004878044 |
+| 2 | 1.0 | 2/9 | 0.16666666 | 0.055555567 |
+| 2 | 0.5 | 2/9 | 0.19047618 | 0.031746045 |
+| 2 | 0.25 | 2/9 | 0.2051282 | 0.017094031 |
+| 2 | 0.125 | 2/9 | 0.21333337 | 0.008888856 |
+| 2 | 0.0625 | 2/9 | 0.21768713 | 0.004535094 |
+| 2 | 0.03125 | 2/9 | 0.21993065 | 0.002291575 |
+| 2 | 0.015625 | 2/9 | 0.22106934 | 0.0011528879 |
+| 2 | 0.0078125 | 2/9 | 0.22164536 | 0.00057686865 |
+| 2 | 0.00390625 | 2/9 | 0.22193146 | 0.00029076636 |
+| 2 | 0.001953125 | 2/9 | 0.22207642 | 0.00014580786 |
+
+* Question Nine
+** C
+
+#+BEGIN_SRC lisp
+ (load "../lizfcm.asd")
+ (ql:quickload :lizfcm)
+
+ (defun factorial (n)
+ (if (= n 0)
+ 1
+ (* n (factorial (- n 1)))))
+
+ (defun taylor-term (n x)
+ (/ (* (expt (- 1) n)
+ (expt x (+ (* 2 n) 1)))
+ (* (factorial n)
+ (+ (* 2 n) 1))))
+
+ (defun f (x &optional (max-iterations 30))
+ (let ((sum 0.0))
+ (dotimes (n max-iterations)
+ (setq sum (+ sum (taylor-term n x))))
+ (* sum (/ 2 (sqrt pi)))))
+
+ (defun fprime (x)
+ (* (/ 2 (sqrt pi)) (exp (- 0 (* x x)))))
+
+ (let ((domain-values (loop for a from 0 to 1
+ append
+ (loop for i from 0 to 9
+ for h = (/ 1.0 (expt 2 i))
+ collect (list a h)))))
+ (lizfcm.utils:table (:headers '("a" "h" "f'" "\\approx f'" "e_{\\text{abs}}")
+ :domain-order (a h)
+ :domain-values domain-values)
+ (fprime a)
+ (lizfcm.approx:central-derivative-at 'f a h)
+ (abs (- (fprime a)
+ (lizfcm.approx:central-derivative-at 'f a h)))))
+#+END_SRC
+
+
+| a | h | f' | \approx f' | e_{\text{abs}} |
+| 0 | 1.0 | 1.1283791670955126d0 | 0.8427006725464232d0 | 0.28567849454908933d0 |
+| 0 | 0.5 | 1.1283791670955126d0 | 1.0409997446922075d0 | 0.0873794224033051d0 |
+| 0 | 0.25 | 1.1283791670955126d0 | 1.1053055663206806d0 | 0.023073600774832004d0 |
+| 0 | 0.125 | 1.1283791670955126d0 | 1.122529655394656d0 | 0.005849511700856569d0 |
+| 0 | 0.0625 | 1.1283791670955126d0 | 1.1269116944798618d0 | 0.0014674726156507223d0 |
+| 0 | 0.03125 | 1.1283791670955126d0 | 1.1280120131008824d0 | 3.6715399463016496d-4 |
+| 0 | 0.015625 | 1.1283791670955126d0 | 1.1282873617826952d0 | 9.180531281738347d-5 |
+| 0 | 0.0078125 | 1.1283791670955126d0 | 1.128356232581468d0 | 2.293451404455915d-5 |
+| 0 | 0.00390625 | 1.1283791670955126d0 | 1.1283734502811613d0 | 5.71681435124205d-6 |
+| 0 | 0.001953125 | 1.1283791670955126d0 | 1.1283777547060847d0 | 1.4123894278572635d-6 |
+| 1 | 1.0 | 0.41510750774498784d0 | 0.4976611317561498d0 | 0.08255362401116195d0 |
+| 1 | 0.5 | 0.41510750774498784d0 | 0.44560523266293384d0 | 0.030497724917946d0 |
+| 1 | 0.25 | 0.41510750774498784d0 | 0.4234889628937013d0 | 0.008381455148713468d0 |
+| 1 | 0.125 | 0.41510750774498784d0 | 0.41725265825950153d0 | 0.002145150514513694d0 |
+| 1 | 0.0625 | 0.41510750774498784d0 | 0.41564710776310854d0 | 5.396000181207006d-4 |
+| 1 | 0.03125 | 0.41510750774498784d0 | 0.4152414157140871d0 | 1.3390796909928948d-4 |
+| 1 | 0.015625 | 0.41510750774498784d0 | 0.41514241394084905d0 | 3.490619586121735d-5 |
+| 1 | 0.0078125 | 0.41510750774498784d0 | 0.41510582632900395d0 | 1.6814159838896003d-6 |
+| 1 | 0.00390625 | 0.41510750774498784d0 | 0.415092913054238d0 | 1.4594690749825112d-5 |
+| 1 | 0.001953125 | 0.41510750774498784d0 | 0.4150670865046777d0 | 4.0421240310117845d-5 |
+
+* Question Twelve
+
+First we'll place a bound on $h$; looking at a graph of $f$ it's pretty obvious from the asymptotes that we don't want to go much further than $|h| = 2 - \frac{pi}{2}$.
+
+Following similar reasoning as Question Four, we can determine an optimal $h$ by computing $e_{\text{abs}}$ for the central difference, but now including a roundoff error for each time we run $f$
+such that $|f_{\text{machine}}(x) - f(x)| \le \epsilon_{\text{dblprec}}$ (we'll use double precision numbers, from HW 2 we know $\epsilon_{\text{dblprec}} \approx 2.22045 (10^{-16})$).
+
+We'll just assume $|f_{\text{machine}}(x) - f(x)| = \epsilon_{\text{dblprec}}$ so our new difference quotient becomes:
+
+\begin{align*}
+e_{\text{abs}} &= |f'(a) - (\frac{f(a+h) - f(a-h) + 2\epsilon_{\text{dblprec}}}{2h})| \\
+&= |\frac{1}{12}f'''(\xi)h^2 + \frac{\epsilon_{\text{dblprec}}}{h}|
+\end{align*}
+
+Because we bounded our $|h| = 2 - \frac{pi}{2}$ we'll find the maximum value of $f'''$ between $a - (2 - \frac{\pi}{2})$ and $a - (2 - \frac{\pi}{3})$. Using [[https://www.desmos.com/calculator/gen1zpohh2][desmos]] I found this to be -2.
+
+Thus, $e_{\text{abs}} \leq \frac{1}{6}h^2 + \frac{\epsilon_{\text{dblprec}}}{h}$. Finding the derivative:
+
+\begin{equation*}
+e' = \frac{1}{3}h - \frac{\epsilon_{\text{dblprec}}}{h^2}
+\end{equation*}
+
+And solving at $e' = 0$:
+
+\begin{equation*}
+\frac{1}{3}h = \frac{\epsilon_{\text{dblprec}}}{h^2} \Rightarrow h^3 = 3\epsilon_{\text{dblprec}} \Rightarrow h = (3\epsilon_{\text{dblprec}})^{1/3}
+\end{equation*}
+
+Which is $\approx (3(2.22045 (10^{-16}))^{\frac{1}{3}} \approx 8.7335 10^{-6}$.
diff --git a/Homework/math4610/homeworks/hw-3.pdf b/Homework/math4610/homeworks/hw-3.pdf
new file mode 100644
index 0000000..1f9bac6
--- /dev/null
+++ b/Homework/math4610/homeworks/hw-3.pdf
Binary files differ
diff --git a/Homework/math4610/homeworks/hw-3.tex b/Homework/math4610/homeworks/hw-3.tex
new file mode 100644
index 0000000..b3d029d
--- /dev/null
+++ b/Homework/math4610/homeworks/hw-3.tex
@@ -0,0 +1,250 @@
+% Created 2023-10-07 Sat 14:49
+% 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{HW 03}
+\hypersetup{
+ pdfauthor={Elizabeth Hunt},
+ pdftitle={HW 03},
+ pdfkeywords={},
+ pdfsubject={},
+ pdfcreator={Emacs 28.2 (Org mode 9.7-pre)},
+ pdflang={English}}
+\begin{document}
+
+\maketitle
+\setlength\parindent{0pt}
+
+\section{Question One}
+\label{sec:org6f2bd27}
+\subsection{Three Terms}
+\label{sec:orgeb827ff}
+\begin{align*}
+Si_3(x) &= \int_0^x \frac{s - \frac{s^3}{3!} + \frac{s^5}{5!}}{s} dx \\
+&= x - \frac{x^3}{(3!)(3)} + \frac{x^5}{(5!)(5)}
+\end{align*}
+\subsection{Five Terms}
+\label{sec:orge6a15e4}
+\begin{align*}
+Si_3(x) &= \int_0^x \frac{s - \frac{s^3}{3!} + \frac{s^5}{5!} - \frac{s^7}{7!} + \frac{s^9}{9!}}{s} dx \\
+&= x - \frac{x^3}{(3!)(3)} + \frac{x^5}{(5!)(5)} - \frac{x^7}{(7!)(7)} + \frac{s^9}{(9!)(9)}
+\end{align*}
+\subsection{Ten Terms}
+\label{sec:orge87e346}
+\begin{align*}
+Si_{10}(x) &= \int_0^x \frac{s - \frac{s^3}{3!} + \frac{s^5}{5!} - \frac{s^7}{7!} + \frac{s^9}{9!} - \frac{s^{11}}{11!} + \frac{s^{13}}{13!} - \frac{s^{15}}{15!} + \frac{s^{17}}{17!} - \frac{s^{19}}{19!}}{s} ds \\
+&= x - \frac{x^3}{(3!)(3)} + \frac{x^5}{(5!)(5)} - \frac{x^7}{(7!)(7)} + \frac{s^9}{(9!)(9)} - \frac{s^{11}}{(11!)(11)} + \frac{s^{13}}{(13!)(13)} - \frac{s^{15}}{(15!)(15)} \\
+&+ \frac{s^{17}}{(17!)(17)} - \frac{s^{19}}{(19!)(19)}
+\end{align*}
+\section{Question Three}
+\label{sec:org6e2f7fc}
+For the second term in the difference quotient, we can expand the taylor series centered at x=a:
+
+\begin{equation*}
+f(x) = f(a) + f'(a)(x-a) + \frac{f''(a)}{2}(x-a)^2 + \cdots \\
+\end{equation*}
+
+Which we substitute into the difference quotient:
+
+\begin{equation*}
+\frac{f(a) - f(a - h)}{h} = \frac{f(a) - (f(a) + f'(a)(x-a) + \frac{f''(a)}{2}(x-a)^2 + \cdots)}{h}
+\end{equation*}
+
+And subs. \(x=a-h\):
+
+\begin{align*}
+\frac{f(a) - (f(a) + f'(a)(x-a) + \frac{f''(a)}{2}(x-a)^2 + \cdots)}{h} &= -f'(a)(-1) + -\frac{1}{2}f''(a)h \\
+&= f'(a) - \frac{1}{2}f''(a)h + \cdots \\
+\end{align*}
+
+Which we now plug into the initial \(e_{\text{abs}}\):
+
+\begin{align*}
+e_{\text{abs}} &= |f'(a) - \frac{f(a) - f(a - h)}{h}| \\
+&= |f'(a) - (f'(a) + -\frac{f''(a)}{2}h + \cdots)| \\
+&= |- \frac{1}{2}f''(a)h + \cdots | \\
+\end{align*}
+
+With the Taylor Remainder theorem we can absorb the series following the second term:
+
+\begin{equation*}
+e_{\text{abs}} = |- \frac{1}{2}f''(a)h + \cdots | = |\frac{1}{2}f''(\xi)h| \leq Ch
+\end{equation*}
+
+Thus our error is bounded linearly with \(h\).
+
+\section{Question Four}
+\label{sec:orga7d02a2}
+For the first term in the difference quotient we know, from the given notes,
+
+\begin{equation*}
+f(a+h) = f(a) + f'(a)h + \frac{1}{2}f''(a)h^2 + \frac{1}{6}f'''(a)(h^3)
+\end{equation*}
+
+And from some of the work in Question Three,
+
+\begin{equation*}
+f(a - h) = f(a) + f'(a)(-h) + \frac{1}{2}f''(a)(-h)^2 + \frac{1}{6}f'''(a)(-h^3)
+\end{equation*}
+
+We can substitute immediately into \(e_{\text{abs}} = |f'(a) - (\frac{f(a+h) - f(a-h)}{2h})|\):
+
+\begin{align*}
+e_{\text{abs}} &= |f'(a) - \frac{1}{2h}((f(a) + f'(a)h + \frac{1}{2}f''(a)h^2 + \cdots) - (f(a) - f'(a)h + \frac{1}{2}f''(a)h^2 + \cdots))| \\
+&= |f'(a) - \frac{1}{2h}(2f'(a)h + \frac{1}{6}f'''(a)h^3 + \cdots)| \\
+&= |f'(a) - f'(a) - \frac{1}{12}f'''(a)h^2 + \cdots| \\
+&= |-\frac{1}{12}f'''(a)h^2 + \cdots|
+\end{align*}
+
+Finally, with the Taylor Remainder theorem we can absorb the series following the third term:
+
+\begin{equation*}
+e_{\text{abs}} = |-\frac{1}{12}f'''(\xi)h^2| = |\frac{1}{12}f'''(\xi)h^2| \leq Ch^2
+\end{equation*}
+
+Meaning that as \(h\) scales linearly, our error is bounded by \(h^2\) as opposed to linearly as in Question Three.
+
+\section{Question Six}
+\label{sec:org7b05811}
+\subsection{A}
+\label{sec:org8341a77}
+\begin{verbatim}
+(load "../lizfcm.asd")
+(ql:quickload :lizfcm)
+
+(defun f (x)
+ (/ (- x 1) (+ x 1)))
+
+(defun fprime (x)
+ (/ 2 (expt (+ x 1) 2)))
+
+(let ((domain-values (loop for a from 0 to 2
+ append
+ (loop for i from 0 to 9
+ for h = (/ 1.0 (expt 2 i))
+ collect (list a h)))))
+ (lizfcm.utils:table (:headers '("a" "h" "f'" "\\approx f'" "e_{\\text{abs}}")
+ :domain-order (a h)
+ :domain-values domain-values)
+ (fprime a)
+ (lizfcm.approx:fwd-derivative-at 'f a h)
+ (abs (- (fprime a)
+ (lizfcm.approx:fwd-derivative-at 'f a h)))))
+\end{verbatim}
+
+
+\section{Question Nine}
+\label{sec:orgeb1839f}
+\subsection{C}
+\label{sec:org5691277}
+
+\begin{verbatim}
+(load "../lizfcm.asd")
+(ql:quickload :lizfcm)
+
+(defun factorial (n)
+ (if (= n 0)
+ 1
+ (* n (factorial (- n 1)))))
+
+(defun taylor-term (n x)
+ (/ (* (expt (- 1) n)
+ (expt x (+ (* 2 n) 1)))
+ (* (factorial n)
+ (+ (* 2 n) 1))))
+
+(defun f (x &optional (max-iterations 30))
+ (let ((sum 0.0))
+ (dotimes (n max-iterations)
+ (setq sum (+ sum (taylor-term n x))))
+ (* sum (/ 2 (sqrt pi)))))
+
+(defun fprime (x)
+ (* (/ 2 (sqrt pi)) (exp (- 0 (* x x)))))
+
+(let ((domain-values (loop for a from 0 to 1
+ append
+ (loop for i from 0 to 9
+ for h = (/ 1.0 (expt 2 i))
+ collect (list a h)))))
+ (lizfcm.utils:table (:headers '("a" "h" "f'" "\\approx f'" "e_{\\text{abs}}")
+ :domain-order (a h)
+ :domain-values domain-values)
+ (fprime a)
+ (lizfcm.approx:central-derivative-at 'f a h)
+ (abs (- (fprime a)
+ (lizfcm.approx:central-derivative-at 'f a h)))))
+\end{verbatim}
+
+
+\begin{center}
+\begin{tabular}{rrrrr}
+a & h & f' & \(\approx\) f' & e\textsubscript{\text{abs}}\\[0pt]
+0 & 1.0 & 1.1283791670955126d0 & 0.8427006725464232d0 & 0.28567849454908933d0\\[0pt]
+0 & 0.5 & 1.1283791670955126d0 & 1.0409997446922075d0 & 0.0873794224033051d0\\[0pt]
+0 & 0.25 & 1.1283791670955126d0 & 1.1053055663206806d0 & 0.023073600774832004d0\\[0pt]
+0 & 0.125 & 1.1283791670955126d0 & 1.122529655394656d0 & 0.005849511700856569d0\\[0pt]
+0 & 0.0625 & 1.1283791670955126d0 & 1.1269116944798618d0 & 0.0014674726156507223d0\\[0pt]
+0 & 0.03125 & 1.1283791670955126d0 & 1.1280120131008824d0 & 3.6715399463016496d-4\\[0pt]
+0 & 0.015625 & 1.1283791670955126d0 & 1.1282873617826952d0 & 9.180531281738347d-5\\[0pt]
+0 & 0.0078125 & 1.1283791670955126d0 & 1.128356232581468d0 & 2.293451404455915d-5\\[0pt]
+0 & 0.00390625 & 1.1283791670955126d0 & 1.1283734502811613d0 & 5.71681435124205d-6\\[0pt]
+0 & 0.001953125 & 1.1283791670955126d0 & 1.1283777547060847d0 & 1.4123894278572635d-6\\[0pt]
+1 & 1.0 & 0.41510750774498784d0 & 0.4976611317561498d0 & 0.08255362401116195d0\\[0pt]
+1 & 0.5 & 0.41510750774498784d0 & 0.44560523266293384d0 & 0.030497724917946d0\\[0pt]
+1 & 0.25 & 0.41510750774498784d0 & 0.4234889628937013d0 & 0.008381455148713468d0\\[0pt]
+1 & 0.125 & 0.41510750774498784d0 & 0.41725265825950153d0 & 0.002145150514513694d0\\[0pt]
+1 & 0.0625 & 0.41510750774498784d0 & 0.41564710776310854d0 & 5.396000181207006d-4\\[0pt]
+1 & 0.03125 & 0.41510750774498784d0 & 0.4152414157140871d0 & 1.3390796909928948d-4\\[0pt]
+1 & 0.015625 & 0.41510750774498784d0 & 0.41514241394084905d0 & 3.490619586121735d-5\\[0pt]
+1 & 0.0078125 & 0.41510750774498784d0 & 0.41510582632900395d0 & 1.6814159838896003d-6\\[0pt]
+1 & 0.00390625 & 0.41510750774498784d0 & 0.415092913054238d0 & 1.4594690749825112d-5\\[0pt]
+1 & 0.001953125 & 0.41510750774498784d0 & 0.4150670865046777d0 & 4.0421240310117845d-5\\[0pt]
+\end{tabular}
+\end{center}
+
+
+\section{Question Twelve}
+\label{sec:orgc55bfd1}
+
+First we'll place a bound on \(h\); looking at a graph of \(f\) it's pretty obvious from the asymptotes that we don't want to go much further than \(|h| = 2 - \frac{pi}{2}\).
+
+Following similar reasoning as Question Four, we can determine an optimal \(h\) by computing \(e_{\text{abs}}\) for the central difference, but now including a roundoff error for each time we run \(f\)
+such that \(|f_{\text{machine}}(x) - f(x)| \le \epsilon_{\text{dblprec}}\) (we'll use double precision numbers, from HW 2 we know \(\epsilon_{\text{dblprec}} \approx 2.22045 (10^{-16})\)).
+
+We'll just assume \(|f_{\text{machine}}(x) - f(x)| = \epsilon_{\text{dblprec}}\) so our new difference quotient becomes:
+
+\begin{align*}
+e_{\text{abs}} &= |f'(a) - (\frac{f(a+h) - f(a-h) + 2\epsilon_{\text{dblprec}}}{2h})| \\
+&= |\frac{1}{12}f'''(\xi)h^2 + \frac{\epsilon_{\text{dblprec}}}{h}|
+\end{align*}
+
+Because we bounded our \(|h| = 2 - \frac{pi}{2}\) we'll find the maximum value of \(f'''\) between \(a - (2 - \frac{\pi}{2})\) and \(a - (2 - \frac{\pi}{3})\). Using \href{https://www.desmos.com/calculator/gen1zpohh2}{desmos} I found this to be -2.
+
+Thus, \(e_{\text{abs}} \leq \frac{1}{6}h^2 + \frac{\epsilon_{\text{dblprec}}}{h}\). Finding the derivative:
+
+\begin{equation*}
+e' = \frac{1}{3}h - \frac{\epsilon_{\text{dblprec}}}{h^2}
+\end{equation*}
+
+And solving at \(e' = 0\):
+
+\begin{equation*}
+\frac{1}{3}h = \frac{\epsilon_{\text{dblprec}}}{h^2} \Rightarrow h^3 = 3\epsilon_{\text{dblprec}} \Rightarrow h = (3\epsilon_{\text{dblprec}})^{1/3}
+\end{equation*}
+
+Which is \(\approx (3(2.22045 (10^{-16}))^{\frac{1}{3}} \approx 8.7335 10^{-6}\).
+\end{document} \ No newline at end of file
diff --git a/Homework/math4610/homeworks/hw-4.org b/Homework/math4610/homeworks/hw-4.org
new file mode 100644
index 0000000..8884f63
--- /dev/null
+++ b/Homework/math4610/homeworks/hw-4.org
@@ -0,0 +1,34 @@
+#+TITLE: Homework 4
+#+AUTHOR: Elizabeth Hunt
+#+LATEX_HEADER: \notindent \notag \usepackage{amsmath} \usepackage[a4paper,margin=1in,portrait]{geometry}
+#+LATEX: \setlength\parindent{0pt}
+#+OPTIONS: toc:nil
+
+* Question 1
+See the attached LIZFCM Software Manual.
+
+* Question 2, 3, 4
+#+attr_latex: :width 350px
+[[./img/make_run.png]]
+
+* Question 5
+#+attr_latex: :width 350px
+[[./img/test_routine_1.png]]
+
+#+attr_latex: :width 350px
+[[./img/test_routine_2.png]]
+
+* Question 6
+See the LIZFCM Software Manual.
+
+* Question 7
+See ~src/matrix.c -> lu_decomp, fsubst, bsubst, solve_matrix~
+
+* Question 8
+See ~test/main.c -> lines 109 - 113~ in correspondence to the run in Question 5
+
+* Question 9
+See ~test/main.c -> lines 118 - 121~ in correspondence to the run in Question 5
+
+* Question 10
+See the TOC on the first page of the LIZFCM Software Manual.
diff --git a/Homework/math4610/homeworks/hw-4.pdf b/Homework/math4610/homeworks/hw-4.pdf
new file mode 100644
index 0000000..35176a1
--- /dev/null
+++ b/Homework/math4610/homeworks/hw-4.pdf
Binary files differ
diff --git a/Homework/math4610/homeworks/hw-4.tex b/Homework/math4610/homeworks/hw-4.tex
new file mode 100644
index 0000000..7a83378
--- /dev/null
+++ b/Homework/math4610/homeworks/hw-4.tex
@@ -0,0 +1,70 @@
+% Created 2023-10-13 Fri 21:11
+% 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 4}
+\hypersetup{
+ pdfauthor={Elizabeth Hunt},
+ pdftitle={Homework 4},
+ pdfkeywords={},
+ pdfsubject={},
+ pdfcreator={Emacs 28.2 (Org mode 9.7-pre)},
+ pdflang={English}}
+\begin{document}
+
+\maketitle
+\setlength\parindent{0pt}
+
+\section{Question 1}
+\label{sec:orgf7348d4}
+See the attached LIZFCM Software Manual.
+
+\section{Question 2, 3, 4}
+\label{sec:orgaf52510}
+\begin{center}
+\includegraphics[width=350px]{./img/make_run.png}
+\end{center}
+
+\section{Question 5}
+\label{sec:orgd0fe6e8}
+\begin{center}
+\includegraphics[width=350px]{./img/test_routine_1.png}
+\end{center}
+
+\begin{center}
+\includegraphics[width=350px]{./img/test_routine_2.png}
+\end{center}
+
+\section{Question 6}
+\label{sec:org9e2023c}
+See the LIZFCM Software Manual.
+
+\section{Question 7}
+\label{sec:org6c11571}
+See \texttt{src/matrix.c -> lu\_decomp, fsubst, bsubst, solve\_matrix}
+
+\section{Question 8}
+\label{sec:org9ba7792}
+See \texttt{test/main.c -> lines 109 - 113} in correspondence to the run in Question 5
+
+\section{Question 9}
+\label{sec:org3cff888}
+See \texttt{test/main.c -> lines 118 - 121} in correspondence to the run in Question 5
+
+\section{Question 10}
+\label{sec:org522eabc}
+See the TOC on the first page of the LIZFCM Software Manual.
+\end{document} \ No newline at end of file
diff --git a/Homework/math4610/homeworks/hw-5.org b/Homework/math4610/homeworks/hw-5.org
new file mode 100644
index 0000000..a2339f9
--- /dev/null
+++ b/Homework/math4610/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 (quite obviously) in 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/Homework/math4610/homeworks/hw-5.pdf b/Homework/math4610/homeworks/hw-5.pdf
new file mode 100644
index 0000000..a7773bc
--- /dev/null
+++ b/Homework/math4610/homeworks/hw-5.pdf
Binary files differ
diff --git a/Homework/math4610/homeworks/hw-5.tex b/Homework/math4610/homeworks/hw-5.tex
new file mode 100644
index 0000000..98cca2e
--- /dev/null
+++ b/Homework/math4610/homeworks/hw-5.tex
@@ -0,0 +1,95 @@
+% Created 2023-11-01 Wed 20:49
+% 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:org4e80298}
+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:orga73d05c}
+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 (quite obviously) in 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:org35163c5}
+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:org79d9061}
+
+See LIZFCM \(\rightarrow\) Matrix Routines \(\rightarrow\) \texttt{gaussian\_elimination} and \texttt{solve\_gaussian\_elimination}.
+
+\section{Question Five}
+\label{sec:orgc6ac464}
+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:org66fedab}
+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:org6897ff2}
+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:org5d529dd}
+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:org0fb8e09}
+See LIZFCM Software manual and shared library in \texttt{dist} after compiling.
+\end{document} \ No newline at end of file
diff --git a/Homework/math4610/homeworks/hw-6.org b/Homework/math4610/homeworks/hw-6.org
new file mode 100644
index 0000000..eebc0c2
--- /dev/null
+++ b/Homework/math4610/homeworks/hw-6.org
@@ -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
+
+
diff --git a/Homework/math4610/homeworks/hw-6.pdf b/Homework/math4610/homeworks/hw-6.pdf
new file mode 100644
index 0000000..c056102
--- /dev/null
+++ b/Homework/math4610/homeworks/hw-6.pdf
Binary files differ
diff --git a/Homework/math4610/homeworks/hw-6.tex b/Homework/math4610/homeworks/hw-6.tex
new file mode 100644
index 0000000..1a0ddc4
--- /dev/null
+++ b/Homework/math4610/homeworks/hw-6.tex
@@ -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}
diff --git a/Homework/math4610/homeworks/hw-7.org b/Homework/math4610/homeworks/hw-7.org
new file mode 100644
index 0000000..2c28af2
--- /dev/null
+++ b/Homework/math4610/homeworks/hw-7.org
@@ -0,0 +1,76 @@
+#+TITLE: Homework 7
+#+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 ~UTEST(eigen, dominant_eigenvalue)~ in ~test/eigen.t.c~ and the entry
+~Eigen-Adjacent -> dominant_eigenvalue~ in the LIZFCM API documentation.
+* Question Two
+See ~UTEST(eigen, leslie_matrix_dominant_eigenvalue)~ in ~test/eigen.t.c~
+and the entry ~Eigen-Adjacent -> leslie_matrix~ in the LIZFCM API
+documentation.
+* Question Three
+See ~UTEST(eigen, least_dominant_eigenvalue)~ in ~test/eigen.t.c~ which
+finds the least dominant eigenvalue on the matrix:
+
+\begin{bmatrix}
+2 & 2 & 4 \\
+1 & 4 & 7 \\
+0 & 2 & 6
+\end{bmatrix}
+
+which has eigenvalues: $5 + \sqrt{17}, 2, 5 - \sqrt{17}$ and should thus produce $5 - \sqrt{17}$.
+
+See also the entry ~Eigen-Adjacent -> least_dominant_eigenvalue~ in the LIZFCM API
+documentation.
+* Question Four
+See ~UTEST(eigen, shifted_eigenvalue)~ in ~test/eigen.t.c~ which
+finds the least dominant eigenvalue on the matrix:
+
+\begin{bmatrix}
+2 & 2 & 4 \\
+1 & 4 & 7 \\
+0 & 2 & 6
+\end{bmatrix}
+
+which has eigenvalues: $5 + \sqrt{17}, 2, 5 - \sqrt{17}$ and should thus produce $2.0$.
+
+With the initial guess: $[0.5, 1.0, 0.75]$.
+
+See also the entry ~Eigen-Adjacent -> shift_inverse_power_eigenvalue~ in the LIZFCM API
+documentation.
+* Question Five
+See ~UTEST(eigen, partition_find_eigenvalues)~ in ~test/eigen.t.c~ which
+finds the eigenvalues in a partition of 10 on the matrix:
+
+\begin{bmatrix}
+2 & 2 & 4 \\
+1 & 4 & 7 \\
+0 & 2 & 6
+\end{bmatrix}
+
+which has eigenvalues: $5 + \sqrt{17}, 2, 5 - \sqrt{17}$, and should produce all three from
+the partitions when given the guesses $[0.5, 1.0, 0.75]$ from the questions above.
+
+See also the entry ~Eigen-Adjacent -> partition_find_eigenvalues~ in the LIZFCM API
+documentation.
+
+* Question Six
+Consider we have the results of two methods developed in this homework: ~least_dominant_eigenvalue~, and ~dominant_eigenvalue~
+into ~lambda_0~, ~lambda_n~, respectively. Also assume that we have the method implemented as we've introduced,
+~shift_inverse_power_eigenvalue~.
+
+Then, we begin at the midpoint of ~lambda_0~ and ~lambda_n~, and compute the
+~new_lambda = shift_inverse_power_eigenvalue~
+with a shift at the midpoint, and some given initial guess.
+
+1. If the result is equal (or within some tolerance) to ~lambda_n~ then the closest eigenvalue to the midpoint
+ is still the dominant eigenvalue, and thus the next most dominant will be on the left. Set ~lambda_n~
+ to the midpoint and reiterate.
+2. If the result is greater or equal to ~lambda_0~ we know an eigenvalue of greater or equal magnitude
+ exists on the right. So, we set ~lambda_0~ to this eigenvalue associated with the midpoint, and
+ re-iterate.
+3. Continue re-iterating until we hit some given maximum number of iterations. Finally we will return
+ ~new_lambda~.
diff --git a/Homework/math4610/homeworks/hw-7.pdf b/Homework/math4610/homeworks/hw-7.pdf
new file mode 100644
index 0000000..4003f59
--- /dev/null
+++ b/Homework/math4610/homeworks/hw-7.pdf
Binary files differ
diff --git a/Homework/math4610/homeworks/hw-7.tex b/Homework/math4610/homeworks/hw-7.tex
new file mode 100644
index 0000000..be3fde4
--- /dev/null
+++ b/Homework/math4610/homeworks/hw-7.tex
@@ -0,0 +1,107 @@
+% Created 2023-11-27 Mon 15: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 7}
+\hypersetup{
+ pdfauthor={Elizabeth Hunt},
+ pdftitle={Homework 7},
+ pdfkeywords={},
+ pdfsubject={},
+ pdfcreator={Emacs 29.1 (Org mode 9.7-pre)},
+ pdflang={English}}
+\begin{document}
+
+\maketitle
+\setlength\parindent{0pt}
+\section{Question One}
+\label{sec:org8ef0ee6}
+See \texttt{UTEST(eigen, dominant\_eigenvalue)} in \texttt{test/eigen.t.c} and the entry
+\texttt{Eigen-Adjacent -> dominant\_eigenvalue} in the LIZFCM API documentation.
+\section{Question Two}
+\label{sec:orgbdba5c1}
+See \texttt{UTEST(eigen, leslie\_matrix\_dominant\_eigenvalue)} in \texttt{test/eigen.t.c}
+and the entry \texttt{Eigen-Adjacent -> leslie\_matrix} in the LIZFCM API
+documentation.
+\section{Question Three}
+\label{sec:org19b04f4}
+See \texttt{UTEST(eigen, least\_dominant\_eigenvalue)} in \texttt{test/eigen.t.c} which
+finds the least dominant eigenvalue on the matrix:
+
+\begin{bmatrix}
+2 & 2 & 4 \\
+1 & 4 & 7 \\
+0 & 2 & 6
+\end{bmatrix}
+
+which has eigenvalues: \(5 + \sqrt{17}, 2, 5 - \sqrt{17}\) and should thus produce \(5 - \sqrt{17}\).
+
+See also the entry \texttt{Eigen-Adjacent -> least\_dominant\_eigenvalue} in the LIZFCM API
+documentation.
+\section{Question Four}
+\label{sec:orgc58d42d}
+See \texttt{UTEST(eigen, shifted\_eigenvalue)} in \texttt{test/eigen.t.c} which
+finds the least dominant eigenvalue on the matrix:
+
+\begin{bmatrix}
+2 & 2 & 4 \\
+1 & 4 & 7 \\
+0 & 2 & 6
+\end{bmatrix}
+
+which has eigenvalues: \(5 + \sqrt{17}, 2, 5 - \sqrt{17}\) and should thus produce \(2.0\).
+
+With the initial guess: \([0.5, 1.0, 0.75]\).
+
+See also the entry \texttt{Eigen-Adjacent -> shift\_inverse\_power\_eigenvalue} in the LIZFCM API
+documentation.
+\section{Question Five}
+\label{sec:orga369221}
+See \texttt{UTEST(eigen, partition\_find\_eigenvalues)} in \texttt{test/eigen.t.c} which
+finds the eigenvalues in a partition of 10 on the matrix:
+
+\begin{bmatrix}
+2 & 2 & 4 \\
+1 & 4 & 7 \\
+0 & 2 & 6
+\end{bmatrix}
+
+which has eigenvalues: \(5 + \sqrt{17}, 2, 5 - \sqrt{17}\), and should produce all three from
+the partitions when given the guesses \([0.5, 1.0, 0.75]\) from the questions above.
+
+See also the entry \texttt{Eigen-Adjacent -> partition\_find\_eigenvalues} in the LIZFCM API
+documentation.
+\section{Question Six}
+\label{sec:orgadc3078}
+Consider we have the results of two methods developed in this homework: \texttt{least\_dominant\_eigenvalue}, and \texttt{dominant\_eigenvalue}
+into \texttt{lambda\_0}, \texttt{lambda\_n}, respectively. Also assume that we have the method implemented as we've introduced,
+\texttt{shift\_inverse\_power\_eigenvalue}.
+
+Then, we begin at the midpoint of \texttt{lambda\_0} and \texttt{lambda\_n}, and compute the
+\texttt{new\_lambda = shift\_inverse\_power\_eigenvalue}
+with a shift at the midpoint, and some given initial guess.
+
+\begin{enumerate}
+\item If the result is equal (or within some tolerance) to \texttt{lambda\_n} then the closest eigenvalue to the midpoint
+is still the dominant eigenvalue, and thus the next most dominant will be on the left. Set \texttt{lambda\_n}
+to the midpoint and reiterate.
+\item If the result is greater or equal to \texttt{lambda\_0} we know an eigenvalue of greater or equal magnitude
+exists on the right. So, we set \texttt{lambda\_0} to this eigenvalue associated with the midpoint, and
+re-iterate.
+\item Continue re-iterating until we hit some given maximum number of iterations. Finally we will return
+\texttt{new\_lambda}.
+\end{enumerate}
+\end{document}
diff --git a/Homework/math4610/homeworks/hw-8.org b/Homework/math4610/homeworks/hw-8.org
new file mode 100644
index 0000000..10c7dd8
--- /dev/null
+++ b/Homework/math4610/homeworks/hw-8.org
@@ -0,0 +1,311 @@
+#+TITLE: Homework 8
+#+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 ~UTEST(jacobi, solve_jacobi)~ in ~test/jacobi.t.c~ and the entry
+~Jacobi / Gauss-Siedel -> solve_jacobi~ in the LIZFCM API documentation.
+* Question Two
+We cannot just perform the Jacobi algorithm on a Leslie matrix since
+it is obviously not diagonally dominant - which is a requirement. It is
+certainly not always the case, but, if a Leslie matrix $L$ is invertible, we can
+first perform gaussian elimination on $L$ augmented with $n_{k+1}$
+to obtain $n_k$ with the Jacobi method. See ~UTEST(jacobi, leslie_solve)~
+in ~test/jacobi.t.c~ for an example wherein this method is tested on a Leslie
+matrix to recompute a given initial population distribution.
+
+In terms of accuracy, an LU factorization and back substitution approach will
+always be as correct as possible within the limits of computation; it's a
+direct solution method. It's simply the nature of the Jacobi algorithm being
+a convergent solution that determines its accuracy.
+
+LU factorization also performs in order $O(n^3)$ runtime for an $n \times n$
+matrix, whereas the Jacobi algorithm runs in order $O(k n^2) = O(n^2)$ on average
+but with the con that $k$ is given by some function on both the convergence criteria and the number of
+nonzero entries in the matrix - which might end up worse in some cases than the LU decomp approach.
+
+* Question Three
+See ~UTEST(jacobi, gauss_siedel_solve)~ in ~test/jacobi.t.c~ which runs the same
+unit test as ~UTEST(jacobi, solve_jacobi)~ but using the
+~Jacobi / Gauss-Siedel -> gauss_siedel_solve~ method as documented in the LIZFCM API reference.
+
+* Question Four, Five
+We produce the following operation counts (by hackily adding the operation count as the last element
+to the solution vector) and errors - the sum of each vector elements' absolute value away from 1.0
+using the proceeding patch and unit test.
+
+| N | JAC opr | JAC err | GS opr | GS err | LU opr | LU err |
+| 5 | 1622 | 0.001244 | 577 | 0.000098 | 430 | 0.000000 |
+| 6 | 2812 | 0.001205 | 775 | 0.000080 | 681 | 0.000000 |
+| 7 | 5396 | 0.001187 | 860 | 0.000178 | 1015 | 0.000000 |
+| 8 | 5618 | 0.001468 | 1255 | 0.000121 | 1444 | 0.000000 |
+| 9 | 7534 | 0.001638 | 1754 | 0.000091 | 1980 | 0.000000 |
+| 10 | 10342 | 0.001425 | 1847 | 0.000435 | 2635 | 0.000000 |
+| 11 | 12870 | 0.001595 | 2185 | 0.000368 | 3421 | 0.000000 |
+| 12 | 17511 | 0.001860 | 2912 | 0.000322 | 4350 | 0.000000 |
+| 13 | 16226 | 0.001631 | 3362 | 0.000270 | 5434 | 0.000000 |
+| 14 | 34333 | 0.001976 | 3844 | 0.000121 | 6685 | 0.000000 |
+| 15 | 38474 | 0.001922 | 4358 | 0.000311 | 8115 | 0.000000 |
+| 16 | 40405 | 0.002061 | 4904 | 0.000204 | 9736 | 0.000000 |
+| 17 | 58518 | 0.002125 | 5482 | 0.000311 | 11560 | 0.000000 |
+| 18 | 68079 | 0.002114 | 6092 | 0.000279 | 13599 | 0.000000 |
+| 19 | 95802 | 0.002159 | 6734 | 0.000335 | 15865 | 0.000000 |
+| 20 | 85696 | 0.002141 | 7408 | 0.000289 | 18370 | 0.000000 |
+| 21 | 89026 | 0.002316 | 8114 | 0.000393 | 21126 | 0.000000 |
+| 22 | 101537 | 0.002344 | 8852 | 0.000414 | 24145 | 0.000000 |
+| 23 | 148040 | 0.002323 | 9622 | 0.000230 | 27439 | 0.000000 |
+| 24 | 137605 | 0.002348 | 10424 | 0.000213 | 31020 | 0.000000 |
+| 25 | 169374 | 0.002409 | 11258 | 0.000894 | 34900 | 0.000000 |
+| 26 | 215166 | 0.002502 | 12124 | 0.000564 | 39091 | 0.000000 |
+| 27 | 175476 | 0.002616 | 13022 | 0.000535 | 43605 | 0.000000 |
+| 28 | 268454 | 0.002651 | 13952 | 0.000690 | 48454 | 0.000000 |
+| 29 | 267034 | 0.002697 | 14914 | 0.000675 | 53650 | 0.000000 |
+| 30 | 277193 | 0.002686 | 15908 | 0.000542 | 59205 | 0.000000 |
+| 31 | 336792 | 0.002736 | 16934 | 0.000390 | 65131 | 0.000000 |
+| 32 | 293958 | 0.002741 | 17992 | 0.000660 | 71440 | 0.000000 |
+| 33 | 323638 | 0.002893 | 19082 | 0.001072 | 78144 | 0.000000 |
+| 34 | 375104 | 0.003001 | 20204 | 0.001018 | 85255 | 0.000000 |
+| 35 | 436092 | 0.003004 | 21358 | 0.000912 | 92785 | 0.000000 |
+| 36 | 538143 | 0.003005 | 22544 | 0.000954 | 100746 | 0.000000 |
+| 37 | 511886 | 0.003029 | 23762 | 0.000462 | 109150 | 0.000000 |
+| 38 | 551332 | 0.003070 | 25012 | 0.000996 | 118009 | 0.000000 |
+| 39 | 592750 | 0.003110 | 26294 | 0.000989 | 127335 | 0.000000 |
+| 40 | 704208 | 0.003165 | 27608 | 0.000583 | 137140 | 0.000000 |
+
+#+BEGIN_SRC
+diff --git a/src/matrix.c b/src/matrix.c
+index 901a426..af5529f 100644
+--- a/src/matrix.c
++++ b/src/matrix.c
+@@ -144,20 +144,54 @@ Array_double *solve_matrix_lu_bsubst(Matrix_double *m, Array_double *b) {
+ assert(b->size == m->rows);
+ assert(m->rows == m->cols);
+
++ double opr = 0;
++
++ opr += b->size;
+ Array_double *x = copy_vector(b);
++
++ size_t n = m->rows;
++ opr += n * n; // (u copy)
++ opr += n * n; // l_empty
++ opr += n * n + n; // copy + put_identity_diagonal
++ opr += n; // pivot check
++ opr += m->cols;
++ for (size_t x = 0; x < m->cols; x++) {
++ opr += (m->rows - (x + 1));
++ for (size_t y = x + 1; y < m->rows; y++) {
++ opr += 1;
++ opr += 2; // -factor
++ opr += 4 * n; // scale, add_v, free_vector
++ opr += 1; // -factor
++ }
++ }
++ opr += n;
+ Matrix_double **u_l = lu_decomp(m);
++
+ Matrix_double *u = u_l[0];
+ Matrix_double *l = u_l[1];
+
++ opr += n;
++ for (int64_t row = n - 1; row >= 0; row--) {
++ opr += 2 * (n - row);
++ opr += 1;
++ }
+ Array_double *b_fsub = fsubst(l, b);
++
++ opr += n;
++ for (size_t x = 0; x < n; x++) {
++ opr += 2 * (x + 1);
++ opr += 1; // /= l->data[row]->data[row]
++ }
+ x = bsubst(u, b_fsub);
+- free_vector(b_fsub);
+
++ free_vector(b_fsub);
+ free_matrix(u);
+ free_matrix(l);
+ free(u_l);
+
+- return x;
++ Array_double *copy = add_element(x, opr);
++ free_vector(x);
++ return copy;
+ }
+
+ Matrix_double *gaussian_elimination(Matrix_double *m) {
+@@ -231,18 +265,36 @@ Array_double *jacobi_solve(Matrix_double *m, Array_double *b,
+ assert(b->size == m->cols);
+ size_t iter = max_iterations;
+
++ double opr = 0;
++
++ opr += 2 * b->size; // to initialize two vectors with the same dim of b twice
+ Array_double *x_k = InitArrayWithSize(double, b->size, 0.0);
+ Array_double *x_k_1 =
+ InitArrayWithSize(double, b->size, rand_from(0.1, 10.0));
+
++ // add since these wouldn't be accounter for after the loop
++ opr += 1; // iter decrement
++ opr +=
++ 3 * x_k_1->size; // 1 to perform x_k_1, x_k and 2 to perform ||x_k_1||_2
+ while ((--iter) > 0 && l2_distance(x_k_1, x_k) > l2_convergence_tolerance) {
++ opr += 1; // iter decrement
++ opr +=
++ 3 * x_k_1->size; // 1 to perform x_k_1, x_k and 2 to perform ||x_k_1||_2
++
++ opr += m->rows; // row for add oprs
+ for (size_t i = 0; i < m->rows; i++) {
+ double delta = 0.0;
++
++ opr += m->cols;
+ for (size_t j = 0; j < m->cols; j++) {
+ if (i == j)
+ continue;
++
++ opr += 1;
+ delta += m->data[i]->data[j] * x_k->data[j];
+ }
++
++ opr += 2;
+ x_k_1->data[i] = (b->data[i] - delta) / m->data[i]->data[i];
+ }
+
+@@ -251,8 +303,9 @@ Array_double *jacobi_solve(Matrix_double *m, Array_double *b,
+ x_k_1 = tmp;
+ }
+
+- free_vector(x_k);
+- return x_k_1;
++ Array_double *copy = add_element(x_k_1, opr);
++ free_vector(x_k_1);
++ return copy;
+ }
+
+ Array_double *gauss_siedel_solve(Matrix_double *m, Array_double *b,
+@@ -262,30 +315,48 @@ Array_double *gauss_siedel_solve(Matrix_double *m, Array_double *b,
+ assert(b->size == m->cols);
+ size_t iter = max_iterations;
+
++ double opr = 0;
++
++ opr += 2 * b->size; // to initialize two vectors with the same dim of b twice
+ Array_double *x_k = InitArrayWithSize(double, b->size, 0.0);
+ Array_double *x_k_1 =
+ InitArrayWithSize(double, b->size, rand_from(0.1, 10.0));
+
+ while ((--iter) > 0) {
++ opr += 1; // iter decrement
++
++ opr += x_k->size; // copy oprs
+ for (size_t i = 0; i < x_k->size; i++)
+ x_k->data[i] = x_k_1->data[i];
+
++ opr += m->rows; // row for add oprs
+ for (size_t i = 0; i < m->rows; i++) {
+ double delta = 0.0;
++
++ opr += m->cols;
+ for (size_t j = 0; j < m->cols; j++) {
+ if (i == j)
+ continue;
++
++ opr += 1;
+ delta += m->data[i]->data[j] * x_k_1->data[j];
+ }
++
++ opr += 2;
+ x_k_1->data[i] = (b->data[i] - delta) / m->data[i]->data[i];
+ }
+
++ opr +=
++ 3 * x_k_1->size; // 1 to perform x_k_1, x_k and 2 to perform ||x_k_1||_2
+ if (l2_distance(x_k_1, x_k) <= l2_convergence_tolerance)
+ break;
+ }
+
+ free_vector(x_k);
+- return x_k_1;
++
++ Array_double *copy = add_element(x_k_1, opr);
++ free_vector(x_k_1);
++ return copy;
+ }
+#+END_SRC
+
+
+And this unit test:
+#+BEGIN_SRC c
+UTEST(hw_8, p4_5) {
+ printf("| N | JAC opr | JAC err | GS opr | GS err | LU opr | LU err | \n");
+
+ for (size_t i = 5; i < 100; i++) {
+ Matrix_double *m = generate_ddm(i);
+ double oprs[3] = {0.0, 0.0, 0.0};
+ double errs[3] = {0.0, 0.0, 0.0};
+
+ Array_double *b_1 = InitArrayWithSize(double, m->rows, 1.0);
+ Array_double *b = m_dot_v(m, b_1);
+ double tolerance = 0.001;
+ size_t max_iter = 400;
+
+ // JACOBI
+ {
+ Array_double *solution_with_opr_count =
+ jacobi_solve(m, b, tolerance, max_iter);
+ Array_double *solution = slice_element(solution_with_opr_count,
+ solution_with_opr_count->size - 1);
+
+ for (size_t i = 0; i < solution->size; i++)
+ errs[0] += fabs(solution->data[i] - 1.0);
+
+ oprs[0] =
+ solution_with_opr_count->data[solution_with_opr_count->size - 1];
+
+ free_vector(solution);
+ free_vector(solution_with_opr_count);
+ }
+
+ // GAUSS-SIEDEL
+ {
+ Array_double *solution_with_opr_count =
+ gauss_siedel_solve(m, b, tolerance, max_iter);
+ Array_double *solution = slice_element(solution_with_opr_count,
+ solution_with_opr_count->size - 1);
+
+ for (size_t i = 0; i < solution->size; i++)
+ errs[1] += fabs(solution->data[i] - 1.0);
+
+ oprs[1] =
+ solution_with_opr_count->data[solution_with_opr_count->size - 1];
+
+ free_vector(solution);
+ free_vector(solution_with_opr_count);
+ }
+
+ // LU-BSUBST
+ {
+ Array_double *solution_with_opr_count = solve_matrix_lu_bsubst(m, b);
+ Array_double *solution = slice_element(solution_with_opr_count,
+ solution_with_opr_count->size - 1);
+
+ for (size_t i = 0; i < solution->size; i++)
+ errs[2] += fabs(solution->data[i] - 1.0);
+
+ oprs[2] =
+ solution_with_opr_count->data[solution_with_opr_count->size - 1];
+
+ free_vector(solution);
+ free_vector(solution_with_opr_count);
+ }
+ free_matrix(m);
+ free_vector(b_1);
+ free_vector(b);
+
+ printf("| %zu | %f | %f | %f | %f | %f | %f | \n", i, oprs[0], errs[0],
+ oprs[1], errs[1], oprs[2], errs[2]);
+ }
+}
+#+END_SRC
diff --git a/Homework/math4610/homeworks/hw-8.pdf b/Homework/math4610/homeworks/hw-8.pdf
new file mode 100644
index 0000000..c14bb2e
--- /dev/null
+++ b/Homework/math4610/homeworks/hw-8.pdf
Binary files differ
diff --git a/Homework/math4610/homeworks/hw-8.tex b/Homework/math4610/homeworks/hw-8.tex
new file mode 100644
index 0000000..9071f5b
--- /dev/null
+++ b/Homework/math4610/homeworks/hw-8.tex
@@ -0,0 +1,344 @@
+% Created 2023-12-09 Sat 22:06
+% 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 8}
+\hypersetup{
+ pdfauthor={Elizabeth Hunt},
+ pdftitle={Homework 8},
+ pdfkeywords={},
+ pdfsubject={},
+ pdfcreator={Emacs 28.2 (Org mode 9.7-pre)},
+ pdflang={English}}
+\begin{document}
+
+\maketitle
+\setlength\parindent{0pt}
+
+\section{Question One}
+\label{sec:org800c743}
+See \texttt{UTEST(jacobi, solve\_jacobi)} in \texttt{test/jacobi.t.c} and the entry
+\texttt{Jacobi / Gauss-Siedel -> solve\_jacobi} in the LIZFCM API documentation.
+\section{Question Two}
+\label{sec:org6121bef}
+We cannot just perform the Jacobi algorithm on a Leslie matrix since
+it is obviously not diagonally dominant - which is a requirement. It is
+certainly not always the case, but, if a Leslie matrix \(L\) is invertible, we can
+first perform gaussian elimination on \(L\) augmented with \(n_{k+1}\)
+to obtain \(n_k\) with the Jacobi method. See \texttt{UTEST(jacobi, leslie\_solve)}
+in \texttt{test/jacobi.t.c} for an example wherein this method is tested on a Leslie
+matrix to recompute a given initial population distribution.
+
+In terms of accuracy, an LU factorization and back substitution approach will
+always be as correct as possible within the limits of computation; it's a
+direct solution method. It's simply the nature of the Jacobi algorithm being
+a convergent solution that determines its accuracy.
+
+LU factorization also performs in order \(O(n^3)\) runtime for an \(n \times n\)
+matrix, whereas the Jacobi algorithm runs in order \(O(k n^2) = O(n^2)\) on average
+but with the con that \(k\) is given by some function on both the convergence criteria and the number of
+nonzero entries in the matrix - which might end up worse in some cases than the LU decomp approach.
+
+\section{Question Three}
+\label{sec:org11282e6}
+See \texttt{UTEST(jacobi, gauss\_siedel\_solve)} in \texttt{test/jacobi.t.c} which runs the same
+unit test as \texttt{UTEST(jacobi, solve\_jacobi)} but using the
+\texttt{Jacobi / Gauss-Siedel -> gauss\_siedel\_solve} method as documented in the LIZFCM API reference.
+
+\section{Question Four, Five}
+\label{sec:org22b52a9}
+We produce the following operation counts (by hackily adding the operation count as the last element
+to the solution vector) and errors - the sum of each vector elements' absolute value away from 1.0
+using the proceeding patch and unit test.
+
+\begin{center}
+\begin{tabular}{rrrrrrr}
+N & JAC opr & JAC err & GS opr & GS err & LU opr & LU err\\[0pt]
+5 & 1622 & 0.001244 & 577 & 0.000098 & 430 & 0.000000\\[0pt]
+6 & 2812 & 0.001205 & 775 & 0.000080 & 681 & 0.000000\\[0pt]
+7 & 5396 & 0.001187 & 860 & 0.000178 & 1015 & 0.000000\\[0pt]
+8 & 5618 & 0.001468 & 1255 & 0.000121 & 1444 & 0.000000\\[0pt]
+9 & 7534 & 0.001638 & 1754 & 0.000091 & 1980 & 0.000000\\[0pt]
+10 & 10342 & 0.001425 & 1847 & 0.000435 & 2635 & 0.000000\\[0pt]
+11 & 12870 & 0.001595 & 2185 & 0.000368 & 3421 & 0.000000\\[0pt]
+12 & 17511 & 0.001860 & 2912 & 0.000322 & 4350 & 0.000000\\[0pt]
+13 & 16226 & 0.001631 & 3362 & 0.000270 & 5434 & 0.000000\\[0pt]
+14 & 34333 & 0.001976 & 3844 & 0.000121 & 6685 & 0.000000\\[0pt]
+15 & 38474 & 0.001922 & 4358 & 0.000311 & 8115 & 0.000000\\[0pt]
+16 & 40405 & 0.002061 & 4904 & 0.000204 & 9736 & 0.000000\\[0pt]
+17 & 58518 & 0.002125 & 5482 & 0.000311 & 11560 & 0.000000\\[0pt]
+18 & 68079 & 0.002114 & 6092 & 0.000279 & 13599 & 0.000000\\[0pt]
+19 & 95802 & 0.002159 & 6734 & 0.000335 & 15865 & 0.000000\\[0pt]
+20 & 85696 & 0.002141 & 7408 & 0.000289 & 18370 & 0.000000\\[0pt]
+21 & 89026 & 0.002316 & 8114 & 0.000393 & 21126 & 0.000000\\[0pt]
+22 & 101537 & 0.002344 & 8852 & 0.000414 & 24145 & 0.000000\\[0pt]
+23 & 148040 & 0.002323 & 9622 & 0.000230 & 27439 & 0.000000\\[0pt]
+24 & 137605 & 0.002348 & 10424 & 0.000213 & 31020 & 0.000000\\[0pt]
+25 & 169374 & 0.002409 & 11258 & 0.000894 & 34900 & 0.000000\\[0pt]
+26 & 215166 & 0.002502 & 12124 & 0.000564 & 39091 & 0.000000\\[0pt]
+27 & 175476 & 0.002616 & 13022 & 0.000535 & 43605 & 0.000000\\[0pt]
+28 & 268454 & 0.002651 & 13952 & 0.000690 & 48454 & 0.000000\\[0pt]
+29 & 267034 & 0.002697 & 14914 & 0.000675 & 53650 & 0.000000\\[0pt]
+30 & 277193 & 0.002686 & 15908 & 0.000542 & 59205 & 0.000000\\[0pt]
+31 & 336792 & 0.002736 & 16934 & 0.000390 & 65131 & 0.000000\\[0pt]
+32 & 293958 & 0.002741 & 17992 & 0.000660 & 71440 & 0.000000\\[0pt]
+33 & 323638 & 0.002893 & 19082 & 0.001072 & 78144 & 0.000000\\[0pt]
+34 & 375104 & 0.003001 & 20204 & 0.001018 & 85255 & 0.000000\\[0pt]
+35 & 436092 & 0.003004 & 21358 & 0.000912 & 92785 & 0.000000\\[0pt]
+36 & 538143 & 0.003005 & 22544 & 0.000954 & 100746 & 0.000000\\[0pt]
+37 & 511886 & 0.003029 & 23762 & 0.000462 & 109150 & 0.000000\\[0pt]
+38 & 551332 & 0.003070 & 25012 & 0.000996 & 118009 & 0.000000\\[0pt]
+39 & 592750 & 0.003110 & 26294 & 0.000989 & 127335 & 0.000000\\[0pt]
+40 & 704208 & 0.003165 & 27608 & 0.000583 & 137140 & 0.000000\\[0pt]
+\end{tabular}
+\end{center}
+
+\begin{verbatim}
+diff --git a/src/matrix.c b/src/matrix.c
+index 901a426..af5529f 100644
+--- a/src/matrix.c
++++ b/src/matrix.c
+@@ -144,20 +144,54 @@ Array_double *solve_matrix_lu_bsubst(Matrix_double *m, Array_double *b) {
+ assert(b->size == m->rows);
+ assert(m->rows == m->cols);
+
++ double opr = 0;
++
++ opr += b->size;
+ Array_double *x = copy_vector(b);
++
++ size_t n = m->rows;
++ opr += n * n; // (u copy)
++ opr += n * n; // l_empty
++ opr += n * n + n; // copy + put_identity_diagonal
++ opr += n; // pivot check
++ opr += m->cols;
++ for (size_t x = 0; x < m->cols; x++) {
++ opr += (m->rows - (x + 1));
++ for (size_t y = x + 1; y < m->rows; y++) {
++ opr += 1;
++ opr += 2; // -factor
++ opr += 4 * n; // scale, add_v, free_vector
++ opr += 1; // -factor
++ }
++ }
++ opr += n;
+ Matrix_double **u_l = lu_decomp(m);
++
+ Matrix_double *u = u_l[0];
+ Matrix_double *l = u_l[1];
+
++ opr += n;
++ for (int64_t row = n - 1; row >= 0; row--) {
++ opr += 2 * (n - row);
++ opr += 1;
++ }
+ Array_double *b_fsub = fsubst(l, b);
++
++ opr += n;
++ for (size_t x = 0; x < n; x++) {
++ opr += 2 * (x + 1);
++ opr += 1; // /= l->data[row]->data[row]
++ }
+ x = bsubst(u, b_fsub);
+- free_vector(b_fsub);
+
++ free_vector(b_fsub);
+ free_matrix(u);
+ free_matrix(l);
+ free(u_l);
+
+- return x;
++ Array_double *copy = add_element(x, opr);
++ free_vector(x);
++ return copy;
+ }
+
+ Matrix_double *gaussian_elimination(Matrix_double *m) {
+@@ -231,18 +265,36 @@ Array_double *jacobi_solve(Matrix_double *m, Array_double *b,
+ assert(b->size == m->cols);
+ size_t iter = max_iterations;
+
++ double opr = 0;
++
++ opr += 2 * b->size; // to initialize two vectors with the same dim of b twice
+ Array_double *x_k = InitArrayWithSize(double, b->size, 0.0);
+ Array_double *x_k_1 =
+ InitArrayWithSize(double, b->size, rand_from(0.1, 10.0));
+
++ // add since these wouldn't be accounter for after the loop
++ opr += 1; // iter decrement
++ opr +=
++ 3 * x_k_1->size; // 1 to perform x_k_1, x_k and 2 to perform ||x_k_1||_2
+ while ((--iter) > 0 && l2_distance(x_k_1, x_k) > l2_convergence_tolerance) {
++ opr += 1; // iter decrement
++ opr +=
++ 3 * x_k_1->size; // 1 to perform x_k_1, x_k and 2 to perform ||x_k_1||_2
++
++ opr += m->rows; // row for add oprs
+ for (size_t i = 0; i < m->rows; i++) {
+ double delta = 0.0;
++
++ opr += m->cols;
+ for (size_t j = 0; j < m->cols; j++) {
+ if (i == j)
+ continue;
++
++ opr += 1;
+ delta += m->data[i]->data[j] * x_k->data[j];
+ }
++
++ opr += 2;
+ x_k_1->data[i] = (b->data[i] - delta) / m->data[i]->data[i];
+ }
+
+@@ -251,8 +303,9 @@ Array_double *jacobi_solve(Matrix_double *m, Array_double *b,
+ x_k_1 = tmp;
+ }
+
+- free_vector(x_k);
+- return x_k_1;
++ Array_double *copy = add_element(x_k_1, opr);
++ free_vector(x_k_1);
++ return copy;
+ }
+
+ Array_double *gauss_siedel_solve(Matrix_double *m, Array_double *b,
+@@ -262,30 +315,48 @@ Array_double *gauss_siedel_solve(Matrix_double *m, Array_double *b,
+ assert(b->size == m->cols);
+ size_t iter = max_iterations;
+
++ double opr = 0;
++
++ opr += 2 * b->size; // to initialize two vectors with the same dim of b twice
+ Array_double *x_k = InitArrayWithSize(double, b->size, 0.0);
+ Array_double *x_k_1 =
+ InitArrayWithSize(double, b->size, rand_from(0.1, 10.0));
+
+ while ((--iter) > 0) {
++ opr += 1; // iter decrement
++
++ opr += x_k->size; // copy oprs
+ for (size_t i = 0; i < x_k->size; i++)
+ x_k->data[i] = x_k_1->data[i];
+
++ opr += m->rows; // row for add oprs
+ for (size_t i = 0; i < m->rows; i++) {
+ double delta = 0.0;
++
++ opr += m->cols;
+ for (size_t j = 0; j < m->cols; j++) {
+ if (i == j)
+ continue;
++
++ opr += 1;
+ delta += m->data[i]->data[j] * x_k_1->data[j];
+ }
++
++ opr += 2;
+ x_k_1->data[i] = (b->data[i] - delta) / m->data[i]->data[i];
+ }
+
++ opr +=
++ 3 * x_k_1->size; // 1 to perform x_k_1, x_k and 2 to perform ||x_k_1||_2
+ if (l2_distance(x_k_1, x_k) <= l2_convergence_tolerance)
+ break;
+ }
+
+ free_vector(x_k);
+- return x_k_1;
++
++ Array_double *copy = add_element(x_k_1, opr);
++ free_vector(x_k_1);
++ return copy;
+ }
+\end{verbatim}
+
+
+And this unit test:
+\begin{verbatim}
+UTEST(hw_8, p4_5) {
+ printf("| N | JAC opr | JAC err | GS opr | GS err | LU opr | LU err | \n");
+
+ for (size_t i = 5; i < 100; i++) {
+ Matrix_double *m = generate_ddm(i);
+ double oprs[3] = {0.0, 0.0, 0.0};
+ double errs[3] = {0.0, 0.0, 0.0};
+
+ Array_double *b_1 = InitArrayWithSize(double, m->rows, 1.0);
+ Array_double *b = m_dot_v(m, b_1);
+ double tolerance = 0.001;
+ size_t max_iter = 400;
+
+ // JACOBI
+ {
+ Array_double *solution_with_opr_count =
+ jacobi_solve(m, b, tolerance, max_iter);
+ Array_double *solution = slice_element(solution_with_opr_count,
+ solution_with_opr_count->size - 1);
+
+ for (size_t i = 0; i < solution->size; i++)
+ errs[0] += fabs(solution->data[i] - 1.0);
+
+ oprs[0] =
+ solution_with_opr_count->data[solution_with_opr_count->size - 1];
+
+ free_vector(solution);
+ free_vector(solution_with_opr_count);
+ }
+
+ // GAUSS-SIEDEL
+ {
+ Array_double *solution_with_opr_count =
+ gauss_siedel_solve(m, b, tolerance, max_iter);
+ Array_double *solution = slice_element(solution_with_opr_count,
+ solution_with_opr_count->size - 1);
+
+ for (size_t i = 0; i < solution->size; i++)
+ errs[1] += fabs(solution->data[i] - 1.0);
+
+ oprs[1] =
+ solution_with_opr_count->data[solution_with_opr_count->size - 1];
+
+ free_vector(solution);
+ free_vector(solution_with_opr_count);
+ }
+
+ // LU-BSUBST
+ {
+ Array_double *solution_with_opr_count = solve_matrix_lu_bsubst(m, b);
+ Array_double *solution = slice_element(solution_with_opr_count,
+ solution_with_opr_count->size - 1);
+
+ for (size_t i = 0; i < solution->size; i++)
+ errs[2] += fabs(solution->data[i] - 1.0);
+
+ oprs[2] =
+ solution_with_opr_count->data[solution_with_opr_count->size - 1];
+
+ free_vector(solution);
+ free_vector(solution_with_opr_count);
+ }
+ free_matrix(m);
+ free_vector(b_1);
+ free_vector(b);
+
+ printf("| %zu | %f | %f | %f | %f | %f | %f | \n", i, oprs[0], errs[0],
+ oprs[1], errs[1], oprs[2], errs[2]);
+ }
+}
+\end{verbatim}
+\end{document} \ No newline at end of file
diff --git a/Homework/math4610/homeworks/hw-9.org b/Homework/math4610/homeworks/hw-9.org
new file mode 100644
index 0000000..de58d2a
--- /dev/null
+++ b/Homework/math4610/homeworks/hw-9.org
@@ -0,0 +1,222 @@
+#+TITLE: Homework 9
+#+AUTHOR: Elizabeth Hunt
+#+LATEX_HEADER: \notindent \notag \usepackage{amsmath} \usepackage[a4paper,margin=1in,portrait]{geometry}
+#+LATEX: \setlength\parindent{0pt}
+#+OPTIONS: toc:nil
+
+* Question One
+
+With a ~matrix_dimension~ set to 700, I consistently see about a 3x improvement in performance on my
+10-thread machine. The serial implementation gives an average ~0.189s~ total runtime, while the below
+parallel implementation runs in about ~0.066s~ after the cpu cache has filled on the first run.
+
+#+BEGIN_SRC c
+#include <math.h>
+#include <omp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#define matrix_dimension 700
+
+int n = matrix_dimension;
+float sum;
+
+int main() {
+ float A[n][n];
+ float x0[n];
+ float b[n];
+ float x1[n];
+ float res[n];
+
+ srand((unsigned int)(time(NULL)));
+
+ // not worth parallellization - rand() is not thread-safe
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < n; j++) {
+ A[i][j] = ((float)rand() / (float)(RAND_MAX) * 5.0);
+ }
+ x0[i] = ((float)rand() / (float)(RAND_MAX) * 5.0);
+ }
+
+#pragma omp parallel for private(sum)
+ for (int i = 0; i < n; i++) {
+ sum = 0.0;
+ for (int j = 0; j < n; j++) {
+ sum += fabs(A[i][j]);
+ }
+ A[i][i] += sum;
+ }
+
+#pragma omp parallel for private(sum)
+ for (int i = 0; i < n; i++) {
+ sum = 0.0;
+ for (int j = 0; j < n; j++) {
+ sum += A[i][j];
+ }
+ b[i] = sum;
+ }
+
+ float tol = 0.0001;
+ float error = 10.0 * tol;
+ int maxiter = 100;
+ int iter = 0;
+
+ while (error > tol && iter < maxiter) {
+#pragma omp parallel for
+ for (int i = 0; i < n; i++) {
+ float temp_sum = b[i];
+ for (int j = 0; j < n; j++) {
+ temp_sum -= A[i][j] * x0[j];
+ }
+ res[i] = temp_sum;
+ x1[i] = x0[i] + res[i] / A[i][i];
+ }
+
+ sum = 0.0;
+#pragma omp parallel for reduction(+ : sum)
+ for (int i = 0; i < n; i++) {
+ float val = x1[i] - x0[i];
+ sum += val * val;
+ }
+ error = sqrt(sum);
+
+#pragma omp parallel for
+ for (int i = 0; i < n; i++) {
+ x0[i] = x1[i];
+ }
+
+ iter++;
+ }
+
+ for (int i = 0; i < n; i++)
+ printf("x[%d] = %6f \t res[%d] = %6f\n", i, x1[i], i, res[i]);
+
+ return 0;
+}
+
+#+END_SRC
+
+* Question Two
+
+I only see lowerings in performance (likely due to overhead) on my machine using OpenMP until
+~matrix_dimension~ becomes quite large, about ~300~ in testing. At ~matrix_dimension=1000~, I see another
+about 3x improvement in total runtime (including initialization & I/O which was untouched, so, even further
+improvements could be made) on my 10-thread machine; from around ~0.174~ seconds to ~.052~.
+
+#+BEGIN_SRC c
+ #include <math.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <time.h>
+
+ #ifdef _OPENMP
+ #include <omp.h>
+ #else
+ #define omp_get_num_threads() 0
+ #define omp_set_num_threads(int) 0
+ #define omp_get_thread_num() 0
+ #endif
+
+ #define matrix_dimension 1000
+
+ int n = matrix_dimension;
+ float ynrm;
+
+ int main() {
+ float A[n][n];
+ float v0[n];
+ float v1[n];
+ float y[n];
+ //
+ // create a matrix
+ //
+ // not worth parallellization - rand() is not thread-safe
+ srand((unsigned int)(time(NULL)));
+ float a = 5.0;
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < n; j++) {
+ A[i][j] = ((float)rand() / (float)(RAND_MAX)*a);
+ }
+ v0[i] = ((float)rand() / (float)(RAND_MAX)*a);
+ }
+ //
+ // modify the diagonal entries for diagonal dominance
+ // --------------------------------------------------
+ //
+ for (int i = 0; i < n; i++) {
+ float sum = 0.0;
+ for (int j = 0; j < n; j++) {
+ sum = sum + fabs(A[i][j]);
+ }
+ A[i][i] = A[i][i] + sum;
+ }
+ //
+ // generate a vector of ones
+ // -------------------------
+ //
+ for (int j = 0; j < n; j++) {
+ v0[j] = 1.0;
+ }
+ //
+ // power iteration test
+ // --------------------
+ //
+ float tol = 0.0000001;
+ float error = 10.0 * tol;
+ float lam1, lam0;
+ int maxiter = 100;
+ int iter = 0;
+
+ while (error > tol && iter < maxiter) {
+ #pragma omp parallel for
+ for (int i = 0; i < n; i++) {
+ y[i] = 0;
+ for (int j = 0; j < n; j++) {
+ y[i] = y[i] + A[i][j] * v0[j];
+ }
+ }
+
+ ynrm = 0.0;
+ #pragma omp parallel for reduction(+ : ynrm)
+ for (int i = 0; i < n; i++) {
+ ynrm += y[i] * y[i];
+ }
+ ynrm = sqrt(ynrm);
+
+ #pragma omp parallel for
+ for (int i = 0; i < n; i++) {
+ v1[i] = y[i] / ynrm;
+ }
+
+ #pragma omp parallel for
+ for (int i = 0; i < n; i++) {
+ y[i] = 0.0;
+ for (int j = 0; j < n; j++) {
+ y[i] += A[i][j] * v1[j];
+ }
+ }
+
+ lam1 = 0.0;
+ #pragma omp parallel for reduction(+ : lam1)
+ for (int i = 0; i < n; i++) {
+ lam1 += v1[i] * y[i];
+ }
+
+ error = fabs(lam1 - lam0);
+ lam0 = lam1;
+
+ #pragma omp parallel for
+ for (int i = 0; i < n; i++) {
+ v0[i] = v1[i];
+ }
+
+ iter++;
+ }
+
+ printf("in %d iterations, eigenvalue = %f\n", iter, lam1);
+ }
+#+END_SRC
+
+* Question Three
+[[https://static.simponic.xyz/lizfcm.pdf]]
diff --git a/Homework/math4610/homeworks/hw-9.pdf b/Homework/math4610/homeworks/hw-9.pdf
new file mode 100644
index 0000000..4753a3b
--- /dev/null
+++ b/Homework/math4610/homeworks/hw-9.pdf
Binary files differ
diff --git a/Homework/math4610/homeworks/hw-9.tex b/Homework/math4610/homeworks/hw-9.tex
new file mode 100644
index 0000000..9d5693a
--- /dev/null
+++ b/Homework/math4610/homeworks/hw-9.tex
@@ -0,0 +1,250 @@
+% Created 2023-12-11 Mon 19:24
+% 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 9}
+\hypersetup{
+ pdfauthor={Elizabeth Hunt},
+ pdftitle={Homework 9},
+ pdfkeywords={},
+ pdfsubject={},
+ pdfcreator={Emacs 28.2 (Org mode 9.7-pre)},
+ pdflang={English}}
+\begin{document}
+
+\maketitle
+\setlength\parindent{0pt}
+
+\section{Question One}
+\label{sec:org69bed2d}
+
+With a \texttt{matrix\_dimension} set to 700, I consistently see about a 3x improvement in performance on my
+10-thread machine. The serial implementation gives an average \texttt{0.189s} total runtime, while the below
+parallel implementation runs in about \texttt{0.066s} after the cpu cache has filled on the first run.
+
+\begin{verbatim}
+#include <math.h>
+#include <omp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#define matrix_dimension 700
+
+int n = matrix_dimension;
+float sum;
+
+int main() {
+ float A[n][n];
+ float x0[n];
+ float b[n];
+ float x1[n];
+ float res[n];
+
+ srand((unsigned int)(time(NULL)));
+
+ // not worth parallellization - rand() is not thread-safe
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < n; j++) {
+ A[i][j] = ((float)rand() / (float)(RAND_MAX) * 5.0);
+ }
+ x0[i] = ((float)rand() / (float)(RAND_MAX) * 5.0);
+ }
+
+#pragma omp parallel for private(sum)
+ for (int i = 0; i < n; i++) {
+ sum = 0.0;
+ for (int j = 0; j < n; j++) {
+ sum += fabs(A[i][j]);
+ }
+ A[i][i] += sum;
+ }
+
+#pragma omp parallel for private(sum)
+ for (int i = 0; i < n; i++) {
+ sum = 0.0;
+ for (int j = 0; j < n; j++) {
+ sum += A[i][j];
+ }
+ b[i] = sum;
+ }
+
+ float tol = 0.0001;
+ float error = 10.0 * tol;
+ int maxiter = 100;
+ int iter = 0;
+
+ while (error > tol && iter < maxiter) {
+#pragma omp parallel for
+ for (int i = 0; i < n; i++) {
+ float temp_sum = b[i];
+ for (int j = 0; j < n; j++) {
+ temp_sum -= A[i][j] * x0[j];
+ }
+ res[i] = temp_sum;
+ x1[i] = x0[i] + res[i] / A[i][i];
+ }
+
+ sum = 0.0;
+#pragma omp parallel for reduction(+ : sum)
+ for (int i = 0; i < n; i++) {
+ float val = x1[i] - x0[i];
+ sum += val * val;
+ }
+ error = sqrt(sum);
+
+#pragma omp parallel for
+ for (int i = 0; i < n; i++) {
+ x0[i] = x1[i];
+ }
+
+ iter++;
+ }
+
+ for (int i = 0; i < n; i++)
+ printf("x[%d] = %6f \t res[%d] = %6f\n", i, x1[i], i, res[i]);
+
+ return 0;
+}
+
+\end{verbatim}
+
+\section{Question Two}
+\label{sec:orgbeace25}
+
+I only see lowerings in performance (likely due to overhead) on my machine using OpenMP until
+\texttt{matrix\_dimension} becomes quite large, about \texttt{300} in testing. At \texttt{matrix\_dimension=1000}, I see another
+about 3x improvement in total runtime (including initialization \& I/O which was untouched, so, even further
+improvements could be made) on my 10-thread machine; from around \texttt{0.174} seconds to \texttt{.052}.
+
+\begin{verbatim}
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#ifdef _OPENMP
+#include <omp.h>
+#else
+#define omp_get_num_threads() 0
+#define omp_set_num_threads(int) 0
+#define omp_get_thread_num() 0
+#endif
+
+#define matrix_dimension 1000
+
+int n = matrix_dimension;
+float ynrm;
+
+int main() {
+ float A[n][n];
+ float v0[n];
+ float v1[n];
+ float y[n];
+ //
+ // create a matrix
+ //
+ // not worth parallellization - rand() is not thread-safe
+ srand((unsigned int)(time(NULL)));
+ float a = 5.0;
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < n; j++) {
+ A[i][j] = ((float)rand() / (float)(RAND_MAX)*a);
+ }
+ v0[i] = ((float)rand() / (float)(RAND_MAX)*a);
+ }
+ //
+ // modify the diagonal entries for diagonal dominance
+ // --------------------------------------------------
+ //
+ for (int i = 0; i < n; i++) {
+ float sum = 0.0;
+ for (int j = 0; j < n; j++) {
+ sum = sum + fabs(A[i][j]);
+ }
+ A[i][i] = A[i][i] + sum;
+ }
+ //
+ // generate a vector of ones
+ // -------------------------
+ //
+ for (int j = 0; j < n; j++) {
+ v0[j] = 1.0;
+ }
+ //
+ // power iteration test
+ // --------------------
+ //
+ float tol = 0.0000001;
+ float error = 10.0 * tol;
+ float lam1, lam0;
+ int maxiter = 100;
+ int iter = 0;
+
+ while (error > tol && iter < maxiter) {
+#pragma omp parallel for
+ for (int i = 0; i < n; i++) {
+ y[i] = 0;
+ for (int j = 0; j < n; j++) {
+ y[i] = y[i] + A[i][j] * v0[j];
+ }
+ }
+
+ ynrm = 0.0;
+#pragma omp parallel for reduction(+ : ynrm)
+ for (int i = 0; i < n; i++) {
+ ynrm += y[i] * y[i];
+ }
+ ynrm = sqrt(ynrm);
+
+#pragma omp parallel for
+ for (int i = 0; i < n; i++) {
+ v1[i] = y[i] / ynrm;
+ }
+
+#pragma omp parallel for
+ for (int i = 0; i < n; i++) {
+ y[i] = 0.0;
+ for (int j = 0; j < n; j++) {
+ y[i] += A[i][j] * v1[j];
+ }
+ }
+
+ lam1 = 0.0;
+#pragma omp parallel for reduction(+ : lam1)
+ for (int i = 0; i < n; i++) {
+ lam1 += v1[i] * y[i];
+ }
+
+ error = fabs(lam1 - lam0);
+ lam0 = lam1;
+
+#pragma omp parallel for
+ for (int i = 0; i < n; i++) {
+ v0[i] = v1[i];
+ }
+
+ iter++;
+ }
+
+ printf("in %d iterations, eigenvalue = %f\n", iter, lam1);
+}
+\end{verbatim}
+
+\section{Question Three}
+\label{sec:org33439e0}
+\url{https://static.simponic.xyz/lizfcm.pdf}
+\end{document} \ No newline at end of file
diff --git a/Homework/math4610/homeworks/hw_6_p_8 b/Homework/math4610/homeworks/hw_6_p_8
new file mode 100644
index 0000000..46b58a2
--- /dev/null
+++ b/Homework/math4610/homeworks/hw_6_p_8
Binary files differ
diff --git a/Homework/math4610/homeworks/hw_6_p_8.c b/Homework/math4610/homeworks/hw_6_p_8.c
new file mode 100644
index 0000000..56f199f
--- /dev/null
+++ b/Homework/math4610/homeworks/hw_6_p_8.c
@@ -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;
+}
diff --git a/Homework/math4610/homeworks/img/make_run.png b/Homework/math4610/homeworks/img/make_run.png
new file mode 100644
index 0000000..f20015e
--- /dev/null
+++ b/Homework/math4610/homeworks/img/make_run.png
Binary files differ
diff --git a/Homework/math4610/homeworks/img/test_routine_1.png b/Homework/math4610/homeworks/img/test_routine_1.png
new file mode 100644
index 0000000..57ce59f
--- /dev/null
+++ b/Homework/math4610/homeworks/img/test_routine_1.png
Binary files differ
diff --git a/Homework/math4610/homeworks/img/test_routine_2.png b/Homework/math4610/homeworks/img/test_routine_2.png
new file mode 100644
index 0000000..b116620
--- /dev/null
+++ b/Homework/math4610/homeworks/img/test_routine_2.png
Binary files differ
diff --git a/Homework/math4610/homeworks/virtualization/hw1.pdf b/Homework/math4610/homeworks/virtualization/hw1.pdf
new file mode 100644
index 0000000..00d84a4
--- /dev/null
+++ b/Homework/math4610/homeworks/virtualization/hw1.pdf
Binary files differ
diff --git a/Homework/math4610/homeworks/virtualization/img/htop.png b/Homework/math4610/homeworks/virtualization/img/htop.png
new file mode 100644
index 0000000..880befa
--- /dev/null
+++ b/Homework/math4610/homeworks/virtualization/img/htop.png
Binary files differ
diff --git a/Homework/math4610/homeworks/virtualization/img/no_virtualization.png b/Homework/math4610/homeworks/virtualization/img/no_virtualization.png
new file mode 100644
index 0000000..2322456
--- /dev/null
+++ b/Homework/math4610/homeworks/virtualization/img/no_virtualization.png
Binary files differ
diff --git a/Homework/math4610/homeworks/virtualization/virtual_machines.md b/Homework/math4610/homeworks/virtualization/virtual_machines.md
new file mode 100644
index 0000000..c6d3e12
--- /dev/null
+++ b/Homework/math4610/homeworks/virtualization/virtual_machines.md
@@ -0,0 +1,41 @@
+* Elizabeth Hunt (A02364151), MATH 4610
+
+## Virtual Machines
+
+**Question 1**
+
+Run the Linux OS as a virtual machine, or run the application in a containerized Linux environment (which
+is the same abstraction).
+
+**Question 2**
+
+A native system virtual machine has dedicated hardware to run the hypervisor, while a hosted system
+virtual machine runs a hypervisor as a process in the operating system.
+
+**Question 3**
+
+A virtual machine hosts an entire operating system and requires users to perform configuration if they
+want to run an application, whereas a Virtual Appliance is built to provide an easy plug-and-play virtual
+machine image built to run some specific software stack.
+
+**Question 4**
+
+In a large application sense, containerizing services into their own virtual machines allows for easier
+replication, scaling, and networking. Instead of running several smaller servers, one large server can
+host several applications in parallel. This provides a good seperation of concern. And, if one service
+goes down, the whole system does not go down with it.
+
+Locally, it can help in development when targeting another operating system. Virtual machines can be
+used to verify builds without installing a whole other operating system.
+
+**Question 5**
+
+A virtual machine monitor is just another term for a hypervisor, so, see question 2.
+
+**Question 6**
+
+The three components of a virtual machine are:
+
+1. The host
+2. The virtualization layer
+3. The guest
diff --git a/Homework/math4610/homeworks/virtualization/virtualization.md b/Homework/math4610/homeworks/virtualization/virtualization.md
new file mode 100644
index 0000000..4d03637
--- /dev/null
+++ b/Homework/math4610/homeworks/virtualization/virtualization.md
@@ -0,0 +1,103 @@
+## Virtualization
+
+**Question 1**
+
+I use an Apple Silicon Mac which is based on the ARM architecture - so it's necessary to use
+[Multipass](https://multipass.run/), as native virtualization is _not available to us_.
+
+![No Virtualization Strings](./img/no_virtualization.png)
+
+**Question 2**
+
+One of the downsides of running a virtual machine, as opposed to a hosted virtual instance, is that local
+resources are used. On a laptop especially, this increases power draw, draining the battery. Additionally,
+the security of mind provided by "faster disaster recovery", as discussed in the article, is not as
+necessary for consumer applications on personal machines as servers. Finally, virtual machines are
+inherently slower in compute due to general overhead.
+
+**Question 3**
+
+![htop resources](./img/htop.png)
+
+**Question 4**
+
+In a large application sense, containerizing services into their own virtual machines allows for easier
+replication, scaling, and networking. Instead of running several smaller servers, one large server can
+host several applications in parallel.
+
+Locally, it can help in development when targeting another operating system. Virtual machines can be
+used to verify builds without installing a whole other operating system.
+
+**Question 5**
+
+A native system virtual machine has dedicated hardware to run the hypervisor, while a hosted system
+virtual machine runs a hypervisor as a process in the operating system.
+
+**Question 6**
+
+1. Easier networking between "servers"
+2. Efficient resource use
+
+**Question 7**
+
+A Virtual Appliance is built to provide an easy plug-and-play virtual machine image built to run some
+specific software stack.
+
+**Question 8**
+
+A Virtual Appliance would be desirable to eliminate maintenance and configuration overhead when running an
+application. In my own experience, I've used a form of virtual appliances - "Docker Containers", to easily
+spin up multiple versions of small services at work.
+
+**Question 9** What are 2 benefits of Virtualization?
+
+See question 6.
+
+**Question 10**
+
+See question 4.
+
+**Question 11**
+
+See question 8.
+
+**Question 12** What are the three main types of virtualization?
+
+1. Full virtualization
+2. Para virtualization
+3. OS-level virtualization
+
+**Question 13** What you should know about virtualization?
+
+How to create a virtual machine, and maintain it.
+
+**Question 14** What is the weakness of virtualization?
+
+Inherent overhead in all system operations.
+
+**Question 15** What are the six areas of virtualization?
+
+Source: [HiTechNectar](https://www.hitechnectar.com/blogs/virtualization-types)
+
+1. Application - run individual applications in a seperate environment than a host OS
+2. Data - abstract exact location and formatting information away from retrieval of data
+3. Desktop - hosts a desktop environment virtually on another machine (reminds me of mainframes).
+4. Network - physical networking tools are abstracted into software resources
+5. Server - division of a server into multiple guest operating systems
+6. Storage - abstraction over multiple storage arrays into a single pool
+
+**Question 16** What is the biggest challenge in virtualization?
+
+Resource distribution is a big one; it's difficult to keep track of several resources on a host machine
+and ensure a Virtual Machine accesses them correctly.
+
+**Question 17** What is the risk of using virtualization?
+
+The biggest risk of using virtualization is sandbox escape vulnerabilities. Although mostly research and
+proof-of-concept, highly skilled engineers can theoretically craft exploits to escape the sandbox of the
+VM and directly mess with the host operating system.
+
+**Question 18**
+
+When (question 17) is trusted; sandboxing. Virtualization should supply no access to resources within the
+host operating system.
diff --git a/Homework/math4610/inc/lizfcm.h b/Homework/math4610/inc/lizfcm.h
new file mode 100644
index 0000000..1dcdb6b
--- /dev/null
+++ b/Homework/math4610/inc/lizfcm.h
@@ -0,0 +1,100 @@
+#include "macros.h"
+#include "types.h"
+
+#ifndef LIZFCM_H
+#define LIZFCM_H
+
+extern float smaceps();
+extern double dmaceps();
+
+extern double central_derivative_at(double (*f)(double), double a, double h);
+extern double forward_derivative_at(double (*f)(double), double a, double h);
+extern double backward_derivative_at(double (*f)(double), double a, double h);
+
+extern double sum_v(Array_double *v);
+extern Array_double *scale_v(Array_double *v1, double m);
+extern Array_double *add_v(Array_double *v1, Array_double *v2);
+extern Array_double *minus_v(Array_double *v1, Array_double *v2);
+extern double v_dot_v(Array_double *v1, Array_double *v2);
+extern double l2_norm(Array_double *v);
+extern double l1_norm(Array_double *v);
+extern double linf_norm(Array_double *v);
+extern double vector_distance(Array_double *v1, Array_double *v2,
+ double (*norm)(Array_double *));
+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);
+
+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_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 Matrix_double *transpose(Matrix_double *m);
+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);
+
+extern Line *least_squares_lin_reg(Array_double *x, Array_double *y);
+
+extern Array_double *find_ivt_range(double (*f)(double), double start_x,
+ double delta, size_t max_steps);
+extern Array_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);
+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);
+
+extern double dominant_eigenvalue(Matrix_double *m, Array_double *v,
+ double tolerance, size_t max_iterations);
+extern double shift_inverse_power_eigenvalue(Matrix_double *m, Array_double *v,
+ double shift, double tolerance,
+ size_t max_iterations);
+extern double least_dominant_eigenvalue(Matrix_double *m, Array_double *v,
+ double tolerance,
+ size_t max_iterations);
+extern Array_double *partition_find_eigenvalues(Matrix_double *m,
+ Matrix_double *guesses,
+ double tolerance,
+ size_t max_iterations);
+extern Matrix_double *leslie_matrix(Array_double *age_class_surivor_ratio,
+ Array_double *age_class_offspring);
+
+extern double rand_from(double min, double max);
+
+extern Array_double *jacobi_solve(Matrix_double *m, Array_double *b,
+ double tolerance, size_t max_iterations);
+extern Array_double *gauss_siedel_solve(Matrix_double *m, Array_double *b,
+ double l2_convergence_tolerance,
+ size_t max_iterations);
+
+#endif // LIZFCM_H
diff --git a/Homework/math4610/inc/macros.h b/Homework/math4610/inc/macros.h
new file mode 100644
index 0000000..d081869
--- /dev/null
+++ b/Homework/math4610/inc/macros.h
@@ -0,0 +1,58 @@
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef MACROS_H
+#define MACROS_H
+
+#define DEFINE_ARRAY(TYPE) \
+ typedef struct { \
+ TYPE *data; \
+ size_t size; \
+ } Array_##TYPE
+
+#define DEFINE_MATRIX(TYPE) \
+ typedef struct { \
+ Array_##TYPE **data; \
+ size_t cols; \
+ size_t rows; \
+ } Matrix_##TYPE
+
+#define InitArray(TYPE, ...) \
+ ({ \
+ TYPE temp[] = __VA_ARGS__; \
+ Array_##TYPE *arr = malloc(sizeof(Array_##TYPE)); \
+ arr->size = sizeof(temp) / sizeof(temp[0]); \
+ arr->data = malloc(arr->size * sizeof(TYPE)); \
+ memcpy(arr->data, temp, arr->size * sizeof(TYPE)); \
+ arr; \
+ })
+
+#define InitArrayWithSize(TYPE, SIZE, INIT_VALUE) \
+ ({ \
+ Array_##TYPE *arr = malloc(sizeof(Array_##TYPE)); \
+ arr->size = SIZE; \
+ arr->data = malloc(arr->size * sizeof(TYPE)); \
+ for (size_t i = 0; i < arr->size; i++) \
+ arr->data[i] = INIT_VALUE; \
+ arr; \
+ })
+
+#define InitMatrixWithSize(TYPE, ROWS, COLS, INIT_VALUE) \
+ ({ \
+ Matrix_##TYPE *matrix = malloc(sizeof(Matrix_##TYPE)); \
+ matrix->rows = ROWS; \
+ matrix->cols = COLS; \
+ matrix->data = malloc(matrix->rows * sizeof(Array_##TYPE *)); \
+ for (size_t y = 0; y < matrix->rows; y++) \
+ matrix->data[y] = InitArrayWithSize(TYPE, COLS, INIT_VALUE); \
+ matrix; \
+ })
+
+#define c_max(x, y) (((x) >= (y)) ? (x) : (y))
+#define c_min(x, y) (((x) <= (y)) ? (x) : (y))
+
+#define true 1
+#define false 0
+
+#endif // MACROS_H
diff --git a/Homework/math4610/inc/types.h b/Homework/math4610/inc/types.h
new file mode 100644
index 0000000..95ab96d
--- /dev/null
+++ b/Homework/math4610/inc/types.h
@@ -0,0 +1,24 @@
+#include "macros.h"
+#include <stdint.h>
+
+#ifndef TYPES_H
+#define TYPES_H
+
+DEFINE_ARRAY(int);
+DEFINE_ARRAY(uint32_t);
+DEFINE_ARRAY(int32_t);
+DEFINE_ARRAY(float);
+DEFINE_ARRAY(double);
+
+DEFINE_MATRIX(int);
+DEFINE_MATRIX(uint32_t);
+DEFINE_MATRIX(int32_t);
+DEFINE_MATRIX(float);
+DEFINE_MATRIX(double);
+
+typedef struct Line {
+ double m;
+ double a;
+} Line;
+
+#endif // TYPES_H
diff --git a/Homework/math4610/lib/lizfcm.a b/Homework/math4610/lib/lizfcm.a
new file mode 100644
index 0000000..d28d9aa
--- /dev/null
+++ b/Homework/math4610/lib/lizfcm.a
Binary files differ
diff --git a/Homework/math4610/notes/29-Nov.org b/Homework/math4610/notes/29-Nov.org
new file mode 100644
index 0000000..a478ebf
--- /dev/null
+++ b/Homework/math4610/notes/29-Nov.org
@@ -0,0 +1,20 @@
+Jacobi Iteration (cont.)
+
+x^{k+1} = D^{-1}(b - (L + U)x^k)
+
+{
+ x^{k+1} = x^k + D^-1 r^k
+ r^{k} = b - Ax^k
+}
+
+error: || x^{k+1} - x^k ||_2
+residual: || r^k ||_2
+
+Gauss-Seidel Iteration:
+A = (L + D + U)
+\Rightarrow Ax = b
+ (D + U)x = b - Lx
+ x = (D + U)^-1 (b - Lx)
+
+x^{k+1} = (D+U)^{-1}(b - Lx^k)
+(D + U)^{-1} x (bsubst)
diff --git a/Homework/math4610/notes/4-Dec.org b/Homework/math4610/notes/4-Dec.org
new file mode 100644
index 0000000..d148bc8
--- /dev/null
+++ b/Homework/math4610/notes/4-Dec.org
@@ -0,0 +1,2 @@
+
+
diff --git a/Homework/math4610/notes/Nov-27.org b/Homework/math4610/notes/Nov-27.org
new file mode 100644
index 0000000..ae4ded0
--- /dev/null
+++ b/Homework/math4610/notes/Nov-27.org
@@ -0,0 +1,20 @@
+x^{k+1} = D^{-1}(b - (L + U) x^k)
+x^{k + 1} \rightarrow Ax^k
+
+
+#+BEGIN_SRC c
+ loop while (err > tol && iter < maxiter) {
+ for (int i = 0; i < n; i++) {
+ sum = b[i];
+ for (int j = 0; j < i; j++) {
+ sum = sum - a[i][x] * x_0[i];
+ }
+ for (int j = i; j < n; j++) {
+ sum = sum + a[i][j] * x_0[j];
+ }
+ x_1[i] = sum / a[i][i];
+ }
+
+ err = 0.0;
+ }
+#+END_SRC
diff --git a/Homework/math4610/notes/Nov-3.org b/Homework/math4610/notes/Nov-3.org
new file mode 100644
index 0000000..5a65d2a
--- /dev/null
+++ b/Homework/math4610/notes/Nov-3.org
@@ -0,0 +1,62 @@
+* eigenvalues \rightarrow power method
+
+we iterate on the x_{k+1} = A x_k
+
+y = Av_0
+v_1 = \frac{1}{|| y ||} (y)
+\lambda_0 = v_0^T A v_0 = v_0^T y
+
+Find the largest eigenvalue;
+
+#+BEGIN_SRC c
+ while (error > tol && iter < max_iter) {
+ v_1 = (1 / magnitude(y)) * y;
+ w = m_dot_v(a, v_1);
+ lambda_1 = v_dot_v(transpose(v_1), w);
+ error = abs(lambda_1 - lambda_0);
+ iter++;
+ lambda_0 = lambda_1;
+ y = v_1;
+ }
+
+ return [lambda_1, error];
+#+END_SRC
+
+Find the smallest eigenvalue:
+
+** We know:
+If \lambda_1 is the largest eigenvalue of $A$ then \frac{1}{\lambda_1} is the smallest eigenvalue of $A^{-1}$.
+
+If \lambda_n is the smallest eigenvalue of $A$ then \frac{1}{\lambda_n} is the largest eigenvalue of $A^{-1}$.
+*** However, calculating $A^{-1}$ is inefficient
+So, transform $w = A^{-1} v_1 \Rightarrow$ Solve $Aw = v_1$ with LU or GE (line 3 of above snippet).
+
+And, transform $y = A^{-1} v_0 \Rightarrow$ Solve $Ay = v_0$ with LU or GE.
+
+** Conclusions
+
+We have the means to compute the approximations of \lambda_1 and \lambda_n.
+
+(\lambda_1 \rightarrow power method)
+
+(\lambda_n \rightarrow inverse power method)
+
+* Eigenvalue Shifting
+
+If (\lambda, v) is an eigen pair, (v \neq 0)
+
+Av = \lambdav
+
+Thus for any \mu \in R
+
+(Av - \mu I v) = (A - \mu I)v = \lambda v - \mu I v
+ = (\lambda - \mu)v
+ \Rightarrow \lambda - \mu is an eigenvalue of (A - \mu I)
+
+(A - \mu I)v = (\lambda - \mu)v
+
+Idea is to choose \mu close to our eigenvalue. We can then inverse iterate to
+construct an approximation of \lambda - \mu and then add \mu back to get \lambda.
+
+v_0 = a_1 v_1 + a_2 v_2 + \cdots + a_n v_n
+A v_0 = a_1 (\lambda_1 v_1) + \cdots
diff --git a/Homework/math4610/notes/Nov-6.org b/Homework/math4610/notes/Nov-6.org
new file mode 100644
index 0000000..4a9562f
--- /dev/null
+++ b/Homework/math4610/notes/Nov-6.org
@@ -0,0 +1,25 @@
+* Power Method
+v_{k+1} = A v_k, k = 0,1,2
+
+** Properties
+1. \frac{A v_k}{||v_k||} \rightarrow v_1
+2. \frac{v_k^T A v_k}{v_k^T v_k} \rightarrow \lambda_1
+3. If \lambda is a n eigenvalue of A, then \frac{1}{\lambda} is an eigenvalue of A^-1
+4. Av = \lambda v
+ Av - \mu v = (\lambda-\mu)v = (A - \mu I)v
+5. If \lambda is an eigenvalue of A, then \lambda - \mu is an eigenvalue of A \cdot \mu I
+
+** Shifting Eigenvalues
+1. Partition [\lambda_n, \lambda_1]
+
+
+* Lanczos Algorithm
+
+#+BEGIN_SRC c
+ for (int i = 0; i < n; i++) {
+ sum = a0;
+ v_dot_v(a[i], x);
+
+ b[i] = sum;
+ }
+#+END_SRC
diff --git a/Homework/math4610/notes/Oct-11.org b/Homework/math4610/notes/Oct-11.org
new file mode 100644
index 0000000..575ea74
--- /dev/null
+++ b/Homework/math4610/notes/Oct-11.org
@@ -0,0 +1,15 @@
+* Diagonal Dominance
+Suppose that A \in R^{n \times n} is diagonally dominant then Gaussian eliminiation of A produces no zero pivot
+elements.
+
+Def. A \in R^{n \times n} is diagonally dominant if for each i=1,2,...n |a_{i,i}| \geq \Sigma_{j=1}^n |a_i,j|
+
+
+* To test solution code:
+ [[1]
+ [1]
+Set y = [\cdots] \in R^n
+ [1]]
+
+Compute b=Ay
+Solve Ax=b
diff --git a/Homework/math4610/notes/Oct-13.org b/Homework/math4610/notes/Oct-13.org
new file mode 100644
index 0000000..853a6d6
--- /dev/null
+++ b/Homework/math4610/notes/Oct-13.org
@@ -0,0 +1,8 @@
+* Root Finding
+Finx x \in R such that f(x) = 0
+
+If g(x) is a function and we want to find x such that g(x) is
+extremal then we find x \in R such that g'(x) = 0
+
+
+Hanging Cable Problem y(x) = c_1 cosh(\frac{x- c_2}{c_2})
diff --git a/Homework/math4610/notes/Oct-16.org b/Homework/math4610/notes/Oct-16.org
new file mode 100644
index 0000000..1406737
--- /dev/null
+++ b/Homework/math4610/notes/Oct-16.org
@@ -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)
+
+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
+
+
diff --git a/Homework/math4610/notes/Oct-18.org b/Homework/math4610/notes/Oct-18.org
new file mode 100644
index 0000000..0104164
--- /dev/null
+++ b/Homework/math4610/notes/Oct-18.org
@@ -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^* |
diff --git a/Homework/math4610/notes/Oct-27.org b/Homework/math4610/notes/Oct-27.org
new file mode 100644
index 0000000..6d23576
--- /dev/null
+++ b/Homework/math4610/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/Homework/math4610/notes/Oct-30.org b/Homework/math4610/notes/Oct-30.org
new file mode 100644
index 0000000..7d6ee03
--- /dev/null
+++ b/Homework/math4610/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/Homework/math4610/notes/Oct-4.org b/Homework/math4610/notes/Oct-4.org
new file mode 100644
index 0000000..8b8466f
--- /dev/null
+++ b/Homework/math4610/notes/Oct-4.org
@@ -0,0 +1,22 @@
+[[ a_{11} a_{12} \cdots a_{1n} | b_1]
+ [ 0 (a_{22} - \frac{a_{}_{21}}{a_{22}}a_{11}) \cdots a_{2n} | b_2 - \frac{a_{21}}{a_{11}}b_1 ]]
+
+#+BEGIN_SRC c
+ for (int i = 1; i < n; i++) {
+ float factor = -a[i][0] / a[0][0];
+ for (int j = 1; j < n; j++) {
+ a[i][j] = a[i][j] + factor * a[0][j];
+ }
+ b[i] = b[i] + factor * b[0];
+ }
+
+ for (int k = 0; k < (n - 1); k++) {
+ for (int i = k+1; i < n; i++) {
+ float factor = -a[i][k] / a[k][k];
+ for (int j = k+1; j < n; j++) {
+ a[i][j] = a[i][j] + factor * a[j][k];
+ }
+ b[i] = b[i] + factor*b[k];
+ }
+ }
+#+END_SRC
diff --git a/Homework/math4610/notes/Oct-6.org b/Homework/math4610/notes/Oct-6.org
new file mode 100644
index 0000000..8cbff29
--- /dev/null
+++ b/Homework/math4610/notes/Oct-6.org
@@ -0,0 +1,13 @@
+#+BEGIN_SRC c
+ for (int k = 0; i < (n - 1); k++) {
+ for (int i = k+1; i< n; i++) {
+ float factor = a[i][k] / a[k][k];
+ for (int j = k+1; j < k; j++) {
+ a[i][j] = a[i][j] - factor * a[k][j];
+ }
+ b[i] = b[i] - factor * b[k];
+ }
+ }
+#+END_SRC
+
+
diff --git a/Homework/math4610/notes/Sep-11.org b/Homework/math4610/notes/Sep-11.org
new file mode 100644
index 0000000..3d71f2f
--- /dev/null
+++ b/Homework/math4610/notes/Sep-11.org
@@ -0,0 +1,94 @@
+#+TITLE: Errors
+#+AUTHOR: Elizabeth Hunt
+#+STARTUP: entitiespretty fold inlineimages
+#+LATEX_HEADER: \notindent \notag \usepackage{amsmath} \usepackage[a4paper,margin=1in,landscape]{geometry}
+#+LATEX: \setlength\parindent{0pt}
+#+OPTIONS: toc:nil
+
+* Errors
+$x,y \in \mathds{R}$, using y as a way to approximate x. Then the
+absolute error of in approximating x w/ y is $e_{abs}(x, y) = |x-y|$.
+
+and the relative error is $e_{rel}(x, y) = \frac{|x-y|}{|x|}$
+
+Table of Errors
+
+#+BEGIN_SRC lisp :results table
+ (load "../cl/lizfcm.asd")
+ (ql:quickload 'lizfcm)
+
+ (defun eabs (x y) (abs (- x y)))
+ (defun erel (x y) (/ (abs (- x y)) (abs x)))
+
+ (defparameter *u-v* '(
+ (1 0.99)
+ (1 1.01)
+ (-1.5 -1.2)
+ (100 99.9)
+ (100 99)
+ ))
+
+ (lizfcm.utils:table (:headers '("u" "v" "e_{abs}" "e_{rel}")
+ :domain-order (u v)
+ :domain-values *u-v*)
+ (eabs u v)
+ (erel u v))
+#+END_SRC
+
+#+RESULTS:
+| u | v | e_{abs} | e_{rel} |
+| 1 | 0.99 | 0.00999999 | 0.00999999 |
+| 1 | 1.01 | 0.00999999 | 0.00999999 |
+| -1.5 | -1.2 | 0.29999995 | 0.19999997 |
+| 100 | 99.9 | 0.099998474 | 0.0009999848 |
+| 100 | 99 | 1 | 1/100 |
+
+
+Look at $u \approx 0$ then $v \approx 0$, $e_{abs}$ is better error since $e_{rel}$ is high.
+
+* Vector spaces & measures
+Suppose we want solutions fo a linear system of the form $Ax = b$, and we want to approximate $x$,
+we need to find a form of "distance" between vectors in $\mathds{R}^n$
+
+** Vector Distances
+A norm on a vector space $|| v ||$ is a function from $\mathds{R}^n$ such that:
+
+1. $||v|| \geq 0$ for all $v \in \mathds{R}^n$ and $||v|| = \Leftrightarrow v = 0$
+2. $||cv|| = |c| ||v||$ for all $c \in \mathds{R}, v \in \mathds{R}^n$
+3. $||x + y|| \leq ||x|| + ||y|| \forall x,y \in \mathds{R}^n$
+
+*** Example norms:
+$||v||_2 = || [v_1, v_2, \dots v_n] || = (v_1^2 + v_2^2 + \dots + v_n^2)^{}^{\frac{1}{2}}$
+
+$||v||_1 = |v_1| + |v_2| + \dots + |v_n|$
+
+$||v||_{\infty} = \text{max}(|v_i|)$ (most restriction)
+
+p-norm:
+$||v||_p = \sum_{i=1}^{h} (|v_i|^p)^{\frac{1}{p}}$
+
+** Length
+The length of a vector in a given norm is $||v|| \forall v \in \mathds{R}^n$
+
+All norms on finite dimensional vectors are equivalent. Then exist constants
+$\alpha, \beta > 0 \ni \alpha ||v||_p \leq ||v||_q \leq \beta||v||_p$
+
+** Distance
+Let $u,v$ be vectors in $\mathds{R}^n$ then the distance is $||u - v||$ by some norm:
+$e_{abs} = d(v, u) = ||u - v||$
+
+The relative errors is:
+
+$e_{rel} = \frac{||u - v||}{||v||}$
+
+
+** Approxmiating Solutions to $Ax = b$
+We define the residual vector $r(x) = b - Ax$
+
+If $x$ is the exact solution, then $r(x) = 0$.
+
+Then we can measure the "correctness" of the approximated solution on the norm of the
+residual. We want to minimize the norm.
+
+But, $r(y) = b - Ay \approx 0 \nRightarrow y \equiv x$, if $A$ is not invertible.
+
diff --git a/Homework/math4610/notes/Sep-13.org b/Homework/math4610/notes/Sep-13.org
new file mode 100644
index 0000000..0ebff2b
--- /dev/null
+++ b/Homework/math4610/notes/Sep-13.org
@@ -0,0 +1,16 @@
+* Homework 2
+1. maceps - single precision
+
+2. maceps - double precision
+
+3. 2-norm of a vector
+
+4. 1-norm of a vector
+
+5. infinity-norm of a vector (max-norm)
+
+6. 2-norm distance between 2 vectors
+
+7. 1-norm distance between 2 vectors
+
+8. infinity-norm distance
diff --git a/Homework/math4610/notes/Sep-15.org b/Homework/math4610/notes/Sep-15.org
new file mode 100644
index 0000000..8a64089
--- /dev/null
+++ b/Homework/math4610/notes/Sep-15.org
@@ -0,0 +1,52 @@
+* Taylor Series Approx.
+Suppose f has $\infty$ many derivatives near a point a. Then the taylor series is given by
+
+$f(x) = \Sigma_{n=0}^{\infty} \frac{f^{(n)}(a)}{n!}(x-a)^n$
+
+For increment notation we can write
+
+$f(a + h) = f(a) + f'(a)(a+h - a) + \dots$
+
+$= \Sigma_{n=0}^{\infty} \frac{f^{(n)}(a)}{h!} (h^n)$
+
+Consider the approximation
+
+$e = |f'(a) - \frac{f(a + h) - f(a)}{h}| = |f'(a) - \frac{1}{h}(f(a + h) - f(a))|$
+
+Substituting...
+
+$= |f'(a) - \frac{1}{h}((f(a) + f'(a) h + \frac{f''(a)}{2} h^2 + \cdots) - f(a))|$
+
+$f(a) - f(a) = 0$... and $distribute the h$
+
+$= |-1/2 f''(a) h + \frac{1}{6}f'''(a)h^2 \cdots|$
+
+** With Remainder
+We can determine for some u $f(a + h) = f(a) + f'(a)h + \frac{1}{2}f''(u)h^2$
+
+and so the error is $e = |f'(a) - \frac{f(a + h) - f(a)}{h}| = |\frac{h}{2}f''(u)|$
+
+- [https://openstax.org/books/calculus-volume-2/pages/6-3-taylor-and-maclaurin-series]
+ + > Taylor's Theorem w/ Remainder
+
+
+** Of Deriviatives
+
+Again, $f'(a) \approx \frac{f(a+h) - f(a)}{h}$,
+
+$e = |\frac{1}{2} f''(a) + \frac{1}{3!}h^2 f'''(a) + \cdots$
+
+$R_2 = \frac{h}{2} f''(\xi)$
+
+$|\frac{h}{2} f''(\xi)| \leq M h^1$
+
+$M = \frac{1}{2}|f'(\xi)|$
+
+*** Another approximation
+
+$\text{err} = |f'(a) - \frac{f(a) - f(a - h)}{h}|$
+
+$= f'(a) - \frac{1}{h}(f(a) - (f(a) + f'(a)(a - (a - h)) + \frac{1}{2}f''(a)(a-(a-h))^2 + \cdots))$
+
+$= |f'(a) - (f'(a) + \frac{1}{2}f''(a)h)|$
+
diff --git a/Homework/math4610/notes/Sep-15.pdf b/Homework/math4610/notes/Sep-15.pdf
new file mode 100644
index 0000000..43a4f34
--- /dev/null
+++ b/Homework/math4610/notes/Sep-15.pdf
Binary files differ
diff --git a/Homework/math4610/notes/Sep-15.tex b/Homework/math4610/notes/Sep-15.tex
new file mode 100644
index 0000000..52610ed
--- /dev/null
+++ b/Homework/math4610/notes/Sep-15.tex
@@ -0,0 +1,88 @@
+% Created 2023-09-29 Fri 10:00
+% Intended LaTeX compiler: pdflatex
+\documentclass[11pt]{article}
+\usepackage[utf8]{inputenc}
+\usepackage[T1]{fontenc}
+\usepackage{graphicx}
+\usepackage{longtable}
+\usepackage{wrapfig}
+\usepackage{rotating}
+\usepackage[normalem]{ulem}
+\usepackage{amsmath}
+\usepackage{amssymb}
+\usepackage{capt-of}
+\usepackage{hyperref}
+\author{Elizabeth Hunt}
+\date{\today}
+\title{}
+\hypersetup{
+ pdfauthor={Elizabeth Hunt},
+ pdftitle={},
+ pdfkeywords={},
+ pdfsubject={},
+ pdfcreator={Emacs 28.2 (Org mode 9.7-pre)},
+ pdflang={English}}
+\begin{document}
+
+\tableofcontents
+
+\section{Taylor Series Approx.}
+\label{sec:orgcc72ed1}
+Suppose f has \(\infty\) many derivatives near a point a. Then the taylor series is given by
+
+\(f(x) = \Sigma_{n=0}^{\infty} \frac{f^{(n)}(a)}{n!}(x-a)^n\)
+
+For increment notation we can write
+
+\(f(a + h) = f(a) + f'(a)(a+h - a) + \dots\)
+
+\(= \Sigma_{n=0}^{\infty} \frac{f^{(n)}(a)}{h!} (h^n)\)
+
+Consider the approximation
+
+\(e = |f'(a) - \frac{f(a + h) - f(a)}{h}| = |f'(a) - \frac{1}{h}(f(a + h) - f(a))|\)
+
+Substituting\ldots{}
+
+\(= |f'(a) - \frac{1}{h}((f(a) + f'(a) h + \frac{f''(a)}{2} h^2 + \cdots) - f(a))|\)
+
+\(f(a) - f(a) = 0\)\ldots{} and \(distribute the h\)
+
+\(= |-1/2 f''(a) h + \frac{1}{6}f'''(a)h^2 \cdots|\)
+
+\subsection{With Remainder}
+\label{sec:org7dfd6c7}
+We can determine for some u \(f(a + h) = f(a) + f'(a)h + \frac{1}{2}f''(u)h^2\)
+
+and so the error is \(e = |f'(a) - \frac{f(a + h) - f(a)}{h}| = |\frac{h}{2}f''(u)|\)
+
+\begin{itemize}
+\item\relax [\url{https://openstax.org/books/calculus-volume-2/pages/6-3-taylor-and-maclaurin-series}]
+\begin{itemize}
+\item > Taylor's Theorem w/ Remainder
+\end{itemize}
+\end{itemize}
+
+
+\subsection{Of Deriviatives}
+\label{sec:org1ec7c9b}
+
+Again, \(f'(a) \approx \frac{f(a+h) - f(a)}{h}\),
+
+\(e = |\frac{1}{2} f''(a) + \frac{1}{3!}h^2 f'''(a) + \cdots\)
+
+\(R_2 = \frac{h}{2} f''(u)\)
+
+\(|\frac{h}{2} f''(u)| \leq M h^1\)
+
+\(M = \frac{1}{2}|f'(u)|\)
+
+\subsubsection{Another approximation}
+\label{sec:org16193b9}
+
+\(\text{err} = |f'(a) - \frac{f(a) - f(a - h)}{h}|\)
+
+\(= f'(a) - \frac{1}{h}(f(a) - (f(a) + f'(a)(a - (a - h)) + \frac{1}{2}f''(a)(a-(a-h))^2 + \cdots))\)
+
+\(= |f'(a) - \frac{1}{h}(f'(a) + \frac{1}{2}f''(a)h)|\)
+\end{document} \ No newline at end of file
diff --git a/Homework/math4610/notes/Sep-20.org b/Homework/math4610/notes/Sep-20.org
new file mode 100644
index 0000000..ba067bb
--- /dev/null
+++ b/Homework/math4610/notes/Sep-20.org
@@ -0,0 +1,21 @@
+* Review & Summary
+Approx f'(a) with
+
++ forward difference $f'(a) \approx \frac{f(a+h) - f(a)}{h}$
+
++ backward difference $f'(a) \approx \frac{f(a) - f(a-h)}{h}$
+
++ central difference $f'(a) \approx \frac{f(a+h) - f(a-h)}{2h}$
+
+** Taylor Series
+given $C = \frac{1}{2}(|f''(\xi)|) \cdot h^1$
+
+with f.d. $e_{\text{abs}} \leq Ch^1$
+
+b.d. $e_{\text{abs}} \leq Ch^1$
+
+c.d. $e_{\text{abs}} \leq Ch^2$
+
+$e_{\text{abs}} \leq Ch^r$
+
+$log(e(h)) \leq log(ch^r) = log(C) + log(h^r) = log(C) + rlog(h)$
diff --git a/Homework/math4610/notes/Sep-22.org b/Homework/math4610/notes/Sep-22.org
new file mode 100644
index 0000000..b631e3b
--- /dev/null
+++ b/Homework/math4610/notes/Sep-22.org
@@ -0,0 +1,45 @@
+* regression
+consider the generic problem of fitting a dataset to a linear polynomial
+
+given discrete f: x \rightarrow y
+
+interpolation: y = a + bx
+
+[[1 x_0] [[y_0]
+ [1 x_1] \cdot [[a] = [y_1]
+ [1 x_n]] [b]] [y_n]]
+
+consider p \in col(A)
+
+then y = p + q for some q \cdot p = 0
+
+then we can generate n \in col(A) by $Az$ and n must be orthogonal to q as well
+
+(Az)^T \cdot q = 0 = (Az)^T (y - p)
+
+0 = (z^T A^T)(y - Ax)
+ = z^T (A^T y - A^T A x)
+ = A^T Ax
+ = A^T y
+
+
+A^T A = [[n+1 \Sigma_{n=0}^n x_n]
+ [\Sigma_{n=0}^n x_n \Sigma_{n=0}^n x_n^2]]
+
+A^T y = [[\Sigma_{n=0}^n y_n]
+ [\Sigma_{n=0}^n x_n y_n]]
+
+a_11 = n+1
+a_12 = \Sigma_{n=0}^n x_n
+a_21 = a_12
+a_22 = \Sigma_{n=0}^n x_n^2
+b_1 = \Sigma_{n=0}^n y_n
+b_2 = \Sigma_{n=0}^n x_n y_n
+
+then apply this with:
+
+log(e(h)) \leq log(C) + rlog(h)
+
+* homework 3:
+
+two columns \Rightarrow coefficients for linear regression
diff --git a/Homework/math4610/notes/Sep-25.org b/Homework/math4610/notes/Sep-25.org
new file mode 100644
index 0000000..b2d63e3
--- /dev/null
+++ b/Homework/math4610/notes/Sep-25.org
@@ -0,0 +1,48 @@
+ex: erfc(x) = \int_{0}^x (\frac{2}{\sqrt{pi}})e^{-t^2 }dt
+ex: IVP \frac{dP}{dt} = \alpha P - \beta P^2
+ P(0) = P_0
+
+Explicit Euler Method
+
+$\frac{P(t + \Delta t) - P(t)}{\Delta t} \approx \alpha P(t) - \beta P^2(t)$
+
+From 0 \rightarrow T
+P(T) \approx n steps
+
+* Steps
+** Calculus: defference quotient
+$f'(a) \approx \frac{f(a+h) - f(a)}{h}$
+
+** Test.
+Roundoff for h \approx 0
+
+** Calculus: Taylor Serioes w/ Remainder
+$e_{abs}(h) \leq Ch^r$
+
+(see Sep-20 . Taylor Series)
+
+* Pseudo Code
+#+BEGIN_SRC python
+ for i in range(n):
+ a12 = a12 + x[i+1]
+ a22 = a22 + x[i+1]**2
+ a21 = a12
+ b1 = y[0]
+ b2 = y[0] * x[0]
+ for i in range(n):
+ b1 = b1 + y[i+1]
+ b2 = b2 + y[i+1]*x[i+1]
+ detA = a22*a11 - a12*a21
+ c = (a22*b1 - a12*b2) / detA
+ d = (-a21 * b1 + a11 * b2) / detA
+
+ return (c, d)
+#+END_SRC
+
+* Error
+We want
+$e_k = |df(h_kk) - f'(a)|$
+
+$= |df(h_k) - df(h_m) + df(h_m) - f'(a)|$
+
+$\leq |df(h_k) - df(h_m)| + |df(h_m) - f'(a)|$ and $|df(h_m) - f'(a)|$ is negligible
diff --git a/Homework/math4610/src/approx_derivative.c b/Homework/math4610/src/approx_derivative.c
new file mode 100644
index 0000000..63d0b05
--- /dev/null
+++ b/Homework/math4610/src/approx_derivative.c
@@ -0,0 +1,38 @@
+#include "lizfcm.h"
+#include <assert.h>
+
+double central_derivative_at(double (*f)(double), double a, double h) {
+ assert(h > 0);
+
+ double x2 = a + h;
+ double x1 = a - h;
+
+ double y2 = f(x2);
+ double y1 = f(x1);
+
+ return (y2 - y1) / (x2 - x1);
+}
+
+double forward_derivative_at(double (*f)(double), double a, double h) {
+ assert(h > 0);
+
+ double x2 = a + h;
+ double x1 = a;
+
+ double y2 = f(x2);
+ double y1 = f(x1);
+
+ return (y2 - y1) / (x2 - x1);
+}
+
+double backward_derivative_at(double (*f)(double), double a, double h) {
+ assert(h > 0);
+
+ double x2 = a;
+ double x1 = a - h;
+
+ double y2 = f(x2);
+ double y1 = f(x1);
+
+ return (y2 - y1) / (x2 - x1);
+}
diff --git a/Homework/math4610/src/eigen.c b/Homework/math4610/src/eigen.c
new file mode 100644
index 0000000..49cc0e4
--- /dev/null
+++ b/Homework/math4610/src/eigen.c
@@ -0,0 +1,116 @@
+#include "lizfcm.h"
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+double least_dominant_eigenvalue(Matrix_double *m, Array_double *v,
+ double tolerance, size_t max_iterations) {
+ return shift_inverse_power_eigenvalue(m, v, 0.0, tolerance, max_iterations);
+}
+
+double dominant_eigenvalue(Matrix_double *m, Array_double *v, double tolerance,
+ size_t max_iterations) {
+ assert(m->rows == m->cols);
+ assert(m->rows == v->size);
+
+ double error = tolerance;
+ size_t iter = max_iterations;
+ double lambda = 0.0;
+ Array_double *eigenvector_1 = copy_vector(v);
+
+ while (error >= tolerance && (--iter) > 0) {
+ Array_double *eigenvector_2 = m_dot_v(m, eigenvector_1);
+ Array_double *normalized_eigenvector_2 =
+ scale_v(eigenvector_2, 1.0 / linf_norm(eigenvector_2));
+ free_vector(eigenvector_2);
+ eigenvector_2 = normalized_eigenvector_2;
+
+ Array_double *mx = m_dot_v(m, eigenvector_2);
+ double new_lambda =
+ v_dot_v(mx, eigenvector_2) / v_dot_v(eigenvector_2, eigenvector_2);
+
+ error = fabs(new_lambda - lambda);
+ lambda = new_lambda;
+ free_vector(eigenvector_1);
+ eigenvector_1 = eigenvector_2;
+ }
+
+ return lambda;
+}
+
+double shift_inverse_power_eigenvalue(Matrix_double *m, Array_double *v,
+ double shift, double tolerance,
+ size_t max_iterations) {
+ assert(m->rows == m->cols);
+ assert(m->rows == v->size);
+
+ Matrix_double *m_c = copy_matrix(m);
+ for (size_t y = 0; y < m_c->rows; ++y)
+ m_c->data[y]->data[y] = m_c->data[y]->data[y] - shift;
+
+ double error = tolerance;
+ size_t iter = max_iterations;
+ double lambda = shift;
+ Array_double *eigenvector_1 = copy_vector(v);
+
+ while (error >= tolerance && (--iter) > 0) {
+ Array_double *eigenvector_2 = solve_matrix_lu_bsubst(m_c, eigenvector_1);
+ Array_double *normalized_eigenvector_2 =
+ scale_v(eigenvector_2, 1.0 / linf_norm(eigenvector_2));
+ free_vector(eigenvector_2);
+
+ Array_double *mx = m_dot_v(m, normalized_eigenvector_2);
+ double new_lambda =
+ v_dot_v(mx, normalized_eigenvector_2) /
+ v_dot_v(normalized_eigenvector_2, normalized_eigenvector_2);
+
+ error = fabs(new_lambda - lambda);
+ lambda = new_lambda;
+ free_vector(eigenvector_1);
+ eigenvector_1 = normalized_eigenvector_2;
+ }
+
+ return lambda;
+}
+
+Array_double *partition_find_eigenvalues(Matrix_double *m,
+ Matrix_double *guesses,
+ double tolerance,
+ size_t max_iterations) {
+ assert(guesses->rows >=
+ 2); // we need at least, the most and least dominant eigenvalues
+
+ double end = dominant_eigenvalue(m, guesses->data[guesses->rows - 1],
+ tolerance, max_iterations);
+ double begin =
+ least_dominant_eigenvalue(m, guesses->data[0], tolerance, max_iterations);
+
+ double delta = (end - begin) / guesses->rows;
+ Array_double *eigenvalues = InitArrayWithSize(double, guesses->rows, 0.0);
+ for (size_t i = 0; i < guesses->rows; i++) {
+ double box_midpoint = ((delta * i) + (delta * (i + 1))) / 2;
+
+ double nearest_eigenvalue = shift_inverse_power_eigenvalue(
+ m, guesses->data[i], box_midpoint, tolerance, max_iterations);
+
+ eigenvalues->data[i] = nearest_eigenvalue;
+ }
+
+ return eigenvalues;
+}
+
+Matrix_double *leslie_matrix(Array_double *age_class_surivor_ratio,
+ Array_double *age_class_offspring) {
+ assert(age_class_surivor_ratio->size + 1 == age_class_offspring->size);
+
+ Matrix_double *leslie = InitMatrixWithSize(double, age_class_offspring->size,
+ age_class_offspring->size, 0.0);
+
+ free_vector(leslie->data[0]);
+ leslie->data[0] = copy_vector(age_class_offspring);
+
+ for (size_t i = 0; i < age_class_surivor_ratio->size; i++)
+ leslie->data[i + 1]->data[i] = age_class_surivor_ratio->data[i];
+ return leslie;
+}
diff --git a/Homework/math4610/src/lin.c b/Homework/math4610/src/lin.c
new file mode 100644
index 0000000..d531025
--- /dev/null
+++ b/Homework/math4610/src/lin.c
@@ -0,0 +1,19 @@
+#include "lizfcm.h"
+#include <assert.h>
+
+Line *least_squares_lin_reg(Array_double *x, Array_double *y) {
+ assert(x->size == y->size);
+
+ uint64_t n = x->size;
+ double sum_x = sum_v(x);
+ double sum_y = sum_v(y);
+ double sum_xy = v_dot_v(x, y);
+ double sum_xx = v_dot_v(x, x);
+ double denom = ((n * sum_xx) - (sum_x * sum_x));
+
+ Line *line = malloc(sizeof(Line));
+ line->m = ((sum_xy * n) - (sum_x * sum_y)) / denom;
+ line->a = ((sum_y * sum_xx) - (sum_x * sum_xy)) / denom;
+
+ return line;
+}
diff --git a/Homework/math4610/src/maceps.c b/Homework/math4610/src/maceps.c
new file mode 100644
index 0000000..23bc9db
--- /dev/null
+++ b/Homework/math4610/src/maceps.c
@@ -0,0 +1,28 @@
+#include "lizfcm.h"
+#include <math.h>
+
+float smaceps() {
+ float one = 1.0;
+ float machine_epsilon = 1.0;
+ float one_approx = one + machine_epsilon;
+
+ while (fabsf(one_approx - one) > 0) {
+ machine_epsilon /= 2;
+ one_approx = one + machine_epsilon;
+ }
+
+ return machine_epsilon;
+}
+
+double dmaceps() {
+ double one = 1.0;
+ double machine_epsilon = 1.0;
+ double one_approx = one + machine_epsilon;
+
+ while (fabs(one_approx - one) > 0) {
+ machine_epsilon /= 2;
+ one_approx = one + machine_epsilon;
+ }
+
+ return machine_epsilon;
+}
diff --git a/Homework/math4610/src/matrix.c b/Homework/math4610/src/matrix.c
new file mode 100644
index 0000000..901a426
--- /dev/null
+++ b/Homework/math4610/src/matrix.c
@@ -0,0 +1,346 @@
+#include "lizfcm.h"
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+Array_double *m_dot_v(Matrix_double *m, Array_double *v) {
+ assert(v->size == m->cols);
+
+ Array_double *product = copy_vector(v);
+
+ for (size_t row = 0; row < v->size; ++row)
+ product->data[row] = v_dot_v(m->data[row], v);
+
+ return product;
+}
+
+Array_double *col_v(Matrix_double *m, size_t x) {
+ assert(x < m->cols);
+
+ Array_double *col = InitArrayWithSize(double, m->rows, 0.0);
+ for (size_t y = 0; y < m->rows; y++)
+ col->data[y] = m->data[y]->data[x];
+
+ return col;
+}
+
+Matrix_double *m_dot_m(Matrix_double *a, Matrix_double *b) {
+ assert(a->cols == b->rows);
+
+ Matrix_double *prod = InitMatrixWithSize(double, a->rows, b->cols, 0.0);
+
+ Array_double *curr_col;
+ for (size_t y = 0; y < a->rows; y++) {
+ for (size_t x = 0; x < b->cols; x++) {
+ curr_col = col_v(b, x);
+ prod->data[y]->data[x] = v_dot_v(curr_col, a->data[y]);
+ free_vector(curr_col);
+ }
+ }
+
+ return prod;
+}
+
+Matrix_double *transpose(Matrix_double *m) {
+ Matrix_double *transposed = InitMatrixWithSize(double, m->cols, m->rows, 0.0);
+
+ for (size_t x = 0; x < m->rows; x++)
+ for (size_t y = 0; y < m->cols; y++)
+ transposed->data[y]->data[x] = m->data[x]->data[y];
+
+ return transposed;
+}
+
+Matrix_double *put_identity_diagonal(Matrix_double *m) {
+ assert(m->rows == m->cols);
+ Matrix_double *copy = copy_matrix(m);
+ for (size_t y = 0; y < m->rows; ++y)
+ copy->data[y]->data[y] = 1.0;
+ return copy;
+}
+
+Matrix_double *copy_matrix(Matrix_double *m) {
+ Matrix_double *copy = InitMatrixWithSize(double, m->rows, m->cols, 0.0);
+ for (size_t y = 0; y < copy->rows; y++) {
+ free_vector(copy->data[y]);
+ copy->data[y] = copy_vector(m->data[y]);
+ }
+ return copy;
+}
+
+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_matrix(l_empt);
+
+ 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");
+ 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");
+ 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;
+}
+
+Array_double *bsubst(Matrix_double *u, Array_double *b) {
+ assert(u->rows == b->size && u->cols == u->rows);
+
+ Array_double *x = copy_vector(b);
+ for (int64_t row = b->size - 1; row >= 0; row--) {
+ for (size_t col = b->size - 1; col > row; col--)
+ x->data[row] -= x->data[col] * u->data[row]->data[col];
+ x->data[row] /= u->data[row]->data[row];
+ }
+ return x;
+}
+
+Array_double *fsubst(Matrix_double *l, Array_double *b) {
+ assert(l->rows == b->size && l->cols == l->rows);
+
+ Array_double *x = copy_vector(b);
+
+ for (size_t row = 0; row < b->size; row++) {
+ for (size_t col = 0; col < row; col++)
+ x->data[row] -= x->data[col] * l->data[row]->data[col];
+ x->data[row] /= l->data[row]->data[row];
+ }
+
+ return x;
+}
+
+Array_double *solve_matrix_lu_bsubst(Matrix_double *m, Array_double *b) {
+ assert(b->size == m->rows);
+ assert(m->rows == m->cols);
+
+ Array_double *x = copy_vector(b);
+ Matrix_double **u_l = lu_decomp(m);
+ Matrix_double *u = u_l[0];
+ Matrix_double *l = u_l[1];
+
+ Array_double *b_fsub = fsubst(l, b);
+ x = bsubst(u, b_fsub);
+ free_vector(b_fsub);
+
+ free_matrix(u);
+ free_matrix(l);
+ free(u_l);
+
+ return x;
+}
+
+Matrix_double *gaussian_elimination(Matrix_double *m) {
+ uint64_t h = 0, k = 0;
+
+ Matrix_double *m_cp = copy_matrix(m);
+
+ while (h < m_cp->rows && k < m_cp->cols) {
+ uint64_t max_row = h;
+ double max_val = 0.0;
+
+ for (uint64_t row = h; row < m_cp->rows; row++) {
+ double val = fabs(m_cp->data[row]->data[k]);
+ if (val > max_val) {
+ max_val = val;
+ max_row = row;
+ }
+ }
+
+ if (max_val == 0.0) {
+ k++;
+ continue;
+ }
+
+ if (max_row != h) {
+ Array_double *swp = m_cp->data[max_row];
+ m_cp->data[max_row] = m_cp->data[h];
+ m_cp->data[h] = swp;
+ }
+
+ 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;
+}
+
+Array_double *jacobi_solve(Matrix_double *m, Array_double *b,
+ double l2_convergence_tolerance,
+ size_t max_iterations) {
+ assert(m->rows == m->cols);
+ assert(b->size == m->cols);
+ size_t iter = max_iterations;
+
+ Array_double *x_k = InitArrayWithSize(double, b->size, 0.0);
+ Array_double *x_k_1 =
+ InitArrayWithSize(double, b->size, rand_from(0.1, 10.0));
+
+ while ((--iter) > 0 && l2_distance(x_k_1, x_k) > l2_convergence_tolerance) {
+ for (size_t i = 0; i < m->rows; i++) {
+ double delta = 0.0;
+ for (size_t j = 0; j < m->cols; j++) {
+ if (i == j)
+ continue;
+ delta += m->data[i]->data[j] * x_k->data[j];
+ }
+ x_k_1->data[i] = (b->data[i] - delta) / m->data[i]->data[i];
+ }
+
+ Array_double *tmp = x_k;
+ x_k = x_k_1;
+ x_k_1 = tmp;
+ }
+
+ free_vector(x_k);
+ return x_k_1;
+}
+
+Array_double *gauss_siedel_solve(Matrix_double *m, Array_double *b,
+ double l2_convergence_tolerance,
+ size_t max_iterations) {
+ assert(m->rows == m->cols);
+ assert(b->size == m->cols);
+ size_t iter = max_iterations;
+
+ Array_double *x_k = InitArrayWithSize(double, b->size, 0.0);
+ Array_double *x_k_1 =
+ InitArrayWithSize(double, b->size, rand_from(0.1, 10.0));
+
+ while ((--iter) > 0) {
+ for (size_t i = 0; i < x_k->size; i++)
+ x_k->data[i] = x_k_1->data[i];
+
+ for (size_t i = 0; i < m->rows; i++) {
+ double delta = 0.0;
+ for (size_t j = 0; j < m->cols; j++) {
+ if (i == j)
+ continue;
+ delta += m->data[i]->data[j] * x_k_1->data[j];
+ }
+ x_k_1->data[i] = (b->data[i] - delta) / m->data[i]->data[i];
+ }
+
+ if (l2_distance(x_k_1, x_k) <= l2_convergence_tolerance)
+ break;
+ }
+
+ free_vector(x_k);
+ return x_k_1;
+}
+
+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]);
+ free(m);
+}
+
+void format_matrix_into(Matrix_double *m, char *s) {
+ if (m->rows == 0)
+ strcpy(s, "empty");
+
+ for (size_t y = 0; y < m->rows; ++y) {
+ char row_s[5192];
+ strcpy(row_s, "");
+
+ format_vector_into(m->data[y], row_s);
+ strcat(s, row_s);
+ }
+ 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;
+}
diff --git a/Homework/math4610/src/rand.c b/Homework/math4610/src/rand.c
new file mode 100644
index 0000000..574a955
--- /dev/null
+++ b/Homework/math4610/src/rand.c
@@ -0,0 +1,5 @@
+#include "lizfcm.h"
+
+double rand_from(double min, double max) {
+ return min + (rand() / (RAND_MAX / (max - min)));
+}
diff --git a/Homework/math4610/src/roots.c b/Homework/math4610/src/roots.c
new file mode 100644
index 0000000..d6b22af
--- /dev/null
+++ b/Homework/math4610/src/roots.c
@@ -0,0 +1,127 @@
+#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_iterations]
+Array_double *find_ivt_range(double (*f)(double), double start_x, double delta,
+ size_t max_iterations) {
+ double a = start_x;
+
+ while (f(a) * f(a + delta) >= 0 && max_iterations > 0) {
+ max_iterations--;
+ a += delta;
+ }
+
+ double end = a + delta;
+ double begin = a - delta;
+
+ if (max_iterations == 0 && f(begin) * f(end) >= 0)
+ return NULL;
+ return InitArray(double, {begin, end});
+}
+
+// f is continuous on [a, b]
+Array_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 InitArray(double, {a, b, 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));
+
+ 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;
+}
diff --git a/Homework/math4610/src/vector.c b/Homework/math4610/src/vector.c
new file mode 100644
index 0000000..1b3e0b0
--- /dev/null
+++ b/Homework/math4610/src/vector.c
@@ -0,0 +1,143 @@
+#include "lizfcm.h"
+#include <assert.h>
+#include <float.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+Array_double *add_v(Array_double *v1, Array_double *v2) {
+ assert(v1->size == v2->size);
+
+ Array_double *sum = copy_vector(v1);
+ for (size_t i = 0; i < v1->size; i++)
+ sum->data[i] += v2->data[i];
+ return sum;
+}
+
+Array_double *minus_v(Array_double *v1, Array_double *v2) {
+ assert(v1->size == v2->size);
+
+ Array_double *sub = InitArrayWithSize(double, v1->size, 0);
+ for (size_t i = 0; i < v1->size; i++)
+ sub->data[i] = v1->data[i] - v2->data[i];
+ return sub;
+}
+
+Array_double *scale_v(Array_double *v, double m) {
+ Array_double *copy = copy_vector(v);
+ for (size_t i = 0; i < v->size; i++)
+ copy->data[i] *= m;
+ return copy;
+}
+
+double l1_norm(Array_double *v) {
+ double sum = 0;
+ for (size_t i = 0; i < v->size; ++i)
+ sum += fabs(v->data[i]);
+ return sum;
+}
+
+double l2_norm(Array_double *v) {
+ double norm = 0;
+ for (size_t i = 0; i < v->size; ++i)
+ norm += v->data[i] * v->data[i];
+ return sqrt(norm);
+}
+
+double linf_norm(Array_double *v) {
+ assert(v->size > 0);
+ double max = v->data[0];
+ for (size_t i = 0; i < v->size; ++i)
+ max = c_max(v->data[i], max);
+ return max;
+}
+
+double v_dot_v(Array_double *v1, Array_double *v2) {
+ assert(v1->size == v2->size);
+
+ double dot = 0;
+ for (size_t i = 0; i < v1->size; i++)
+ dot += v1->data[i] * v2->data[i];
+ return dot;
+}
+
+double vector_distance(Array_double *v1, Array_double *v2,
+ double (*norm)(Array_double *)) {
+ Array_double *minus = minus_v(v1, v2);
+ double dist = (*norm)(minus);
+ free(minus);
+ return dist;
+}
+
+double l1_distance(Array_double *v1, Array_double *v2) {
+ return vector_distance(v1, v2, &l1_norm);
+}
+
+double l2_distance(Array_double *v1, Array_double *v2) {
+ return vector_distance(v1, v2, &l2_norm);
+}
+
+double linf_distance(Array_double *v1, Array_double *v2) {
+ return vector_distance(v1, v2, &linf_norm);
+}
+
+Array_double *copy_vector(Array_double *v) {
+ Array_double *copy = InitArrayWithSize(double, v->size, 0.0);
+ for (size_t i = 0; i < copy->size; ++i)
+ copy->data[i] = v->data[i];
+ return copy;
+}
+
+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);
+}
+
+void format_vector_into(Array_double *v, char *s) {
+ if (v->size == 0) {
+ strcat(s, "empty");
+ return;
+ }
+
+ for (size_t i = 0; i < v->size; ++i) {
+ char num[64];
+ strcpy(num, "");
+
+ sprintf(num, "%f,", v->data[i]);
+ strcat(s, num);
+ }
+ strcat(s, "\n");
+}
+
+double sum_v(Array_double *v) {
+ double sum = 0;
+ for (size_t i = 0; i < v->size; i++)
+ sum += v->data[i];
+ 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;
+}
diff --git a/Homework/math4610/test/approx_derivative.t.c b/Homework/math4610/test/approx_derivative.t.c
new file mode 100644
index 0000000..6bcac79
--- /dev/null
+++ b/Homework/math4610/test/approx_derivative.t.c
@@ -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);
+}
diff --git a/Homework/math4610/test/eigen.t.c b/Homework/math4610/test/eigen.t.c
new file mode 100644
index 0000000..dc01aa7
--- /dev/null
+++ b/Homework/math4610/test/eigen.t.c
@@ -0,0 +1,147 @@
+#include "lizfcm.test.h"
+#include <math.h>
+
+Matrix_double *eigen_test_matrix() {
+ // produces a matrix that has eigenvalues [5 + sqrt{17}, 2, 5 - sqrt{17}]
+ Matrix_double *m = InitMatrixWithSize(double, 3, 3, 0.0);
+ m->data[0]->data[0] = 2.0;
+ m->data[0]->data[1] = 2.0;
+ m->data[0]->data[2] = 4.0;
+ m->data[1]->data[0] = 1.0;
+ m->data[1]->data[1] = 4.0;
+ m->data[1]->data[2] = 7.0;
+ m->data[2]->data[1] = 2.0;
+ m->data[2]->data[2] = 6.0;
+ return m;
+}
+
+UTEST(eigen, least_dominant_eigenvalue) {
+ Matrix_double *m = eigen_test_matrix();
+
+ double expected_least_dominant_eigenvalue = 0.87689; // 5 - sqrt(17)
+ double tolerance = 0.0001;
+ uint64_t max_iterations = 64;
+
+ Array_double *v_guess = InitArrayWithSize(double, 3, 1.0);
+ double approx_least_dominant_eigenvalue =
+ least_dominant_eigenvalue(m, v_guess, tolerance, max_iterations);
+
+ EXPECT_NEAR(expected_least_dominant_eigenvalue,
+ approx_least_dominant_eigenvalue, tolerance);
+}
+
+UTEST(eigen, dominant_eigenvalue) {
+ Matrix_double *m = InitMatrixWithSize(double, 2, 2, 0.0);
+ m->data[0]->data[0] = 2.0;
+ m->data[0]->data[1] = -12.0;
+ m->data[1]->data[0] = 1.0;
+ m->data[1]->data[1] = -5.0;
+
+ Array_double *v_guess = InitArrayWithSize(double, 2, 1.0);
+ double tolerance = 0.0001;
+ uint64_t max_iterations = 64;
+
+ double expect_dominant_eigenvalue = -2.0;
+
+ double approx_dominant_eigenvalue =
+ dominant_eigenvalue(m, v_guess, tolerance, max_iterations);
+
+ EXPECT_NEAR(expect_dominant_eigenvalue, approx_dominant_eigenvalue,
+ tolerance);
+ free_matrix(m);
+ free_vector(v_guess);
+}
+
+UTEST(eigen, shifted_eigenvalue) {
+ Matrix_double *m = eigen_test_matrix();
+
+ double least_dominant_eigenvalue = 0.87689; // 5 - sqrt{17}
+ double dominant_eigenvalue = 9.12311; // 5 + sqrt{17}
+ double expected_middle_eigenvalue = 2.0;
+ double shift = (dominant_eigenvalue + least_dominant_eigenvalue) / 2.0;
+
+ double tolerance = 0.0001;
+ uint64_t max_iterations = 64;
+ Array_double *v_guess = InitArray(double, {0.5, 1.0, 0.75});
+
+ double approx_middle_eigenvalue = shift_inverse_power_eigenvalue(
+ m, v_guess, shift, tolerance, max_iterations);
+
+ EXPECT_NEAR(approx_middle_eigenvalue, expected_middle_eigenvalue, tolerance);
+}
+
+UTEST(eigen, partition_find_eigenvalues) {
+ Matrix_double *m = eigen_test_matrix();
+
+ double least_dominant_eigenvalue = 0.87689; // 5 - sqrt{17}
+ double dominant_eigenvalue = 9.12311; // 5 + sqrt{17}
+ double expected_middle_eigenvalue = 2.0;
+ double expected_eigenvalues[3] = {least_dominant_eigenvalue,
+ expected_middle_eigenvalue,
+ dominant_eigenvalue};
+
+ size_t partitions = 10;
+ Matrix_double *guesses = InitMatrixWithSize(double, partitions, 3, 0.0);
+ for (size_t y = 0; y < guesses->rows; y++) {
+ free_vector(guesses->data[y]);
+ guesses->data[y] = InitArray(double, {0.5, 1.0, 0.75});
+ }
+
+ double tolerance = 0.0001;
+ uint64_t max_iterations = 64;
+
+ int eigenvalues_found[3] = {false, false, false};
+ Array_double *partition_eigenvalues =
+ partition_find_eigenvalues(m, guesses, tolerance, max_iterations);
+
+ for (size_t i = 0; i < partition_eigenvalues->size; i++)
+ for (size_t eigenvalue_i = 0; eigenvalue_i < 3; eigenvalue_i++)
+ if (fabs(partition_eigenvalues->data[i] - expected_eigenvalues[i]) <=
+ tolerance)
+ eigenvalues_found[eigenvalue_i] = true;
+
+ for (size_t eigenvalue_i = 0; eigenvalue_i < 3; eigenvalue_i++)
+ EXPECT_TRUE(eigenvalues_found[eigenvalue_i]);
+}
+
+UTEST(eigen, leslie_matrix_dominant_eigenvalue) {
+ Array_double *felicity = InitArray(double, {0.0, 1.5, 0.8});
+ Array_double *survivor_ratios = InitArray(double, {0.8, 0.55});
+ Matrix_double *leslie = leslie_matrix(survivor_ratios, felicity);
+ Array_double *v_guess = InitArrayWithSize(double, 3, 2.0);
+ double tolerance = 0.0001;
+ uint64_t max_iterations = 64;
+
+ double expect_dominant_eigenvalue = 1.22005;
+
+ double approx_dominant_eigenvalue =
+ dominant_eigenvalue(leslie, v_guess, tolerance, max_iterations);
+
+ EXPECT_NEAR(expect_dominant_eigenvalue, approx_dominant_eigenvalue,
+ tolerance);
+
+ free_vector(v_guess);
+ free_vector(survivor_ratios);
+ free_vector(felicity);
+ free_matrix(leslie);
+}
+UTEST(eigen, leslie_matrix) {
+ Array_double *felicity = InitArray(double, {0.0, 1.5, 0.8});
+ Array_double *survivor_ratios = InitArray(double, {0.8, 0.55});
+
+ Matrix_double *m = InitMatrixWithSize(double, 3, 3, 0.0);
+ m->data[0]->data[0] = 0.0;
+ m->data[0]->data[1] = 1.5;
+ m->data[0]->data[2] = 0.8;
+ m->data[1]->data[0] = 0.8;
+ m->data[2]->data[1] = 0.55;
+
+ Matrix_double *leslie = leslie_matrix(survivor_ratios, felicity);
+
+ EXPECT_TRUE(matrix_equal(leslie, m));
+
+ free_matrix(leslie);
+ free_matrix(m);
+ free_vector(felicity);
+ free_vector(survivor_ratios);
+}
diff --git a/Homework/math4610/test/jacobi.t.c b/Homework/math4610/test/jacobi.t.c
new file mode 100644
index 0000000..94ed53a
--- /dev/null
+++ b/Homework/math4610/test/jacobi.t.c
@@ -0,0 +1,93 @@
+#include "lizfcm.test.h"
+#include <assert.h>
+#include <math.h>
+
+Matrix_double *generate_ddm(size_t n) {
+ Matrix_double *m = InitMatrixWithSize(double, n, n, rand_from(0.0, 1.0));
+
+ for (size_t y = 0; y < m->rows; y++) {
+ m->data[y]->data[y] += sum_v(m->data[y]);
+ }
+
+ return m;
+}
+
+UTEST(jacobi, jacobi_solve) {
+ Matrix_double *m = generate_ddm(2);
+
+ Array_double *b_1 = InitArrayWithSize(double, m->rows, 1.0);
+ Array_double *b = m_dot_v(m, b_1);
+
+ double tolerance = 0.001;
+ size_t max_iter = 400;
+ Array_double *solution = jacobi_solve(m, b, tolerance, max_iter);
+
+ 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.1);
+ }
+
+ free_matrix(m);
+ free_vector(b_1);
+ free_vector(b);
+ free_vector(solution);
+}
+
+UTEST(jacobi, gauss_siedel_solve) {
+ Matrix_double *m = generate_ddm(2);
+
+ Array_double *b_1 = InitArrayWithSize(double, m->rows, 1.0);
+ Array_double *b = m_dot_v(m, b_1);
+
+ double tolerance = 0.001;
+ size_t max_iter = 400;
+ Array_double *solution = gauss_siedel_solve(m, b, tolerance, max_iter);
+
+ 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.1);
+ }
+
+ free_matrix(m);
+ free_vector(b_1);
+ free_vector(b);
+ free_vector(solution);
+}
+
+UTEST(jacobi, leslie_solve) {
+ Array_double *felicity = InitArray(double, {0.0, 1.5, 0.8});
+ Array_double *survivor_ratios = InitArray(double, {0.8, 0.55});
+ Matrix_double *leslie = leslie_matrix(survivor_ratios, felicity);
+
+ Array_double *initial_pop = InitArray(double, {10.0, 20.0, 15.0});
+ Array_double *next = m_dot_v(leslie, initial_pop);
+
+ Matrix_double *augmented = add_column(leslie, next);
+ Matrix_double *leslie_augmented_echelon = gaussian_elimination(augmented);
+
+ Array_double *next_echelon =
+ col_v(leslie_augmented_echelon, leslie_augmented_echelon->cols - 1);
+ Matrix_double *leslie_echelon = slice_column(
+ leslie_augmented_echelon, leslie_augmented_echelon->cols - 1);
+
+ double tolerance = 0.001;
+ size_t max_iter = 400;
+ Array_double *initial_pop_guess =
+ jacobi_solve(leslie_echelon, next_echelon, tolerance, max_iter);
+
+ for (size_t y = 0; y < initial_pop->size; y++) {
+ EXPECT_NEAR(initial_pop_guess->data[y], initial_pop->data[y], 0.05);
+ }
+
+ free_matrix(leslie);
+ free_matrix(augmented);
+ free_matrix(leslie_augmented_echelon);
+ free_matrix(leslie_echelon);
+
+ free_vector(felicity);
+ free_vector(survivor_ratios);
+ free_vector(next);
+ free_vector(next_echelon);
+ free_vector(initial_pop);
+ free_vector(initial_pop_guess);
+}
diff --git a/Homework/math4610/test/lin.t.c b/Homework/math4610/test/lin.t.c
new file mode 100644
index 0000000..6ad1613
--- /dev/null
+++ b/Homework/math4610/test/lin.t.c
@@ -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);
+}
diff --git a/Homework/math4610/test/lizfcm.test.h b/Homework/math4610/test/lizfcm.test.h
new file mode 100644
index 0000000..9819d46
--- /dev/null
+++ b/Homework/math4610/test/lizfcm.test.h
@@ -0,0 +1,8 @@
+#ifndef LIZFCM_TEST_H
+#define LIZFCM_TEST_H
+
+#include "lizfcm.h"
+
+#include "utest.h"
+
+#endif // LIZFCM_TEST_H
diff --git a/Homework/math4610/test/maceps.t.c b/Homework/math4610/test/maceps.t.c
new file mode 100644
index 0000000..9c45659
--- /dev/null
+++ b/Homework/math4610/test/maceps.t.c
@@ -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);
+}
diff --git a/Homework/math4610/test/main.c b/Homework/math4610/test/main.c
new file mode 100644
index 0000000..6a92d4a
--- /dev/null
+++ b/Homework/math4610/test/main.c
@@ -0,0 +1,12 @@
+#include "lizfcm.test.h"
+#include <stdlib.h>
+#include <time.h>
+
+UTEST(basic, unit_tests) { ASSERT_TRUE(1); }
+
+UTEST_STATE();
+int main(int argc, const char *const argv[]) {
+ srand(time(NULL));
+
+ return utest_main(argc, argv);
+}
diff --git a/Homework/math4610/test/matrix.t.c b/Homework/math4610/test/matrix.t.c
new file mode 100644
index 0000000..597d6e0
--- /dev/null
+++ b/Homework/math4610/test/matrix.t.c
@@ -0,0 +1,247 @@
+#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, 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);
+
+ 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, 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, 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;
+ }
+
+ 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_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 ? 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_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);
+ EXPECT_NEAR(b->data[y], dot, 0.0001);
+ }
+
+ free_matrix(m);
+ free_vector(b);
+ free_vector(b_1);
+ free_vector(solution);
+}
+
+UTEST(matrix, col_v) {
+ Matrix_double *m = InitMatrixWithSize(double, 2, 3, 0.0);
+ // set element to its column index
+ for (size_t y = 0; y < m->rows; y++) {
+ for (size_t x = 0; x < m->cols; x++) {
+ m->data[y]->data[x] = x;
+ }
+ }
+
+ Array_double *col, *expected;
+ for (size_t x = 0; x < m->cols; x++) {
+ col = col_v(m, x);
+ expected = InitArrayWithSize(double, m->rows, (double)x);
+ EXPECT_TRUE(vector_equal(expected, col));
+ free_vector(col);
+ free_vector(expected);
+ }
+
+ free_matrix(m);
+}
+
+UTEST(matrix, m_dot_m) {
+ Matrix_double *a = InitMatrixWithSize(double, 1, 3, 12.0);
+ Matrix_double *b = InitMatrixWithSize(double, 3, 1, 10.0);
+
+ Matrix_double *prod = m_dot_m(a, b);
+
+ EXPECT_EQ(prod->cols, 1);
+ EXPECT_EQ(prod->rows, 1);
+ EXPECT_EQ(12.0 * 10.0 * 3, prod->data[0]->data[0]);
+
+ free_matrix(a);
+ free_matrix(b);
+ free_matrix(prod);
+}
+
+UTEST(matrix, transpose) {
+ Matrix_double *a = InitMatrixWithSize(double, 1, 3, 12.0);
+ a->data[0]->data[1] = 13.0;
+ Matrix_double *b = InitMatrixWithSize(double, 3, 1, 12.0);
+ b->data[1]->data[0] = 13.0;
+
+ Matrix_double *a_t = transpose(a);
+
+ EXPECT_TRUE(matrix_equal(a_t, b));
+
+ free_matrix(a_t);
+ free_matrix(a);
+ free_matrix(b);
+}
diff --git a/Homework/math4610/test/rand.t.c b/Homework/math4610/test/rand.t.c
new file mode 100644
index 0000000..9ed2e9c
--- /dev/null
+++ b/Homework/math4610/test/rand.t.c
@@ -0,0 +1,10 @@
+#include "lizfcm.test.h"
+
+UTEST(rand, rand_from) {
+ double min = -2.0;
+ double max = 5.0;
+ for (size_t i = 0; i < 1000; i++) {
+ double r = rand_from(min, max);
+ ASSERT_TRUE(min <= r && r <= max);
+ }
+}
diff --git a/Homework/math4610/test/roots.t.c b/Homework/math4610/test/roots.t.c
new file mode 100644
index 0000000..c20f22e
--- /dev/null
+++ b/Homework/math4610/test/roots.t.c
@@ -0,0 +1,114 @@
+#include "lizfcm.test.h"
+#include <math.h>
+#include <stdio.h>
+
+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) {
+ Array_double *range = find_ivt_range(&f1, -10.0, 0.10, 200);
+ EXPECT_LT(f1(range->data[0]) * f1(range->data[1]), 0);
+
+ free_vector(range);
+}
+
+UTEST(root, bisection_with_error_assumption) {
+ Array_double *range = find_ivt_range(&f2, 2.5, 0.10, 200);
+
+ 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);
+}
diff --git a/Homework/math4610/test/utest.h b/Homework/math4610/test/utest.h
new file mode 100644
index 0000000..8767600
--- /dev/null
+++ b/Homework/math4610/test/utest.h
@@ -0,0 +1,1668 @@
+/*
+ The latest version of this library is available on GitHub;
+ https://github.com/sheredom/utest.h
+*/
+
+/*
+ This is free and unencumbered software released into the public domain.
+
+ Anyone is free to copy, modify, publish, use, compile, sell, or
+ distribute this software, either in source code form or as a compiled
+ binary, for any purpose, commercial or non-commercial, and by any
+ means.
+
+ In jurisdictions that recognize copyright laws, the author or authors
+ of this software dedicate any and all copyright interest in the
+ software to the public domain. We make this dedication for the benefit
+ of the public at large and to the detriment of our heirs and
+ successors. We intend this dedication to be an overt act of
+ relinquishment in perpetuity of all present and future rights to this
+ software under copyright law.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+
+ For more information, please refer to <http://unlicense.org/>
+*/
+
+#ifndef SHEREDOM_UTEST_H_INCLUDED
+#define SHEREDOM_UTEST_H_INCLUDED
+
+#ifdef _MSC_VER
+/*
+ Disable warning about not inlining 'inline' functions.
+*/
+#pragma warning(disable : 4710)
+
+/*
+ Disable warning about inlining functions that are not marked 'inline'.
+*/
+#pragma warning(disable : 4711)
+
+/*
+ Disable warning for alignment padding added
+*/
+#pragma warning(disable : 4820)
+
+#if _MSC_VER > 1900
+/*
+ Disable warning about preprocessor macros not being defined in MSVC headers.
+*/
+#pragma warning(disable : 4668)
+
+/*
+ Disable warning about no function prototype given in MSVC headers.
+*/
+#pragma warning(disable : 4255)
+
+/*
+ Disable warning about pointer or reference to potentially throwing function.
+*/
+#pragma warning(disable : 5039)
+
+/*
+ Disable warning about macro expansion producing 'defined' has undefined
+ behavior.
+*/
+#pragma warning(disable : 5105)
+#endif
+
+#if _MSC_VER > 1930
+/*
+ Disable warning about 'const' variable is not used.
+*/
+#pragma warning(disable : 5264)
+#endif
+
+#pragma warning(push, 1)
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER < 1920)
+typedef __int64 utest_int64_t;
+typedef unsigned __int64 utest_uint64_t;
+typedef unsigned __int32 utest_uint32_t;
+#else
+#include <stdint.h>
+typedef int64_t utest_int64_t;
+typedef uint64_t utest_uint64_t;
+typedef uint32_t utest_uint32_t;
+#endif
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#if defined(__cplusplus)
+#if defined(_MSC_VER) && !defined(_CPPUNWIND)
+/* We're on MSVC and the compiler is compiling without exception support! */
+#elif !defined(_MSC_VER) && !defined(__EXCEPTIONS)
+/* We're on a GCC/Clang compiler that doesn't have exception support! */
+#else
+#define UTEST_HAS_EXCEPTIONS 1
+#endif
+#endif
+
+#if defined(UTEST_HAS_EXCEPTIONS)
+#include <stdexcept>
+#endif
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+#if defined(__cplusplus)
+#define UTEST_C_FUNC extern "C"
+#else
+#define UTEST_C_FUNC
+#endif
+
+#define UTEST_TEST_PASSED (0)
+#define UTEST_TEST_FAILURE (1)
+#define UTEST_TEST_SKIPPED (2)
+
+#if defined(__TINYC__)
+#define UTEST_ATTRIBUTE(a) __attribute((a))
+#else
+#define UTEST_ATTRIBUTE(a) __attribute__((a))
+#endif
+
+#if defined(_MSC_VER) || defined(__MINGW64__) || defined(__MINGW32__)
+
+#if defined(__MINGW64__) || defined(__MINGW32__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpragmas"
+#pragma GCC diagnostic ignored "-Wunknown-pragmas"
+#endif
+
+#if defined(_WINDOWS_) || defined(_WINDOWS_H)
+typedef LARGE_INTEGER utest_large_integer;
+#else
+// use old QueryPerformanceCounter definitions (not sure is this needed in some
+// edge cases or not) on Win7 with VS2015 these extern declaration cause "second
+// C linkage of overloaded function not allowed" error
+typedef union {
+ struct {
+ unsigned long LowPart;
+ long HighPart;
+ } DUMMYSTRUCTNAME;
+ struct {
+ unsigned long LowPart;
+ long HighPart;
+ } u;
+ utest_int64_t QuadPart;
+} utest_large_integer;
+
+UTEST_C_FUNC __declspec(dllimport) int __stdcall QueryPerformanceCounter(
+ utest_large_integer *);
+UTEST_C_FUNC __declspec(dllimport) int __stdcall QueryPerformanceFrequency(
+ utest_large_integer *);
+
+#if defined(__MINGW64__) || defined(__MINGW32__)
+#pragma GCC diagnostic pop
+#endif
+#endif
+
+#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
+ defined(__NetBSD__) || defined(__DragonFly__) || defined(__sun__) || \
+ defined(__HAIKU__)
+/*
+ slightly obscure include here - we need to include glibc's features.h, but
+ we don't want to just include a header that might not be defined for other
+ c libraries like musl. Instead we include limits.h, which we know on all
+ glibc distributions includes features.h
+*/
+#include <limits.h>
+
+#if defined(__GLIBC__) && defined(__GLIBC_MINOR__)
+#include <time.h>
+
+#if ((2 < __GLIBC__) || ((2 == __GLIBC__) && (17 <= __GLIBC_MINOR__)))
+/* glibc is version 2.17 or above, so we can just use clock_gettime */
+#define UTEST_USE_CLOCKGETTIME
+#else
+#include <sys/syscall.h>
+#include <unistd.h>
+#endif
+#else // Other libc implementations
+#include <time.h>
+#define UTEST_USE_CLOCKGETTIME
+#endif
+
+#elif defined(__APPLE__)
+#include <time.h>
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER < 1920)
+#define UTEST_PRId64 "I64d"
+#define UTEST_PRIu64 "I64u"
+#else
+#include <inttypes.h>
+
+#define UTEST_PRId64 PRId64
+#define UTEST_PRIu64 PRIu64
+#endif
+
+#if defined(__cplusplus)
+#define UTEST_INLINE inline
+
+#if defined(__clang__)
+#define UTEST_INITIALIZER_BEGIN_DISABLE_WARNINGS \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Wglobal-constructors\"")
+
+#define UTEST_INITIALIZER_END_DISABLE_WARNINGS _Pragma("clang diagnostic pop")
+#else
+#define UTEST_INITIALIZER_BEGIN_DISABLE_WARNINGS
+#define UTEST_INITIALIZER_END_DISABLE_WARNINGS
+#endif
+
+#define UTEST_INITIALIZER(f) \
+ struct f##_cpp_struct { \
+ f##_cpp_struct(); \
+ }; \
+ UTEST_INITIALIZER_BEGIN_DISABLE_WARNINGS static f##_cpp_struct \
+ f##_cpp_global UTEST_INITIALIZER_END_DISABLE_WARNINGS; \
+ f##_cpp_struct::f##_cpp_struct()
+#elif defined(_MSC_VER)
+#define UTEST_INLINE __forceinline
+
+#if defined(_WIN64)
+#define UTEST_SYMBOL_PREFIX
+#else
+#define UTEST_SYMBOL_PREFIX "_"
+#endif
+
+#if defined(__clang__)
+#define UTEST_INITIALIZER_BEGIN_DISABLE_WARNINGS \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Wmissing-variable-declarations\"")
+
+#define UTEST_INITIALIZER_END_DISABLE_WARNINGS _Pragma("clang diagnostic pop")
+#else
+#define UTEST_INITIALIZER_BEGIN_DISABLE_WARNINGS
+#define UTEST_INITIALIZER_END_DISABLE_WARNINGS
+#endif
+
+#pragma section(".CRT$XCU", read)
+#define UTEST_INITIALIZER(f) \
+ static void __cdecl f(void); \
+ UTEST_INITIALIZER_BEGIN_DISABLE_WARNINGS \
+ __pragma(comment(linker, "/include:" UTEST_SYMBOL_PREFIX #f "_")) \
+ UTEST_C_FUNC __declspec(allocate(".CRT$XCU")) void(__cdecl * \
+ f##_)(void) = f; \
+ UTEST_INITIALIZER_END_DISABLE_WARNINGS \
+ static void __cdecl f(void)
+#else
+#if defined(__linux__)
+#if defined(__clang__)
+#if __has_warning("-Wreserved-id-macro")
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wreserved-id-macro"
+#endif
+#endif
+
+#define __STDC_FORMAT_MACROS 1
+
+#if defined(__clang__)
+#if __has_warning("-Wreserved-id-macro")
+#pragma clang diagnostic pop
+#endif
+#endif
+#endif
+
+#define UTEST_INLINE inline
+
+#define UTEST_INITIALIZER(f) \
+ static void f(void) UTEST_ATTRIBUTE(constructor); \
+ static void f(void)
+#endif
+
+#if defined(__cplusplus)
+#define UTEST_CAST(type, x) static_cast<type>(x)
+#define UTEST_PTR_CAST(type, x) reinterpret_cast<type>(x)
+#define UTEST_EXTERN extern "C"
+#define UTEST_NULL NULL
+#else
+#define UTEST_CAST(type, x) ((type)(x))
+#define UTEST_PTR_CAST(type, x) ((type)(x))
+#define UTEST_EXTERN extern
+#define UTEST_NULL 0
+#endif
+
+#ifdef _MSC_VER
+/*
+ io.h contains definitions for some structures with natural padding. This is
+ uninteresting, but for some reason MSVC's behaviour is to warn about
+ including this system header. That *is* interesting
+*/
+#pragma warning(disable : 4820)
+#pragma warning(push, 1)
+#include <io.h>
+#pragma warning(pop)
+#define UTEST_COLOUR_OUTPUT() (_isatty(_fileno(stdout)))
+#else
+#if defined(__EMSCRIPTEN__)
+#include <emscripten/html5.h>
+#define UTEST_COLOUR_OUTPUT() false
+#else
+#include <unistd.h>
+#define UTEST_COLOUR_OUTPUT() (isatty(STDOUT_FILENO))
+#endif
+#endif
+
+static UTEST_INLINE void *utest_realloc(void *const pointer, size_t new_size) {
+ void *const new_pointer = realloc(pointer, new_size);
+
+ if (UTEST_NULL == new_pointer) {
+ free(new_pointer);
+ }
+
+ return new_pointer;
+}
+
+static UTEST_INLINE utest_int64_t utest_ns(void) {
+#if defined(_MSC_VER) || defined(__MINGW64__) || defined(__MINGW32__)
+ utest_large_integer counter;
+ utest_large_integer frequency;
+ QueryPerformanceCounter(&counter);
+ QueryPerformanceFrequency(&frequency);
+ return UTEST_CAST(utest_int64_t,
+ (counter.QuadPart * 1000000000) / frequency.QuadPart);
+#elif defined(__linux__) && defined(__STRICT_ANSI__)
+ return UTEST_CAST(utest_int64_t, clock()) * 1000000000 / CLOCKS_PER_SEC;
+#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
+ defined(__NetBSD__) || defined(__DragonFly__) || defined(__sun__) || \
+ defined(__HAIKU__)
+ struct timespec ts;
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \
+ !defined(__HAIKU__)
+ timespec_get(&ts, TIME_UTC);
+#else
+ const clockid_t cid = CLOCK_REALTIME;
+#if defined(UTEST_USE_CLOCKGETTIME)
+ clock_gettime(cid, &ts);
+#else
+ syscall(SYS_clock_gettime, cid, &ts);
+#endif
+#endif
+ return UTEST_CAST(utest_int64_t, ts.tv_sec) * 1000 * 1000 * 1000 + ts.tv_nsec;
+#elif __APPLE__
+ return UTEST_CAST(utest_int64_t, clock_gettime_nsec_np(CLOCK_UPTIME_RAW));
+#elif __EMSCRIPTEN__
+ return emscripten_performance_now() * 1000000.0;
+#else
+#error Unsupported platform!
+#endif
+}
+
+typedef void (*utest_testcase_t)(int *, size_t);
+
+struct utest_test_state_s {
+ utest_testcase_t func;
+ size_t index;
+ char *name;
+};
+
+struct utest_state_s {
+ struct utest_test_state_s *tests;
+ size_t tests_length;
+ FILE *output;
+};
+
+/* extern to the global state utest needs to execute */
+UTEST_EXTERN struct utest_state_s utest_state;
+
+#if defined(_MSC_VER)
+#define UTEST_WEAK __forceinline
+#elif defined(__MINGW32__) || defined(__MINGW64__)
+#define UTEST_WEAK static UTEST_ATTRIBUTE(used)
+#elif defined(__clang__) || defined(__GNUC__) || defined(__TINYC__)
+#define UTEST_WEAK UTEST_ATTRIBUTE(weak)
+#else
+#error Non clang, non gcc, non MSVC, non tcc compiler found!
+#endif
+
+#if defined(_MSC_VER)
+#define UTEST_UNUSED
+#else
+#define UTEST_UNUSED UTEST_ATTRIBUTE(unused)
+#endif
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wvariadic-macros"
+#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
+#endif
+#define UTEST_PRINTF(...) \
+ if (utest_state.output) { \
+ fprintf(utest_state.output, __VA_ARGS__); \
+ } \
+ printf(__VA_ARGS__)
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wvariadic-macros"
+#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
+#endif
+
+#ifdef _MSC_VER
+#define UTEST_SNPRINTF(BUFFER, N, ...) _snprintf_s(BUFFER, N, N, __VA_ARGS__)
+#else
+#define UTEST_SNPRINTF(...) snprintf(__VA_ARGS__)
+#endif
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#if defined(__cplusplus)
+/* if we are using c++ we can use overloaded methods (its in the language) */
+#define UTEST_OVERLOADABLE
+#elif defined(__clang__)
+/* otherwise, if we are using clang with c - use the overloadable attribute */
+#define UTEST_OVERLOADABLE UTEST_ATTRIBUTE(overloadable)
+#endif
+
+#if defined(__cplusplus) && (__cplusplus >= 201103L)
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
+#endif
+
+#include <type_traits>
+
+template <typename T, bool is_enum = std::is_enum<T>::value>
+struct utest_type_deducer final {
+ static void _(const T t);
+};
+
+template <> struct utest_type_deducer<signed char, false> {
+ static void _(const signed char c) {
+ UTEST_PRINTF("%d", static_cast<int>(c));
+ }
+};
+
+template <> struct utest_type_deducer<unsigned char, false> {
+ static void _(const unsigned char c) {
+ UTEST_PRINTF("%u", static_cast<unsigned int>(c));
+ }
+};
+
+template <> struct utest_type_deducer<short, false> {
+ static void _(const short s) { UTEST_PRINTF("%d", static_cast<int>(s)); }
+};
+
+template <> struct utest_type_deducer<unsigned short, false> {
+ static void _(const unsigned short s) {
+ UTEST_PRINTF("%u", static_cast<int>(s));
+ }
+};
+
+template <> struct utest_type_deducer<float, false> {
+ static void _(const float f) { UTEST_PRINTF("%f", static_cast<double>(f)); }
+};
+
+template <> struct utest_type_deducer<double, false> {
+ static void _(const double d) { UTEST_PRINTF("%f", d); }
+};
+
+template <> struct utest_type_deducer<long double, false> {
+ static void _(const long double d) {
+#if defined(__MINGW32__) || defined(__MINGW64__)
+ /* MINGW is weird - doesn't like LF at all?! */
+ UTEST_PRINTF("%f", (double)d);
+#else
+ UTEST_PRINTF("%Lf", d);
+#endif
+ }
+};
+
+template <> struct utest_type_deducer<int, false> {
+ static void _(const int i) { UTEST_PRINTF("%d", i); }
+};
+
+template <> struct utest_type_deducer<unsigned int, false> {
+ static void _(const unsigned int i) { UTEST_PRINTF("%u", i); }
+};
+
+template <> struct utest_type_deducer<long, false> {
+ static void _(const long i) { UTEST_PRINTF("%ld", i); }
+};
+
+template <> struct utest_type_deducer<unsigned long, false> {
+ static void _(const unsigned long i) { UTEST_PRINTF("%lu", i); }
+};
+
+template <> struct utest_type_deducer<long long, false> {
+ static void _(const long long i) { UTEST_PRINTF("%lld", i); }
+};
+
+template <> struct utest_type_deducer<unsigned long long, false> {
+ static void _(const unsigned long long i) { UTEST_PRINTF("%llu", i); }
+};
+
+template <typename T> struct utest_type_deducer<const T *, false> {
+ static void _(const T *t) {
+ UTEST_PRINTF("%p", static_cast<void *>(const_cast<T *>(t)));
+ }
+};
+
+template <typename T> struct utest_type_deducer<T *, false> {
+ static void _(T *t) { UTEST_PRINTF("%p", static_cast<void *>(t)); }
+};
+
+template <typename T> struct utest_type_deducer<T, true> {
+ static void _(const T t) {
+ UTEST_PRINTF("%llu", static_cast<unsigned long long>(t));
+ }
+};
+
+template <typename T>
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(const T t) {
+ utest_type_deducer<T>::_(t);
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#elif defined(UTEST_OVERLOADABLE)
+
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(signed char c);
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(signed char c) {
+ UTEST_PRINTF("%d", UTEST_CAST(int, c));
+}
+
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(unsigned char c);
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(unsigned char c) {
+ UTEST_PRINTF("%u", UTEST_CAST(unsigned int, c));
+}
+
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(float f);
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(float f) {
+ UTEST_PRINTF("%f", UTEST_CAST(double, f));
+}
+
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(double d);
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(double d) {
+ UTEST_PRINTF("%f", d);
+}
+
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long double d);
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long double d) {
+#if defined(__MINGW32__) || defined(__MINGW64__)
+ /* MINGW is weird - doesn't like LF at all?! */
+ UTEST_PRINTF("%f", (double)d);
+#else
+ UTEST_PRINTF("%Lf", d);
+#endif
+}
+
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(int i);
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(int i) {
+ UTEST_PRINTF("%d", i);
+}
+
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(unsigned int i);
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(unsigned int i) {
+ UTEST_PRINTF("%u", i);
+}
+
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long int i);
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long int i) {
+ UTEST_PRINTF("%ld", i);
+}
+
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long unsigned int i);
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long unsigned int i) {
+ UTEST_PRINTF("%lu", i);
+}
+
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(const void *p);
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(const void *p) {
+ UTEST_PRINTF("%p", p);
+}
+
+/*
+ long long is a c++11 extension
+*/
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) || \
+ defined(__cplusplus) && (__cplusplus >= 201103L) || \
+ (defined(__MINGW32__) || defined(__MINGW64__))
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
+#endif
+
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long long int i);
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long long int i) {
+ UTEST_PRINTF("%lld", i);
+}
+
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long long unsigned int i);
+UTEST_WEAK UTEST_OVERLOADABLE void
+utest_type_printer(long long unsigned int i) {
+ UTEST_PRINTF("%llu", i);
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#endif
+#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \
+ !(defined(__MINGW32__) || defined(__MINGW64__)) || \
+ defined(__TINYC__)
+#define utest_type_printer(val) \
+ UTEST_PRINTF(_Generic((val), signed char \
+ : "%d", unsigned char \
+ : "%u", short \
+ : "%d", unsigned short \
+ : "%u", int \
+ : "%d", long \
+ : "%ld", long long \
+ : "%lld", unsigned \
+ : "%u", unsigned long \
+ : "%lu", unsigned long long \
+ : "%llu", float \
+ : "%f", double \
+ : "%f", long double \
+ : "%Lf", default \
+ : _Generic((val - val), ptrdiff_t \
+ : "%p", default \
+ : "undef")), \
+ (val))
+#else
+/*
+ we don't have the ability to print the values we got, so we create a macro
+ to tell our users we can't do anything fancy
+*/
+#define utest_type_printer(...) UTEST_PRINTF("undef")
+#endif
+
+#if defined(_MSC_VER)
+#define UTEST_SURPRESS_WARNING_BEGIN \
+ __pragma(warning(push)) __pragma(warning(disable : 4127)) \
+ __pragma(warning(disable : 4571)) __pragma(warning(disable : 4130))
+#define UTEST_SURPRESS_WARNING_END __pragma(warning(pop))
+#else
+#define UTEST_SURPRESS_WARNING_BEGIN
+#define UTEST_SURPRESS_WARNING_END
+#endif
+
+#if defined(__cplusplus) && (__cplusplus >= 201103L)
+#define UTEST_AUTO(x) auto
+#elif !defined(__cplusplus)
+
+#if defined(__clang__)
+/* clang-format off */
+/* had to disable clang-format here because it malforms the pragmas */
+#define UTEST_AUTO(x) \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Wgnu-auto-type\"") __auto_type \
+ _Pragma("clang diagnostic pop")
+/* clang-format on */
+#else
+#define UTEST_AUTO(x) __typeof__(x + 0)
+#endif
+
+#else
+#define UTEST_AUTO(x) typeof(x + 0)
+#endif
+
+#if defined(__clang__)
+#define UTEST_STRNCMP(x, y, size) \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Wdisabled-macro-expansion\"") \
+ strncmp(x, y, size) _Pragma("clang diagnostic pop")
+#else
+#define UTEST_STRNCMP(x, y, size) strncmp(x, y, size)
+#endif
+
+#if defined(_MSC_VER)
+#define UTEST_STRNCPY(x, y, size) strcpy_s(x, size, y)
+#elif !defined(__clang__) && defined(__GNUC__)
+static UTEST_INLINE char *
+utest_strncpy_gcc(char *const dst, const char *const src, const size_t size) {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstringop-overflow"
+ return strncpy(dst, src, size);
+#pragma GCC diagnostic pop
+}
+
+#define UTEST_STRNCPY(x, y, size) utest_strncpy_gcc(x, y, size)
+#else
+#define UTEST_STRNCPY(x, y, size) strncpy(x, y, size)
+#endif
+
+#define UTEST_SKIP(msg) \
+ do { \
+ UTEST_PRINTF(" Skipped : '%s'\n", (msg)); \
+ *utest_result = UTEST_TEST_SKIPPED; \
+ return; \
+ } while (0)
+
+#if defined(__clang__)
+#define UTEST_COND(x, y, cond, msg, is_assert) \
+ UTEST_SURPRESS_WARNING_BEGIN do { \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Wlanguage-extension-token\"") \
+ _Pragma("clang diagnostic ignored \"-Wc++98-compat-pedantic\"") \
+ _Pragma("clang diagnostic ignored \"-Wfloat-equal\"") \
+ UTEST_AUTO(x) xEval = (x); \
+ UTEST_AUTO(y) yEval = (y); \
+ if (!((xEval)cond(yEval))) { \
+ _Pragma("clang diagnostic pop") \
+ UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \
+ UTEST_PRINTF(" Expected : ("); \
+ UTEST_PRINTF(#x ") " #cond " (" #y); \
+ UTEST_PRINTF(")\n"); \
+ UTEST_PRINTF(" Actual : "); \
+ utest_type_printer(xEval); \
+ UTEST_PRINTF(" vs "); \
+ utest_type_printer(yEval); \
+ UTEST_PRINTF("\n"); \
+ if (strlen(msg) > 0) { \
+ UTEST_PRINTF(" Message : %s\n", msg); \
+ } \
+ *utest_result = UTEST_TEST_FAILURE; \
+ if (is_assert) { \
+ return; \
+ } \
+ } \
+ } \
+ while (0) \
+ UTEST_SURPRESS_WARNING_END
+#elif defined(__GNUC__) || defined(__TINYC__)
+#define UTEST_COND(x, y, cond, msg, is_assert) \
+ UTEST_SURPRESS_WARNING_BEGIN do { \
+ UTEST_AUTO(x) xEval = (x); \
+ UTEST_AUTO(y) yEval = (y); \
+ if (!((xEval)cond(yEval))) { \
+ UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \
+ UTEST_PRINTF(" Expected : ("); \
+ UTEST_PRINTF(#x ") " #cond " (" #y); \
+ UTEST_PRINTF(")\n"); \
+ UTEST_PRINTF(" Actual : "); \
+ utest_type_printer(xEval); \
+ UTEST_PRINTF(" vs "); \
+ utest_type_printer(yEval); \
+ UTEST_PRINTF("\n"); \
+ if (strlen(msg) > 0) { \
+ UTEST_PRINTF(" Message : %s\n", msg); \
+ } \
+ *utest_result = UTEST_TEST_FAILURE; \
+ if (is_assert) { \
+ return; \
+ } \
+ } \
+ } \
+ while (0) \
+ UTEST_SURPRESS_WARNING_END
+#else
+#define UTEST_COND(x, y, cond, msg, is_assert) \
+ UTEST_SURPRESS_WARNING_BEGIN do { \
+ if (!((x)cond(y))) { \
+ UTEST_PRINTF("%s:%i: Failure (Expected " #cond " Actual)", __FILE__, \
+ __LINE__); \
+ if (strlen(msg) > 0) { \
+ UTEST_PRINTF(" Message : %s", msg); \
+ } \
+ UTEST_PRINTF("\n"); \
+ *utest_result = UTEST_TEST_FAILURE; \
+ if (is_assert) { \
+ return; \
+ } \
+ } \
+ } \
+ while (0) \
+ UTEST_SURPRESS_WARNING_END
+#endif
+
+#define EXPECT_EQ(x, y) UTEST_COND(x, y, ==, "", 0)
+#define EXPECT_EQ_MSG(x, y, msg) UTEST_COND(x, y, ==, msg, 0)
+#define ASSERT_EQ(x, y) UTEST_COND(x, y, ==, "", 1)
+#define ASSERT_EQ_MSG(x, y, msg) UTEST_COND(x, y, ==, msg, 1)
+
+#define EXPECT_NE(x, y) UTEST_COND(x, y, !=, "", 0)
+#define EXPECT_NE_MSG(x, y, msg) UTEST_COND(x, y, !=, msg, 0)
+#define ASSERT_NE(x, y) UTEST_COND(x, y, !=, "", 1)
+#define ASSERT_NE_MSG(x, y, msg) UTEST_COND(x, y, !=, msg, 1)
+
+#define EXPECT_LT(x, y) UTEST_COND(x, y, <, "", 0)
+#define EXPECT_LT_MSG(x, y, msg) UTEST_COND(x, y, <, msg, 0)
+#define ASSERT_LT(x, y) UTEST_COND(x, y, <, "", 1)
+#define ASSERT_LT_MSG(x, y, msg) UTEST_COND(x, y, <, msg, 1)
+
+#define EXPECT_LE(x, y) UTEST_COND(x, y, <=, "", 0)
+#define EXPECT_LE_MSG(x, y, msg) UTEST_COND(x, y, <=, msg, 0)
+#define ASSERT_LE(x, y) UTEST_COND(x, y, <=, "", 1)
+#define ASSERT_LE_MSG(x, y, msg) UTEST_COND(x, y, <=, msg, 1)
+
+#define EXPECT_GT(x, y) UTEST_COND(x, y, >, "", 0)
+#define EXPECT_GT_MSG(x, y, msg) UTEST_COND(x, y, >, msg, 0)
+#define ASSERT_GT(x, y) UTEST_COND(x, y, >, "", 1)
+#define ASSERT_GT_MSG(x, y, msg) UTEST_COND(x, y, >, msg, 1)
+
+#define EXPECT_GE(x, y) UTEST_COND(x, y, >=, "", 0)
+#define EXPECT_GE_MSG(x, y, msg) UTEST_COND(x, y, >=, msg, 0)
+#define ASSERT_GE(x, y) UTEST_COND(x, y, >=, "", 1)
+#define ASSERT_GE_MSG(x, y, msg) UTEST_COND(x, y, >=, msg, 1)
+
+#define UTEST_TRUE(x, msg, is_assert) \
+ UTEST_SURPRESS_WARNING_BEGIN do { \
+ const int xEval = !!(x); \
+ if (!(xEval)) { \
+ UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \
+ UTEST_PRINTF(" Expected : true\n"); \
+ UTEST_PRINTF(" Actual : %s\n", (xEval) ? "true" : "false"); \
+ if (strlen(msg) > 0) { \
+ UTEST_PRINTF(" Message : %s\n", msg); \
+ } \
+ *utest_result = UTEST_TEST_FAILURE; \
+ if (is_assert) { \
+ return; \
+ } \
+ } \
+ } \
+ while (0) \
+ UTEST_SURPRESS_WARNING_END
+
+#define EXPECT_TRUE(x) UTEST_TRUE(x, "", 0)
+#define EXPECT_TRUE_MSG(x, msg) UTEST_TRUE(x, msg, 0)
+#define ASSERT_TRUE(x) UTEST_TRUE(x, "", 1)
+#define ASSERT_TRUE_MSG(x, msg) UTEST_TRUE(x, msg, 1)
+
+#define UTEST_FALSE(x, msg, is_assert) \
+ UTEST_SURPRESS_WARNING_BEGIN do { \
+ const int xEval = !!(x); \
+ if (xEval) { \
+ UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \
+ UTEST_PRINTF(" Expected : false\n"); \
+ UTEST_PRINTF(" Actual : %s\n", (xEval) ? "true" : "false"); \
+ if (strlen(msg) > 0) { \
+ UTEST_PRINTF(" Message : %s\n", msg); \
+ } \
+ *utest_result = UTEST_TEST_FAILURE; \
+ if (is_assert) { \
+ return; \
+ } \
+ } \
+ } \
+ while (0) \
+ UTEST_SURPRESS_WARNING_END
+
+#define EXPECT_FALSE(x) UTEST_FALSE(x, "", 0)
+#define EXPECT_FALSE_MSG(x, msg) UTEST_FALSE(x, msg, 0)
+#define ASSERT_FALSE(x) UTEST_FALSE(x, "", 1)
+#define ASSERT_FALSE_MSG(x, msg) UTEST_FALSE(x, msg, 1)
+
+#define UTEST_STREQ(x, y, msg, is_assert) \
+ UTEST_SURPRESS_WARNING_BEGIN do { \
+ const char *xEval = (x); \
+ const char *yEval = (y); \
+ if (UTEST_NULL == xEval || UTEST_NULL == yEval || \
+ 0 != strcmp(xEval, yEval)) { \
+ UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \
+ UTEST_PRINTF(" Expected : \"%s\"\n", xEval); \
+ UTEST_PRINTF(" Actual : \"%s\"\n", yEval); \
+ if (strlen(msg) > 0) { \
+ UTEST_PRINTF(" Message : %s\n", msg); \
+ } \
+ *utest_result = UTEST_TEST_FAILURE; \
+ if (is_assert) { \
+ return; \
+ } \
+ } \
+ } \
+ while (0) \
+ UTEST_SURPRESS_WARNING_END
+
+#define EXPECT_STREQ(x, y) UTEST_STREQ(x, y, "", 0)
+#define EXPECT_STREQ_MSG(x, y, msg) UTEST_STREQ(x, y, msg, 0)
+#define ASSERT_STREQ(x, y) UTEST_STREQ(x, y, "", 1)
+#define ASSERT_STREQ_MSG(x, y, msg) UTEST_STREQ(x, y, msg, 1)
+
+#define UTEST_STRNE(x, y, msg, is_assert) \
+ UTEST_SURPRESS_WARNING_BEGIN do { \
+ const char *xEval = (x); \
+ const char *yEval = (y); \
+ if (UTEST_NULL == xEval || UTEST_NULL == yEval || \
+ 0 == strcmp(xEval, yEval)) { \
+ UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \
+ UTEST_PRINTF(" Expected : \"%s\"\n", xEval); \
+ UTEST_PRINTF(" Actual : \"%s\"\n", yEval); \
+ if (strlen(msg) > 0) { \
+ UTEST_PRINTF(" Message : %s\n", msg); \
+ } \
+ *utest_result = UTEST_TEST_FAILURE; \
+ if (is_assert) { \
+ return; \
+ } \
+ } \
+ } \
+ while (0) \
+ UTEST_SURPRESS_WARNING_END
+
+#define EXPECT_STRNE(x, y) UTEST_STRNE(x, y, "", 0)
+#define EXPECT_STRNE_MSG(x, y, msg) UTEST_STRNE(x, y, msg, 0)
+#define ASSERT_STRNE(x, y) UTEST_STRNE(x, y, "", 1)
+#define ASSERT_STRNE_MSG(x, y, msg) UTEST_STRNE(x, y, msg, 1)
+
+#define UTEST_STRNEQ(x, y, n, msg, is_assert) \
+ UTEST_SURPRESS_WARNING_BEGIN do { \
+ const char *xEval = (x); \
+ const char *yEval = (y); \
+ const size_t nEval = UTEST_CAST(size_t, n); \
+ if (UTEST_NULL == xEval || UTEST_NULL == yEval || \
+ 0 != UTEST_STRNCMP(xEval, yEval, nEval)) { \
+ UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \
+ UTEST_PRINTF(" Expected : \"%.*s\"\n", UTEST_CAST(int, nEval), xEval); \
+ UTEST_PRINTF(" Actual : \"%.*s\"\n", UTEST_CAST(int, nEval), yEval); \
+ if (strlen(msg) > 0) { \
+ UTEST_PRINTF(" Message : %s\n", msg); \
+ } \
+ *utest_result = UTEST_TEST_FAILURE; \
+ if (is_assert) { \
+ return; \
+ } \
+ } \
+ } \
+ while (0) \
+ UTEST_SURPRESS_WARNING_END
+
+#define EXPECT_STRNEQ(x, y, n) UTEST_STRNEQ(x, y, n, "", 0)
+#define EXPECT_STRNEQ_MSG(x, y, n, msg) UTEST_STRNEQ(x, y, n, msg, 0)
+#define ASSERT_STRNEQ(x, y, n) UTEST_STRNEQ(x, y, n, "", 1)
+#define ASSERT_STRNEQ_MSG(x, y, n, msg) UTEST_STRNEQ(x, y, n, msg, 1)
+
+#define UTEST_STRNNE(x, y, n, msg, is_assert) \
+ UTEST_SURPRESS_WARNING_BEGIN do { \
+ const char *xEval = (x); \
+ const char *yEval = (y); \
+ const size_t nEval = UTEST_CAST(size_t, n); \
+ if (UTEST_NULL == xEval || UTEST_NULL == yEval || \
+ 0 == UTEST_STRNCMP(xEval, yEval, nEval)) { \
+ UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \
+ UTEST_PRINTF(" Expected : \"%.*s\"\n", UTEST_CAST(int, nEval), xEval); \
+ UTEST_PRINTF(" Actual : \"%.*s\"\n", UTEST_CAST(int, nEval), yEval); \
+ if (strlen(msg) > 0) { \
+ UTEST_PRINTF(" Message : %s\n", msg); \
+ } \
+ *utest_result = UTEST_TEST_FAILURE; \
+ if (is_assert) { \
+ return; \
+ } \
+ } \
+ } \
+ while (0) \
+ UTEST_SURPRESS_WARNING_END
+
+#define EXPECT_STRNNE(x, y, n) UTEST_STRNNE(x, y, n, "", 0)
+#define EXPECT_STRNNE_MSG(x, y, n, msg) UTEST_STRNNE(x, y, n, msg, 0)
+#define ASSERT_STRNNE(x, y, n) UTEST_STRNNE(x, y, n, "", 1)
+#define ASSERT_STRNNE_MSG(x, y, n, msg) UTEST_STRNNE(x, y, n, msg, 1)
+
+#define UTEST_NEAR(x, y, epsilon, msg, is_assert) \
+ UTEST_SURPRESS_WARNING_BEGIN do { \
+ const double diff = \
+ utest_fabs(UTEST_CAST(double, x) - UTEST_CAST(double, y)); \
+ if (diff > UTEST_CAST(double, epsilon) || utest_isnan(diff)) { \
+ UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \
+ UTEST_PRINTF(" Expected : %f\n", UTEST_CAST(double, x)); \
+ UTEST_PRINTF(" Actual : %f\n", UTEST_CAST(double, y)); \
+ if (strlen(msg) > 0) { \
+ UTEST_PRINTF(" Message : %s\n", msg); \
+ } \
+ *utest_result = UTEST_TEST_FAILURE; \
+ if (is_assert) { \
+ return; \
+ } \
+ } \
+ } \
+ while (0) \
+ UTEST_SURPRESS_WARNING_END
+
+#define EXPECT_NEAR(x, y, epsilon) UTEST_NEAR(x, y, epsilon, "", 0)
+#define EXPECT_NEAR_MSG(x, y, epsilon, msg) UTEST_NEAR(x, y, epsilon, msg, 0)
+#define ASSERT_NEAR(x, y, epsilon) UTEST_NEAR(x, y, epsilon, "", 1)
+#define ASSERT_NEAR_MSG(x, y, epsilon, msg) UTEST_NEAR(x, y, epsilon, msg, 1)
+
+#if defined(UTEST_HAS_EXCEPTIONS)
+#define UTEST_EXCEPTION(x, exception_type, msg, is_assert) \
+ UTEST_SURPRESS_WARNING_BEGIN do { \
+ int exception_caught = 0; \
+ try { \
+ x; \
+ } catch (const exception_type &) { \
+ exception_caught = 1; \
+ } catch (...) { \
+ exception_caught = 2; \
+ } \
+ if (1 != exception_caught) { \
+ UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \
+ UTEST_PRINTF(" Expected : %s exception\n", #exception_type); \
+ UTEST_PRINTF(" Actual : %s\n", (2 == exception_caught) \
+ ? "Unexpected exception" \
+ : "No exception"); \
+ if (strlen(msg) > 0) { \
+ UTEST_PRINTF(" Message : %s\n", msg); \
+ } \
+ *utest_result = UTEST_TEST_FAILURE; \
+ if (is_assert) { \
+ return; \
+ } \
+ } \
+ } \
+ while (0) \
+ UTEST_SURPRESS_WARNING_END
+
+#define EXPECT_EXCEPTION(x, exception_type) \
+ UTEST_EXCEPTION(x, exception_type, "", 0)
+#define EXPECT_EXCEPTION_MSG(x, exception_type, msg) \
+ UTEST_EXCEPTION(x, exception_type, msg, 0)
+#define ASSERT_EXCEPTION(x, exception_type) \
+ UTEST_EXCEPTION(x, exception_type, "", 1)
+#define ASSERT_EXCEPTION_MSG(x, exception_type, msg) \
+ UTEST_EXCEPTION(x, exception_type, msg, 1)
+
+#define UTEST_EXCEPTION_WITH_MESSAGE(x, exception_type, exception_message, \
+ msg, is_assert) \
+ UTEST_SURPRESS_WARNING_BEGIN do { \
+ int exception_caught = 0; \
+ char *message_caught = UTEST_NULL; \
+ try { \
+ x; \
+ } catch (const exception_type &e) { \
+ const char *const what = e.what(); \
+ exception_caught = 1; \
+ if (0 != \
+ UTEST_STRNCMP(what, exception_message, strlen(exception_message))) { \
+ const size_t message_size = strlen(what) + 1; \
+ message_caught = UTEST_PTR_CAST(char *, malloc(message_size)); \
+ UTEST_STRNCPY(message_caught, what, message_size); \
+ } \
+ } catch (...) { \
+ exception_caught = 2; \
+ } \
+ if (1 != exception_caught) { \
+ UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \
+ UTEST_PRINTF(" Expected : %s exception\n", #exception_type); \
+ UTEST_PRINTF(" Actual : %s\n", (2 == exception_caught) \
+ ? "Unexpected exception" \
+ : "No exception"); \
+ if (strlen(msg) > 0) { \
+ UTEST_PRINTF(" Message : %s\n", msg); \
+ } \
+ *utest_result = UTEST_TEST_FAILURE; \
+ if (is_assert) { \
+ return; \
+ } \
+ } else if (UTEST_NULL != message_caught) { \
+ UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \
+ UTEST_PRINTF(" Expected : %s exception with message %s\n", \
+ #exception_type, exception_message); \
+ UTEST_PRINTF(" Actual message : %s\n", message_caught); \
+ if (strlen(msg) > 0) { \
+ UTEST_PRINTF(" Message : %s\n", msg); \
+ } \
+ *utest_result = UTEST_TEST_FAILURE; \
+ free(message_caught); \
+ if (is_assert) { \
+ return; \
+ } \
+ } \
+ } \
+ while (0) \
+ UTEST_SURPRESS_WARNING_END
+
+#define EXPECT_EXCEPTION_WITH_MESSAGE(x, exception_type, exception_message) \
+ UTEST_EXCEPTION_WITH_MESSAGE(x, exception_type, exception_message, "", 0)
+#define EXPECT_EXCEPTION_WITH_MESSAGE_MSG(x, exception_type, \
+ exception_message, msg) \
+ UTEST_EXCEPTION_WITH_MESSAGE(x, exception_type, exception_message, msg, 0)
+#define ASSERT_EXCEPTION_WITH_MESSAGE(x, exception_type, exception_message) \
+ UTEST_EXCEPTION_WITH_MESSAGE(x, exception_type, exception_message, "", 1)
+#define ASSERT_EXCEPTION_WITH_MESSAGE_MSG(x, exception_type, \
+ exception_message, msg) \
+ UTEST_EXCEPTION_WITH_MESSAGE(x, exception_type, exception_message, msg, 1)
+#endif
+
+#if defined(__clang__)
+#if __has_warning("-Wunsafe-buffer-usage")
+#define UTEST_SURPRESS_WARNINGS_BEGIN \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Wunsafe-buffer-usage\"")
+#define UTEST_SURPRESS_WARNINGS_END _Pragma("clang diagnostic pop")
+#else
+#define UTEST_SURPRESS_WARNINGS_BEGIN
+#define UTEST_SURPRESS_WARNINGS_END
+#endif
+#elif defined(__GNUC__) && __GNUC__ >= 8 && defined(__cplusplus)
+#define UTEST_SURPRESS_WARNINGS_BEGIN \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Wclass-memaccess\"")
+#define UTEST_SURPRESS_WARNINGS_END _Pragma("GCC diagnostic pop")
+#else
+#define UTEST_SURPRESS_WARNINGS_BEGIN
+#define UTEST_SURPRESS_WARNINGS_END
+#endif
+
+#define UTEST(SET, NAME) \
+ UTEST_SURPRESS_WARNINGS_BEGIN \
+ UTEST_EXTERN struct utest_state_s utest_state; \
+ static void utest_run_##SET##_##NAME(int *utest_result); \
+ static void utest_##SET##_##NAME(int *utest_result, size_t utest_index) { \
+ (void)utest_index; \
+ utest_run_##SET##_##NAME(utest_result); \
+ } \
+ UTEST_INITIALIZER(utest_register_##SET##_##NAME) { \
+ const size_t index = utest_state.tests_length++; \
+ const char *name_part = #SET "." #NAME; \
+ const size_t name_size = strlen(name_part) + 1; \
+ char *name = UTEST_PTR_CAST(char *, malloc(name_size)); \
+ utest_state.tests = UTEST_PTR_CAST( \
+ struct utest_test_state_s *, \
+ utest_realloc(UTEST_PTR_CAST(void *, utest_state.tests), \
+ sizeof(struct utest_test_state_s) * \
+ utest_state.tests_length)); \
+ if (utest_state.tests) { \
+ utest_state.tests[index].func = &utest_##SET##_##NAME; \
+ utest_state.tests[index].name = name; \
+ utest_state.tests[index].index = 0; \
+ UTEST_SNPRINTF(name, name_size, "%s", name_part); \
+ } else if (name) { \
+ free(name); \
+ } \
+ } \
+ UTEST_SURPRESS_WARNINGS_END \
+ void utest_run_##SET##_##NAME(int *utest_result)
+
+#define UTEST_F_SETUP(FIXTURE) \
+ static void utest_f_setup_##FIXTURE(int *utest_result, \
+ struct FIXTURE *utest_fixture)
+
+#define UTEST_F_TEARDOWN(FIXTURE) \
+ static void utest_f_teardown_##FIXTURE(int *utest_result, \
+ struct FIXTURE *utest_fixture)
+
+#define UTEST_F(FIXTURE, NAME) \
+ UTEST_SURPRESS_WARNINGS_BEGIN \
+ UTEST_EXTERN struct utest_state_s utest_state; \
+ static void utest_f_setup_##FIXTURE(int *, struct FIXTURE *); \
+ static void utest_f_teardown_##FIXTURE(int *, struct FIXTURE *); \
+ static void utest_run_##FIXTURE##_##NAME(int *, struct FIXTURE *); \
+ static void utest_f_##FIXTURE##_##NAME(int *utest_result, \
+ size_t utest_index) { \
+ struct FIXTURE fixture; \
+ (void)utest_index; \
+ memset(&fixture, 0, sizeof(fixture)); \
+ utest_f_setup_##FIXTURE(utest_result, &fixture); \
+ if (UTEST_TEST_PASSED != *utest_result) { \
+ return; \
+ } \
+ utest_run_##FIXTURE##_##NAME(utest_result, &fixture); \
+ utest_f_teardown_##FIXTURE(utest_result, &fixture); \
+ } \
+ UTEST_INITIALIZER(utest_register_##FIXTURE##_##NAME) { \
+ const size_t index = utest_state.tests_length++; \
+ const char *name_part = #FIXTURE "." #NAME; \
+ const size_t name_size = strlen(name_part) + 1; \
+ char *name = UTEST_PTR_CAST(char *, malloc(name_size)); \
+ utest_state.tests = UTEST_PTR_CAST( \
+ struct utest_test_state_s *, \
+ utest_realloc(UTEST_PTR_CAST(void *, utest_state.tests), \
+ sizeof(struct utest_test_state_s) * \
+ utest_state.tests_length)); \
+ if (utest_state.tests) { \
+ utest_state.tests[index].func = &utest_f_##FIXTURE##_##NAME; \
+ utest_state.tests[index].name = name; \
+ UTEST_SNPRINTF(name, name_size, "%s", name_part); \
+ } else if (name) { \
+ free(name); \
+ } \
+ } \
+ UTEST_SURPRESS_WARNINGS_END \
+ void utest_run_##FIXTURE##_##NAME(int *utest_result, \
+ struct FIXTURE *utest_fixture)
+
+#define UTEST_I_SETUP(FIXTURE) \
+ static void utest_i_setup_##FIXTURE( \
+ int *utest_result, struct FIXTURE *utest_fixture, size_t utest_index)
+
+#define UTEST_I_TEARDOWN(FIXTURE) \
+ static void utest_i_teardown_##FIXTURE( \
+ int *utest_result, struct FIXTURE *utest_fixture, size_t utest_index)
+
+#define UTEST_I(FIXTURE, NAME, INDEX) \
+ UTEST_SURPRESS_WARNINGS_BEGIN \
+ UTEST_EXTERN struct utest_state_s utest_state; \
+ static void utest_run_##FIXTURE##_##NAME##_##INDEX(int *, struct FIXTURE *); \
+ static void utest_i_##FIXTURE##_##NAME##_##INDEX(int *utest_result, \
+ size_t index) { \
+ struct FIXTURE fixture; \
+ memset(&fixture, 0, sizeof(fixture)); \
+ utest_i_setup_##FIXTURE(utest_result, &fixture, index); \
+ if (UTEST_TEST_PASSED != *utest_result) { \
+ return; \
+ } \
+ utest_run_##FIXTURE##_##NAME##_##INDEX(utest_result, &fixture); \
+ utest_i_teardown_##FIXTURE(utest_result, &fixture, index); \
+ } \
+ UTEST_INITIALIZER(utest_register_##FIXTURE##_##NAME##_##INDEX) { \
+ size_t i; \
+ utest_uint64_t iUp; \
+ for (i = 0; i < (INDEX); i++) { \
+ const size_t index = utest_state.tests_length++; \
+ const char *name_part = #FIXTURE "." #NAME; \
+ const size_t name_size = strlen(name_part) + 32; \
+ char *name = UTEST_PTR_CAST(char *, malloc(name_size)); \
+ utest_state.tests = UTEST_PTR_CAST( \
+ struct utest_test_state_s *, \
+ utest_realloc(UTEST_PTR_CAST(void *, utest_state.tests), \
+ sizeof(struct utest_test_state_s) * \
+ utest_state.tests_length)); \
+ if (utest_state.tests) { \
+ utest_state.tests[index].func = &utest_i_##FIXTURE##_##NAME##_##INDEX; \
+ utest_state.tests[index].index = i; \
+ utest_state.tests[index].name = name; \
+ iUp = UTEST_CAST(utest_uint64_t, i); \
+ UTEST_SNPRINTF(name, name_size, "%s/%" UTEST_PRIu64, name_part, iUp); \
+ } else if (name) { \
+ free(name); \
+ } \
+ } \
+ } \
+ UTEST_SURPRESS_WARNINGS_END \
+ void utest_run_##FIXTURE##_##NAME##_##INDEX(int *utest_result, \
+ struct FIXTURE *utest_fixture)
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
+#endif
+
+UTEST_WEAK
+double utest_fabs(double d);
+UTEST_WEAK
+double utest_fabs(double d) {
+ union {
+ double d;
+ utest_uint64_t u;
+ } both;
+ both.d = d;
+ both.u &= 0x7fffffffffffffffu;
+ return both.d;
+}
+
+UTEST_WEAK
+int utest_isnan(double d);
+UTEST_WEAK
+int utest_isnan(double d) {
+ union {
+ double d;
+ utest_uint64_t u;
+ } both;
+ both.d = d;
+ both.u &= 0x7fffffffffffffffu;
+ return both.u > 0x7ff0000000000000u;
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#if defined(__clang__)
+#if __has_warning("-Wunsafe-buffer-usage")
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
+#endif
+#endif
+
+UTEST_WEAK
+int utest_should_filter_test(const char *filter, const char *testcase);
+UTEST_WEAK int utest_should_filter_test(const char *filter,
+ const char *testcase) {
+ if (filter) {
+ const char *filter_cur = filter;
+ const char *testcase_cur = testcase;
+ const char *filter_wildcard = UTEST_NULL;
+
+ while (('\0' != *filter_cur) && ('\0' != *testcase_cur)) {
+ if ('*' == *filter_cur) {
+ /* store the position of the wildcard */
+ filter_wildcard = filter_cur;
+
+ /* skip the wildcard character */
+ filter_cur++;
+
+ while (('\0' != *filter_cur) && ('\0' != *testcase_cur)) {
+ if ('*' == *filter_cur) {
+ /*
+ we found another wildcard (filter is something like *foo*) so we
+ exit the current loop, and return to the parent loop to handle
+ the wildcard case
+ */
+ break;
+ } else if (*filter_cur != *testcase_cur) {
+ /* otherwise our filter didn't match, so reset it */
+ filter_cur = filter_wildcard;
+ }
+
+ /* move testcase along */
+ testcase_cur++;
+
+ /* move filter along */
+ filter_cur++;
+ }
+
+ if (('\0' == *filter_cur) && ('\0' == *testcase_cur)) {
+ return 0;
+ }
+
+ /* if the testcase has been exhausted, we don't have a match! */
+ if ('\0' == *testcase_cur) {
+ return 1;
+ }
+ } else {
+ if (*testcase_cur != *filter_cur) {
+ /* test case doesn't match filter */
+ return 1;
+ } else {
+ /* move our filter and testcase forward */
+ testcase_cur++;
+ filter_cur++;
+ }
+ }
+ }
+
+ if (('\0' != *filter_cur) ||
+ (('\0' != *testcase_cur) &&
+ ((filter == filter_cur) || ('*' != filter_cur[-1])))) {
+ /* we have a mismatch! */
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static UTEST_INLINE FILE *utest_fopen(const char *filename, const char *mode) {
+#ifdef _MSC_VER
+ FILE *file;
+ if (0 == fopen_s(&file, filename, mode)) {
+ return file;
+ } else {
+ return UTEST_NULL;
+ }
+#else
+ return fopen(filename, mode);
+#endif
+}
+
+static UTEST_INLINE int utest_main(int argc, const char *const argv[]);
+int utest_main(int argc, const char *const argv[]) {
+ utest_uint64_t failed = 0;
+ utest_uint64_t skipped = 0;
+ size_t index = 0;
+ size_t *failed_testcases = UTEST_NULL;
+ size_t failed_testcases_length = 0;
+ size_t *skipped_testcases = UTEST_NULL;
+ size_t skipped_testcases_length = 0;
+ const char *filter = UTEST_NULL;
+ utest_uint64_t ran_tests = 0;
+ int enable_mixed_units = 0;
+ int random_order = 0;
+ utest_uint32_t seed = 0;
+
+ enum colours { RESET, GREEN, RED, YELLOW };
+
+ const int use_colours = UTEST_COLOUR_OUTPUT();
+ const char *colours[] = {"\033[0m", "\033[32m", "\033[31m", "\033[33m"};
+
+ if (!use_colours) {
+ for (index = 0; index < sizeof colours / sizeof colours[0]; index++) {
+ colours[index] = "";
+ }
+ }
+ /* loop through all arguments looking for our options */
+ for (index = 1; index < UTEST_CAST(size_t, argc); index++) {
+ /* Informational switches */
+ const char help_str[] = "--help";
+ const char list_str[] = "--list-tests";
+ /* Test config switches */
+ const char filter_str[] = "--filter=";
+ const char output_str[] = "--output=";
+ const char enable_mixed_units_str[] = "--enable-mixed-units";
+ const char random_order_str[] = "--random-order";
+ const char random_order_with_seed_str[] = "--random-order=";
+
+ if (0 == UTEST_STRNCMP(argv[index], help_str, strlen(help_str))) {
+ printf("utest.h - the single file unit testing solution for C/C++!\n"
+ "Command line Options:\n"
+ " --help Show this message and exit.\n"
+ " --filter=<filter> Filter the test cases to run (EG. "
+ "MyTest*.a would run MyTestCase.a but not MyTestCase.b).\n"
+ " --list-tests List testnames, one per line. Output "
+ "names can be passed to --filter.\n");
+ printf(" --output=<output> Output an xunit XML file to the file "
+ "specified in <output>.\n"
+ " --enable-mixed-units Enable the per-test output to contain "
+ "mixed units (s/ms/us/ns).\n"
+ " --random-order[=<seed>] Randomize the order that the tests are "
+ "ran in. If the optional <seed> argument is not provided, then a "
+ "random starting seed is used.\n");
+ goto cleanup;
+ } else if (0 ==
+ UTEST_STRNCMP(argv[index], filter_str, strlen(filter_str))) {
+ /* user wants to filter what test cases run! */
+ filter = argv[index] + strlen(filter_str);
+ } else if (0 ==
+ UTEST_STRNCMP(argv[index], output_str, strlen(output_str))) {
+ utest_state.output = utest_fopen(argv[index] + strlen(output_str), "w+");
+ } else if (0 == UTEST_STRNCMP(argv[index], list_str, strlen(list_str))) {
+ for (index = 0; index < utest_state.tests_length; index++) {
+ UTEST_PRINTF("%s\n", utest_state.tests[index].name);
+ }
+ /* when printing the test list, don't actually run the tests */
+ return 0;
+ } else if (0 == UTEST_STRNCMP(argv[index], enable_mixed_units_str,
+ strlen(enable_mixed_units_str))) {
+ enable_mixed_units = 1;
+ } else if (0 == UTEST_STRNCMP(argv[index], random_order_with_seed_str,
+ strlen(random_order_with_seed_str))) {
+ seed =
+ UTEST_CAST(utest_uint32_t,
+ strtoul(argv[index] + strlen(random_order_with_seed_str),
+ UTEST_NULL, 10));
+ random_order = 1;
+ } else if (0 == UTEST_STRNCMP(argv[index], random_order_str,
+ strlen(random_order_str))) {
+ const utest_int64_t ns = utest_ns();
+
+ // Some really poor pseudo-random using the current time. I do this
+ // because I really want to avoid using C's rand() because that'd mean our
+ // random would be affected by any srand() usage by the user (which I
+ // don't want).
+ seed = UTEST_CAST(utest_uint32_t, ns >> 32) * 31 +
+ UTEST_CAST(utest_uint32_t, ns & 0xffffffff);
+ random_order = 1;
+ }
+ }
+
+ if (random_order) {
+ // Use Fisher-Yates with the Durstenfield's version to randomly re-order the
+ // tests.
+ for (index = utest_state.tests_length; index > 1; index--) {
+ // For the random order we'll use PCG.
+ const utest_uint32_t state = seed;
+ const utest_uint32_t word =
+ ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
+ const utest_uint32_t next =
+ ((word >> 22u) ^ word) % UTEST_CAST(utest_uint32_t, index);
+
+ // Swap the randomly chosen element into the last location.
+ const struct utest_test_state_s copy = utest_state.tests[index - 1];
+ utest_state.tests[index - 1] = utest_state.tests[next];
+ utest_state.tests[next] = copy;
+
+ // Move the seed onwards.
+ seed = seed * 747796405u + 2891336453u;
+ }
+ }
+
+ for (index = 0; index < utest_state.tests_length; index++) {
+ if (utest_should_filter_test(filter, utest_state.tests[index].name)) {
+ continue;
+ }
+
+ ran_tests++;
+ }
+
+ printf("%s[==========]%s Running %" UTEST_PRIu64 " test cases.\n",
+ colours[GREEN], colours[RESET], UTEST_CAST(utest_uint64_t, ran_tests));
+
+ if (utest_state.output) {
+ fprintf(utest_state.output, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ fprintf(utest_state.output,
+ "<testsuites tests=\"%" UTEST_PRIu64 "\" name=\"All\">\n",
+ UTEST_CAST(utest_uint64_t, ran_tests));
+ fprintf(utest_state.output,
+ "<testsuite name=\"Tests\" tests=\"%" UTEST_PRIu64 "\">\n",
+ UTEST_CAST(utest_uint64_t, ran_tests));
+ }
+
+ for (index = 0; index < utest_state.tests_length; index++) {
+ int result = UTEST_TEST_PASSED;
+ utest_int64_t ns = 0;
+
+ if (utest_should_filter_test(filter, utest_state.tests[index].name)) {
+ continue;
+ }
+
+ printf("%s[ RUN ]%s %s\n", colours[GREEN], colours[RESET],
+ utest_state.tests[index].name);
+
+ if (utest_state.output) {
+ fprintf(utest_state.output, "<testcase name=\"%s\">",
+ utest_state.tests[index].name);
+ }
+
+ ns = utest_ns();
+ errno = 0;
+#if defined(UTEST_HAS_EXCEPTIONS)
+ UTEST_SURPRESS_WARNING_BEGIN
+ try {
+ utest_state.tests[index].func(&result, utest_state.tests[index].index);
+ } catch (const std::exception &err) {
+ printf(" Exception : %s\n", err.what());
+ result = UTEST_TEST_FAILURE;
+ } catch (...) {
+ printf(" Exception : Unknown\n");
+ result = UTEST_TEST_FAILURE;
+ }
+ UTEST_SURPRESS_WARNING_END
+#else
+ utest_state.tests[index].func(&result, utest_state.tests[index].index);
+#endif
+ ns = utest_ns() - ns;
+
+ if (utest_state.output) {
+ fprintf(utest_state.output, "</testcase>\n");
+ }
+
+ // Record the failing test.
+ if (UTEST_TEST_FAILURE == result) {
+ const size_t failed_testcase_index = failed_testcases_length++;
+ failed_testcases = UTEST_PTR_CAST(
+ size_t *, utest_realloc(UTEST_PTR_CAST(void *, failed_testcases),
+ sizeof(size_t) * failed_testcases_length));
+ if (UTEST_NULL != failed_testcases) {
+ failed_testcases[failed_testcase_index] = index;
+ }
+ failed++;
+ } else if (UTEST_TEST_SKIPPED == result) {
+ const size_t skipped_testcase_index = skipped_testcases_length++;
+ skipped_testcases = UTEST_PTR_CAST(
+ size_t *, utest_realloc(UTEST_PTR_CAST(void *, skipped_testcases),
+ sizeof(size_t) * skipped_testcases_length));
+ if (UTEST_NULL != skipped_testcases) {
+ skipped_testcases[skipped_testcase_index] = index;
+ }
+ skipped++;
+ }
+
+ {
+ const char *const units[] = {"ns", "us", "ms", "s", UTEST_NULL};
+ unsigned int unit_index = 0;
+ utest_int64_t time = ns;
+
+ if (enable_mixed_units) {
+ for (unit_index = 0; UTEST_NULL != units[unit_index]; unit_index++) {
+ if (10000 > time) {
+ break;
+ }
+
+ time /= 1000;
+ }
+ }
+
+ if (UTEST_TEST_FAILURE == result) {
+ printf("%s[ FAILED ]%s %s (%" UTEST_PRId64 "%s)\n", colours[RED],
+ colours[RESET], utest_state.tests[index].name, time,
+ units[unit_index]);
+ } else if (UTEST_TEST_SKIPPED == result) {
+ printf("%s[ SKIPPED ]%s %s (%" UTEST_PRId64 "%s)\n", colours[YELLOW],
+ colours[RESET], utest_state.tests[index].name, time,
+ units[unit_index]);
+ } else {
+ printf("%s[ OK ]%s %s (%" UTEST_PRId64 "%s)\n", colours[GREEN],
+ colours[RESET], utest_state.tests[index].name, time,
+ units[unit_index]);
+ }
+ }
+ }
+
+ printf("%s[==========]%s %" UTEST_PRIu64 " test cases ran.\n", colours[GREEN],
+ colours[RESET], ran_tests);
+ printf("%s[ PASSED ]%s %" UTEST_PRIu64 " tests.\n", colours[GREEN],
+ colours[RESET], ran_tests - failed - skipped);
+
+ if (0 != skipped) {
+ printf("%s[ SKIPPED ]%s %" UTEST_PRIu64 " tests, listed below:\n",
+ colours[YELLOW], colours[RESET], skipped);
+ for (index = 0; index < skipped_testcases_length; index++) {
+ printf("%s[ SKIPPED ]%s %s\n", colours[YELLOW], colours[RESET],
+ utest_state.tests[skipped_testcases[index]].name);
+ }
+ }
+
+ if (0 != failed) {
+ printf("%s[ FAILED ]%s %" UTEST_PRIu64 " tests, listed below:\n",
+ colours[RED], colours[RESET], failed);
+ for (index = 0; index < failed_testcases_length; index++) {
+ printf("%s[ FAILED ]%s %s\n", colours[RED], colours[RESET],
+ utest_state.tests[failed_testcases[index]].name);
+ }
+ }
+
+ if (utest_state.output) {
+ fprintf(utest_state.output, "</testsuite>\n</testsuites>\n");
+ }
+
+cleanup:
+ for (index = 0; index < utest_state.tests_length; index++) {
+ free(UTEST_PTR_CAST(void *, utest_state.tests[index].name));
+ }
+
+ free(UTEST_PTR_CAST(void *, skipped_testcases));
+ free(UTEST_PTR_CAST(void *, failed_testcases));
+ free(UTEST_PTR_CAST(void *, utest_state.tests));
+
+ if (utest_state.output) {
+ fclose(utest_state.output);
+ }
+
+ return UTEST_CAST(int, failed);
+}
+
+#if defined(__clang__)
+#if __has_warning("-Wunsafe-buffer-usage")
+#pragma clang diagnostic pop
+#endif
+#endif
+
+/*
+ we need, in exactly one source file, define the global struct that will hold
+ the data we need to run utest. This macro allows the user to declare the
+ data without having to use the UTEST_MAIN macro, thus allowing them to write
+ their own main() function.
+*/
+#define UTEST_STATE() struct utest_state_s utest_state = {0, 0, 0}
+
+/*
+ define a main() function to call into utest.h and start executing tests! A
+ user can optionally not use this macro, and instead define their own main()
+ function and manually call utest_main. The user must, in exactly one source
+ file, use the UTEST_STATE macro to declare a global struct variable that
+ utest requires.
+*/
+#define UTEST_MAIN() \
+ UTEST_STATE(); \
+ int main(int argc, const char *const argv[]) { \
+ return utest_main(argc, argv); \
+ }
+
+#endif /* SHEREDOM_UTEST_H_INCLUDED */
diff --git a/Homework/math4610/test/vector.t.c b/Homework/math4610/test/vector.t.c
new file mode 100644
index 0000000..4811113
--- /dev/null
+++ b/Homework/math4610/test/vector.t.c
@@ -0,0 +1,115 @@
+#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, 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;
+ 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);
+}