From 26ececd96cc142991b4314c7f98455d6eb5c2850 Mon Sep 17 00:00:00 2001 From: leios Date: Sun, 15 Jul 2018 21:11:14 +0900 Subject: [PATCH 1/3] removing principles of code chapter. --- SUMMARY.md | 29 ++-- TODO.md | 29 ---- chapters/data_structures/data_structures.md | 4 + .../stacks_and_queues/stacks_and_queues.md} | 0 chapters/introduction/how_to_contribute.md | 2 +- .../res/clone.png | Bin .../res/fork.png | Bin .../version_control.md | 0 .../choosing_a_language.md | 0 .../compiled/FORTRAN.md | 0 .../compiled/compiled.md | 0 .../compiled/makefiles.md | 0 .../bitlogic}/bitlogic.md | 6 +- .../bitlogic}/res/and.jpg | Bin .../bitlogic}/res/nand.jpg | Bin .../bitlogic}/res/nor.jpg | Bin .../bitlogic}/res/not.jpg | Bin .../bitlogic}/res/or.jpg | Bin .../bitlogic}/res/xor.jpg | Bin .../convolutions/code/c++/convolutions.cpp | 130 +++++++++++++++++ .../convolutions/code/c/convolutions.c | 68 +++++++++ .../convolutions/code/c/fft.h | 41 ++++++ .../convolutions/code/haskell/convolution.hs | 5 + .../convolutions/code/julia/conv.jl | 22 +++ .../convolutions/convolutions.md | 133 ++++++++++++++++++ .../mathematical_background.md | 13 ++ .../notation/notation.md | 0 .../notation/out.dat | 0 .../notation/res/cplot.png | Bin .../taylor_series/taylor_series.md | 68 +++++++++ .../building_blocks/building_blocks.md | 9 -- .../building_blocks/classes.md | 26 ---- .../building_blocks/conditions.md | 102 -------------- .../building_blocks/functions.md | 82 ----------- .../building_blocks/loops.md | 59 -------- .../building_blocks/variables.md | 113 --------------- chapters/principles_of_code/code_quality.md | 19 --- .../principles_of_code/principles_of_code.md | 30 ---- 38 files changed, 496 insertions(+), 494 deletions(-) delete mode 100644 TODO.md create mode 100644 chapters/data_structures/data_structures.md rename chapters/{principles_of_code/building_blocks/stacks.md => data_structures/stacks_and_queues/stacks_and_queues.md} (100%) rename chapters/{principles_of_code => introduction}/res/clone.png (100%) rename chapters/{principles_of_code => introduction}/res/fork.png (100%) rename chapters/{principles_of_code => introduction}/version_control.md (100%) rename chapters/{principles_of_code/choosing_a_language => languages}/choosing_a_language.md (100%) rename chapters/{principles_of_code/choosing_a_language => languages}/compiled/FORTRAN.md (100%) rename chapters/{principles_of_code/choosing_a_language => languages}/compiled/compiled.md (100%) rename chapters/{principles_of_code/choosing_a_language => languages}/compiled/makefiles.md (100%) rename chapters/{principles_of_code/building_blocks => mathematical_background/bitlogic}/bitlogic.md (99%) rename chapters/{principles_of_code/building_blocks => mathematical_background/bitlogic}/res/and.jpg (100%) rename chapters/{principles_of_code/building_blocks => mathematical_background/bitlogic}/res/nand.jpg (100%) rename chapters/{principles_of_code/building_blocks => mathematical_background/bitlogic}/res/nor.jpg (100%) rename chapters/{principles_of_code/building_blocks => mathematical_background/bitlogic}/res/not.jpg (100%) rename chapters/{principles_of_code/building_blocks => mathematical_background/bitlogic}/res/or.jpg (100%) rename chapters/{principles_of_code/building_blocks => mathematical_background/bitlogic}/res/xor.jpg (100%) create mode 100644 chapters/mathematical_background/convolutions/code/c++/convolutions.cpp create mode 100644 chapters/mathematical_background/convolutions/code/c/convolutions.c create mode 100644 chapters/mathematical_background/convolutions/code/c/fft.h create mode 100644 chapters/mathematical_background/convolutions/code/haskell/convolution.hs create mode 100644 chapters/mathematical_background/convolutions/code/julia/conv.jl create mode 100644 chapters/mathematical_background/convolutions/convolutions.md create mode 100644 chapters/mathematical_background/mathematical_background.md rename chapters/{principles_of_code => mathematical_background}/notation/notation.md (100%) rename chapters/{principles_of_code => mathematical_background}/notation/out.dat (100%) rename chapters/{principles_of_code => mathematical_background}/notation/res/cplot.png (100%) create mode 100644 chapters/mathematical_background/taylor_series/taylor_series.md delete mode 100644 chapters/principles_of_code/building_blocks/building_blocks.md delete mode 100644 chapters/principles_of_code/building_blocks/classes.md delete mode 100644 chapters/principles_of_code/building_blocks/conditions.md delete mode 100644 chapters/principles_of_code/building_blocks/functions.md delete mode 100644 chapters/principles_of_code/building_blocks/loops.md delete mode 100644 chapters/principles_of_code/building_blocks/variables.md delete mode 100644 chapters/principles_of_code/code_quality.md delete mode 100644 chapters/principles_of_code/principles_of_code.md diff --git a/SUMMARY.md b/SUMMARY.md index c81780ac3..56bf4db6d 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -1,33 +1,21 @@ # Summary * [Algorithm Archive](README.md) -* [TODO](TODO.md) * [Introduction](chapters/introduction/introduction.md) -* [A Personal Note](chapters/introduction/my_introduction_to_hobby_programming.md) * [How To Contribute](chapters/introduction/how_to_contribute.md) -* [Principles of Code](chapters/principles_of_code/principles_of_code.md) - * [Choosing A Language](chapters/principles_of_code/choosing_a_language/choosing_a_language.md) - * [Compiled Languages](chapters/principles_of_code/choosing_a_language/compiled/compiled.md) - * [Makefiles](chapters/principles_of_code/choosing_a_language/compiled/makefiles.md) - * [FORTRAN](chapters/principles_of_code/choosing_a_language/compiled/FORTRAN.md) - * [Building Blocks](chapters/principles_of_code/building_blocks/building_blocks.md) - * [Variables and Types](chapters/principles_of_code/building_blocks/variables.md) - * [Conditions](chapters/principles_of_code/building_blocks/conditions.md) - * [Loops](chapters/principles_of_code/building_blocks/loops.md) - * [Functions](chapters/principles_of_code/building_blocks/functions.md) - * [Classes](chapters/principles_of_code/building_blocks/classes.md) - * [Stacks and Queues](chapters/principles_of_code/building_blocks/stacks.md) - * [Bit Logic](chapters/principles_of_code/building_blocks/bitlogic.md) - * [Version Control](chapters/principles_of_code/version_control.md) - * [Complexity Notation](chapters/principles_of_code/notation/notation.md) -* [Convolutions](chapters/algorithms/convolutions/convolutions.md) -* [Taylor Series](chapters/general/taylor_series_expansion/taylor_series_expansion.md) +* [Version Control](chapters/introduction/version_control.md) +* [Data Structures](chapters/data_structures/data_structures.md) + * [Stacks and Queues](chapters/data_structures/stacks_and_queues/stacks_and_queues.md) +* [Mathematical Background](chapters/mathematical_background/mathematical_background.md) + * [Complexity Notation](chapters/mathematical_background/notation/notation.md) + * [Bit Logic](chapters/mathematical_background/bitlogic/bitlogic.md) + * [Convolutions](chapters/mathematical_background/convolutions/convolutions.md) + * [Taylor Series](chapters/mathematical_background/taylor_series/taylor_series.md) * [Sorting and Searching](chapters/general/sorting_and_searching/sorting_and_searching.md) * [Bubble Sort](chapters/algorithms/bubble_sort/bubble_sort.md) * [Bogo Sort](chapters/algorithms/bogo_sort/bogo_sort.md) * [Tree Traversal](chapters/algorithms/tree_traversal/tree_traversal.md) * [Euclidean Algorithm](chapters/algorithms/euclidean_algorithm/euclidean_algorithm.md) -* [Multiplication](chapters/general/multiplication/multiplication.md) * [Monte Carlo](chapters/algorithms/monte_carlo_integration/monte_carlo_integration.md) * [Matrix Methods](chapters/general/matrix_methods/matrix_methods.md) * [Gaussian Elimination](chapters/algorithms/gaussian_elimination/gaussian_elimination.md) @@ -45,7 +33,6 @@ * [Backward Euler Methods](chapters/algorithms/backward_euler_method/backward_euler_method.md) * [Physics Solvers](chapters/general/physics_solvers/physics_solvers.md) * [Verlet Integration](chapters/algorithms/verlet_integration/verlet_integration.md) - * [Barnes-Hut](chapters/algorithms/barnes_hut_algorithm/barnes_hut_algorithm.md) * [Quantum Systems](chapters/general/quantum_systems/quantum_systems.md) * [Split-Operator Method](chapters/algorithms/split-operator_method/split-operator_method.md) * [Data Compression](chapters/general/data_compression/data_compression.md) diff --git a/TODO.md b/TODO.md deleted file mode 100644 index 9d19c7a50..000000000 --- a/TODO.md +++ /dev/null @@ -1,29 +0,0 @@ -# TO DO - -The Algorithm Archive is currently being written and is quite small at the moment. -This is a list of all the things we need to get done ASAP. -That said, because of my (real-world) work schedule and such, ASAP is not as fast as I'd like, but that's how it goes. -I apologize for taking so long with each chapter, but I figure making this list public is a good step towards being as open as possible. - -## For James (Leios) - -Write: - -* Algorithms already covered (Chan's, Monte Carlo) -* Language choices (Makefiles, Fortran, Julia...). Note that I kinda wanted to turn this into a series of sorts where I review each language with a series of standard tests. - -Revise: - -* Mathematical Background -- Transform into "mathematical methods." - -I'll try to keep this list updated as I write more sections - -## Points of Discussion - -Here are points of discussion that need to be had about the Algorithm Archive before it gets too big and becomes too difficult to revise everything - -* **Should community-submitted code be clean or efficient?** When it comes to writing code, I often feel readability is the most important factor to keep in mind; however, with the code submitted to this archive, there will be pseudocode available to guide new folks through the process of writing the algorithm for the first time. For this reason, it might be best for the community to submit the most efficient code they can write in their own languages, commenting in any tricks to improve performance. -* **Is the current method of writing optimal?** When I originally envisioned this project, I thought that I would do all the writing and the community would do (most of) the coding. That said, I am becoming more open to the idea of letting community members write for the Archive. The advantage to this is obvious: The book gets written faster. The disadvantage is also obvious: We lose focus and consistency throughout the book. -* **We need a Logo.** I have no idea how to go about this. Maybe a logo contest at 16384 subscribers on youtube? The project will be large enough at that point to warrant a good logo. I really want something simple, though, like a [Trefoil Knot](https://en.wikipedia.org/wiki/Trefoil_knot#/media/File:Trefoil_knot_left.svg) or something. It kinda looks like 3 A's if you look at it the right way, and we'll definitely cover knot algorithms at some point because they are fascinating! - -Anyway, let me know what you think. I love the community we have here and appreciate all the conversations we've had so far! diff --git a/chapters/data_structures/data_structures.md b/chapters/data_structures/data_structures.md new file mode 100644 index 000000000..2ec5efbe3 --- /dev/null +++ b/chapters/data_structures/data_structures.md @@ -0,0 +1,4 @@ +# Data Structures + +This is a book about algorithms. +The fundamental building blocks of algorithms are data structures, and thus as more algorithms are added to the Archive, more data structures will be added to this section. diff --git a/chapters/principles_of_code/building_blocks/stacks.md b/chapters/data_structures/stacks_and_queues/stacks_and_queues.md similarity index 100% rename from chapters/principles_of_code/building_blocks/stacks.md rename to chapters/data_structures/stacks_and_queues/stacks_and_queues.md diff --git a/chapters/introduction/how_to_contribute.md b/chapters/introduction/how_to_contribute.md index f1209e07b..073cdb125 100644 --- a/chapters/introduction/how_to_contribute.md +++ b/chapters/introduction/how_to_contribute.md @@ -2,7 +2,7 @@ The *Algorithm Archive* is an effort to learn about and teach algorithms as a community. As such, it requires a certain level of trust between community members. -For the most part, the collaboration can be done via GitHub and gitbook, so it is important to understand the basics of [version control](../principles_of_code/version_control.md). +For the most part, the collaboration can be done via GitHub and gitbook, so it is important to understand the basics of [version control](version_control.md). Ideally, all code provided by the community will be submitted via pull requests and discussed accordingly; however, I understand that many individuals are new to collaborative projects, so I will allow submissions by other means (comments, tweets, etc...). As this project grows in size, it will be harder and harder to facilitate these submissions. In addition, by submitting in any way other than pull requests, I cannot guarantee I will be able to list you as a collaborator (though I will certainly do my best to update the `CONTRIBUTORS.md` file accordingly). diff --git a/chapters/principles_of_code/res/clone.png b/chapters/introduction/res/clone.png similarity index 100% rename from chapters/principles_of_code/res/clone.png rename to chapters/introduction/res/clone.png diff --git a/chapters/principles_of_code/res/fork.png b/chapters/introduction/res/fork.png similarity index 100% rename from chapters/principles_of_code/res/fork.png rename to chapters/introduction/res/fork.png diff --git a/chapters/principles_of_code/version_control.md b/chapters/introduction/version_control.md similarity index 100% rename from chapters/principles_of_code/version_control.md rename to chapters/introduction/version_control.md diff --git a/chapters/principles_of_code/choosing_a_language/choosing_a_language.md b/chapters/languages/choosing_a_language.md similarity index 100% rename from chapters/principles_of_code/choosing_a_language/choosing_a_language.md rename to chapters/languages/choosing_a_language.md diff --git a/chapters/principles_of_code/choosing_a_language/compiled/FORTRAN.md b/chapters/languages/compiled/FORTRAN.md similarity index 100% rename from chapters/principles_of_code/choosing_a_language/compiled/FORTRAN.md rename to chapters/languages/compiled/FORTRAN.md diff --git a/chapters/principles_of_code/choosing_a_language/compiled/compiled.md b/chapters/languages/compiled/compiled.md similarity index 100% rename from chapters/principles_of_code/choosing_a_language/compiled/compiled.md rename to chapters/languages/compiled/compiled.md diff --git a/chapters/principles_of_code/choosing_a_language/compiled/makefiles.md b/chapters/languages/compiled/makefiles.md similarity index 100% rename from chapters/principles_of_code/choosing_a_language/compiled/makefiles.md rename to chapters/languages/compiled/makefiles.md diff --git a/chapters/principles_of_code/building_blocks/bitlogic.md b/chapters/mathematical_background/bitlogic/bitlogic.md similarity index 99% rename from chapters/principles_of_code/building_blocks/bitlogic.md rename to chapters/mathematical_background/bitlogic/bitlogic.md index 077356490..32898cd11 100644 --- a/chapters/principles_of_code/building_blocks/bitlogic.md +++ b/chapters/mathematical_background/bitlogic/bitlogic.md @@ -1,10 +1,10 @@ -### Bit Logic +# Bit Logic We write code in a language that makes a little sense to us, but does not make sense at all to our computer without a compiler to transform the code we write into a language the computer can understand. In the end, whenever we write code, all of the data structures we write are transformed into binary strings of 1's and 0's to be interpreted by our computer. That said, it's not always obvious how this happens, so let's start the simple case of integer numbers. -#### Integers +## Integers For integer numbers, 0 is still 0 and 1 is still 1; however, for 2, we need to use 2 digits because binary only has 0's and 1's. When we get to 4, we'll need 3 digits and when we get to 8, we'll need 4. Ever time we cross a power of 2, we'll need to add a new digit. Here's a table of the first 10 integers in binary: | Integer Number | Binary Number | @@ -45,7 +45,7 @@ Another method is to "roll over" to negative numbers when the bit count gets too Ultimately, integer numbers are not that difficult to deal with in binary, so let's move onto something more complicated: *floating-point numbers!* -#### Floating-point Numbers +## Floating-point Numbers Floats are numbers with a decimal point. 9.125 is a float. 9.000 is a float. 9 is an integer. Here are a few floats and their integer representations: diff --git a/chapters/principles_of_code/building_blocks/res/and.jpg b/chapters/mathematical_background/bitlogic/res/and.jpg similarity index 100% rename from chapters/principles_of_code/building_blocks/res/and.jpg rename to chapters/mathematical_background/bitlogic/res/and.jpg diff --git a/chapters/principles_of_code/building_blocks/res/nand.jpg b/chapters/mathematical_background/bitlogic/res/nand.jpg similarity index 100% rename from chapters/principles_of_code/building_blocks/res/nand.jpg rename to chapters/mathematical_background/bitlogic/res/nand.jpg diff --git a/chapters/principles_of_code/building_blocks/res/nor.jpg b/chapters/mathematical_background/bitlogic/res/nor.jpg similarity index 100% rename from chapters/principles_of_code/building_blocks/res/nor.jpg rename to chapters/mathematical_background/bitlogic/res/nor.jpg diff --git a/chapters/principles_of_code/building_blocks/res/not.jpg b/chapters/mathematical_background/bitlogic/res/not.jpg similarity index 100% rename from chapters/principles_of_code/building_blocks/res/not.jpg rename to chapters/mathematical_background/bitlogic/res/not.jpg diff --git a/chapters/principles_of_code/building_blocks/res/or.jpg b/chapters/mathematical_background/bitlogic/res/or.jpg similarity index 100% rename from chapters/principles_of_code/building_blocks/res/or.jpg rename to chapters/mathematical_background/bitlogic/res/or.jpg diff --git a/chapters/principles_of_code/building_blocks/res/xor.jpg b/chapters/mathematical_background/bitlogic/res/xor.jpg similarity index 100% rename from chapters/principles_of_code/building_blocks/res/xor.jpg rename to chapters/mathematical_background/bitlogic/res/xor.jpg diff --git a/chapters/mathematical_background/convolutions/code/c++/convolutions.cpp b/chapters/mathematical_background/convolutions/code/c++/convolutions.cpp new file mode 100644 index 000000000..e2b8e9c6b --- /dev/null +++ b/chapters/mathematical_background/convolutions/code/c++/convolutions.cpp @@ -0,0 +1,130 @@ +#include +#include +#include +#include +#include +#include +#include + +// These headers are for presentation not for the algorithm. +#include +#include +#include + +using std::begin; +using std::end; +using std::swap; + +using std::ptrdiff_t; +using std::size_t; + +using c64 = std::complex; +template +constexpr T pi() { + return 3.14159265358979323846264338327950288419716; +} + +// This section is not a part of the algorithm +template +void fft(Iter const first, Iter const last) { + auto const size = last - first; + if (size >= 2) { + auto temp = std::vector(size / 2); + for (ptrdiff_t i = 0; i < size / 2; ++i) { + temp[i] = first[i * 2 + 1]; + first[i] = first[i * 2]; + } + for (ptrdiff_t i = 0; i < size / 2; ++i) { + first[i + size / 2] = temp[i]; + } + + auto const split = first + size / 2; + fft(first, split); + fft(split, last); + + for (ptrdiff_t k = 0; k < size / 2; ++k) { + auto w = std::exp(c64(0, -2.0 * pi() * k / size)); + + auto& bottom = first[k]; + auto& top = first[k + size / 2]; + top = bottom - w * top; + bottom -= top - bottom; + } + } +} + +template +void inverse_fft(Iter const first, Iter const last) { + std::for_each(first, last, [](auto& it) { it = std::conj(it); }); + + fft(first, last); + + auto const size = static_cast(last - first); + std::for_each(first, last, [&](auto& it) { it = std::conj(it) / size; }); +} + +// This section is a part of the algorithm + +template +void conv( + S1 const s1, + S1 const s1_last, + S2 const s2, + S2 const s2_last, + Out const out) { + auto const size1 = s1_last - s1; + auto const size2 = s2_last - s2; + auto const size = size1 + size2; + + for (ptrdiff_t i = 0; i < size; ++i) { + c64 sum = 0; + for (ptrdiff_t j = 0; j < i; ++j) { + if (j < size1) { + sum += s1[j] * s2[i - j]; + } + } + out[i] = sum; + } +} + +template +void conv_fft(S1 const s1, S1 const s1_last, S2 const s2, Out const out) { + auto const size = s1_last - s1; + + fft(s1, s1_last); + fft(s2, s2 + size); + + auto s1_it = s1; + auto s2_it = s2; + auto out_it = out; + for (; s1_it != s1_last; ++s1_it, ++s2_it, ++out_it) { + *out_it = *s1_it * *s2_it; + } + + inverse_fft(out, out_it); +} + +int main() { + auto signal1 = std::array(); + std::fill(begin(signal1) + 16, begin(signal1) + 48, 1); + + auto signal2 = signal1; + + auto out1 = std::array(); + conv(begin(signal1), end(signal1), begin(signal2), end(signal2), begin(out1)); + + auto signal3 = std::array(); + std::copy(begin(signal1), end(signal1), begin(signal3)); + auto signal4 = signal3; + + auto out2 = std::array(); + conv_fft(begin(signal3), end(signal3), begin(signal4), begin(out2)); + + std::cout << std::right << std::setw(16) << "i" << std::setw(16) + << "subtracted" << '\n'; + + for (size_t i = 0; i < signal1.size(); ++i) { + std::cout << std::setw(16) << i << std::setw(16) + << (std::abs(out1[i]) - std::abs(out2[i])) << '\n'; + } +} diff --git a/chapters/mathematical_background/convolutions/code/c/convolutions.c b/chapters/mathematical_background/convolutions/code/c/convolutions.c new file mode 100644 index 000000000..386285a1d --- /dev/null +++ b/chapters/mathematical_background/convolutions/code/c/convolutions.c @@ -0,0 +1,68 @@ +#include "fft.h" + +#include + +void conv(double complex *signal1, double complex *signal2, double complex* out, + size_t n1, size_t n2) { + double complex sum = 0; + + for (size_t i = 0; i < (n1 < n2? n2 : n1); ++i) { + for (size_t j = 0; j < i; ++j) { + if (j < n1) { + sum += signal1[j] * signal2[i-j]; + } + } + out[i] = sum; + sum = 0; + } +} + +void conv_fft(double complex *signal1, double complex *signal2, + double complex* out, size_t n) { + fft(signal1, n); + fft(signal2, n); + + for (size_t i = 0; i < n; ++i) { + out[i] = signal1[i] * signal2[i]; + } + + ifft(out, n); +} + +int main() { + double complex signal1[64], signal2[64], signal3[128], signal4[128], + out1[128], out2[128]; + + for (size_t i = 0; i < 128; ++i) { + if (i >= 16 && i < 48) { + signal1[i] = 1.0; + signal2[i] = 1.0; + signal3[i] = 1.0; + signal4[i] = 1.0; + out1[i] = 0.0; + out2[i] = 0.0; + } else if (i >= 64) { + signal3[i] = 0.0; + signal4[i] = 0.0; + out1[i] = 0.0; + out2[i] = 0.0; + } else { + signal1[i] = 0.0; + signal2[i] = 0.0; + signal3[i] = 0.0; + signal4[i] = 0.0; + out1[i] = 0.0; + out2[i] = 0.0; + } + } + + conv(signal1, signal2, out1, 64, 64); + conv_fft(signal3, signal4, out2, 128); + + for (size_t i = 0; i < 64; ++i) { + printf("%zu %f %+fi\n", i, creal(out1[i]) - creal(out2[i]), + cimag(out1[i]) - cimag(out2[i])); + } + + return 0; +} diff --git a/chapters/mathematical_background/convolutions/code/c/fft.h b/chapters/mathematical_background/convolutions/code/c/fft.h new file mode 100644 index 000000000..de789f197 --- /dev/null +++ b/chapters/mathematical_background/convolutions/code/c/fft.h @@ -0,0 +1,41 @@ +#ifndef FFT_H +#define FFT_H + +#include +#include + +void fft(double complex *X, size_t N) { + if (N >= 2) { + double complex tmp [N / 2]; + for (size_t i = 0; i < N / 2; ++i) { + tmp[i] = X[2 * i + 1]; + X[i] = X[2 * i]; + } + + for (size_t i = 0; i < N / 2; ++i) { + X[i + N / 2] = tmp[i]; + } + + fft(X, N / 2); + fft(X + N / 2, N / 2); + + for (size_t i = 0; i < N / 2; ++i) { + X[i + N/2] = X[i] - cexp(-2.0 * I * M_PI * i / N) * X[i + N / 2]; + X[i] -= (X[i + N / 2] - X[i]); + } + } +} + +void ifft(double complex *x, size_t n) { + for (size_t i = 0; i < n; ++i) { + x[i] = conj(x[i]); + } + + fft(x, n); + + for (size_t i = 0; i < n; ++i) { + x[i] = conj(x[i]) / n; + } +} + +#endif //FFT_H diff --git a/chapters/mathematical_background/convolutions/code/haskell/convolution.hs b/chapters/mathematical_background/convolutions/code/haskell/convolution.hs new file mode 100644 index 000000000..59bc1a135 --- /dev/null +++ b/chapters/mathematical_background/convolutions/code/haskell/convolution.hs @@ -0,0 +1,5 @@ +import Data.List (tails) + +convolution :: (Num a) => [a] -> [a] -> [a] +convolution x = map (sum . zipWith (*) (reverse x)) . spread + where spread = init . tails . (replicate (length x - 1) 0 ++) diff --git a/chapters/mathematical_background/convolutions/code/julia/conv.jl b/chapters/mathematical_background/convolutions/code/julia/conv.jl new file mode 100644 index 000000000..253a11d4f --- /dev/null +++ b/chapters/mathematical_background/convolutions/code/julia/conv.jl @@ -0,0 +1,22 @@ +function conv(signal1::Vector{Complex}, signal2::Vector{Complex}) + n = length(signal1) + length(signal2) + out = Vector{Complex}(n) + sum = 0 + + for i = 0:n + for j = 0:i + if(j < length(signal1)) + sum += signal1[j] * signal2[i-j] + end + end + out[i] = sum + sum = 0 + end + + return out +end + +function conv_fft(signal1::Vector{Complex}, signal2::Vector{Complex}) + return ifft(fft(signal1).*fft(signal2)) +end + diff --git a/chapters/mathematical_background/convolutions/convolutions.md b/chapters/mathematical_background/convolutions/convolutions.md new file mode 100644 index 000000000..637c9b720 --- /dev/null +++ b/chapters/mathematical_background/convolutions/convolutions.md @@ -0,0 +1,133 @@ +# Convolutions +Alright, I am going to come right out and say it: convolutions can be confusing. +Not only are they hard to really describe, but if you do not see them in practice, it's hard to understand why you would ever want to use them. +I'm going to do what I can to describe them in an intuitive way; however, I may need to come back to this in the future. +Let me know if there is anything here that is unclear, and I'll do what I can to clear it up. + +If you take two functions $$f(x)$$ and $$g(x)$$, there are a number of ways you can combine them. +All basic operations can do this (addition, subtraction, multiplication, and division), but there are also special operations that only work with functions and do not work on standard variables or numbers. +For example, $$f \circ g$$ is a *composition* of the two functions, where you plug $$g(x)$$ into $$f(x)$$. +A convolution is another function-related operation, and is often notated with a star ($$*$$) operator, where + +$$f(x)*g(x)=c(x)$$ + +provides a third function $$c(x)$$ that blends $$f(x)$$ and $$g(x)$$. + +As a rather important side-note: there is an incredibly similar operator known as a *correlation* which will be discussed in the near future. +For now, let's focus on convolutions, which are defined as: + +$$(f*g)(x) = \int_{-\infty}^{\infty}f(\xi)g(x-\xi)d\xi = \int_{-\infty}^{\infty}f(x-\xi)g(\xi)d\xi$$ + +Note that in this case, $$x$$ is not necessarily a spatial element. +Often times, it is time or something else entirely! +The easiest way to think about this is that the function $$g(x)$$ is being shifted across all of space by the variable $$\xi$$. +At every point $$x$$, we multiply $$f(x)$$ and $$g(x)$$ and integrate the multiplied output to find the convolution for that spatial step, $$(f*g)(x)$$. +Note that in code, this is often discretized to look like: + +$$(f*g)[n] = \sum_{m = -\infty}^{\infty}f[m]g[n-m] = \sum_{m = -\infty}^{\infty}f[n-m]g[m]$$ + +Where `f[n]` and `g[n]` are arrays of some form. +This means we basically just need to keep one array steady, flip the second array around, and move it through the first array one step at a time, performing a simple element-wise multiplication each step. + + + + + +In code, this looks something like: + +{% method %} +{% sample lang="jl" %} +[import:1-17, lang:"julia"](code/julia/conv.jl) +{% sample lang="hs" %} +[import:1-5, lang:"haskell"](code/haskell/convolution.hs) +{% sample lang="c"%} +[import:5-18, lang:"c_cpp"](code/c/convolutions.c) +{% sample lang="cpp"%} +[import:68-88, lang:"c_cpp"](code/c++/convolutions.cpp) +{% endmethod %} + +Note that in this case, the output array will be the size of `f[n]` and `g[n]` put together. +Sometimes, though, we have an large size for `f[n]` and a small size for `g[n]`. +In this case `g[n]` is often called a *filter*, and often times when we are using a filter on an array (that might represent an image or some form of data), we want the output array to be the same size as the input. +In this case, rather than outputting a larger array, we often do something special at the borders of the array. +Depending on the situation, this may be necessary. +Note that there are different methods to deal with the edges in this case, so it's best to do whatever seems right when the situation arises. + +### Convolutional Theorem + +Now, let me tell you about a bit of black computational magic: + +**Convolutions can be performed with Fourier Transforms!** + +That is crazy! +It's also incredibly hard to explain, so let me do my best. +As described in the chapter on [Fourier Transforms](../cooley_tukey/cooley_tukey.md), Fourier Transforms allow programmers to move from real space to frequency space. +When we transform a wave into frequency space, we see a single peak in frequency space related to the frequency of that wave. +No matter what function we send into a Fourier Transform, the frequency-space image can be interpreted as a series of different waves with a specified frequency. + +So here's the idea: if we take two functions $$f(x)$$ and $$g(x)$$ and move them to frequency space to be $$\hat f(\xi)$$ and $$\hat g(\xi)$$, we can then multiply those two functions and transform them back into a third function to blend the signals together. +In this way, we will have a third function that relates the frequency-space images of the two input functions. +*This is precisely a convolution!* + +Don't believe me? +Well, this is because of something known as the *convolution theorem* which looks something like this: + +$$\mathcal{F}(f*g) = \mathcal{F}(f) \cdot \mathcal{F}(g)$$ + +Where $$\mathcal{F}$$ denotes the Fourier Transform. +Now, by using a Fast Fourier Transform (fft) in code, this can take a standard convolution on two arrays of length $$n$$, which is an $$\mathcal{O}(n^2)$$ process, to $$\mathcal{O}(n\log(n))$$. +This means that the convolution theorem is fundamental to creating fast convolutional methods for large inputs, assuming that both of the input signals are similar sizes. +That said, it is debatable whether the convolution theorem will be faster when the filter size is small. +Also: depending on the language used, we might need to read in a separate library for FFT's. + +{% method %} +{% sample lang="jl" %} +That said, Julia has an in-built fft routine, so the code for this method could not be simpler: +[import:19-22, lang:"julia"](code/julia/conv.jl) +Where the `.*` operator is an element-wise multiplication. +{% sample lang="hs" %} +The FFT-based convolution in Haskell is complicated, so here is some simple julia code: +[import:19-22, lang:"julia"](code/julia/conv.jl) +Where the `.*` operator is an element-wise multiplication. +{% sample lang="c"%} +[import:20-30, lang:"c_cpp"](code/c/convolutions.c) +{% sample lang="cpp"%} +[import:90-105, lang:"c_cpp"](code/c++/convolutions.cpp) +{% endmethod %} + +This method also has the added advantage that it will *always output an array of the size of your signal*; however, if your signals are not of equal size, we need to pad the smaller signal with zeros. +Also note that the Fourier Transform is a periodic or cyclical operation, so there are no real edges in this method, instead the arrays "wrap around" to the other side. +For this reason, this convolution is often called a *cyclic convolution* instead of a *linear convolution* like above. +Note that cyclic convolutions can definitely still be done without Fourier Transforms and we can do linear convolutions with Fourier Transforms, but it makes the code slightly more complicated than described above. + + + + +$$ +\newcommand{\d}{\mathrm{d}} +\newcommand{\bff}{\boldsymbol{f}} +\newcommand{\bfg}{\boldsymbol{g}} +\newcommand{\bfp}{\boldsymbol{p}} +\newcommand{\bfq}{\boldsymbol{q}} +\newcommand{\bfx}{\boldsymbol{x}} +\newcommand{\bfu}{\boldsymbol{u}} +\newcommand{\bfv}{\boldsymbol{v}} +\newcommand{\bfA}{\boldsymbol{A}} +\newcommand{\bfB}{\boldsymbol{B}} +\newcommand{\bfC}{\boldsymbol{C}} +\newcommand{\bfM}{\boldsymbol{M}} +\newcommand{\bfJ}{\boldsymbol{J}} +\newcommand{\bfR}{\boldsymbol{R}} +\newcommand{\bfT}{\boldsymbol{T}} +\newcommand{\bfomega}{\boldsymbol{\omega}} +\newcommand{\bftau}{\boldsymbol{\tau}} +$$ + diff --git a/chapters/mathematical_background/mathematical_background.md b/chapters/mathematical_background/mathematical_background.md new file mode 100644 index 000000000..7cad9457b --- /dev/null +++ b/chapters/mathematical_background/mathematical_background.md @@ -0,0 +1,13 @@ +# Mathematical Background + +No matter who you ask, programming requires at least a little math. +That said, for most programmers, it doesn't require *too* much. +For the most part, depending on your specialty, you will probably not see too much calculus or differential equations. +Honestly, you could probably get away with what you learned in high school. + +However, this is a book about algorithms, and algorithms sometimes require a deeper understanding of mathematics. +This section attemps to provide the mathematical foundations that you will need to understand certain algorithms. +As we add new algorithms and need new mathematical tools, we will add them to this section. + +A notable exception to this rule will be in the case of classes of algorithms that require domain-specific knowledge, like quantum simulations or bioinformatics. +In those cases, we will place the mathematical methods in more relevant sections. diff --git a/chapters/principles_of_code/notation/notation.md b/chapters/mathematical_background/notation/notation.md similarity index 100% rename from chapters/principles_of_code/notation/notation.md rename to chapters/mathematical_background/notation/notation.md diff --git a/chapters/principles_of_code/notation/out.dat b/chapters/mathematical_background/notation/out.dat similarity index 100% rename from chapters/principles_of_code/notation/out.dat rename to chapters/mathematical_background/notation/out.dat diff --git a/chapters/principles_of_code/notation/res/cplot.png b/chapters/mathematical_background/notation/res/cplot.png similarity index 100% rename from chapters/principles_of_code/notation/res/cplot.png rename to chapters/mathematical_background/notation/res/cplot.png diff --git a/chapters/mathematical_background/taylor_series/taylor_series.md b/chapters/mathematical_background/taylor_series/taylor_series.md new file mode 100644 index 000000000..4cf7df71f --- /dev/null +++ b/chapters/mathematical_background/taylor_series/taylor_series.md @@ -0,0 +1,68 @@ +NOTE: Incomplete! + +# Taylor Series Expansion + +I have been formally trained as a physicist. In my mind, there are several mathematical topics that blur the boundary between mathematics and physics. Taylor Series Expansions are one of those topics. + +On the one hand, I can see how the expansion could be considered purely mathematical. I mean, here is the definition: +$$ +f(x) \simeq \sum_{n=0}^{\infty} \frac{f^{(n)}(a)}{n!}(x-a)^n +$$ + +where $$f(x)$$ is some function along real or complex space, $$a$$ is the point that we are expanding from, and $$f^{(n)}(x)$$ denotes the $$n^{\text{th}}$$ derivative of $$f(x)$$. +From this perspective, the expansion just looks like a bunch of derivatives strung together! Where's the physics? Well, let's expand this series for the first few derivatives: + +$$ +f(x) \simeq f(a) + \frac{df(a)}{dx}(x-a) + + \frac{1}{2}\frac{d^2f(a)}{dx^2}(x-a)^2 +$$ + +If we substitute the derivatives for their physical quantities with $$f(x) \rightarrow x(t)$$, expanding from 0, and set + +$$ +\begin{align} +\frac{dx(t)}{dt} &= \text{velocity} = v(t) \\ +\frac{d^2x(t)}{dt^2} &= \text{acceleration} = a \\ +\end{align} +$$ + +The Taylor series expansion turns into one of the most common formulas in classical physics, the *kinematic equation*! + +$$ +x(t) \simeq x_0 + v_0t + + \frac{1}{2}at^2 +$$ + +Note that here, we assume the acceleration to be constant, but it could technically have higher order terms. + +Truth be told, the Taylor Series Expansion can be found in the most unusual places and is used as the foundation of many different algorithms throughout this book. At first, it might not seem obvious why, but we can approximate almost any smooth function with a Taylor Series Expansion, and the more terms we include, the better our approximation becomes! For example, take Figure 1. Any function can be approximated as a sum of all the derivatives for that function. If we evaluate these derivatives at any point, we closely approximate the actual function. + +

+ +

+ +This shows the true power of the Taylor Series Expansion. It allows us to more easily tackle complicated functions by approximating them as functions we can actually use and imagine! + + +$$ +\newcommand{\d}{\mathrm{d}} +\newcommand{\bff}{\boldsymbol{f}} +\newcommand{\bfg}{\boldsymbol{g}} +\newcommand{\bfp}{\boldsymbol{p}} +\newcommand{\bfq}{\boldsymbol{q}} +\newcommand{\bfx}{\boldsymbol{x}} +\newcommand{\bfu}{\boldsymbol{u}} +\newcommand{\bfv}{\boldsymbol{v}} +\newcommand{\bfA}{\boldsymbol{A}} +\newcommand{\bfB}{\boldsymbol{B}} +\newcommand{\bfC}{\boldsymbol{C}} +\newcommand{\bfM}{\boldsymbol{M}} +\newcommand{\bfJ}{\boldsymbol{J}} +\newcommand{\bfR}{\boldsymbol{R}} +\newcommand{\bfT}{\boldsymbol{T}} +\newcommand{\bfomega}{\boldsymbol{\omega}} +\newcommand{\bftau}{\boldsymbol{\tau}} +$$ + diff --git a/chapters/principles_of_code/building_blocks/building_blocks.md b/chapters/principles_of_code/building_blocks/building_blocks.md deleted file mode 100644 index 12cf2b5ca..000000000 --- a/chapters/principles_of_code/building_blocks/building_blocks.md +++ /dev/null @@ -1,9 +0,0 @@ -## Building Blocks - -When it comes to programming, there are certain features that will be used again and again, so it's a good idea to mention how these features work and where they are used. -This section attempts to explain anything that might confuse beginner programmers; however, it is not meant as an exhaustive list of every tool available in the coding toolbox. -Instead, it's meant to provide an accessible understanding of the data structures used throughout this text and the pseudocode that will be used to express these structures. - -It's worth pointing out that algorithms and data stuctures almost always go hand-in-hand. -There are many different ways to climb a mountain, but depending on the mountain you need to climb, you might need different tools. -Similarly, many different algorithms do similar tasks; however, with the right data structures, some algorithms become much more efficient than others. diff --git a/chapters/principles_of_code/building_blocks/classes.md b/chapters/principles_of_code/building_blocks/classes.md deleted file mode 100644 index 371894b1a..000000000 --- a/chapters/principles_of_code/building_blocks/classes.md +++ /dev/null @@ -1,26 +0,0 @@ -### Classes and Structs - -A while ago, one of my friends asked me the purpose of classes in programming. -No matter what I did or how I tried to reason with him, I could not convince him that classes were useful and necessary programming constructs. -To put it simply, classes are data types that allow programmers to store multiple data types within them. -That said, depending on the language, classes might look slightly different. -For example, Julia forgoes classes altogether and simply allows programmers to define a type of types. -I am personally a fan of this approach and will be using it the bulk psuedocode for this text: - -```julia -type Human - Height::Float64 - Weight::Float64 - Popularity::Float64 -end -``` - -Now, here's where things get a little sticky. -The truth is that there is a philosophical difference between how languages implement classes (among other things), which basically boils down to whether languages allow functions to be held within data types or not. -*Functional* programming languages argue that functions should always act on data types. -*Object-Oriented* languages argue that certain data types (like Human, above), should be able to *do* things, so it makes sense to put functions within classes. -There is merit to both of these arguments, so it's best to go with whatever you feel comfortable with. - -In the case of object-oriented languages, classes have an additional layer of complexity associated with them that should definitely be discussed. -That said, I would like to forgo that discussion at this time and come back to it in the near future. -Please bug me if you think I might have forgotten! diff --git a/chapters/principles_of_code/building_blocks/conditions.md b/chapters/principles_of_code/building_blocks/conditions.md deleted file mode 100644 index 41a8ec979..000000000 --- a/chapters/principles_of_code/building_blocks/conditions.md +++ /dev/null @@ -1,102 +0,0 @@ -### Conditions - -Of all the programming building blocks, conditions might be the most intuitive and they basically flow from natural speech. -Let's say you are up late studying for an exam schedule for later in the month, but you are finding yourself lacking in motivation and distracted by the internet. -You hate wasting time, so you try to figure out how tired you are and think to yourself, *if I am tired, I will go to sleep. Otherwise, I should get back to work!* -In code, this looks like: - -```julia -if (me.tired() == true) - me.sleep() -else - me.work() -end -``` - -Here, we are assuming you are a type of `human` with the abilities to both `sleep()` and `work()`. -Note that the condition is checking to see if the statement provided is `true` or `false` before continuing. -In other words, it is condensing the statement `me.tired() == true` into a simple boolean value. -This is important to remember when dealing with loops later. -Conditions allow you to modify the flow of your program depending on other values produced and are a powerful and intuitive tool. - -It's worth noting here that all the mathematical conditions work in these statements: - -| Symbol | Meaning | -| --------------------------- | --------------------------------------- | -| a == b | a is equal to b | -| a > b | a is greater than b | -| a < b | a is less than b | -| a != b | a is not equal to b | -| a == b && b == c | a is equal to b **and** b is equal to c | -| a == b || b == c | a is equal to b **or** b is equal to c | - -Here, the `&&` operator means both conditions must be `true` for the statement as a whole to be considered `true`, while the `||` operator means that only one of the two statements must be `true` for the statement to be considered `true`. -Also note that the `!` operator can be used in front of boolean values to signify the value should be to opposite. -For example, if you are trying to indicate that you are not tired (even though you clearly are), you might say `!me.tired()`. -`me.tired()` will return `true`, but the `!` operator will flip the `true` to `false`. - -In addition to the `if` and `else` keywords, there is also the `else if`, which varies notationally depending on the language you are using. -Imagine that we wanted to add two additional functions to the `human` type: `care()`, which evaluates the amount you care about a particular topic and `procrastinate()`, which is the action of wasting time. -Imagine (again) that you are studying for an exam that is a month away, but this time, you are studying for a class you do not care about. -You might update your thought to be something like, *if I am tired, I will go to sleep. If I don't care about the class, I can continue procrastinating. Otherwise, I should get back to work!* -In code, this looks like: - -```julia -if (me.tired()) - me.sleep() -else if(!me.care()) - me.procrastinate() -else - me.work() -end -``` - -To be clear: if `me.care()` returns `true`, then the `!` will flip the statement in the `else if` to `false`, and thus you will not procrastinate. -If `me.care()` returns `false`, the `!` will flip the statement to `true` and you will begin procrastinating if you are not tired. -This might take a little thought, and I encourage you to meditate on it, if you so desire. - -Now on to something slightly more complicated: *switches*. -Imagine you have a lot of conditions to keep in mind, all of which depend on the same variable. -You couldgo through these conditions one-by-one with a chain of `if` and `else if` conditions, like so: - -```julia -if (val == 0) - scenario_0() -else if (val == 1) - scenario_1() -else if (val == 2) - scenario_2() -else if (val == 3) - scenario_3() -else - scenario_4() -end -``` -Here, we need to run different functions depending on the value of the variable `val`. -In these cases, it's worth bringing in a faster and sometimes more elegant solution: the `switch` statement. - -```julia -switch(val) - case 0: - scenario_0() - break - case 1: - scenario_1() - break - case 2: - scenario_2() - break - case 3: - scenario_3() - break - case 4: - scenario_4() - break -end -``` - - -To clarify: not all languages have a `switch` statement, and as mentioned, it's not precisely necessary. -That said, in languages that do have a `switch`, it's often preferred to a chain of `else if` statements; - -Though simple, conditions are essential to almost all modern code, so get used to seeing them everywhere! diff --git a/chapters/principles_of_code/building_blocks/functions.md b/chapters/principles_of_code/building_blocks/functions.md deleted file mode 100644 index 128441247..000000000 --- a/chapters/principles_of_code/building_blocks/functions.md +++ /dev/null @@ -1,82 +0,0 @@ -### Functions - -Functions make sense from a mathematical point of view. -$$f(x) = 2x+5$$ returns a value for $$f(x)$$ at any point $$x$$ that you want. -For example $$f(5) = 15$$, or $$f(10) = 25$$. -Often times, the function is graphed for *every point* indicating the precise nature of how the function and variable relate to one another, but that is another matter entirely. -For the most part, functions in programming work exactly the same way. -They are dependent on certain variables and return something at the end. -In code, the above function might look like: - -``` -function f(x) - return 2*x+5 -end -``` - -Syntactically, they are a little different, but the content is identical. -That said, it's not obvious how functions help when writing code at this point; however, this will become incredibly obvious once you see them in action. -Basically, functions allow programmers to create reusable operations that can be called at any point in the code. -In a sense, functions make understanding code much, much easier. - -### Recursion - -Simply put, recursion is the process of putting a function inside itself. -Now, I know what you are thinking, "Why does this deserve a special name?" -That is a very good question and one that tooke me a while to understand. -Let's take a simple example: - -```julia -function f(x) - x = x + 1 - f(x) -end -``` - -Every time `f(x)` is called, it calls `f(x)`, which then calls `f(x)` again and again and again... -Basically, we just replicated a `while` loop! -The problem here is that *we forgot a stop condition!* -This means that our function will run forever, constantly incrementing the value of x for all eternity! - -There are many possible solutions, one of which looks like this: - -```julia -function f(x, cutoff) - if (x < cutoff) - x = x + 1 - f(x) - end -end -``` - -In the end, no matter how you choose to use recursion, you need to think carefully about what you want the code to do. -For example, in the case shown here, recursion is definitely not the most straightforward way to increment the value of $$x$$ by $$1$$. -In some cases, though, recursion not only makes the code easier to use and understand, but it might also be the only way to solve a provided problem. -In addition, the proper use of recursion can speed up certain code tremendously. - -I guess the main point is this: *recursion is powerful, but with great power comes great resposibility!* - - - -$$ -\newcommand{\d}{\mathrm{d}} -\newcommand{\bff}{\boldsymbol{f}} -\newcommand{\bfg}{\boldsymbol{g}} -\newcommand{\bfp}{\boldsymbol{p}} -\newcommand{\bfq}{\boldsymbol{q}} -\newcommand{\bfx}{\boldsymbol{x}} -\newcommand{\bfu}{\boldsymbol{u}} -\newcommand{\bfv}{\boldsymbol{v}} -\newcommand{\bfA}{\boldsymbol{A}} -\newcommand{\bfB}{\boldsymbol{B}} -\newcommand{\bfC}{\boldsymbol{C}} -\newcommand{\bfM}{\boldsymbol{M}} -\newcommand{\bfJ}{\boldsymbol{J}} -\newcommand{\bfR}{\boldsymbol{R}} -\newcommand{\bfT}{\boldsymbol{T}} -\newcommand{\bfomega}{\boldsymbol{\omega}} -\newcommand{\bftau}{\boldsymbol{\tau}} -$$ - diff --git a/chapters/principles_of_code/building_blocks/loops.md b/chapters/principles_of_code/building_blocks/loops.md deleted file mode 100644 index 12062ff34..000000000 --- a/chapters/principles_of_code/building_blocks/loops.md +++ /dev/null @@ -1,59 +0,0 @@ -### Loops - -Loops are weird. I'm not going to lie, it took me a super long time to figure out how and when to use them appropriately. -Nowadays, I see them as essential elements to almost any program I write. -There two basic loop types: `for` and `while`, which are syntactically similar and reasonably intuitive. -Let's say you want to walk out of a room with a closed door. -In code, this might look something like: - -```julia -while(me.position < door.position) - me.take_step() -end - -me.open_door() -``` - -Like before, we assume that you are part of a type of `human`s with the functions `take_step()` and `open_door()`. -Here, the `while` loop simply keeps going until the condition is no longer met, and it's assumed that the `take_step()` function changes your `position` value. -When the condition returns `false`, we assume that you are either at the door or have run into it, so it's safe to assume you can use the `open_door()` function. - -The other possible loop type is the `for` loop, which is arguable more common and iterates through a container (such as `vectors` mentioned before). -Often times, the `for` loop will look something like this: - -```julia -for i = 1:10 - print(i) -end -``` - -In this case, we are creating a range of values between $$1$$ and $$10$$ and setting the value of $$i$$ every iteration of the loop. -In this case $$i$$ is an interable variable that steps through the range of `1:10`, and is the primary reason for using a `for` loop instead of a `while` loop for the same task. -To be clear, $$i$$ does not need to iterate through integers and could instead iterate through any number of types held in some other container. - -Ultimately, loops allow programmers to repeat the same operation multiple times and are the heart most programs and simulations I have seen. - - - -$$ -\newcommand{\d}{\mathrm{d}} -\newcommand{\bff}{\boldsymbol{f}} -\newcommand{\bfg}{\boldsymbol{g}} -\newcommand{\bfp}{\boldsymbol{p}} -\newcommand{\bfq}{\boldsymbol{q}} -\newcommand{\bfx}{\boldsymbol{x}} -\newcommand{\bfu}{\boldsymbol{u}} -\newcommand{\bfv}{\boldsymbol{v}} -\newcommand{\bfA}{\boldsymbol{A}} -\newcommand{\bfB}{\boldsymbol{B}} -\newcommand{\bfC}{\boldsymbol{C}} -\newcommand{\bfM}{\boldsymbol{M}} -\newcommand{\bfJ}{\boldsymbol{J}} -\newcommand{\bfR}{\boldsymbol{R}} -\newcommand{\bfT}{\boldsymbol{T}} -\newcommand{\bfomega}{\boldsymbol{\omega}} -\newcommand{\bftau}{\boldsymbol{\tau}} -$$ - diff --git a/chapters/principles_of_code/building_blocks/variables.md b/chapters/principles_of_code/building_blocks/variables.md deleted file mode 100644 index a27ea350c..000000000 --- a/chapters/principles_of_code/building_blocks/variables.md +++ /dev/null @@ -1,113 +0,0 @@ -### Variable and Types - -For many people, declaring variables and types is a straightforward process. -The idea is simple: variables hold values. -We set these values with the `=` sign. -For example, if we say - -``` -x = 5 -``` -Then we have set the value of the variable $$x$$ to be $$5$$. -But here's a question that your computer has to answer: what is $$5$$? - -To us, the answer's trivial, it's a number! -This is true, but there are different kinds of numbers. -There are integers that include all counting numbers from negative to positive infinity: $$-\infty, \cdots, -1, 0, 1, \cdots, \infty$$. -Then there are floating-point numbers which include everything in-between every counting number; however, that is not the end of the story. -Floating-point numbers also have certain levels of precision, the numbers of $$0$$'s after the decimal point. -For example, $$1.01$$ is more precise than $$1.0$$. -Each of these levels of precision will require a different level of storage space on the computer, so it make sense to differentiate them based on the amount of storage they require. -In the end, all of these variables will be stored as some number, $$n$$, binary bits, which are constrained to be either $$0$$ or $$1$$ and as we increase the number of bits, we can hold $$2^n$$ possible values. - -This means that we have multiple different floating-point and integer types: `float16`, `int16`, `float32`, `int32`, `float64`, `int64`, and so on. -Here, the number ($$16, 32, 64,\cdots$$) at the end of the declared variable corresponds to the number of bits used to represent that number. -For the most part, *double precision* or `float64` is good enough for almost all computation; however, sometimes higher precision is necessary and other times lower precision will speed up computation tremendously. - -Most languages allow you to explicitly state the type of every variable, but some languages may treat these variables differently than expected, depending on the type provided. -For example: - -``` -float x = 5 -int y = 5 - -print(1/x) -print(1/y) -``` - ----- -**OUTPUT** -``` -0.2 -0 -``` - -Here, the same mathematical expression provided two radically different results! -Now, you might be thinking that the first output is *more correct*, but this is not exactly true. -The second expression was simply a case of *integer division* and is useful in many cases. -Unfortunately, it is also a notorious source of errors, which is why it's always a good idea to check the types of all variables in a program just to be sure you are doing the appropriate computation. -To be explicit: - -``` -1/5 != 1.0/5.0 -``` - -It's important to keep in mind what you are trying to say and what your computer hears you saying. - -Now, variables do not need to be explicitly numbers. -They can be strings (`"hello world!"`), or any data structure you could want. -These data structures will interact with each other differently and these interactions are sometimes language-dependent, so be careful when working with them! -In addition, some of these data structures have functions unique to them that me may call upon as programmers. - -For example, `vectors` are data containers that hold other data structures. -In almost every language, there is a function that can be used to get the size of a `vector` in order to tell how many elements it holds. -In addition, the vector also has methods to `push` elements into it. - -In C++, for example, vectors often look like this: - -```cpp -#include - -... -// Creating a vector of integers -std::vector vector_of_ints; - -//Adding elements to our vector_of_ints -vector_of_ints.push_back(1); -vector_of_ints.push_back(2); -vector_of_ints.push_back(3); - -// Finding size of our vector_of_ints -vector_of_ints.size(); - -... -``` - -Here, the `size()` function should return 3, because we have put in 3 elements. -We will talk more about vectors in a bit, but for now, know that certain functions are available to be used on certain types, and in most object-oriented languages, these functions are called with a simple `.`. -Almost all laguages also allow users to define their own types in the form of `classes`, which will also be touched on later in this section. - - - -$$ -\newcommand{\d}{\mathrm{d}} -\newcommand{\bff}{\boldsymbol{f}} -\newcommand{\bfg}{\boldsymbol{g}} -\newcommand{\bfp}{\boldsymbol{p}} -\newcommand{\bfq}{\boldsymbol{q}} -\newcommand{\bfx}{\boldsymbol{x}} -\newcommand{\bfu}{\boldsymbol{u}} -\newcommand{\bfv}{\boldsymbol{v}} -\newcommand{\bfA}{\boldsymbol{A}} -\newcommand{\bfB}{\boldsymbol{B}} -\newcommand{\bfC}{\boldsymbol{C}} -\newcommand{\bfM}{\boldsymbol{M}} -\newcommand{\bfJ}{\boldsymbol{J}} -\newcommand{\bfR}{\boldsymbol{R}} -\newcommand{\bfT}{\boldsymbol{T}} -\newcommand{\bfomega}{\boldsymbol{\omega}} -\newcommand{\bftau}{\boldsymbol{\tau}} -$$ - diff --git a/chapters/principles_of_code/code_quality.md b/chapters/principles_of_code/code_quality.md deleted file mode 100644 index c4ed35ac2..000000000 --- a/chapters/principles_of_code/code_quality.md +++ /dev/null @@ -1,19 +0,0 @@ -## Code Quality - -I am a computational physicist. Industry programmers give researchers a hard time for their programming capabilities, not because they cannot code, but because (for the most part) research code looks bad. -Programming, like any other form of creative expression, is limited by the artist's ability to creatively express themselves. -For many computational researchers, the code is not their art. Science is. -Programming is simply the brush they use to stroke the canvas of reality. -Many times, they become so consumed with their painting that they ignore their tools. Now, truth be told, I have seen some pretty repulsive industry code, too, so this complaint is not exclusively biased towards researchers. - -No matter what the intended goal might be, it is important to be able to read and understand the code you are writing. I know putting a comment block at the start of programs might seem like a chore, but it's not so bad, and letting everyone know up-front what the code is intended to do is incredibly useful to readers. Remember that in a few months, you will be a reader too. Take the time to properly care for your code, to clean your brush after using it. It'll pay off in the long run, I promise. - -### Comments / style - -Comments. Every language has a different way to introduce them. Some use the noble #, others the //, still others the ! or $ or C. Regardless of your language of choice, every single language offers you the ability to tell readers what you are intending to do with your code. This is a necessary component to programming. In fact, I would argue that it is one of the most useful part of any code. Sure, the code has to work. It's gotta compile and do something useful, but I cannot tell you how many times I have had to fix broken code that no one had looked at for years. Sometimes this is a long and laborious process, taking every ounce of my mental abilities, and other times it only takes a few minutes. What's the difference? Comments and documentation. - -I remember the first time I learned to program, I found commenting tedious. I remember thinking, "Hah. This is completely useless. Any programmer worth their salt will be able to figure out what I am trying to do in no time!" Turns out, I wasn't worth my salt because after trying to figure out my code a month later, I couldn't figure out what on Earth I was trying to do. Here's the truth: when it comes to programming, you are often your own audience. Trust me, I know it seems like a good idea to keep the code short -- to go for witty one-liners that make you feel brilliant, but these make your code impossible to read. - -When researching, we keep lab notebooks. It's common practice for obvious reasons. If I forget what I was doing the other day or need to look up parameters, I check the lab notebook. If other researchers question the results of my simulations, I check my lab notebook. If I don't know what to do because I have tried everything I can possibly think of, I check my lab notebook. It's a place for inspiration, for validation, and for guidance. When programming, your code should tell the story of your program. It should reveal the hidden secrets that make your code tick. If anyone finds a bug in the code downstream, they should be able to figure out exactly what went wrong and fix it themselves. - -I guess my point is that commenting your code and keeping proper documentation is about more than just cleaning up after yourself. It is a fundamental part to the art of programming. It's like polishing your guitar on a sunny day. It's revising your poems after a long evening of writing. It's levelling your monk before the next raid. It's essential. Do not neglect it! diff --git a/chapters/principles_of_code/principles_of_code.md b/chapters/principles_of_code/principles_of_code.md deleted file mode 100644 index 7e7a58ec3..000000000 --- a/chapters/principles_of_code/principles_of_code.md +++ /dev/null @@ -1,30 +0,0 @@ -# The Principles of Code - -At least to me, programming is a form of creative expression. Sure, programming is difficult. It's difficult in the same way that art, music, or writing is difficult: you know exactly what you want to create, but it takes time to learn how to create it. As I mentioned previously, for a significant portion of my life, I wanted to be an author, so I spent hours and hours every day writing fantasy novels. The more I wrote, the better I got at writing, but when I went back to read the initial chapters of my books, I was frankly revolted at how poor my writing was. By the time I finished revising those chapters and writing more on the side, I felt that the second half of the story was in need of revision too. In the end, I wrote and re-wrote and re-wrote again until I was sick of the story altogether, so I wrote something else. Same characters, different story. It was a vicious cycle that ultimately lead to failure on my part to publish anything. - -Here's that cycle again in code: - -```julia -type Human - ability::Int64 - standard::Int64 -end - -function create_something(me::Human) - while (me.ability < me.standard) - me.ability += 1 - me.standard += 1 - println("I am not good enough. Continuing...") - end -end - -create_something(Human(0,1)) -``` - -I am sure this has a name, but I like to call it the *perfectionist's loop*. It's obviously endless and the only way out is by forcing the code to terminate early with `ctrl+c`. Any artist knows this problem. At first, the act of creation is fun, but after a few iterations, it becomes frustrating. Soon, you are curled into a ball in the corner of a room with a paintbrush in your hand and a myriad of colors splattered all over you and the immediate area. In front of you lay the remains of your art, toppled to the ground. It happens. It will probably happen when you learn programming. When it happens, there is only one thing to do: *keep iterating through the loop!* - -The moment you press `ctrl+c` is the moment you stop improving. Don't stop improving. Don't lower your standards. If you ever need motivation to continue, look at who you were a few months ago. You should be "better" than that person. If not, figure out what's holding you back and keep iterating through the loop! - -The problem is that when it comes to programming, there are a bunch of technical problems that crop up and prevent us from improving. This chapter is specifically written to help you make decisions and improve your ability to program. We'll start with choosing a language -- a question that kept me from even starting programming to begin with. Then we'll move on to programming building blocks and important data structures to remember. The idea is that we'll link to the building block sections when necessary throughout the book. This section will probably be the section that changes the most frequently as the archive evolves. after all, the more algorithms we cover, the more building blocks will be necessary to write them. - -As always, let me know if there's anything that is unclear or you think needs to be fixed! Thanks for reading and good luck! From 21d77c4f20943dea387ce27f1fa39a3467848fa4 Mon Sep 17 00:00:00 2001 From: leios Date: Sun, 15 Jul 2018 21:13:26 +0900 Subject: [PATCH 2/3] Revert "removing principles of code chapter." This reverts commit 26ececd96cc142991b4314c7f98455d6eb5c2850. --- SUMMARY.md | 29 ++-- TODO.md | 29 ++++ chapters/data_structures/data_structures.md | 4 - chapters/introduction/how_to_contribute.md | 2 +- .../convolutions/code/c++/convolutions.cpp | 130 ----------------- .../convolutions/code/c/convolutions.c | 68 --------- .../convolutions/code/c/fft.h | 41 ------ .../convolutions/code/haskell/convolution.hs | 5 - .../convolutions/code/julia/conv.jl | 22 --- .../convolutions/convolutions.md | 133 ------------------ .../mathematical_background.md | 13 -- .../taylor_series/taylor_series.md | 68 --------- .../building_blocks}/bitlogic.md | 6 +- .../building_blocks/building_blocks.md | 9 ++ .../building_blocks/classes.md | 26 ++++ .../building_blocks/conditions.md | 102 ++++++++++++++ .../building_blocks/functions.md | 82 +++++++++++ .../building_blocks/loops.md | 59 ++++++++ .../building_blocks}/res/and.jpg | Bin .../building_blocks}/res/nand.jpg | Bin .../building_blocks}/res/nor.jpg | Bin .../building_blocks}/res/not.jpg | Bin .../building_blocks}/res/or.jpg | Bin .../building_blocks}/res/xor.jpg | Bin .../building_blocks/stacks.md} | 0 .../building_blocks/variables.md | 113 +++++++++++++++ .../choosing_a_language.md | 0 .../choosing_a_language}/compiled/FORTRAN.md | 0 .../choosing_a_language}/compiled/compiled.md | 0 .../compiled/makefiles.md | 0 chapters/principles_of_code/code_quality.md | 19 +++ .../notation/notation.md | 0 .../notation/out.dat | 0 .../notation/res/cplot.png | Bin .../principles_of_code/principles_of_code.md | 30 ++++ .../res/clone.png | Bin .../res/fork.png | Bin .../version_control.md | 0 38 files changed, 494 insertions(+), 496 deletions(-) create mode 100644 TODO.md delete mode 100644 chapters/data_structures/data_structures.md delete mode 100644 chapters/mathematical_background/convolutions/code/c++/convolutions.cpp delete mode 100644 chapters/mathematical_background/convolutions/code/c/convolutions.c delete mode 100644 chapters/mathematical_background/convolutions/code/c/fft.h delete mode 100644 chapters/mathematical_background/convolutions/code/haskell/convolution.hs delete mode 100644 chapters/mathematical_background/convolutions/code/julia/conv.jl delete mode 100644 chapters/mathematical_background/convolutions/convolutions.md delete mode 100644 chapters/mathematical_background/mathematical_background.md delete mode 100644 chapters/mathematical_background/taylor_series/taylor_series.md rename chapters/{mathematical_background/bitlogic => principles_of_code/building_blocks}/bitlogic.md (99%) create mode 100644 chapters/principles_of_code/building_blocks/building_blocks.md create mode 100644 chapters/principles_of_code/building_blocks/classes.md create mode 100644 chapters/principles_of_code/building_blocks/conditions.md create mode 100644 chapters/principles_of_code/building_blocks/functions.md create mode 100644 chapters/principles_of_code/building_blocks/loops.md rename chapters/{mathematical_background/bitlogic => principles_of_code/building_blocks}/res/and.jpg (100%) rename chapters/{mathematical_background/bitlogic => principles_of_code/building_blocks}/res/nand.jpg (100%) rename chapters/{mathematical_background/bitlogic => principles_of_code/building_blocks}/res/nor.jpg (100%) rename chapters/{mathematical_background/bitlogic => principles_of_code/building_blocks}/res/not.jpg (100%) rename chapters/{mathematical_background/bitlogic => principles_of_code/building_blocks}/res/or.jpg (100%) rename chapters/{mathematical_background/bitlogic => principles_of_code/building_blocks}/res/xor.jpg (100%) rename chapters/{data_structures/stacks_and_queues/stacks_and_queues.md => principles_of_code/building_blocks/stacks.md} (100%) create mode 100644 chapters/principles_of_code/building_blocks/variables.md rename chapters/{languages => principles_of_code/choosing_a_language}/choosing_a_language.md (100%) rename chapters/{languages => principles_of_code/choosing_a_language}/compiled/FORTRAN.md (100%) rename chapters/{languages => principles_of_code/choosing_a_language}/compiled/compiled.md (100%) rename chapters/{languages => principles_of_code/choosing_a_language}/compiled/makefiles.md (100%) create mode 100644 chapters/principles_of_code/code_quality.md rename chapters/{mathematical_background => principles_of_code}/notation/notation.md (100%) rename chapters/{mathematical_background => principles_of_code}/notation/out.dat (100%) rename chapters/{mathematical_background => principles_of_code}/notation/res/cplot.png (100%) create mode 100644 chapters/principles_of_code/principles_of_code.md rename chapters/{introduction => principles_of_code}/res/clone.png (100%) rename chapters/{introduction => principles_of_code}/res/fork.png (100%) rename chapters/{introduction => principles_of_code}/version_control.md (100%) diff --git a/SUMMARY.md b/SUMMARY.md index 56bf4db6d..c81780ac3 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -1,21 +1,33 @@ # Summary * [Algorithm Archive](README.md) +* [TODO](TODO.md) * [Introduction](chapters/introduction/introduction.md) +* [A Personal Note](chapters/introduction/my_introduction_to_hobby_programming.md) * [How To Contribute](chapters/introduction/how_to_contribute.md) -* [Version Control](chapters/introduction/version_control.md) -* [Data Structures](chapters/data_structures/data_structures.md) - * [Stacks and Queues](chapters/data_structures/stacks_and_queues/stacks_and_queues.md) -* [Mathematical Background](chapters/mathematical_background/mathematical_background.md) - * [Complexity Notation](chapters/mathematical_background/notation/notation.md) - * [Bit Logic](chapters/mathematical_background/bitlogic/bitlogic.md) - * [Convolutions](chapters/mathematical_background/convolutions/convolutions.md) - * [Taylor Series](chapters/mathematical_background/taylor_series/taylor_series.md) +* [Principles of Code](chapters/principles_of_code/principles_of_code.md) + * [Choosing A Language](chapters/principles_of_code/choosing_a_language/choosing_a_language.md) + * [Compiled Languages](chapters/principles_of_code/choosing_a_language/compiled/compiled.md) + * [Makefiles](chapters/principles_of_code/choosing_a_language/compiled/makefiles.md) + * [FORTRAN](chapters/principles_of_code/choosing_a_language/compiled/FORTRAN.md) + * [Building Blocks](chapters/principles_of_code/building_blocks/building_blocks.md) + * [Variables and Types](chapters/principles_of_code/building_blocks/variables.md) + * [Conditions](chapters/principles_of_code/building_blocks/conditions.md) + * [Loops](chapters/principles_of_code/building_blocks/loops.md) + * [Functions](chapters/principles_of_code/building_blocks/functions.md) + * [Classes](chapters/principles_of_code/building_blocks/classes.md) + * [Stacks and Queues](chapters/principles_of_code/building_blocks/stacks.md) + * [Bit Logic](chapters/principles_of_code/building_blocks/bitlogic.md) + * [Version Control](chapters/principles_of_code/version_control.md) + * [Complexity Notation](chapters/principles_of_code/notation/notation.md) +* [Convolutions](chapters/algorithms/convolutions/convolutions.md) +* [Taylor Series](chapters/general/taylor_series_expansion/taylor_series_expansion.md) * [Sorting and Searching](chapters/general/sorting_and_searching/sorting_and_searching.md) * [Bubble Sort](chapters/algorithms/bubble_sort/bubble_sort.md) * [Bogo Sort](chapters/algorithms/bogo_sort/bogo_sort.md) * [Tree Traversal](chapters/algorithms/tree_traversal/tree_traversal.md) * [Euclidean Algorithm](chapters/algorithms/euclidean_algorithm/euclidean_algorithm.md) +* [Multiplication](chapters/general/multiplication/multiplication.md) * [Monte Carlo](chapters/algorithms/monte_carlo_integration/monte_carlo_integration.md) * [Matrix Methods](chapters/general/matrix_methods/matrix_methods.md) * [Gaussian Elimination](chapters/algorithms/gaussian_elimination/gaussian_elimination.md) @@ -33,6 +45,7 @@ * [Backward Euler Methods](chapters/algorithms/backward_euler_method/backward_euler_method.md) * [Physics Solvers](chapters/general/physics_solvers/physics_solvers.md) * [Verlet Integration](chapters/algorithms/verlet_integration/verlet_integration.md) + * [Barnes-Hut](chapters/algorithms/barnes_hut_algorithm/barnes_hut_algorithm.md) * [Quantum Systems](chapters/general/quantum_systems/quantum_systems.md) * [Split-Operator Method](chapters/algorithms/split-operator_method/split-operator_method.md) * [Data Compression](chapters/general/data_compression/data_compression.md) diff --git a/TODO.md b/TODO.md new file mode 100644 index 000000000..9d19c7a50 --- /dev/null +++ b/TODO.md @@ -0,0 +1,29 @@ +# TO DO + +The Algorithm Archive is currently being written and is quite small at the moment. +This is a list of all the things we need to get done ASAP. +That said, because of my (real-world) work schedule and such, ASAP is not as fast as I'd like, but that's how it goes. +I apologize for taking so long with each chapter, but I figure making this list public is a good step towards being as open as possible. + +## For James (Leios) + +Write: + +* Algorithms already covered (Chan's, Monte Carlo) +* Language choices (Makefiles, Fortran, Julia...). Note that I kinda wanted to turn this into a series of sorts where I review each language with a series of standard tests. + +Revise: + +* Mathematical Background -- Transform into "mathematical methods." + +I'll try to keep this list updated as I write more sections + +## Points of Discussion + +Here are points of discussion that need to be had about the Algorithm Archive before it gets too big and becomes too difficult to revise everything + +* **Should community-submitted code be clean or efficient?** When it comes to writing code, I often feel readability is the most important factor to keep in mind; however, with the code submitted to this archive, there will be pseudocode available to guide new folks through the process of writing the algorithm for the first time. For this reason, it might be best for the community to submit the most efficient code they can write in their own languages, commenting in any tricks to improve performance. +* **Is the current method of writing optimal?** When I originally envisioned this project, I thought that I would do all the writing and the community would do (most of) the coding. That said, I am becoming more open to the idea of letting community members write for the Archive. The advantage to this is obvious: The book gets written faster. The disadvantage is also obvious: We lose focus and consistency throughout the book. +* **We need a Logo.** I have no idea how to go about this. Maybe a logo contest at 16384 subscribers on youtube? The project will be large enough at that point to warrant a good logo. I really want something simple, though, like a [Trefoil Knot](https://en.wikipedia.org/wiki/Trefoil_knot#/media/File:Trefoil_knot_left.svg) or something. It kinda looks like 3 A's if you look at it the right way, and we'll definitely cover knot algorithms at some point because they are fascinating! + +Anyway, let me know what you think. I love the community we have here and appreciate all the conversations we've had so far! diff --git a/chapters/data_structures/data_structures.md b/chapters/data_structures/data_structures.md deleted file mode 100644 index 2ec5efbe3..000000000 --- a/chapters/data_structures/data_structures.md +++ /dev/null @@ -1,4 +0,0 @@ -# Data Structures - -This is a book about algorithms. -The fundamental building blocks of algorithms are data structures, and thus as more algorithms are added to the Archive, more data structures will be added to this section. diff --git a/chapters/introduction/how_to_contribute.md b/chapters/introduction/how_to_contribute.md index 073cdb125..f1209e07b 100644 --- a/chapters/introduction/how_to_contribute.md +++ b/chapters/introduction/how_to_contribute.md @@ -2,7 +2,7 @@ The *Algorithm Archive* is an effort to learn about and teach algorithms as a community. As such, it requires a certain level of trust between community members. -For the most part, the collaboration can be done via GitHub and gitbook, so it is important to understand the basics of [version control](version_control.md). +For the most part, the collaboration can be done via GitHub and gitbook, so it is important to understand the basics of [version control](../principles_of_code/version_control.md). Ideally, all code provided by the community will be submitted via pull requests and discussed accordingly; however, I understand that many individuals are new to collaborative projects, so I will allow submissions by other means (comments, tweets, etc...). As this project grows in size, it will be harder and harder to facilitate these submissions. In addition, by submitting in any way other than pull requests, I cannot guarantee I will be able to list you as a collaborator (though I will certainly do my best to update the `CONTRIBUTORS.md` file accordingly). diff --git a/chapters/mathematical_background/convolutions/code/c++/convolutions.cpp b/chapters/mathematical_background/convolutions/code/c++/convolutions.cpp deleted file mode 100644 index e2b8e9c6b..000000000 --- a/chapters/mathematical_background/convolutions/code/c++/convolutions.cpp +++ /dev/null @@ -1,130 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -// These headers are for presentation not for the algorithm. -#include -#include -#include - -using std::begin; -using std::end; -using std::swap; - -using std::ptrdiff_t; -using std::size_t; - -using c64 = std::complex; -template -constexpr T pi() { - return 3.14159265358979323846264338327950288419716; -} - -// This section is not a part of the algorithm -template -void fft(Iter const first, Iter const last) { - auto const size = last - first; - if (size >= 2) { - auto temp = std::vector(size / 2); - for (ptrdiff_t i = 0; i < size / 2; ++i) { - temp[i] = first[i * 2 + 1]; - first[i] = first[i * 2]; - } - for (ptrdiff_t i = 0; i < size / 2; ++i) { - first[i + size / 2] = temp[i]; - } - - auto const split = first + size / 2; - fft(first, split); - fft(split, last); - - for (ptrdiff_t k = 0; k < size / 2; ++k) { - auto w = std::exp(c64(0, -2.0 * pi() * k / size)); - - auto& bottom = first[k]; - auto& top = first[k + size / 2]; - top = bottom - w * top; - bottom -= top - bottom; - } - } -} - -template -void inverse_fft(Iter const first, Iter const last) { - std::for_each(first, last, [](auto& it) { it = std::conj(it); }); - - fft(first, last); - - auto const size = static_cast(last - first); - std::for_each(first, last, [&](auto& it) { it = std::conj(it) / size; }); -} - -// This section is a part of the algorithm - -template -void conv( - S1 const s1, - S1 const s1_last, - S2 const s2, - S2 const s2_last, - Out const out) { - auto const size1 = s1_last - s1; - auto const size2 = s2_last - s2; - auto const size = size1 + size2; - - for (ptrdiff_t i = 0; i < size; ++i) { - c64 sum = 0; - for (ptrdiff_t j = 0; j < i; ++j) { - if (j < size1) { - sum += s1[j] * s2[i - j]; - } - } - out[i] = sum; - } -} - -template -void conv_fft(S1 const s1, S1 const s1_last, S2 const s2, Out const out) { - auto const size = s1_last - s1; - - fft(s1, s1_last); - fft(s2, s2 + size); - - auto s1_it = s1; - auto s2_it = s2; - auto out_it = out; - for (; s1_it != s1_last; ++s1_it, ++s2_it, ++out_it) { - *out_it = *s1_it * *s2_it; - } - - inverse_fft(out, out_it); -} - -int main() { - auto signal1 = std::array(); - std::fill(begin(signal1) + 16, begin(signal1) + 48, 1); - - auto signal2 = signal1; - - auto out1 = std::array(); - conv(begin(signal1), end(signal1), begin(signal2), end(signal2), begin(out1)); - - auto signal3 = std::array(); - std::copy(begin(signal1), end(signal1), begin(signal3)); - auto signal4 = signal3; - - auto out2 = std::array(); - conv_fft(begin(signal3), end(signal3), begin(signal4), begin(out2)); - - std::cout << std::right << std::setw(16) << "i" << std::setw(16) - << "subtracted" << '\n'; - - for (size_t i = 0; i < signal1.size(); ++i) { - std::cout << std::setw(16) << i << std::setw(16) - << (std::abs(out1[i]) - std::abs(out2[i])) << '\n'; - } -} diff --git a/chapters/mathematical_background/convolutions/code/c/convolutions.c b/chapters/mathematical_background/convolutions/code/c/convolutions.c deleted file mode 100644 index 386285a1d..000000000 --- a/chapters/mathematical_background/convolutions/code/c/convolutions.c +++ /dev/null @@ -1,68 +0,0 @@ -#include "fft.h" - -#include - -void conv(double complex *signal1, double complex *signal2, double complex* out, - size_t n1, size_t n2) { - double complex sum = 0; - - for (size_t i = 0; i < (n1 < n2? n2 : n1); ++i) { - for (size_t j = 0; j < i; ++j) { - if (j < n1) { - sum += signal1[j] * signal2[i-j]; - } - } - out[i] = sum; - sum = 0; - } -} - -void conv_fft(double complex *signal1, double complex *signal2, - double complex* out, size_t n) { - fft(signal1, n); - fft(signal2, n); - - for (size_t i = 0; i < n; ++i) { - out[i] = signal1[i] * signal2[i]; - } - - ifft(out, n); -} - -int main() { - double complex signal1[64], signal2[64], signal3[128], signal4[128], - out1[128], out2[128]; - - for (size_t i = 0; i < 128; ++i) { - if (i >= 16 && i < 48) { - signal1[i] = 1.0; - signal2[i] = 1.0; - signal3[i] = 1.0; - signal4[i] = 1.0; - out1[i] = 0.0; - out2[i] = 0.0; - } else if (i >= 64) { - signal3[i] = 0.0; - signal4[i] = 0.0; - out1[i] = 0.0; - out2[i] = 0.0; - } else { - signal1[i] = 0.0; - signal2[i] = 0.0; - signal3[i] = 0.0; - signal4[i] = 0.0; - out1[i] = 0.0; - out2[i] = 0.0; - } - } - - conv(signal1, signal2, out1, 64, 64); - conv_fft(signal3, signal4, out2, 128); - - for (size_t i = 0; i < 64; ++i) { - printf("%zu %f %+fi\n", i, creal(out1[i]) - creal(out2[i]), - cimag(out1[i]) - cimag(out2[i])); - } - - return 0; -} diff --git a/chapters/mathematical_background/convolutions/code/c/fft.h b/chapters/mathematical_background/convolutions/code/c/fft.h deleted file mode 100644 index de789f197..000000000 --- a/chapters/mathematical_background/convolutions/code/c/fft.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef FFT_H -#define FFT_H - -#include -#include - -void fft(double complex *X, size_t N) { - if (N >= 2) { - double complex tmp [N / 2]; - for (size_t i = 0; i < N / 2; ++i) { - tmp[i] = X[2 * i + 1]; - X[i] = X[2 * i]; - } - - for (size_t i = 0; i < N / 2; ++i) { - X[i + N / 2] = tmp[i]; - } - - fft(X, N / 2); - fft(X + N / 2, N / 2); - - for (size_t i = 0; i < N / 2; ++i) { - X[i + N/2] = X[i] - cexp(-2.0 * I * M_PI * i / N) * X[i + N / 2]; - X[i] -= (X[i + N / 2] - X[i]); - } - } -} - -void ifft(double complex *x, size_t n) { - for (size_t i = 0; i < n; ++i) { - x[i] = conj(x[i]); - } - - fft(x, n); - - for (size_t i = 0; i < n; ++i) { - x[i] = conj(x[i]) / n; - } -} - -#endif //FFT_H diff --git a/chapters/mathematical_background/convolutions/code/haskell/convolution.hs b/chapters/mathematical_background/convolutions/code/haskell/convolution.hs deleted file mode 100644 index 59bc1a135..000000000 --- a/chapters/mathematical_background/convolutions/code/haskell/convolution.hs +++ /dev/null @@ -1,5 +0,0 @@ -import Data.List (tails) - -convolution :: (Num a) => [a] -> [a] -> [a] -convolution x = map (sum . zipWith (*) (reverse x)) . spread - where spread = init . tails . (replicate (length x - 1) 0 ++) diff --git a/chapters/mathematical_background/convolutions/code/julia/conv.jl b/chapters/mathematical_background/convolutions/code/julia/conv.jl deleted file mode 100644 index 253a11d4f..000000000 --- a/chapters/mathematical_background/convolutions/code/julia/conv.jl +++ /dev/null @@ -1,22 +0,0 @@ -function conv(signal1::Vector{Complex}, signal2::Vector{Complex}) - n = length(signal1) + length(signal2) - out = Vector{Complex}(n) - sum = 0 - - for i = 0:n - for j = 0:i - if(j < length(signal1)) - sum += signal1[j] * signal2[i-j] - end - end - out[i] = sum - sum = 0 - end - - return out -end - -function conv_fft(signal1::Vector{Complex}, signal2::Vector{Complex}) - return ifft(fft(signal1).*fft(signal2)) -end - diff --git a/chapters/mathematical_background/convolutions/convolutions.md b/chapters/mathematical_background/convolutions/convolutions.md deleted file mode 100644 index 637c9b720..000000000 --- a/chapters/mathematical_background/convolutions/convolutions.md +++ /dev/null @@ -1,133 +0,0 @@ -# Convolutions -Alright, I am going to come right out and say it: convolutions can be confusing. -Not only are they hard to really describe, but if you do not see them in practice, it's hard to understand why you would ever want to use them. -I'm going to do what I can to describe them in an intuitive way; however, I may need to come back to this in the future. -Let me know if there is anything here that is unclear, and I'll do what I can to clear it up. - -If you take two functions $$f(x)$$ and $$g(x)$$, there are a number of ways you can combine them. -All basic operations can do this (addition, subtraction, multiplication, and division), but there are also special operations that only work with functions and do not work on standard variables or numbers. -For example, $$f \circ g$$ is a *composition* of the two functions, where you plug $$g(x)$$ into $$f(x)$$. -A convolution is another function-related operation, and is often notated with a star ($$*$$) operator, where - -$$f(x)*g(x)=c(x)$$ - -provides a third function $$c(x)$$ that blends $$f(x)$$ and $$g(x)$$. - -As a rather important side-note: there is an incredibly similar operator known as a *correlation* which will be discussed in the near future. -For now, let's focus on convolutions, which are defined as: - -$$(f*g)(x) = \int_{-\infty}^{\infty}f(\xi)g(x-\xi)d\xi = \int_{-\infty}^{\infty}f(x-\xi)g(\xi)d\xi$$ - -Note that in this case, $$x$$ is not necessarily a spatial element. -Often times, it is time or something else entirely! -The easiest way to think about this is that the function $$g(x)$$ is being shifted across all of space by the variable $$\xi$$. -At every point $$x$$, we multiply $$f(x)$$ and $$g(x)$$ and integrate the multiplied output to find the convolution for that spatial step, $$(f*g)(x)$$. -Note that in code, this is often discretized to look like: - -$$(f*g)[n] = \sum_{m = -\infty}^{\infty}f[m]g[n-m] = \sum_{m = -\infty}^{\infty}f[n-m]g[m]$$ - -Where `f[n]` and `g[n]` are arrays of some form. -This means we basically just need to keep one array steady, flip the second array around, and move it through the first array one step at a time, performing a simple element-wise multiplication each step. - - - - - -In code, this looks something like: - -{% method %} -{% sample lang="jl" %} -[import:1-17, lang:"julia"](code/julia/conv.jl) -{% sample lang="hs" %} -[import:1-5, lang:"haskell"](code/haskell/convolution.hs) -{% sample lang="c"%} -[import:5-18, lang:"c_cpp"](code/c/convolutions.c) -{% sample lang="cpp"%} -[import:68-88, lang:"c_cpp"](code/c++/convolutions.cpp) -{% endmethod %} - -Note that in this case, the output array will be the size of `f[n]` and `g[n]` put together. -Sometimes, though, we have an large size for `f[n]` and a small size for `g[n]`. -In this case `g[n]` is often called a *filter*, and often times when we are using a filter on an array (that might represent an image or some form of data), we want the output array to be the same size as the input. -In this case, rather than outputting a larger array, we often do something special at the borders of the array. -Depending on the situation, this may be necessary. -Note that there are different methods to deal with the edges in this case, so it's best to do whatever seems right when the situation arises. - -### Convolutional Theorem - -Now, let me tell you about a bit of black computational magic: - -**Convolutions can be performed with Fourier Transforms!** - -That is crazy! -It's also incredibly hard to explain, so let me do my best. -As described in the chapter on [Fourier Transforms](../cooley_tukey/cooley_tukey.md), Fourier Transforms allow programmers to move from real space to frequency space. -When we transform a wave into frequency space, we see a single peak in frequency space related to the frequency of that wave. -No matter what function we send into a Fourier Transform, the frequency-space image can be interpreted as a series of different waves with a specified frequency. - -So here's the idea: if we take two functions $$f(x)$$ and $$g(x)$$ and move them to frequency space to be $$\hat f(\xi)$$ and $$\hat g(\xi)$$, we can then multiply those two functions and transform them back into a third function to blend the signals together. -In this way, we will have a third function that relates the frequency-space images of the two input functions. -*This is precisely a convolution!* - -Don't believe me? -Well, this is because of something known as the *convolution theorem* which looks something like this: - -$$\mathcal{F}(f*g) = \mathcal{F}(f) \cdot \mathcal{F}(g)$$ - -Where $$\mathcal{F}$$ denotes the Fourier Transform. -Now, by using a Fast Fourier Transform (fft) in code, this can take a standard convolution on two arrays of length $$n$$, which is an $$\mathcal{O}(n^2)$$ process, to $$\mathcal{O}(n\log(n))$$. -This means that the convolution theorem is fundamental to creating fast convolutional methods for large inputs, assuming that both of the input signals are similar sizes. -That said, it is debatable whether the convolution theorem will be faster when the filter size is small. -Also: depending on the language used, we might need to read in a separate library for FFT's. - -{% method %} -{% sample lang="jl" %} -That said, Julia has an in-built fft routine, so the code for this method could not be simpler: -[import:19-22, lang:"julia"](code/julia/conv.jl) -Where the `.*` operator is an element-wise multiplication. -{% sample lang="hs" %} -The FFT-based convolution in Haskell is complicated, so here is some simple julia code: -[import:19-22, lang:"julia"](code/julia/conv.jl) -Where the `.*` operator is an element-wise multiplication. -{% sample lang="c"%} -[import:20-30, lang:"c_cpp"](code/c/convolutions.c) -{% sample lang="cpp"%} -[import:90-105, lang:"c_cpp"](code/c++/convolutions.cpp) -{% endmethod %} - -This method also has the added advantage that it will *always output an array of the size of your signal*; however, if your signals are not of equal size, we need to pad the smaller signal with zeros. -Also note that the Fourier Transform is a periodic or cyclical operation, so there are no real edges in this method, instead the arrays "wrap around" to the other side. -For this reason, this convolution is often called a *cyclic convolution* instead of a *linear convolution* like above. -Note that cyclic convolutions can definitely still be done without Fourier Transforms and we can do linear convolutions with Fourier Transforms, but it makes the code slightly more complicated than described above. - - - - -$$ -\newcommand{\d}{\mathrm{d}} -\newcommand{\bff}{\boldsymbol{f}} -\newcommand{\bfg}{\boldsymbol{g}} -\newcommand{\bfp}{\boldsymbol{p}} -\newcommand{\bfq}{\boldsymbol{q}} -\newcommand{\bfx}{\boldsymbol{x}} -\newcommand{\bfu}{\boldsymbol{u}} -\newcommand{\bfv}{\boldsymbol{v}} -\newcommand{\bfA}{\boldsymbol{A}} -\newcommand{\bfB}{\boldsymbol{B}} -\newcommand{\bfC}{\boldsymbol{C}} -\newcommand{\bfM}{\boldsymbol{M}} -\newcommand{\bfJ}{\boldsymbol{J}} -\newcommand{\bfR}{\boldsymbol{R}} -\newcommand{\bfT}{\boldsymbol{T}} -\newcommand{\bfomega}{\boldsymbol{\omega}} -\newcommand{\bftau}{\boldsymbol{\tau}} -$$ - diff --git a/chapters/mathematical_background/mathematical_background.md b/chapters/mathematical_background/mathematical_background.md deleted file mode 100644 index 7cad9457b..000000000 --- a/chapters/mathematical_background/mathematical_background.md +++ /dev/null @@ -1,13 +0,0 @@ -# Mathematical Background - -No matter who you ask, programming requires at least a little math. -That said, for most programmers, it doesn't require *too* much. -For the most part, depending on your specialty, you will probably not see too much calculus or differential equations. -Honestly, you could probably get away with what you learned in high school. - -However, this is a book about algorithms, and algorithms sometimes require a deeper understanding of mathematics. -This section attemps to provide the mathematical foundations that you will need to understand certain algorithms. -As we add new algorithms and need new mathematical tools, we will add them to this section. - -A notable exception to this rule will be in the case of classes of algorithms that require domain-specific knowledge, like quantum simulations or bioinformatics. -In those cases, we will place the mathematical methods in more relevant sections. diff --git a/chapters/mathematical_background/taylor_series/taylor_series.md b/chapters/mathematical_background/taylor_series/taylor_series.md deleted file mode 100644 index 4cf7df71f..000000000 --- a/chapters/mathematical_background/taylor_series/taylor_series.md +++ /dev/null @@ -1,68 +0,0 @@ -NOTE: Incomplete! - -# Taylor Series Expansion - -I have been formally trained as a physicist. In my mind, there are several mathematical topics that blur the boundary between mathematics and physics. Taylor Series Expansions are one of those topics. - -On the one hand, I can see how the expansion could be considered purely mathematical. I mean, here is the definition: -$$ -f(x) \simeq \sum_{n=0}^{\infty} \frac{f^{(n)}(a)}{n!}(x-a)^n -$$ - -where $$f(x)$$ is some function along real or complex space, $$a$$ is the point that we are expanding from, and $$f^{(n)}(x)$$ denotes the $$n^{\text{th}}$$ derivative of $$f(x)$$. -From this perspective, the expansion just looks like a bunch of derivatives strung together! Where's the physics? Well, let's expand this series for the first few derivatives: - -$$ -f(x) \simeq f(a) + \frac{df(a)}{dx}(x-a) - + \frac{1}{2}\frac{d^2f(a)}{dx^2}(x-a)^2 -$$ - -If we substitute the derivatives for their physical quantities with $$f(x) \rightarrow x(t)$$, expanding from 0, and set - -$$ -\begin{align} -\frac{dx(t)}{dt} &= \text{velocity} = v(t) \\ -\frac{d^2x(t)}{dt^2} &= \text{acceleration} = a \\ -\end{align} -$$ - -The Taylor series expansion turns into one of the most common formulas in classical physics, the *kinematic equation*! - -$$ -x(t) \simeq x_0 + v_0t - + \frac{1}{2}at^2 -$$ - -Note that here, we assume the acceleration to be constant, but it could technically have higher order terms. - -Truth be told, the Taylor Series Expansion can be found in the most unusual places and is used as the foundation of many different algorithms throughout this book. At first, it might not seem obvious why, but we can approximate almost any smooth function with a Taylor Series Expansion, and the more terms we include, the better our approximation becomes! For example, take Figure 1. Any function can be approximated as a sum of all the derivatives for that function. If we evaluate these derivatives at any point, we closely approximate the actual function. - -

- -

- -This shows the true power of the Taylor Series Expansion. It allows us to more easily tackle complicated functions by approximating them as functions we can actually use and imagine! - - -$$ -\newcommand{\d}{\mathrm{d}} -\newcommand{\bff}{\boldsymbol{f}} -\newcommand{\bfg}{\boldsymbol{g}} -\newcommand{\bfp}{\boldsymbol{p}} -\newcommand{\bfq}{\boldsymbol{q}} -\newcommand{\bfx}{\boldsymbol{x}} -\newcommand{\bfu}{\boldsymbol{u}} -\newcommand{\bfv}{\boldsymbol{v}} -\newcommand{\bfA}{\boldsymbol{A}} -\newcommand{\bfB}{\boldsymbol{B}} -\newcommand{\bfC}{\boldsymbol{C}} -\newcommand{\bfM}{\boldsymbol{M}} -\newcommand{\bfJ}{\boldsymbol{J}} -\newcommand{\bfR}{\boldsymbol{R}} -\newcommand{\bfT}{\boldsymbol{T}} -\newcommand{\bfomega}{\boldsymbol{\omega}} -\newcommand{\bftau}{\boldsymbol{\tau}} -$$ - diff --git a/chapters/mathematical_background/bitlogic/bitlogic.md b/chapters/principles_of_code/building_blocks/bitlogic.md similarity index 99% rename from chapters/mathematical_background/bitlogic/bitlogic.md rename to chapters/principles_of_code/building_blocks/bitlogic.md index 32898cd11..077356490 100644 --- a/chapters/mathematical_background/bitlogic/bitlogic.md +++ b/chapters/principles_of_code/building_blocks/bitlogic.md @@ -1,10 +1,10 @@ -# Bit Logic +### Bit Logic We write code in a language that makes a little sense to us, but does not make sense at all to our computer without a compiler to transform the code we write into a language the computer can understand. In the end, whenever we write code, all of the data structures we write are transformed into binary strings of 1's and 0's to be interpreted by our computer. That said, it's not always obvious how this happens, so let's start the simple case of integer numbers. -## Integers +#### Integers For integer numbers, 0 is still 0 and 1 is still 1; however, for 2, we need to use 2 digits because binary only has 0's and 1's. When we get to 4, we'll need 3 digits and when we get to 8, we'll need 4. Ever time we cross a power of 2, we'll need to add a new digit. Here's a table of the first 10 integers in binary: | Integer Number | Binary Number | @@ -45,7 +45,7 @@ Another method is to "roll over" to negative numbers when the bit count gets too Ultimately, integer numbers are not that difficult to deal with in binary, so let's move onto something more complicated: *floating-point numbers!* -## Floating-point Numbers +#### Floating-point Numbers Floats are numbers with a decimal point. 9.125 is a float. 9.000 is a float. 9 is an integer. Here are a few floats and their integer representations: diff --git a/chapters/principles_of_code/building_blocks/building_blocks.md b/chapters/principles_of_code/building_blocks/building_blocks.md new file mode 100644 index 000000000..12cf2b5ca --- /dev/null +++ b/chapters/principles_of_code/building_blocks/building_blocks.md @@ -0,0 +1,9 @@ +## Building Blocks + +When it comes to programming, there are certain features that will be used again and again, so it's a good idea to mention how these features work and where they are used. +This section attempts to explain anything that might confuse beginner programmers; however, it is not meant as an exhaustive list of every tool available in the coding toolbox. +Instead, it's meant to provide an accessible understanding of the data structures used throughout this text and the pseudocode that will be used to express these structures. + +It's worth pointing out that algorithms and data stuctures almost always go hand-in-hand. +There are many different ways to climb a mountain, but depending on the mountain you need to climb, you might need different tools. +Similarly, many different algorithms do similar tasks; however, with the right data structures, some algorithms become much more efficient than others. diff --git a/chapters/principles_of_code/building_blocks/classes.md b/chapters/principles_of_code/building_blocks/classes.md new file mode 100644 index 000000000..371894b1a --- /dev/null +++ b/chapters/principles_of_code/building_blocks/classes.md @@ -0,0 +1,26 @@ +### Classes and Structs + +A while ago, one of my friends asked me the purpose of classes in programming. +No matter what I did or how I tried to reason with him, I could not convince him that classes were useful and necessary programming constructs. +To put it simply, classes are data types that allow programmers to store multiple data types within them. +That said, depending on the language, classes might look slightly different. +For example, Julia forgoes classes altogether and simply allows programmers to define a type of types. +I am personally a fan of this approach and will be using it the bulk psuedocode for this text: + +```julia +type Human + Height::Float64 + Weight::Float64 + Popularity::Float64 +end +``` + +Now, here's where things get a little sticky. +The truth is that there is a philosophical difference between how languages implement classes (among other things), which basically boils down to whether languages allow functions to be held within data types or not. +*Functional* programming languages argue that functions should always act on data types. +*Object-Oriented* languages argue that certain data types (like Human, above), should be able to *do* things, so it makes sense to put functions within classes. +There is merit to both of these arguments, so it's best to go with whatever you feel comfortable with. + +In the case of object-oriented languages, classes have an additional layer of complexity associated with them that should definitely be discussed. +That said, I would like to forgo that discussion at this time and come back to it in the near future. +Please bug me if you think I might have forgotten! diff --git a/chapters/principles_of_code/building_blocks/conditions.md b/chapters/principles_of_code/building_blocks/conditions.md new file mode 100644 index 000000000..41a8ec979 --- /dev/null +++ b/chapters/principles_of_code/building_blocks/conditions.md @@ -0,0 +1,102 @@ +### Conditions + +Of all the programming building blocks, conditions might be the most intuitive and they basically flow from natural speech. +Let's say you are up late studying for an exam schedule for later in the month, but you are finding yourself lacking in motivation and distracted by the internet. +You hate wasting time, so you try to figure out how tired you are and think to yourself, *if I am tired, I will go to sleep. Otherwise, I should get back to work!* +In code, this looks like: + +```julia +if (me.tired() == true) + me.sleep() +else + me.work() +end +``` + +Here, we are assuming you are a type of `human` with the abilities to both `sleep()` and `work()`. +Note that the condition is checking to see if the statement provided is `true` or `false` before continuing. +In other words, it is condensing the statement `me.tired() == true` into a simple boolean value. +This is important to remember when dealing with loops later. +Conditions allow you to modify the flow of your program depending on other values produced and are a powerful and intuitive tool. + +It's worth noting here that all the mathematical conditions work in these statements: + +| Symbol | Meaning | +| --------------------------- | --------------------------------------- | +| a == b | a is equal to b | +| a > b | a is greater than b | +| a < b | a is less than b | +| a != b | a is not equal to b | +| a == b && b == c | a is equal to b **and** b is equal to c | +| a == b || b == c | a is equal to b **or** b is equal to c | + +Here, the `&&` operator means both conditions must be `true` for the statement as a whole to be considered `true`, while the `||` operator means that only one of the two statements must be `true` for the statement to be considered `true`. +Also note that the `!` operator can be used in front of boolean values to signify the value should be to opposite. +For example, if you are trying to indicate that you are not tired (even though you clearly are), you might say `!me.tired()`. +`me.tired()` will return `true`, but the `!` operator will flip the `true` to `false`. + +In addition to the `if` and `else` keywords, there is also the `else if`, which varies notationally depending on the language you are using. +Imagine that we wanted to add two additional functions to the `human` type: `care()`, which evaluates the amount you care about a particular topic and `procrastinate()`, which is the action of wasting time. +Imagine (again) that you are studying for an exam that is a month away, but this time, you are studying for a class you do not care about. +You might update your thought to be something like, *if I am tired, I will go to sleep. If I don't care about the class, I can continue procrastinating. Otherwise, I should get back to work!* +In code, this looks like: + +```julia +if (me.tired()) + me.sleep() +else if(!me.care()) + me.procrastinate() +else + me.work() +end +``` + +To be clear: if `me.care()` returns `true`, then the `!` will flip the statement in the `else if` to `false`, and thus you will not procrastinate. +If `me.care()` returns `false`, the `!` will flip the statement to `true` and you will begin procrastinating if you are not tired. +This might take a little thought, and I encourage you to meditate on it, if you so desire. + +Now on to something slightly more complicated: *switches*. +Imagine you have a lot of conditions to keep in mind, all of which depend on the same variable. +You couldgo through these conditions one-by-one with a chain of `if` and `else if` conditions, like so: + +```julia +if (val == 0) + scenario_0() +else if (val == 1) + scenario_1() +else if (val == 2) + scenario_2() +else if (val == 3) + scenario_3() +else + scenario_4() +end +``` +Here, we need to run different functions depending on the value of the variable `val`. +In these cases, it's worth bringing in a faster and sometimes more elegant solution: the `switch` statement. + +```julia +switch(val) + case 0: + scenario_0() + break + case 1: + scenario_1() + break + case 2: + scenario_2() + break + case 3: + scenario_3() + break + case 4: + scenario_4() + break +end +``` + + +To clarify: not all languages have a `switch` statement, and as mentioned, it's not precisely necessary. +That said, in languages that do have a `switch`, it's often preferred to a chain of `else if` statements; + +Though simple, conditions are essential to almost all modern code, so get used to seeing them everywhere! diff --git a/chapters/principles_of_code/building_blocks/functions.md b/chapters/principles_of_code/building_blocks/functions.md new file mode 100644 index 000000000..128441247 --- /dev/null +++ b/chapters/principles_of_code/building_blocks/functions.md @@ -0,0 +1,82 @@ +### Functions + +Functions make sense from a mathematical point of view. +$$f(x) = 2x+5$$ returns a value for $$f(x)$$ at any point $$x$$ that you want. +For example $$f(5) = 15$$, or $$f(10) = 25$$. +Often times, the function is graphed for *every point* indicating the precise nature of how the function and variable relate to one another, but that is another matter entirely. +For the most part, functions in programming work exactly the same way. +They are dependent on certain variables and return something at the end. +In code, the above function might look like: + +``` +function f(x) + return 2*x+5 +end +``` + +Syntactically, they are a little different, but the content is identical. +That said, it's not obvious how functions help when writing code at this point; however, this will become incredibly obvious once you see them in action. +Basically, functions allow programmers to create reusable operations that can be called at any point in the code. +In a sense, functions make understanding code much, much easier. + +### Recursion + +Simply put, recursion is the process of putting a function inside itself. +Now, I know what you are thinking, "Why does this deserve a special name?" +That is a very good question and one that tooke me a while to understand. +Let's take a simple example: + +```julia +function f(x) + x = x + 1 + f(x) +end +``` + +Every time `f(x)` is called, it calls `f(x)`, which then calls `f(x)` again and again and again... +Basically, we just replicated a `while` loop! +The problem here is that *we forgot a stop condition!* +This means that our function will run forever, constantly incrementing the value of x for all eternity! + +There are many possible solutions, one of which looks like this: + +```julia +function f(x, cutoff) + if (x < cutoff) + x = x + 1 + f(x) + end +end +``` + +In the end, no matter how you choose to use recursion, you need to think carefully about what you want the code to do. +For example, in the case shown here, recursion is definitely not the most straightforward way to increment the value of $$x$$ by $$1$$. +In some cases, though, recursion not only makes the code easier to use and understand, but it might also be the only way to solve a provided problem. +In addition, the proper use of recursion can speed up certain code tremendously. + +I guess the main point is this: *recursion is powerful, but with great power comes great resposibility!* + + + +$$ +\newcommand{\d}{\mathrm{d}} +\newcommand{\bff}{\boldsymbol{f}} +\newcommand{\bfg}{\boldsymbol{g}} +\newcommand{\bfp}{\boldsymbol{p}} +\newcommand{\bfq}{\boldsymbol{q}} +\newcommand{\bfx}{\boldsymbol{x}} +\newcommand{\bfu}{\boldsymbol{u}} +\newcommand{\bfv}{\boldsymbol{v}} +\newcommand{\bfA}{\boldsymbol{A}} +\newcommand{\bfB}{\boldsymbol{B}} +\newcommand{\bfC}{\boldsymbol{C}} +\newcommand{\bfM}{\boldsymbol{M}} +\newcommand{\bfJ}{\boldsymbol{J}} +\newcommand{\bfR}{\boldsymbol{R}} +\newcommand{\bfT}{\boldsymbol{T}} +\newcommand{\bfomega}{\boldsymbol{\omega}} +\newcommand{\bftau}{\boldsymbol{\tau}} +$$ + diff --git a/chapters/principles_of_code/building_blocks/loops.md b/chapters/principles_of_code/building_blocks/loops.md new file mode 100644 index 000000000..12062ff34 --- /dev/null +++ b/chapters/principles_of_code/building_blocks/loops.md @@ -0,0 +1,59 @@ +### Loops + +Loops are weird. I'm not going to lie, it took me a super long time to figure out how and when to use them appropriately. +Nowadays, I see them as essential elements to almost any program I write. +There two basic loop types: `for` and `while`, which are syntactically similar and reasonably intuitive. +Let's say you want to walk out of a room with a closed door. +In code, this might look something like: + +```julia +while(me.position < door.position) + me.take_step() +end + +me.open_door() +``` + +Like before, we assume that you are part of a type of `human`s with the functions `take_step()` and `open_door()`. +Here, the `while` loop simply keeps going until the condition is no longer met, and it's assumed that the `take_step()` function changes your `position` value. +When the condition returns `false`, we assume that you are either at the door or have run into it, so it's safe to assume you can use the `open_door()` function. + +The other possible loop type is the `for` loop, which is arguable more common and iterates through a container (such as `vectors` mentioned before). +Often times, the `for` loop will look something like this: + +```julia +for i = 1:10 + print(i) +end +``` + +In this case, we are creating a range of values between $$1$$ and $$10$$ and setting the value of $$i$$ every iteration of the loop. +In this case $$i$$ is an interable variable that steps through the range of `1:10`, and is the primary reason for using a `for` loop instead of a `while` loop for the same task. +To be clear, $$i$$ does not need to iterate through integers and could instead iterate through any number of types held in some other container. + +Ultimately, loops allow programmers to repeat the same operation multiple times and are the heart most programs and simulations I have seen. + + + +$$ +\newcommand{\d}{\mathrm{d}} +\newcommand{\bff}{\boldsymbol{f}} +\newcommand{\bfg}{\boldsymbol{g}} +\newcommand{\bfp}{\boldsymbol{p}} +\newcommand{\bfq}{\boldsymbol{q}} +\newcommand{\bfx}{\boldsymbol{x}} +\newcommand{\bfu}{\boldsymbol{u}} +\newcommand{\bfv}{\boldsymbol{v}} +\newcommand{\bfA}{\boldsymbol{A}} +\newcommand{\bfB}{\boldsymbol{B}} +\newcommand{\bfC}{\boldsymbol{C}} +\newcommand{\bfM}{\boldsymbol{M}} +\newcommand{\bfJ}{\boldsymbol{J}} +\newcommand{\bfR}{\boldsymbol{R}} +\newcommand{\bfT}{\boldsymbol{T}} +\newcommand{\bfomega}{\boldsymbol{\omega}} +\newcommand{\bftau}{\boldsymbol{\tau}} +$$ + diff --git a/chapters/mathematical_background/bitlogic/res/and.jpg b/chapters/principles_of_code/building_blocks/res/and.jpg similarity index 100% rename from chapters/mathematical_background/bitlogic/res/and.jpg rename to chapters/principles_of_code/building_blocks/res/and.jpg diff --git a/chapters/mathematical_background/bitlogic/res/nand.jpg b/chapters/principles_of_code/building_blocks/res/nand.jpg similarity index 100% rename from chapters/mathematical_background/bitlogic/res/nand.jpg rename to chapters/principles_of_code/building_blocks/res/nand.jpg diff --git a/chapters/mathematical_background/bitlogic/res/nor.jpg b/chapters/principles_of_code/building_blocks/res/nor.jpg similarity index 100% rename from chapters/mathematical_background/bitlogic/res/nor.jpg rename to chapters/principles_of_code/building_blocks/res/nor.jpg diff --git a/chapters/mathematical_background/bitlogic/res/not.jpg b/chapters/principles_of_code/building_blocks/res/not.jpg similarity index 100% rename from chapters/mathematical_background/bitlogic/res/not.jpg rename to chapters/principles_of_code/building_blocks/res/not.jpg diff --git a/chapters/mathematical_background/bitlogic/res/or.jpg b/chapters/principles_of_code/building_blocks/res/or.jpg similarity index 100% rename from chapters/mathematical_background/bitlogic/res/or.jpg rename to chapters/principles_of_code/building_blocks/res/or.jpg diff --git a/chapters/mathematical_background/bitlogic/res/xor.jpg b/chapters/principles_of_code/building_blocks/res/xor.jpg similarity index 100% rename from chapters/mathematical_background/bitlogic/res/xor.jpg rename to chapters/principles_of_code/building_blocks/res/xor.jpg diff --git a/chapters/data_structures/stacks_and_queues/stacks_and_queues.md b/chapters/principles_of_code/building_blocks/stacks.md similarity index 100% rename from chapters/data_structures/stacks_and_queues/stacks_and_queues.md rename to chapters/principles_of_code/building_blocks/stacks.md diff --git a/chapters/principles_of_code/building_blocks/variables.md b/chapters/principles_of_code/building_blocks/variables.md new file mode 100644 index 000000000..a27ea350c --- /dev/null +++ b/chapters/principles_of_code/building_blocks/variables.md @@ -0,0 +1,113 @@ +### Variable and Types + +For many people, declaring variables and types is a straightforward process. +The idea is simple: variables hold values. +We set these values with the `=` sign. +For example, if we say + +``` +x = 5 +``` +Then we have set the value of the variable $$x$$ to be $$5$$. +But here's a question that your computer has to answer: what is $$5$$? + +To us, the answer's trivial, it's a number! +This is true, but there are different kinds of numbers. +There are integers that include all counting numbers from negative to positive infinity: $$-\infty, \cdots, -1, 0, 1, \cdots, \infty$$. +Then there are floating-point numbers which include everything in-between every counting number; however, that is not the end of the story. +Floating-point numbers also have certain levels of precision, the numbers of $$0$$'s after the decimal point. +For example, $$1.01$$ is more precise than $$1.0$$. +Each of these levels of precision will require a different level of storage space on the computer, so it make sense to differentiate them based on the amount of storage they require. +In the end, all of these variables will be stored as some number, $$n$$, binary bits, which are constrained to be either $$0$$ or $$1$$ and as we increase the number of bits, we can hold $$2^n$$ possible values. + +This means that we have multiple different floating-point and integer types: `float16`, `int16`, `float32`, `int32`, `float64`, `int64`, and so on. +Here, the number ($$16, 32, 64,\cdots$$) at the end of the declared variable corresponds to the number of bits used to represent that number. +For the most part, *double precision* or `float64` is good enough for almost all computation; however, sometimes higher precision is necessary and other times lower precision will speed up computation tremendously. + +Most languages allow you to explicitly state the type of every variable, but some languages may treat these variables differently than expected, depending on the type provided. +For example: + +``` +float x = 5 +int y = 5 + +print(1/x) +print(1/y) +``` + +---- +**OUTPUT** +``` +0.2 +0 +``` + +Here, the same mathematical expression provided two radically different results! +Now, you might be thinking that the first output is *more correct*, but this is not exactly true. +The second expression was simply a case of *integer division* and is useful in many cases. +Unfortunately, it is also a notorious source of errors, which is why it's always a good idea to check the types of all variables in a program just to be sure you are doing the appropriate computation. +To be explicit: + +``` +1/5 != 1.0/5.0 +``` + +It's important to keep in mind what you are trying to say and what your computer hears you saying. + +Now, variables do not need to be explicitly numbers. +They can be strings (`"hello world!"`), or any data structure you could want. +These data structures will interact with each other differently and these interactions are sometimes language-dependent, so be careful when working with them! +In addition, some of these data structures have functions unique to them that me may call upon as programmers. + +For example, `vectors` are data containers that hold other data structures. +In almost every language, there is a function that can be used to get the size of a `vector` in order to tell how many elements it holds. +In addition, the vector also has methods to `push` elements into it. + +In C++, for example, vectors often look like this: + +```cpp +#include + +... +// Creating a vector of integers +std::vector vector_of_ints; + +//Adding elements to our vector_of_ints +vector_of_ints.push_back(1); +vector_of_ints.push_back(2); +vector_of_ints.push_back(3); + +// Finding size of our vector_of_ints +vector_of_ints.size(); + +... +``` + +Here, the `size()` function should return 3, because we have put in 3 elements. +We will talk more about vectors in a bit, but for now, know that certain functions are available to be used on certain types, and in most object-oriented languages, these functions are called with a simple `.`. +Almost all laguages also allow users to define their own types in the form of `classes`, which will also be touched on later in this section. + + + +$$ +\newcommand{\d}{\mathrm{d}} +\newcommand{\bff}{\boldsymbol{f}} +\newcommand{\bfg}{\boldsymbol{g}} +\newcommand{\bfp}{\boldsymbol{p}} +\newcommand{\bfq}{\boldsymbol{q}} +\newcommand{\bfx}{\boldsymbol{x}} +\newcommand{\bfu}{\boldsymbol{u}} +\newcommand{\bfv}{\boldsymbol{v}} +\newcommand{\bfA}{\boldsymbol{A}} +\newcommand{\bfB}{\boldsymbol{B}} +\newcommand{\bfC}{\boldsymbol{C}} +\newcommand{\bfM}{\boldsymbol{M}} +\newcommand{\bfJ}{\boldsymbol{J}} +\newcommand{\bfR}{\boldsymbol{R}} +\newcommand{\bfT}{\boldsymbol{T}} +\newcommand{\bfomega}{\boldsymbol{\omega}} +\newcommand{\bftau}{\boldsymbol{\tau}} +$$ + diff --git a/chapters/languages/choosing_a_language.md b/chapters/principles_of_code/choosing_a_language/choosing_a_language.md similarity index 100% rename from chapters/languages/choosing_a_language.md rename to chapters/principles_of_code/choosing_a_language/choosing_a_language.md diff --git a/chapters/languages/compiled/FORTRAN.md b/chapters/principles_of_code/choosing_a_language/compiled/FORTRAN.md similarity index 100% rename from chapters/languages/compiled/FORTRAN.md rename to chapters/principles_of_code/choosing_a_language/compiled/FORTRAN.md diff --git a/chapters/languages/compiled/compiled.md b/chapters/principles_of_code/choosing_a_language/compiled/compiled.md similarity index 100% rename from chapters/languages/compiled/compiled.md rename to chapters/principles_of_code/choosing_a_language/compiled/compiled.md diff --git a/chapters/languages/compiled/makefiles.md b/chapters/principles_of_code/choosing_a_language/compiled/makefiles.md similarity index 100% rename from chapters/languages/compiled/makefiles.md rename to chapters/principles_of_code/choosing_a_language/compiled/makefiles.md diff --git a/chapters/principles_of_code/code_quality.md b/chapters/principles_of_code/code_quality.md new file mode 100644 index 000000000..c4ed35ac2 --- /dev/null +++ b/chapters/principles_of_code/code_quality.md @@ -0,0 +1,19 @@ +## Code Quality + +I am a computational physicist. Industry programmers give researchers a hard time for their programming capabilities, not because they cannot code, but because (for the most part) research code looks bad. +Programming, like any other form of creative expression, is limited by the artist's ability to creatively express themselves. +For many computational researchers, the code is not their art. Science is. +Programming is simply the brush they use to stroke the canvas of reality. +Many times, they become so consumed with their painting that they ignore their tools. Now, truth be told, I have seen some pretty repulsive industry code, too, so this complaint is not exclusively biased towards researchers. + +No matter what the intended goal might be, it is important to be able to read and understand the code you are writing. I know putting a comment block at the start of programs might seem like a chore, but it's not so bad, and letting everyone know up-front what the code is intended to do is incredibly useful to readers. Remember that in a few months, you will be a reader too. Take the time to properly care for your code, to clean your brush after using it. It'll pay off in the long run, I promise. + +### Comments / style + +Comments. Every language has a different way to introduce them. Some use the noble #, others the //, still others the ! or $ or C. Regardless of your language of choice, every single language offers you the ability to tell readers what you are intending to do with your code. This is a necessary component to programming. In fact, I would argue that it is one of the most useful part of any code. Sure, the code has to work. It's gotta compile and do something useful, but I cannot tell you how many times I have had to fix broken code that no one had looked at for years. Sometimes this is a long and laborious process, taking every ounce of my mental abilities, and other times it only takes a few minutes. What's the difference? Comments and documentation. + +I remember the first time I learned to program, I found commenting tedious. I remember thinking, "Hah. This is completely useless. Any programmer worth their salt will be able to figure out what I am trying to do in no time!" Turns out, I wasn't worth my salt because after trying to figure out my code a month later, I couldn't figure out what on Earth I was trying to do. Here's the truth: when it comes to programming, you are often your own audience. Trust me, I know it seems like a good idea to keep the code short -- to go for witty one-liners that make you feel brilliant, but these make your code impossible to read. + +When researching, we keep lab notebooks. It's common practice for obvious reasons. If I forget what I was doing the other day or need to look up parameters, I check the lab notebook. If other researchers question the results of my simulations, I check my lab notebook. If I don't know what to do because I have tried everything I can possibly think of, I check my lab notebook. It's a place for inspiration, for validation, and for guidance. When programming, your code should tell the story of your program. It should reveal the hidden secrets that make your code tick. If anyone finds a bug in the code downstream, they should be able to figure out exactly what went wrong and fix it themselves. + +I guess my point is that commenting your code and keeping proper documentation is about more than just cleaning up after yourself. It is a fundamental part to the art of programming. It's like polishing your guitar on a sunny day. It's revising your poems after a long evening of writing. It's levelling your monk before the next raid. It's essential. Do not neglect it! diff --git a/chapters/mathematical_background/notation/notation.md b/chapters/principles_of_code/notation/notation.md similarity index 100% rename from chapters/mathematical_background/notation/notation.md rename to chapters/principles_of_code/notation/notation.md diff --git a/chapters/mathematical_background/notation/out.dat b/chapters/principles_of_code/notation/out.dat similarity index 100% rename from chapters/mathematical_background/notation/out.dat rename to chapters/principles_of_code/notation/out.dat diff --git a/chapters/mathematical_background/notation/res/cplot.png b/chapters/principles_of_code/notation/res/cplot.png similarity index 100% rename from chapters/mathematical_background/notation/res/cplot.png rename to chapters/principles_of_code/notation/res/cplot.png diff --git a/chapters/principles_of_code/principles_of_code.md b/chapters/principles_of_code/principles_of_code.md new file mode 100644 index 000000000..7e7a58ec3 --- /dev/null +++ b/chapters/principles_of_code/principles_of_code.md @@ -0,0 +1,30 @@ +# The Principles of Code + +At least to me, programming is a form of creative expression. Sure, programming is difficult. It's difficult in the same way that art, music, or writing is difficult: you know exactly what you want to create, but it takes time to learn how to create it. As I mentioned previously, for a significant portion of my life, I wanted to be an author, so I spent hours and hours every day writing fantasy novels. The more I wrote, the better I got at writing, but when I went back to read the initial chapters of my books, I was frankly revolted at how poor my writing was. By the time I finished revising those chapters and writing more on the side, I felt that the second half of the story was in need of revision too. In the end, I wrote and re-wrote and re-wrote again until I was sick of the story altogether, so I wrote something else. Same characters, different story. It was a vicious cycle that ultimately lead to failure on my part to publish anything. + +Here's that cycle again in code: + +```julia +type Human + ability::Int64 + standard::Int64 +end + +function create_something(me::Human) + while (me.ability < me.standard) + me.ability += 1 + me.standard += 1 + println("I am not good enough. Continuing...") + end +end + +create_something(Human(0,1)) +``` + +I am sure this has a name, but I like to call it the *perfectionist's loop*. It's obviously endless and the only way out is by forcing the code to terminate early with `ctrl+c`. Any artist knows this problem. At first, the act of creation is fun, but after a few iterations, it becomes frustrating. Soon, you are curled into a ball in the corner of a room with a paintbrush in your hand and a myriad of colors splattered all over you and the immediate area. In front of you lay the remains of your art, toppled to the ground. It happens. It will probably happen when you learn programming. When it happens, there is only one thing to do: *keep iterating through the loop!* + +The moment you press `ctrl+c` is the moment you stop improving. Don't stop improving. Don't lower your standards. If you ever need motivation to continue, look at who you were a few months ago. You should be "better" than that person. If not, figure out what's holding you back and keep iterating through the loop! + +The problem is that when it comes to programming, there are a bunch of technical problems that crop up and prevent us from improving. This chapter is specifically written to help you make decisions and improve your ability to program. We'll start with choosing a language -- a question that kept me from even starting programming to begin with. Then we'll move on to programming building blocks and important data structures to remember. The idea is that we'll link to the building block sections when necessary throughout the book. This section will probably be the section that changes the most frequently as the archive evolves. after all, the more algorithms we cover, the more building blocks will be necessary to write them. + +As always, let me know if there's anything that is unclear or you think needs to be fixed! Thanks for reading and good luck! diff --git a/chapters/introduction/res/clone.png b/chapters/principles_of_code/res/clone.png similarity index 100% rename from chapters/introduction/res/clone.png rename to chapters/principles_of_code/res/clone.png diff --git a/chapters/introduction/res/fork.png b/chapters/principles_of_code/res/fork.png similarity index 100% rename from chapters/introduction/res/fork.png rename to chapters/principles_of_code/res/fork.png diff --git a/chapters/introduction/version_control.md b/chapters/principles_of_code/version_control.md similarity index 100% rename from chapters/introduction/version_control.md rename to chapters/principles_of_code/version_control.md From 56d2ab10d0a1de272d97e455e8da239d981d9325 Mon Sep 17 00:00:00 2001 From: leios Date: Tue, 17 Jul 2018 20:04:23 +0900 Subject: [PATCH 3/3] changing function to output velocity at the end. --- .../verlet_integration/code/julia/verlet.jl | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/chapters/algorithms/verlet_integration/code/julia/verlet.jl b/chapters/algorithms/verlet_integration/code/julia/verlet.jl index ff78a149b..0b0dd6a68 100644 --- a/chapters/algorithms/verlet_integration/code/julia/verlet.jl +++ b/chapters/algorithms/verlet_integration/code/julia/verlet.jl @@ -9,7 +9,7 @@ function verlet(pos::Float64, acc::Float64, dt::Float64) prev_pos = temp_pos end - println(time) + return time end function stormer_verlet(pos::Float64, acc::Float64, dt::Float64) @@ -27,7 +27,7 @@ function stormer_verlet(pos::Float64, acc::Float64, dt::Float64) vel += acc*dt end - println(time) + return time, vel end function velocity_verlet(pos::Float64, acc::Float64, dt::Float64) @@ -41,13 +41,20 @@ function velocity_verlet(pos::Float64, acc::Float64, dt::Float64) vel += acc * dt; end - println(time) + return time, vel end function main() - verlet(5.0, -10.0, 0.01); - stormer_verlet(5.0, -10.0, 0.01); - velocity_verlet(5.0, -10.0, 0.01); + time = verlet(5.0, -10.0, 0.01); + println("Time for Verlet integration is: $(time)\n") + + time, vel = stormer_verlet(5.0, -10.0, 0.01); + println("Time for Stormer Verlet integration is: $(time)") + println("Velocity for Stormer Verlet integration is: $(vel)\n") + + time, vel = velocity_verlet(5.0, -10.0, 0.01); + println("Time for velocity Verlet integration is: $(time)") + println("Velocity for velocity Verlet integration is: $(vel)\n") end main()